From 6d705c51e21ffacb542849d2eadc8b150aa7bda7 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 25 Mar 2014 17:12:40 +0400 Subject: [PATCH] lists, partial implementation --- src/dlangui/widgets/controls.d | 1 + src/dlangui/widgets/lists.d | 205 +++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 src/dlangui/widgets/lists.d diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 9549f63a..a49623ca 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -370,6 +370,7 @@ class ScrollBar : WidgetGroup, OnClickHandler { protected void layoutButtons(Rect irc) { Rect r; + _indicator.visibility = Visibility.Visible; if (_orientation == Orientation.Vertical) { _indicator.layout(irc); if (_scrollArea.top < irc.top) { diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d new file mode 100644 index 00000000..81195fd7 --- /dev/null +++ b/src/dlangui/widgets/lists.d @@ -0,0 +1,205 @@ +module dlangui.widgets.lists; + +import dlangui.widgets.widget; +import dlangui.widgets.controls; + +/// list widget adapter provides items for list widgets +interface ListAdapter { + /// returns number of widgets in list + @property int itemCount(); + /// return list item widget by item index + Widget itemWidget(int index); +} + +class ListWidget : WidgetGroup { + protected Orientation _orientation = Orientation.Vertical; + /// returns linear layout orientation (Vertical, Horizontal) + @property Orientation orientation() { return _orientation; } + /// sets linear layout orientation + @property LinearLayout orientation(Orientation value) { + _orientation = value; + _scrollbar.orientation = value; + requestLayout(); + return this; + } + + protected Rect[] _itemRects; + protected ScrollBar _scrollbar; + + protected ListAdapter _adapter; + /// get adapter + @property ListAdapter adapter() { return _adapter; } + /// set adapter + @property ListWidget adapter(ListAdapter adapter) { + _adapter = adapter; + onAdapterChanged(); + return this; + } + + /// returns number of widgets in list + @property int itemCount() { + if (_adapter !is null) + return _adapter.itemCount; + return 0; + } + + /// return list item widget by item index + Widget itemWidget(int index) { + if (_adapter !is null) + return _adapter.itemWidget(index); + return null; + } + + void onAdapterChanged() { + requestLayout(); + } + + this(string ID = null, Orientation orientation = Orientation.Vertical) { + super(ID); + _orientation = orientation; + _scrollbar = new ScrollBar("listscroll", orientation); + _scrollbar.visibility = Visibility.Gone; + } + + /// 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) { + _measuredWidth = _measuredHeight = 0; + 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; + _scrollbar.measure(pwidth, pheight); + int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight; + // measure children + Point sz; + Point sbsz; + for (int i = 0; i < itemCount; i++) { + Widget w = itemWidget(i); + if (w is null || w.visibility == Visibility.Gone) + continue; + w.measure(pwidth, pheight); + if (_orientation == Orientation.Vertical) { + // Vertical + if (sz.x < w.measuredWidth) + sz.x = w.measuredWidth; + sz.y += w.measuredHeight; + } else { + // Horizontal + w.measure(pwidth, pheight); + if (sz.y < w.measuredHeight) + sz.y = w.measuredHeight; + sz.x += w.measuredWidth; + } + } + bool needScrollbar; + if (_orientation == Orientation.Vertical) { + if (pheight != SIZE_UNSPECIFIED && sz.y > pheight) { + // need scrollbar + if (pwidth != SIZE_UNSPECIFIED) { + pwidth -= sbsize; + sbsz.x = sbsize; + needScrollbar = true; + } + } + } else { + if (pwidth != SIZE_UNSPECIFIED && sz.x > pwidth) { + // need scrollbar + if (pheight != SIZE_UNSPECIFIED) { + pheight -= sbsize; + sbsz.y = sbsize; + needScrollbar = true; + } + } + } + if (needScrollbar) { + // recalculate with scrollbar + sz.x = sz.y = 0; + for (int i = 0; i < itemCount; i++) { + Widget w = itemWidget(i); + if (w is null || w.visibility == Visibility.Gone) + continue; + w.measure(pwidth, pheight); + if (_orientation == Orientation.Vertical) { + // Vertical + if (sz.x < w.measuredWidth) + sz.x = w.measuredWidth; + sz.y += w.measuredHeight; + } else { + // Horizontal + w.measure(pwidth, pheight); + if (sz.y < w.measuredHeight) + sz.y = w.measuredHeight; + sz.x += w.measuredWidth; + } + } + } + measuredContent(parentWidth, parentHeight, sz.x + sbsz.x, sz.y + sbsz.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; + applyMargins(rc); + applyPadding(rc); + + if (_itemRects.length < itemCount) + _itemRects.length = itemCount; + + Rect r; + Point sz; + Point sbsz; + int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight; + r = rc; + for (int i = 0; i < itemCount; i++) { + + Widget w = itemWidget(i); + if (w is null || w.visibility == Visibility.Gone) + continue; + if (_orientation == Orientation.Vertical) { + w.measure(rc.width, SIZE_UNSPECIFIED); + // Vertical + if (sz.x < w.measuredWidth) + sz.x = w.measuredWidth; + sz.y += w.measuredHeight; + r.bottom = + } else { + // Horizontal + w.measure(pwidth, pheight); + if (sz.y < w.measuredHeight) + sz.y = w.measuredHeight; + sz.x += w.measuredWidth; + } + } + + _needLayout = false; + } + /// Draw widget at its position to buffer + override void onDraw(DrawBuf buf) { + if (visibility != Visibility.Visible) + return; + super.onDraw(buf); + Rect rc = _pos; + applyMargins(rc); + applyPadding(rc); + ClipRectSaver(buf, rc); + for (int i = 0; i < _children.count; i++) { + Widget item = _children.get(i); + if (item.visibility != Visibility.Visible) + continue; + item.onDraw(buf); + } + } + +} +