diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index 29b89759..68701bf5 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -572,6 +572,54 @@ extern (C) int UIAppMain(string[] args) { tabs.addTab(grid, "Grid"d); //========================================================================== + // Scroll view example + ScrollWidget scroll = new ScrollWidget("SCROLL1"); + scroll.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + WidgetGroup scrollContent = new VerticalLayout("CONTENT"); + scrollContent.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + + TableLayout table2 = new TableLayout("TABLE2"); + table2.colCount = 2; + // headers + table2.addChild((new TextWidget(null, "Parameter Name"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new TextWidget(null, "Edit Box to edit parameter"d)).alignment(Align.Left | Align.VCenter)); + // row 1 + table2.addChild((new TextWidget(null, "Parameter 1 name"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit1", "Text 1"d)).layoutWidth(FILL_PARENT)); + // row 2 + table2.addChild((new TextWidget(null, "Parameter 2 name bla bla"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit2", "Some text for parameter 2 blah blah blah"d)).layoutWidth(FILL_PARENT)); + // row 3 + table2.addChild((new TextWidget(null, "Param 3"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit3", "Parameter 3 value"d)).layoutWidth(FILL_PARENT)); + // row 4 + table2.addChild((new TextWidget(null, "Param 4"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit3", "Parameter 4 value shdjksdfh hsjdfas hdjkf hdjsfk ah"d)).layoutWidth(FILL_PARENT)); + // row 5 + table2.addChild((new TextWidget(null, "Param 5 - edit text here - blah blah blah"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT)); + // row 6 + table2.addChild((new TextWidget(null, "Param 6 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT)); + // row 7 + table2.addChild((new TextWidget(null, "Param 7 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT)); + // row 8 + table2.addChild((new TextWidget(null, "Param 8 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter)); + table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT)); + table2.margins(Rect(10,10,10,10)).layoutWidth(FILL_PARENT); + scrollContent.addChild(table2); + + scrollContent.addChild(new TextWidget(null, "Now - some buttons"d)); + scrollContent.addChild(new ImageTextButton("btn1", "fileclose", "Close"d)); + scrollContent.addChild(new ImageTextButton("btn2", "fileopen", "Open"d)); + scrollContent.addChild(new TextWidget(null, "And checkboxes"d)); + scrollContent.addChild(new CheckBox("btn1", "CheckBox 1"d)); + scrollContent.addChild(new CheckBox("btn2", "CheckBox 2"d)); + + scroll.contentWidget = scrollContent; + tabs.addTab(scroll, "Scroll"d); + //========================================================================== // tree view example TreeWidget tree = new TreeWidget("TREE1"); tree.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); diff --git a/src/dlangui/all.d b/src/dlangui/all.d index c89d0d29..b15117b3 100644 --- a/src/dlangui/all.d +++ b/src/dlangui/all.d @@ -56,6 +56,7 @@ public import dlangui.widgets.layouts; public import dlangui.widgets.lists; public import dlangui.widgets.tabs; public import dlangui.widgets.menu; +public import dlangui.widgets.scroll; public import dlangui.widgets.editors; public import dlangui.widgets.grid; public import dlangui.widgets.tree; diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 1f721af7..622bd654 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -808,7 +808,7 @@ class EditableContent { } /// base for all editor widgets -class EditWidgetBase : ScrollWidget, EditableContentListener, MenuItemActionHandler { +class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemActionHandler { protected EditableContent _content; protected int _lineHeight; @@ -2344,7 +2344,6 @@ class EditBox : EditWidgetBase { override protected void drawClient(DrawBuf buf) { Rect rc = _clientRect; - auto saver = ClipRectSaver(buf, rc, alpha); FontRef font = font(); //dstring txt = text; diff --git a/src/dlangui/widgets/grid.d b/src/dlangui/widgets/grid.d index 6d4c1448..1e7e1f93 100644 --- a/src/dlangui/widgets/grid.d +++ b/src/dlangui/widgets/grid.d @@ -150,7 +150,7 @@ enum GridActions : int { SelectDocumentEnd, } -class GridWidgetBase : ScrollWidget { +class GridWidgetBase : ScrollWidgetBase { /// column count (including header columns and fixed columns) protected int _cols; /// row count (including header rows and fixed rows) @@ -373,20 +373,6 @@ class GridWidgetBase : ScrollWidget { return false; } - /// update horizontal scrollbar widget position - override protected void updateHScrollBar() { - _hscrollbar.setRange(0, _fullScrollableArea.width); - _hscrollbar.pageSize(_visibleScrollableArea.width); - _hscrollbar.position(_visibleScrollableArea.left - _fullScrollableArea.left); - } - - /// update verticat scrollbar widget position - override protected void updateVScrollBar() { - _vscrollbar.setRange(0, _fullScrollableArea.height); - _vscrollbar.pageSize(_visibleScrollableArea.height); - _vscrollbar.position(_visibleScrollableArea.top - _fullScrollableArea.top); - } - /// update scrollbar positions override protected void updateScrollBars() { calcScrollableAreaPos(); diff --git a/src/dlangui/widgets/scroll.d b/src/dlangui/widgets/scroll.d index 3ab65c90..e0025eb5 100644 --- a/src/dlangui/widgets/scroll.d +++ b/src/dlangui/widgets/scroll.d @@ -14,7 +14,7 @@ enum ScrollBarMode { Auto } -class ScrollWidget : WidgetGroup, OnScrollHandler { +class ScrollWidgetBase : WidgetGroup, OnScrollHandler { protected ScrollBarMode _vscrollbarMode; protected ScrollBarMode _hscrollbarMode; /// vertical scrollbar control @@ -24,6 +24,9 @@ class ScrollWidget : WidgetGroup, OnScrollHandler { /// inner area, excluding additional controls like scrollbars protected Rect _clientRect; + protected Rect _fullScrollableArea; + protected Rect _visibleScrollableArea; + this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { super(ID); _hscrollbarMode = hscrollbarMode; @@ -60,16 +63,6 @@ class ScrollWidget : WidgetGroup, OnScrollHandler { return true; } - /// update horizontal scrollbar widget position - protected void updateHScrollBar() { - // override it - } - - /// update verticat scrollbar widget position - protected void updateVScrollBar() { - // override it - } - /// update scrollbar positions protected void updateScrollBars() { if (_hscrollbar) { @@ -80,6 +73,22 @@ class ScrollWidget : WidgetGroup, OnScrollHandler { } } + /// update horizontal scrollbar widget position + protected void updateHScrollBar() { + // default implementation: use _fullScrollableArea, _visibleScrollableArea: override it if necessary + _hscrollbar.setRange(0, _fullScrollableArea.width); + _hscrollbar.pageSize(_visibleScrollableArea.width); + _hscrollbar.position(_visibleScrollableArea.left - _fullScrollableArea.left); + } + + /// update verticat scrollbar widget position + protected void updateVScrollBar() { + // default implementation: use _fullScrollableArea, _visibleScrollableArea: override it if necessary + _vscrollbar.setRange(0, _fullScrollableArea.height); + _vscrollbar.pageSize(_visibleScrollableArea.height); + _vscrollbar.position(_visibleScrollableArea.top - _fullScrollableArea.top); + } + protected void drawClient(DrawBuf buf) { // override it } @@ -100,6 +109,7 @@ class ScrollWidget : WidgetGroup, OnScrollHandler { _hscrollbar.onDraw(buf); if (_vscrollbar) _vscrollbar.onDraw(buf); + auto saver2 = ClipRectSaver(buf, _clientRect, alpha); drawClient(buf); _needDraw = false; } @@ -178,3 +188,111 @@ class ScrollWidget : WidgetGroup, OnScrollHandler { } } + +/** + Widget which can show content of widget group with optional scrolling. + */ +class ScrollWidget : ScrollWidgetBase { + protected WidgetGroup _contentWidget; + @property WidgetGroup contentWidget() { return _contentWidget; } + @property ScrollWidget contentWidget(WidgetGroup newContent) { + if (_contentWidget) { + removeChild(childIndex(_contentWidget)); + destroy(_contentWidget); + } + _contentWidget = newContent; + addChild(_contentWidget); + requestLayout(); + return this; + } + this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { + super(ID, hscrollbarMode, vscrollbarMode); + } + + /// calculate full content size in pixels + override Point fullContentSize() { + // override it + Point sz; + if (_contentWidget) { + _contentWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED); + sz.x = _contentWidget.measuredWidth; + sz.y = _contentWidget.measuredHeight; + } + _fullScrollableArea.right = sz.x; + _fullScrollableArea.bottom = sz.y; + return sz; + } + + /// update scrollbar positions + override protected void updateScrollBars() { + Point sz = fullContentSize(); + _visibleScrollableArea.right = _visibleScrollableArea.left + _clientRect.width; + _visibleScrollableArea.bottom = _visibleScrollableArea.top + _clientRect.height; + // move back if scroll is too big after window resize + int extrax = _visibleScrollableArea.right - _fullScrollableArea.right; + int extray = _visibleScrollableArea.bottom - _fullScrollableArea.bottom; + if (extrax > _visibleScrollableArea.left) + extrax = _visibleScrollableArea.left; + if (extray > _visibleScrollableArea.top) + extray = _visibleScrollableArea.top; + if (extrax < 0) + extrax = 0; + if (extray < 0) + extray = 0; + _visibleScrollableArea.offset(-extrax, -extray); + super.updateScrollBars(); + } + + override protected void drawClient(DrawBuf buf) { + if (_contentWidget) { + Point sz = fullContentSize(); + Point p = scrollPos; + _contentWidget.layout(Rect(_pos.left - p.x, _pos.top - p.y, _pos.left + sz.x - p.x, _pos.top + sz.y - p.y)); + _contentWidget.onDraw(buf); + } + } + + @property Point scrollPos() { + return Point(_visibleScrollableArea.left - _fullScrollableArea.left, _visibleScrollableArea.top - _fullScrollableArea.top); + } + + protected void scrollTo(int x, int y) { + _visibleScrollableArea.left = x; + _visibleScrollableArea.top = y; + updateScrollBars(); + invalidate(); + } + + /// process horizontal scrollbar event + override bool onHScroll(ScrollEvent event) { + if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { + scrollTo(event.position, scrollPos.y); + } else if (event.action == ScrollAction.PageUp) { + //handleAction(new Action(GridActions.ScrollPageLeft)); + } else if (event.action == ScrollAction.PageDown) { + //handleAction(new Action(GridActions.ScrollPageRight)); + } else if (event.action == ScrollAction.LineUp) { + //handleAction(new Action(GridActions.ScrollLeft)); + } else if (event.action == ScrollAction.LineDown) { + //handleAction(new Action(GridActions.ScrollRight)); + } + return true; + } + + /// process vertical scrollbar event + override bool onVScroll(ScrollEvent event) { + if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { + scrollTo(scrollPos.x, event.position); + } else if (event.action == ScrollAction.PageUp) { + //handleAction(new Action(GridActions.ScrollPageUp)); + } else if (event.action == ScrollAction.PageDown) { + //handleAction(new Action(GridActions.ScrollPageDown)); + } else if (event.action == ScrollAction.LineUp) { + //handleAction(new Action(GridActions.ScrollUp)); + } else if (event.action == ScrollAction.LineDown) { + //handleAction(new Action(GridActions.ScrollDown)); + } + return true; + } + +} diff --git a/src/dlangui/widgets/tree.d b/src/dlangui/widgets/tree.d index 2ec38ebc..f9fdcb05 100644 --- a/src/dlangui/widgets/tree.d +++ b/src/dlangui/widgets/tree.d @@ -5,7 +5,7 @@ import dlangui.widgets.controls; import dlangui.widgets.scroll; import std.conv; -class TreeWidgetBase : ScrollWidget { +class TreeWidgetBase : ScrollWidgetBase { this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) { super(ID, hscrollbarMode, vscrollbarMode); @@ -34,7 +34,7 @@ class TreeWidgetBase : ScrollWidget { } -class TreeWidget : ScrollWidget { +class TreeWidget : TreeWidgetBase { this(string ID = null) { super(ID); } diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index b1848bad..0d337b8f 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -1041,7 +1041,10 @@ class Widget { _measuredHeight = dy; } - /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). + /** + Measure widget according to desired width and height constraints. (Step 1 of two phase layout). + + */ void measure(int parentWidth, int parentHeight) { measuredContent(parentWidth, parentHeight, 0, 0); }