diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index dc527cbc..f7f58a12 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -7,6 +7,27 @@ import std.conv; mixin APP_ENTRY_POINT; +Widget createEditorSettingsControl(EditWidgetBase editor) { + HorizontalLayout res = new HorizontalLayout("editor_options"); + res.addChild((new CheckBox("wantTabs", "wantTabs"d)).checked(editor.wantTabs).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.wantTabs = checked; return true;})); + res.addChild((new CheckBox("useSpacesForTabs", "useSpacesForTabs"d)).checked(editor.useSpacesForTabs).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.useSpacesForTabs = checked; return true;})); + res.addChild((new CheckBox("fixedFont", "fixedFont"d)).checked(editor.fontFamily == FontFamily.MonoSpace).addOnCheckChangeListener(delegate(Widget, bool checked) { + if (checked) + editor.fontFamily(FontFamily.MonoSpace).fontFace("Courier New"); + else + editor.fontFamily(FontFamily.SansSerif).fontFace("Arial"); + return true; + })); + res.addChild((new CheckBox("tabSize", "Tab size 8"d)).checked(editor.tabSize == 8).addOnCheckChangeListener(delegate(Widget, bool checked) { + if (checked) + editor.tabSize(8); + else + editor.tabSize(4); + return true; + })); + return res; +} + /// entry point for dlangui based application extern (C) int UIAppMain(string[] args) { // resource directory search paths @@ -140,31 +161,36 @@ extern (C) int UIAppMain(string[] args) { tabs.addTab((new TextWidget()).id("tab4").textColor(0x00802000).text("Tab 4 contents some long string"), "Tab 4"d); tabs.addTab((new TextWidget()).id("tab5").textColor(0x00802000).text("Tab 5 contents"), "Tab 5"d); + //========================================================================== // create Editors test tab - VerticalLayout editors = new VerticalLayout("editors"); - editors.addChild(new TextWidget(null, "EditLine(Single line editor)"d)); + // EditLine sample + editors.addChild(new TextWidget(null, "EditLine: Single line editor"d)); EditLine editLine = new EditLine("editline1", "Single line editor sample text"); + editors.addChild(createEditorSettingsControl(editLine)); editors.addChild(editLine); - editors.addChild(new TextWidget(null, "EditBox(Multiline editor)"d)); - EditBox editBox = new EditBox("editbox1", "Some text\nSecond line\nYet another line"d); + // EditBox sample + editors.addChild(new TextWidget(null, "EditBox: Multiline editor"d)); + + EditBox editBox = new EditBox("editbox1", "Some text\nSecond line\nYet another line\n\n\tforeach(s;lines);\n\t\twriteln(s);\n"d); editBox.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); dstring text = editBox.text; for (int i = 0; i < 100; i++) { text ~= "\n Line "; - text ~= to!dstring(i + 3); + text ~= to!dstring(i + 5); text ~= " Some long long line. Blah blah blah."; for (int j = 0; j <= i % 4; j++) text ~= " The quick brown fox jumps over the lazy dog."; - text ~= "End of line "; - text ~= to!dstring(i + 3); } editBox.text = text; + editors.addChild(createEditorSettingsControl(editBox)); editors.addChild(editBox); - tabs.addTab(editors, "EditBox"d); + tabs.addTab(editors, "Editors"d); + + //========================================================================== tabs.selectTab("tab1"); diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 8d0dab45..02ec4c10 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -739,12 +739,8 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { protected void updateFontProps() { FontRef font = font(); - _fixedFont = false; - _spaceWidth = font.textSize(" "d).x; - int mwidth = font.textSize("M"d).x; - int iwidth = font.textSize("i"d).x; - if (mwidth == iwidth) - _fixedFont = true; + _fixedFont = font.isFixed; + _spaceWidth = font.spaceWidth; _lineHeight = font.height; } @@ -1149,6 +1145,14 @@ class EditWidgetBase : WidgetGroup, EditableContentListener { } } + /// map key to action + override protected Action findKeyAction(uint keyCode, uint flags) { + // don't handle tabs when disabled + if (keyCode == KeyCode.TAB && (flags == 0 || flags == KeyFlag.Shift) && !_wantTabs) + return null; + return super.findKeyAction(keyCode, flags); + } + /// handle keys override bool onKeyEvent(KeyEvent event) { // @@ -1267,7 +1271,7 @@ class EditLine : EditWidgetBase { //Point sz = font.textSize(text); _measuredText = text; _measuredTextWidths.length = _measuredText.length; - int charsMeasured = font.measureText(_measuredText, _measuredTextWidths, int.max); + int charsMeasured = font.measureText(_measuredText, _measuredTextWidths, int.max, tabSize); _measuredTextSize.x = charsMeasured > 0 ? _measuredTextWidths[charsMeasured - 1]: 0; _measuredTextSize.y = font.height; return _measuredTextSize; @@ -1354,7 +1358,7 @@ class EditLine : EditWidgetBase { dstring txt = text; Point sz = font.textSize(txt); //applyAlign(rc, sz); - font.drawText(buf, rc.left - _scrollPos.x, rc.top + sz.y / 10, txt, textColor); + font.drawText(buf, rc.left - _scrollPos.x, rc.top + sz.y / 10, txt, textColor, tabSize); if (focused) { // draw caret Rect caretRc = textPosToClient(_caretPos); @@ -1419,7 +1423,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { for (int i = 0; i < _numVisibleLines; i++) { _visibleLines[i] = _content[_firstVisibleLine + i]; _visibleLinesMeasurement[i].length = _visibleLines[i].length; - int charsMeasured = font.measureText(_visibleLines[i], _visibleLinesMeasurement[i], int.max); + int charsMeasured = font.measureText(_visibleLines[i], _visibleLinesMeasurement[i], int.max, tabSize); _visibleLinesWidths[i] = charsMeasured > 0 ? _visibleLinesMeasurement[i][charsMeasured - 1] : 0; if (sz.x < _visibleLinesWidths[i]) sz.x = _visibleLinesWidths[i]; // width - max from visible lines @@ -1698,8 +1702,9 @@ class EditBox : EditWidgetBase, OnScrollHandler { /// override to custom highlight of line background protected void drawLineBackground(DrawBuf buf, int lineIndex, Rect lineRect, Rect visibleRect) { - if (lineIndex & 1) - buf.fillRect(visibleRect, 0xF4808080); + // highlight odd lines + //if ((lineIndex & 1)) + // buf.fillRect(visibleRect, 0xF4808080); if (!_selectionRange.empty && _selectionRange.start.line <= lineIndex && _selectionRange.end.line >= lineIndex) { // line inside selection @@ -1716,7 +1721,8 @@ class EditBox : EditWidgetBase, OnScrollHandler { } } - if (lineIndex == _caretPos.line) { + // frame around current line + if (lineIndex == _caretPos.line && _selectionRange.singleLine && _selectionRange.start.line == _caretPos.line) { buf.drawFrame(visibleRect, 0xA0808080, Rect(1,1,1,1)); } } @@ -1747,7 +1753,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { visibleRect.right = _clientRc.right; drawLineBackground(buf, _firstVisibleLine + i, lineRect, visibleRect); if (txt.length > 0) { - font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor); + font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor, tabSize); } } diff --git a/src/dlangui/widgets/styles.d b/src/dlangui/widgets/styles.d index a2f378b2..b915fc2a 100644 --- a/src/dlangui/widgets/styles.d +++ b/src/dlangui/widgets/styles.d @@ -714,13 +714,13 @@ Theme createDefaultTheme() { //listItem.createState(State.Enabled, 0).textColor(0x80000000); // half transparent text for disabled item Style editLine = res.createSubstyle("EDIT_LINE").backgroundImageId("editbox_background").padding(Rect(5,6,5,6)).margins(Rect(2,2,2,2)).minWidth(40); - editLine.fontFace("Courier New").fontFamily(FontFamily.MonoSpace); + editLine.fontFace("Arial").fontFamily(FontFamily.SansSerif).fontSize(16); Style editBox = res.createSubstyle("EDIT_BOX").backgroundImageId("editbox_background").padding(Rect(5,6,5,6)).margins(Rect(2,2,2,2)).minWidth(100).minHeight(60); - editBox.fontFace("Courier New").fontFamily(FontFamily.MonoSpace); + editBox.fontFace("Courier New").fontFamily(FontFamily.MonoSpace).fontSize(16); return res; } shared static ~this() { currentTheme = null; -} \ No newline at end of file +} diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index 1bf7b894..253d9c92 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -216,7 +216,11 @@ class Widget { /// get margins (between widget bounds and its background) @property Rect margins() const { return style.margins; } /// set margins for widget - override one from style - @property Widget margins(Rect rc) { ownStyle.margins = rc; return this; } + @property Widget margins(Rect rc) { + ownStyle.margins = rc; + requestLayout(); + return this; + } /// get padding (between background bounds and content of widget) @property Rect padding() const { // get max padding from style padding and background drawable padding @@ -236,39 +240,75 @@ class Widget { return p; } /// set padding for widget - override one from style - @property Widget padding(Rect rc) { ownStyle.padding = rc; return this; } + @property Widget padding(Rect rc) { + ownStyle.padding = rc; + requestLayout(); + return this; + } /// returns background color @property uint backgroundColor() const { return stateStyle.backgroundColor; } /// set background color for widget - override one from style - @property Widget backgroundColor(uint color) { ownStyle.backgroundColor = color; return this; } + @property Widget backgroundColor(uint color) { + ownStyle.backgroundColor = color; + invalidate(); + return this; + } /// get text color (ARGB 32 bit value) @property uint textColor() const { return stateStyle.textColor; } /// set text color (ARGB 32 bit value) - @property Widget textColor(uint value) { ownStyle.textColor = value; return this; } + @property Widget textColor(uint value) { + ownStyle.textColor = value; + invalidate(); + return this; + } /// returns font face @property string fontFace() const { return stateStyle.fontFace; } /// set font face for widget - override one from style - @property Widget fontFace(string face) { ownStyle.fontFace = face; return this; } + @property Widget fontFace(string face) { + ownStyle.fontFace = face; + requestLayout(); + return this; + } /// returns font style (italic/normal) @property bool fontItalic() const { return stateStyle.fontItalic; } /// set font style (italic/normal) for widget - override one from style - @property Widget fontItalic(bool italic) { ownStyle.fontStyle = italic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL; return this; } + @property Widget fontItalic(bool italic) { + ownStyle.fontStyle = italic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL; + requestLayout(); + return this; + } /// returns font weight @property ushort fontWeight() const { return stateStyle.fontWeight; } /// set font weight for widget - override one from style - @property Widget fontWeight(ushort weight) { ownStyle.fontWeight = weight; return this; } + @property Widget fontWeight(ushort weight) { + ownStyle.fontWeight = weight; + requestLayout(); + return this; + } /// returns font size in pixels @property ushort fontSize() const { return stateStyle.fontSize; } /// set font size for widget - override one from style - @property Widget fontSize(ushort size) { ownStyle.fontSize = size; return this; } + @property Widget fontSize(ushort size) { + ownStyle.fontSize = size; + requestLayout(); + return this; + } /// returns font family @property FontFamily fontFamily() const { return stateStyle.fontFamily; } /// set font family for widget - override one from style - @property Widget fontFamily(FontFamily family) { ownStyle.fontFamily = family; return this; } + @property Widget fontFamily(FontFamily family) { + ownStyle.fontFamily = family; + requestLayout(); + return this; + } /// returns alignment (combined vertical and horizontal) @property ubyte alignment() const { return style.alignment; } /// sets alignment (combined vertical and horizontal) - @property Widget alignment(ubyte value) { ownStyle.alignment = value; return this; } + @property Widget alignment(ubyte value) { + ownStyle.alignment = value; + requestLayout(); + return this; + } /// returns horizontal alignment @property Align valign() { return cast(Align)(alignment & Align.VCenter); } /// returns vertical alignment @@ -468,10 +508,16 @@ class Widget { return res; } + /// map key to action + protected Action findKeyAction(uint keyCode, uint flags) { + Action action = _acceleratorMap.findByKey(keyCode, flags); + return action; + } + /// process key event, return true if event is processed. bool onKeyEvent(KeyEvent event) { if (event.action == KeyAction.KeyDown) { - Action action = _acceleratorMap.findByKey(event.keyCode, event.flags & (KeyFlag.Shift | KeyFlag.Alt | KeyFlag.Control)); + Action action = findKeyAction(event.keyCode, event.flags & (KeyFlag.Shift | KeyFlag.Alt | KeyFlag.Control)); if (action !is null) { return handleAction(action); } @@ -559,6 +605,24 @@ class Widget { /// focus state change event listener (bool delegate(Widget, bool)) Signal!OnFocusHandler onFocusChangeListener; + /// helper function to add onCheckChangeListener in method chain + Widget addOnClickListener(bool delegate(Widget) listener) { + onClickListener.connect(listener); + return this; + } + + /// helper function to add onCheckChangeListener in method chain + Widget addOnCheckChangeListener(bool delegate(Widget, bool) listener) { + onCheckChangeListener.connect(listener); + return this; + } + + /// helper function to add onFocusChangeListener in method chain + Widget addOnFocusChangeListener(bool delegate(Widget, bool) listener) { + onFocusChangeListener.connect(listener); + return this; + } + // ======================================================= // Layout and measurement methods