diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index fc522298..1f721af7 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -24,6 +24,7 @@ module dlangui.widgets.editors; import dlangui.widgets.widget; import dlangui.widgets.controls; +import dlangui.widgets.scroll; import dlangui.core.signals; import dlangui.core.collections; import dlangui.platforms.common.platform; @@ -807,9 +808,8 @@ class EditableContent { } /// base for all editor widgets -class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandler { +class EditWidgetBase : ScrollWidget, EditableContentListener, MenuItemActionHandler { protected EditableContent _content; - protected Rect _clientRc; protected int _lineHeight; protected Point _scrollPos; @@ -830,8 +830,8 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl protected uint _selectionColorNormal = 0xD060A0FF; - this(string ID) { - super(ID); + this(string ID, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { + super(ID, hscrollbarMode, vscrollbarMode); focusable = true; acceleratorMap.add( [ new Action(EditorActions.Up, KeyCode.UP, 0), @@ -922,6 +922,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl return false; return true; } + /// override to change popup menu items state override bool isActionEnabled(const Action action) { switch (action.id) { @@ -1130,7 +1131,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl caretRc.right += _spaceWidth; } } - caretRc.offset(_clientRc.left, _clientRc.top); + caretRc.offset(_clientRect.left, _clientRect.top); return caretRc; } @@ -1139,7 +1140,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl if (focused) { // draw caret Rect caretRc = caretRect(); - if (caretRc.intersects(_clientRc)) { + if (caretRc.intersects(_clientRect)) { Rect rc1 = caretRc; rc1.right = rc1.left + 1; caretRc.left++; @@ -1669,12 +1670,12 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl // support onClick if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { setFocus(); - updateCaretPositionByMouse(event.x - _clientRc.left, event.y - _clientRc.top, false); + updateCaretPositionByMouse(event.x - _clientRect.left, event.y - _clientRect.top, false); invalidate(); return true; } if (event.action == MouseAction.Move && (event.flags & MouseButton.Left) != 0) { - updateCaretPositionByMouse(event.x - _clientRc.left, event.y - _clientRc.top, true); + updateCaretPositionByMouse(event.x - _clientRect.left, event.y - _clientRect.top, true); return true; } if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { @@ -1713,7 +1714,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl class EditLine : EditWidgetBase { this(string ID, dstring initialContent = null) { - super(ID); + super(ID, ScrollBarMode.Invisible, ScrollBarMode.Invisible); _content = new EditableContent(false); _content.contentChangeListeners = this; wantTabs = false; @@ -1727,7 +1728,7 @@ class EditLine : EditWidgetBase { override protected Rect textPosToClient(TextPosition p) { Rect res; - res.bottom = _clientRc.height; + res.bottom = _clientRect.height; if (p.pos == 0) res.left = 0; else if (p.pos >= _measuredText.length) @@ -1760,13 +1761,13 @@ class EditLine : EditWidgetBase { Rect rc = textPosToClient(_caretPos); if (rc.left < 0) { // scroll left - _scrollPos.x -= -rc.left + _clientRc.width / 10; + _scrollPos.x -= -rc.left + _clientRect.width / 10; if (_scrollPos.x < 0) _scrollPos.x = 0; invalidate(); - } else if (rc.left >= _clientRc.width - 10) { + } else if (rc.left >= _clientRect.width - 10) { // scroll right - _scrollPos.x += (rc.left - _clientRc.width) + _spaceWidth * 4; + _scrollPos.x += (rc.left - _clientRect.width) + _spaceWidth * 4; invalidate(); } updateScrollbars(); @@ -1819,16 +1820,16 @@ class EditLine : EditWidgetBase { /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). override void layout(Rect rc) { - _needLayout = false; if (visibility == Visibility.Gone) { return; } + _needLayout = false; Point sz = Point(rc.width, measuredHeight); applyAlign(rc, sz); _pos = rc; - _clientRc = rc; - applyMargins(_clientRc); - applyPadding(_clientRc); + _clientRect = rc; + applyMargins(_clientRect); + applyPadding(_clientRect); } @@ -1838,8 +1839,8 @@ class EditLine : EditWidgetBase { // line inside selection Rect startrc = textPosToClient(_selectionRange.start); Rect endrc = textPosToClient(_selectionRange.end); - int startx = startrc.left + _clientRc.left; - int endx = endrc.left + _clientRc.left; + int startx = startrc.left + _clientRect.left; + int endx = endrc.left + _clientRect.left; Rect rc = lineRect; rc.left = startx; rc.right = endx; @@ -1863,12 +1864,12 @@ class EditLine : EditWidgetBase { dstring txt = text; Point sz = font.textSize(txt); //applyAlign(rc, sz); - Rect lineRect = _clientRc; - lineRect.left = _clientRc.left - _scrollPos.x; + Rect lineRect = _clientRect; + lineRect.left = _clientRect.left - _scrollPos.x; lineRect.right = lineRect.left + calcLineWidth(txt); Rect visibleRect = lineRect; - visibleRect.left = _clientRc.left; - visibleRect.right = _clientRc.right; + visibleRect.left = _clientRect.left; + visibleRect.right = _clientRect.right; drawLineBackground(buf, lineRect, visibleRect); font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize); @@ -1879,22 +1880,13 @@ class EditLine : EditWidgetBase { /// single line editor -class EditBox : EditWidgetBase, OnScrollHandler { - protected ScrollBar _hscrollbar; - protected ScrollBar _vscrollbar; - - this(string ID, dstring initialContent = null) { - super(ID); +class EditBox : EditWidgetBase { + this(string ID, dstring initialContent = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { + super(ID, hscrollbarMode, vscrollbarMode); _content = new EditableContent(true); // multiline _content.contentChangeListeners = this; styleId = "EDIT_BOX"; text = initialContent; - _hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal); - _vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical); - _hscrollbar.onScrollEventListener = this; - _vscrollbar.onScrollEventListener = this; - addChild(_hscrollbar); - addChild(_vscrollbar); } protected int _firstVisibleLine; @@ -1939,7 +1931,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { Point sz; FontRef font = font(); _lineHeight = font.height; - _numVisibleLines = (_clientRc.height + _lineHeight - 1) / _lineHeight; + _numVisibleLines = (_clientRect.height + _lineHeight - 1) / _lineHeight; if (_firstVisibleLine + _numVisibleLines > _content.length) _numVisibleLines = _content.length - _firstVisibleLine; _visibleLines.length = _numVisibleLines; @@ -1958,56 +1950,60 @@ class EditBox : EditWidgetBase, OnScrollHandler { return sz; } - override protected void updateScrollbars() { - int visibleLines = _clientRc.height / _lineHeight; // fully visible lines + /// update horizontal scrollbar widget position + override protected void updateHScrollBar() { + _hscrollbar.setRange(0, _maxLineWidth + _clientRect.width / 4); + _hscrollbar.pageSize = _clientRect.width; + _hscrollbar.position = _scrollPos.x; + } + + /// update verticat scrollbar widget position + override protected void updateVScrollBar() { + int visibleLines = _clientRect.height / _lineHeight; // fully visible lines if (visibleLines < 1) visibleLines = 1; _vscrollbar.setRange(0, _content.length - 1); _vscrollbar.pageSize = visibleLines; _vscrollbar.position = _firstVisibleLine; - _hscrollbar.setRange(0, _maxLineWidth + _clientRc.width / 4); - _hscrollbar.pageSize = _clientRc.width; - _hscrollbar.position = _scrollPos.x; } - /// handle scroll event - override bool onScrollEvent(AbstractSlider source, ScrollEvent event) { - if (source.compareId("hscrollbar")) { - if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { - if (_scrollPos.x != event.position) { - _scrollPos.x = event.position; - invalidate(); - } - } else if (event.action == ScrollAction.PageUp) { - handleAction(new Action(EditorActions.ScrollLeft)); - } else if (event.action == ScrollAction.PageDown) { - handleAction(new Action(EditorActions.ScrollRight)); - } else if (event.action == ScrollAction.LineUp) { - handleAction(new Action(EditorActions.ScrollLeft)); - } else if (event.action == ScrollAction.LineDown) { - handleAction(new Action(EditorActions.ScrollRight)); + /// process horizontal scrollbar event + override bool onHScroll(ScrollEvent event) { + if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { + if (_scrollPos.x != event.position) { + _scrollPos.x = event.position; + invalidate(); } - return true; - } else if (source.compareId("vscrollbar")) { - if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { - if (_firstVisibleLine != event.position) { - _firstVisibleLine = event.position; - measureVisibleText(); - invalidate(); - } - } else if (event.action == ScrollAction.PageUp) { - handleAction(new Action(EditorActions.ScrollPageUp)); - } else if (event.action == ScrollAction.PageDown) { - handleAction(new Action(EditorActions.ScrollPageDown)); - } else if (event.action == ScrollAction.LineUp) { - handleAction(new Action(EditorActions.ScrollLineUp)); - } else if (event.action == ScrollAction.LineDown) { - handleAction(new Action(EditorActions.ScrollLineDown)); - } - return true; + } else if (event.action == ScrollAction.PageUp) { + handleAction(new Action(EditorActions.ScrollLeft)); + } else if (event.action == ScrollAction.PageDown) { + handleAction(new Action(EditorActions.ScrollRight)); + } else if (event.action == ScrollAction.LineUp) { + handleAction(new Action(EditorActions.ScrollLeft)); + } else if (event.action == ScrollAction.LineDown) { + handleAction(new Action(EditorActions.ScrollRight)); } - return false; + return true; + } + /// process vertical scrollbar event + override bool onVScroll(ScrollEvent event) { + if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { + if (_firstVisibleLine != event.position) { + _firstVisibleLine = event.position; + measureVisibleText(); + invalidate(); + } + } else if (event.action == ScrollAction.PageUp) { + handleAction(new Action(EditorActions.ScrollPageUp)); + } else if (event.action == ScrollAction.PageDown) { + handleAction(new Action(EditorActions.ScrollPageDown)); + } else if (event.action == ScrollAction.LineUp) { + handleAction(new Action(EditorActions.ScrollLineUp)); + } else if (event.action == ScrollAction.LineDown) { + handleAction(new Action(EditorActions.ScrollLineDown)); + } + return true; } override protected void ensureCaretVisible() { @@ -2015,7 +2011,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { _caretPos.line = _content.length - 1; if (_caretPos.line < 0) _caretPos.line = 0; - int visibleLines = _clientRc.height / _lineHeight; // fully visible lines + int visibleLines = _clientRect.height / _lineHeight; // fully visible lines if (visibleLines < 1) visibleLines = 1; if (_caretPos.line < _firstVisibleLine) { @@ -2033,13 +2029,13 @@ class EditBox : EditWidgetBase, OnScrollHandler { Rect rc = textPosToClient(_caretPos); if (rc.left < 0) { // scroll left - _scrollPos.x -= -rc.left + _clientRc.width / 4; + _scrollPos.x -= -rc.left + _clientRect.width / 4; if (_scrollPos.x < 0) _scrollPos.x = 0; invalidate(); - } else if (rc.left >= _clientRc.width - 10) { + } else if (rc.left >= _clientRect.width - 10) { // scroll right - _scrollPos.x += (rc.left - _clientRc.width) + _clientRc.width / 4; + _scrollPos.x += (rc.left - _clientRect.width) + _clientRect.width / 4; invalidate(); } updateScrollbars(); @@ -2081,9 +2077,12 @@ class EditBox : EditWidgetBase, OnScrollHandler { } } res.pos = cast(int)_visibleLines[lineIndex].length; - } else { + } else if (_visibleLines.length > 0) { res.line = _firstVisibleLine + cast(int)_visibleLines.length - 1; res.pos = cast(int)_visibleLines[$ - 1].length; + } else { + res.line = 0; + res.pos = 0; } return res; } @@ -2135,7 +2134,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { case EditorActions.SelectPageEnd: { ensureCaretVisible(); - int fullLines = _clientRc.height / _lineHeight; + int fullLines = _clientRect.height / _lineHeight; int newpos = _firstVisibleLine + fullLines - 1; if (newpos >= _content.length) newpos = _content.length - 1; @@ -2147,7 +2146,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { case EditorActions.SelectPageUp: { ensureCaretVisible(); - int fullLines = _clientRc.height / _lineHeight; + int fullLines = _clientRect.height / _lineHeight; int newpos = _firstVisibleLine - fullLines; if (newpos < 0) { _firstVisibleLine = 0; @@ -2166,7 +2165,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { case EditorActions.SelectPageDown: { ensureCaretVisible(); - int fullLines = _clientRc.height / _lineHeight; + int fullLines = _clientRect.height / _lineHeight; int newpos = _firstVisibleLine + fullLines; if (newpos >= _content.length) { _caretPos.line = _content.length - 1; @@ -2194,10 +2193,10 @@ class EditBox : EditWidgetBase, OnScrollHandler { return true; case EditorActions.ScrollRight: { - if (_scrollPos.x < _maxLineWidth - _clientRc.width) { + if (_scrollPos.x < _maxLineWidth - _clientRect.width) { int newpos = _scrollPos.x + _spaceWidth * 4; - if (newpos > _maxLineWidth - _clientRc.width) - newpos = _maxLineWidth - _clientRc.width; + if (newpos > _maxLineWidth - _clientRect.width) + newpos = _maxLineWidth - _clientRect.width; _scrollPos.x = newpos; updateScrollbars(); invalidate(); @@ -2218,7 +2217,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { return true; case EditorActions.ScrollPageUp: { - int fullLines = _clientRc.height / _lineHeight; + int fullLines = _clientRect.height / _lineHeight; if (_firstVisibleLine > 0) { _firstVisibleLine -= fullLines * 3 / 4; if (_firstVisibleLine < 0) @@ -2231,7 +2230,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { return true; case EditorActions.ScrollLineDown: { - int fullLines = _clientRc.height / _lineHeight; + int fullLines = _clientRect.height / _lineHeight; if (_firstVisibleLine + fullLines < _content.length) { _firstVisibleLine += 3; if (_firstVisibleLine > _content.length - fullLines) @@ -2246,7 +2245,7 @@ class EditBox : EditWidgetBase, OnScrollHandler { return true; case EditorActions.ScrollPageDown: { - int fullLines = _clientRc.height / _lineHeight; + int fullLines = _clientRect.height / _lineHeight; if (_firstVisibleLine + fullLines < _content.length) { _firstVisibleLine += fullLines * 3 / 4; if (_firstVisibleLine > _content.length - fullLines) @@ -2295,55 +2294,25 @@ class EditBox : EditWidgetBase, OnScrollHandler { return super.handleAction(a); } + /// calculate full content size in pixels + override Point fullContentSize() { + Point textSz = measureVisibleText(); + int maxy = _lineHeight * 5; // limit measured height + if (textSz.y > maxy) + textSz.y = maxy; + return textSz; + } /// measure override void measure(int parentWidth, int parentHeight) { if (visibility == Visibility.Gone) { return; } - _hscrollbar.measure(parentWidth, parentHeight); - _vscrollbar.measure(parentWidth, parentHeight); - int hsbheight = _hscrollbar.measuredHeight; - int vsbwidth = _vscrollbar.measuredWidth; - updateFontProps(); - updateMaxLineWidth(); - - Point textSz = measureVisibleText(); - int maxy = _lineHeight * 5; // limit measured height - if (textSz.y > maxy) - textSz.y = maxy; - measuredContent(parentWidth, parentHeight, textSz.x + vsbwidth, textSz.y + hsbheight); - } - - /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). - override void layout(Rect rc) { - _needLayout = false; - if (visibility == Visibility.Gone) { - return; - } - _pos = rc; - - - applyMargins(rc); - applyPadding(rc); - int hsbheight = _hscrollbar.measuredHeight; - int vsbwidth = _vscrollbar.measuredWidth; - Rect sbrc = rc; - sbrc.left = sbrc.right - vsbwidth; - sbrc.bottom -= hsbheight; - _vscrollbar.layout(sbrc); - sbrc = rc; - sbrc.right -= vsbwidth; - sbrc.top = sbrc.bottom - hsbheight; - _hscrollbar.layout(sbrc); - // calc client rectangle - _clientRc = rc; - _clientRc.right -= vsbwidth; - _clientRc.bottom -= hsbheight; - Point textSz = measureVisibleText(); - updateScrollbars(); + super.measure(parentWidth, parentHeight); + // do we need to add vsbwidth, hsbheight ??? + //measuredContent(parentWidth, parentHeight, textSz.x + vsbwidth, textSz.y + hsbheight); } /// override to custom highlight of line background @@ -2356,8 +2325,8 @@ class EditBox : EditWidgetBase, OnScrollHandler { // line inside selection Rect startrc = textPosToClient(_selectionRange.start); Rect endrc = textPosToClient(_selectionRange.end); - int startx = lineIndex == _selectionRange.start.line ? startrc.left + _clientRc.left : lineRect.left; - int endx = lineIndex == _selectionRange.end.line ? endrc.left + _clientRc.left : lineRect.right + _spaceWidth; + int startx = lineIndex == _selectionRange.start.line ? startrc.left + _clientRect.left : lineRect.left; + int endx = lineIndex == _selectionRange.end.line ? endrc.left + _clientRect.left : lineRect.right + _spaceWidth; Rect rc = lineRect; rc.left = startx; rc.right = endx; @@ -2373,15 +2342,8 @@ class EditBox : EditWidgetBase, OnScrollHandler { } } - - /// draw content - override void onDraw(DrawBuf buf) { - if (visibility != Visibility.Visible) - return; - super.onDraw(buf); - _hscrollbar.onDraw(buf); - _vscrollbar.onDraw(buf); - Rect rc = _clientRc; + override protected void drawClient(DrawBuf buf) { + Rect rc = _clientRect; auto saver = ClipRectSaver(buf, rc, alpha); FontRef font = font(); @@ -2391,13 +2353,13 @@ class EditBox : EditWidgetBase, OnScrollHandler { for (int i = 0; i < _visibleLines.length; i++) { dstring txt = _visibleLines[i]; Rect lineRect = rc; - lineRect.left = _clientRc.left - _scrollPos.x; + lineRect.left = _clientRect.left - _scrollPos.x; lineRect.right = lineRect.left + calcLineWidth(_content[_firstVisibleLine + i]); - lineRect.top = _clientRc.top + i * _lineHeight; + lineRect.top = _clientRect.top + i * _lineHeight; lineRect.bottom = lineRect.top + _lineHeight; Rect visibleRect = lineRect; - visibleRect.left = _clientRc.left; - visibleRect.right = _clientRc.right; + visibleRect.left = _clientRect.left; + visibleRect.right = _clientRect.right; drawLineBackground(buf, _firstVisibleLine + i, lineRect, visibleRect); if (txt.length > 0) { font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor, tabSize); diff --git a/src/dlangui/widgets/grid.d b/src/dlangui/widgets/grid.d index 8b05f44b..6d4c1448 100644 --- a/src/dlangui/widgets/grid.d +++ b/src/dlangui/widgets/grid.d @@ -179,8 +179,6 @@ class GridWidgetBase : ScrollWidget { protected int _col; /// selected cell row protected int _row; - /// inner area, excluding additional controls like scrollbars - protected Rect _clientRect; /// when true, allows to select only whole row protected bool _rowSelect; /// default column width - for newly added columns @@ -852,7 +850,8 @@ class GridWidgetBase : ScrollWidget { } } - Point fullContentSize() { + /// calculate full content size in pixels + override Point fullContentSize() { Point sz; for (int i = 0; i < _cols; i++) sz.x += _colWidths[i]; @@ -861,62 +860,7 @@ class GridWidgetBase : ScrollWidget { return sz; } - /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). - override void measure(int parentWidth, int parentHeight) { - Rect m = margins; - Rect p = padding; - // calc size constraints for children - int pwidth = parentWidth; - int pheight = parentHeight; - if (parentWidth != SIZE_UNSPECIFIED) - pwidth -= m.left + m.right + p.left + p.right; - if (parentHeight != SIZE_UNSPECIFIED) - pheight -= m.top + m.bottom + p.top + p.bottom; - _hscrollbar.measure(pwidth, pheight); - _vscrollbar.measure(pwidth, pheight); - Point sz = fullContentSize(); - measuredContent(parentWidth, parentHeight, sz.x, sz.y); - } - - /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). - override void layout(Rect rc) { - if (visibility == Visibility.Gone) { - return; - } - _pos = rc; - _needLayout = false; - applyMargins(rc); - applyPadding(rc); - Point sz = fullContentSize(); - bool needHscroll = sz.x > rc.width; - bool needVscroll = sz.y > rc.height; - if (needVscroll) - needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth; - if (needHscroll) - needVscroll = sz.y > rc.height - _hscrollbar.measuredHeight; - if (needVscroll) - needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth; - // scrollbars - Rect vsbrc = rc; - vsbrc.left = vsbrc.right - _vscrollbar.measuredWidth; - vsbrc.bottom = vsbrc.bottom - _hscrollbar.measuredHeight; - Rect hsbrc = rc; - hsbrc.right = hsbrc.right - _vscrollbar.measuredWidth; - hsbrc.top = hsbrc.bottom - _hscrollbar.measuredHeight; - _vscrollbar.layout(vsbrc); - _hscrollbar.layout(hsbrc); - _vscrollbar.visibility = needVscroll ? Visibility.Visible : Visibility.Gone; - _hscrollbar.visibility = needHscroll ? Visibility.Visible : Visibility.Gone; - // client area - _clientRect = rc; - if (needVscroll) - _clientRect.right = vsbrc.left; - if (needHscroll) - _clientRect.bottom = hsbrc.top; - updateScrollBars(); - } - - protected void drawClient(DrawBuf buf) { + override protected void drawClient(DrawBuf buf) { auto saver = ClipRectSaver(buf, _clientRect, 0); //buf.fillRect(_clientRect, 0x80A08080); Rect rc; @@ -961,23 +905,6 @@ class GridWidgetBase : ScrollWidget { } } } - /// Draw widget at its position to buffer - override void onDraw(DrawBuf buf) { - if (visibility != Visibility.Visible) - return; - Rect rc = _pos; - applyMargins(rc); - auto saver = ClipRectSaver(buf, rc, alpha); - DrawableRef bg = backgroundDrawable; - if (!bg.isNull) { - bg.drawTo(buf, rc, state); - } - applyPadding(rc); - _hscrollbar.onDraw(buf); - _vscrollbar.onDraw(buf); - drawClient(buf); - _needDraw = false; - } /// draw data cell content protected void drawCell(DrawBuf buf, Rect rc, int col, int row) { @@ -1051,8 +978,8 @@ class GridWidgetBase : ScrollWidget { autoFitRowHeights(); } - this(string ID = null) { - super(ID); + this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { + super(ID, hscrollbarMode, vscrollbarMode); _headerCols = 1; _headerRows = 1; _defRowHeight = 20; diff --git a/src/dlangui/widgets/scroll.d b/src/dlangui/widgets/scroll.d index 7d5a2582..3ab65c90 100644 --- a/src/dlangui/widgets/scroll.d +++ b/src/dlangui/widgets/scroll.d @@ -4,20 +4,40 @@ import dlangui.widgets.widget; import dlangui.widgets.controls; import std.conv; +/** Scroll bar visibility mode. */ +enum ScrollBarMode { + /** always invisible */ + Invisible, + /** always visible */ + Visible, + /** automatically show/hide scrollbar depending on content size */ + Auto +} + class ScrollWidget : WidgetGroup, OnScrollHandler { + protected ScrollBarMode _vscrollbarMode; + protected ScrollBarMode _hscrollbarMode; /// vertical scrollbar control protected ScrollBar _vscrollbar; /// horizontal scrollbar control protected ScrollBar _hscrollbar; + /// inner area, excluding additional controls like scrollbars + protected Rect _clientRect; - this(string ID = null) { + this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { super(ID); - _vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical); - _hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal); - _hscrollbar.onScrollEventListener = this; - _vscrollbar.onScrollEventListener = this; - addChild(_vscrollbar); - addChild(_hscrollbar); + _hscrollbarMode = hscrollbarMode; + _vscrollbarMode = vscrollbarMode; + if (_vscrollbarMode != ScrollBarMode.Invisible) { + _vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical); + _vscrollbar.onScrollEventListener = this; + addChild(_vscrollbar); + } + if (_hscrollbarMode != ScrollBarMode.Invisible) { + _hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal); + _hscrollbar.onScrollEventListener = this; + addChild(_hscrollbar); + } } /// process horizontal scrollbar event @@ -60,5 +80,101 @@ class ScrollWidget : WidgetGroup, OnScrollHandler { } } + protected void drawClient(DrawBuf buf) { + // override it + } -} \ No newline at end of file + /// Draw widget at its position to buffer + override void onDraw(DrawBuf buf) { + if (visibility != Visibility.Visible) + return; + Rect rc = _pos; + applyMargins(rc); + auto saver = ClipRectSaver(buf, rc, alpha); + DrawableRef bg = backgroundDrawable; + if (!bg.isNull) { + bg.drawTo(buf, rc, state); + } + applyPadding(rc); + if (_hscrollbar) + _hscrollbar.onDraw(buf); + if (_vscrollbar) + _vscrollbar.onDraw(buf); + drawClient(buf); + _needDraw = false; + } + + /// calculate full content size in pixels + Point fullContentSize() { + // override it + Point sz; + return sz; + } + + /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). + override void measure(int parentWidth, int parentHeight) { + if (visibility == Visibility.Gone) { + return; + } + Rect m = margins; + Rect p = padding; + // calc size constraints for children + int pwidth = parentWidth; + int pheight = parentHeight; + if (parentWidth != SIZE_UNSPECIFIED) + pwidth -= m.left + m.right + p.left + p.right; + if (parentHeight != SIZE_UNSPECIFIED) + pheight -= m.top + m.bottom + p.top + p.bottom; + if (_hscrollbar) + _hscrollbar.measure(pwidth, pheight); + if (_vscrollbar) + _vscrollbar.measure(pwidth, pheight); + Point sz = fullContentSize(); + measuredContent(parentWidth, parentHeight, sz.x, sz.y); + } + + /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). + override void layout(Rect rc) { + if (visibility == Visibility.Gone) { + return; + } + _pos = rc; + _needLayout = false; + applyMargins(rc); + applyPadding(rc); + Point sz = fullContentSize(); + bool needHscroll = _hscrollbarMode != ScrollBarMode.Invisible && sz.x > rc.width; + bool needVscroll = _vscrollbarMode != ScrollBarMode.Invisible && sz.y > rc.height; + if (needVscroll && _vscrollbarMode != ScrollBarMode.Invisible) + needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth; + if (needHscroll && _hscrollbarMode != ScrollBarMode.Invisible) + needVscroll = sz.y > rc.height - _hscrollbar.measuredHeight; + if (needVscroll && _vscrollbarMode != ScrollBarMode.Invisible) + needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth; + needVscroll = needVscroll || (_vscrollbarMode == ScrollBarMode.Visible); + needHscroll = needHscroll || (_hscrollbarMode == ScrollBarMode.Visible); + // scrollbars + Rect vsbrc = rc; + vsbrc.left = vsbrc.right - (needVscroll ? _vscrollbar.measuredWidth : 0); + vsbrc.bottom = vsbrc.bottom - (needHscroll ? _hscrollbar.measuredHeight : 0); + Rect hsbrc = rc; + hsbrc.right = hsbrc.right - (needVscroll ? _vscrollbar.measuredWidth : 0); + hsbrc.top = hsbrc.bottom - (needHscroll ? _hscrollbar.measuredHeight : 0); + if (_vscrollbar) { + _vscrollbar.layout(vsbrc); + _vscrollbar.visibility = needVscroll ? Visibility.Visible : Visibility.Gone; + } + if (_hscrollbar) { + _hscrollbar.layout(hsbrc); + _hscrollbar.visibility = needHscroll ? Visibility.Visible : Visibility.Gone; + } + // client area + _clientRect = rc; + if (needVscroll) + _clientRect.right = vsbrc.left; + if (needHscroll) + _clientRect.bottom = hsbrc.top; + updateScrollBars(); + } + +} diff --git a/src/dlangui/widgets/tree.d b/src/dlangui/widgets/tree.d index d88bd37e..2ec38ebc 100644 --- a/src/dlangui/widgets/tree.d +++ b/src/dlangui/widgets/tree.d @@ -6,19 +6,9 @@ import dlangui.widgets.scroll; import std.conv; class TreeWidgetBase : ScrollWidget { - /// vertical scrollbar control - protected ScrollBar _vscrollbar; - /// horizontal scrollbar control - protected ScrollBar _hscrollbar; - this(string ID = null) { - super(ID); - _vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical); - _hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal); - _hscrollbar.onScrollEventListener = this; - _vscrollbar.onScrollEventListener = this; - addChild(_vscrollbar); - addChild(_hscrollbar); + this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { + super(ID, hscrollbarMode, vscrollbarMode); } /// process horizontal scrollbar event