diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index 6afca629..e77e75b8 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -324,6 +324,7 @@ + diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index 81195fd7..a154375a 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -16,7 +16,7 @@ class ListWidget : WidgetGroup { /// returns linear layout orientation (Vertical, Horizontal) @property Orientation orientation() { return _orientation; } /// sets linear layout orientation - @property LinearLayout orientation(Orientation value) { + @property ListWidget orientation(Orientation value) { _orientation = value; _scrollbar.orientation = value; requestLayout(); @@ -24,7 +24,12 @@ class ListWidget : WidgetGroup { } protected Rect[] _itemRects; + protected Point[] _itemSizes; + protected bool _needScrollbar; + protected Point _sbsz; // scrollbar size protected ScrollBar _scrollbar; + protected int _lastMeasureWidth; + protected int _lastMeasureHeight; protected ListAdapter _adapter; /// get adapter @@ -59,6 +64,7 @@ class ListWidget : WidgetGroup { _orientation = orientation; _scrollbar = new ScrollBar("listscroll", orientation); _scrollbar.visibility = Visibility.Gone; + addChild(_scrollbar); } /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). @@ -67,6 +73,8 @@ class ListWidget : WidgetGroup { _measuredWidth = _measuredHeight = 0; return; } + if (_itemSizes.length < itemCount) + _itemSizes.length = itemCount; Rect m = margins; Rect p = padding; // calc size constraints for children @@ -76,16 +84,25 @@ class ListWidget : WidgetGroup { pwidth -= m.left + m.right + p.left + p.right; if (parentHeight != SIZE_UNSPECIFIED) pheight -= m.top + m.bottom + p.top + p.bottom; + _scrollbar.visibility = Visibility.Visible; _scrollbar.measure(pwidth, pheight); + + _lastMeasureWidth = pwidth; + _lastMeasureHeight = pheight; + int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight; // measure children Point sz; - Point sbsz; + _sbsz.clear; for (int i = 0; i < itemCount; i++) { Widget w = itemWidget(i); - if (w is null || w.visibility == Visibility.Gone) + if (w is null || w.visibility == Visibility.Gone) { + _itemSizes[i].x = _itemSizes[i].y = 0; continue; + } w.measure(pwidth, pheight); + _itemSizes[i].x = w.measuredWidth; + _itemSizes[i].y = w.measuredHeight; if (_orientation == Orientation.Vertical) { // Vertical if (sz.x < w.measuredWidth) @@ -99,14 +116,13 @@ class ListWidget : WidgetGroup { 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; + _sbsz.x = sbsize; + _needScrollbar = true; } } } else { @@ -114,12 +130,12 @@ class ListWidget : WidgetGroup { // need scrollbar if (pheight != SIZE_UNSPECIFIED) { pheight -= sbsize; - sbsz.y = sbsize; - needScrollbar = true; + _sbsz.y = sbsize; + _needScrollbar = true; } } } - if (needScrollbar) { + if (_needScrollbar) { // recalculate with scrollbar sz.x = sz.y = 0; for (int i = 0; i < itemCount; i++) { @@ -127,6 +143,8 @@ class ListWidget : WidgetGroup { if (w is null || w.visibility == Visibility.Gone) continue; w.measure(pwidth, pheight); + _itemSizes[i].x = w.measuredWidth; + _itemSizes[i].y = w.measuredHeight; if (_orientation == Orientation.Vertical) { // Vertical if (sz.x < w.measuredWidth) @@ -141,7 +159,7 @@ class ListWidget : WidgetGroup { } } } - measuredContent(parentWidth, parentHeight, sz.x + sbsz.x, sz.y + sbsz.y); + 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). @@ -150,40 +168,64 @@ class ListWidget : WidgetGroup { 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++) { + // measure again if client size has been changed + if (_lastMeasureWidth != rc.width || _lastMeasureHeight != rc.height) + measure(rc.width, rc.height); - Widget w = itemWidget(i); - if (w is null || w.visibility == Visibility.Gone) + // layout scrollbar + if (_needScrollbar) { + _scrollbar.visibility = Visibility.Visible; + Rect sbrect = rc; + if (_orientation == Orientation.Vertical) + sbrect.left = sbrect.right - _sbsz.x; + else + sbrect.top = sbrect.bottom - _sbsz.y; + _scrollbar.layout(sbrect); + rc.right -= _sbsz.x; + rc.bottom -= _sbsz.y; + } else { + _scrollbar.visibility = Visibility.Gone; + } + + // calc item rectangles + Rect r; + int p = 0; + for (int i = 0; i < itemCount; i++) { + if (_itemSizes[i].x == 0 && _itemSizes[i].y == 0) 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 = + int w = rc.width; + int h = _itemSizes[i].y; + r.top = p; + r.bottom = p + h; + r.left = 0; + r.right = w; + _itemRects[i] = r; + p += h; } else { // Horizontal - w.measure(pwidth, pheight); - if (sz.y < w.measuredHeight) - sz.y = w.measuredHeight; - sz.x += w.measuredWidth; + int h = rc.height; + int w = _itemSizes[i].x; + r.top = 0; + r.bottom = h; + r.left = p; + r.right = p + w; + _itemRects[i] = r; + p += w; } } _needLayout = false; } + /// Draw widget at its position to buffer override void onDraw(DrawBuf buf) { if (visibility != Visibility.Visible) @@ -193,11 +235,25 @@ class ListWidget : WidgetGroup { 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); + // draw scrollbar + if (_needScrollbar) + _scrollbar.onDraw(buf); + + Point scrollOffset; + // todo: scrollOffset + // draw items + for (int i = 0; i < itemCount; i++) { + Widget w = itemWidget(i); + if (w is null || w.visibility != Visibility.Visible) + continue; + Rect itemrc = _itemRects[i]; + itemrc.left += rc.left - scrollOffset.x; + itemrc.right += rc.left - scrollOffset.x; + itemrc.top += rc.top - scrollOffset.y; + itemrc.bottom += rc.top - scrollOffset.y; + w.measure(itemrc.width, itemrc.height); + w.layout(itemrc); + w.onDraw(buf); } }