ListWidget

This commit is contained in:
Vadim Lopatin 2014-03-26 11:40:34 +04:00
parent 6d705c51e2
commit 91764870d9
2 changed files with 89 additions and 32 deletions

View File

@ -324,6 +324,7 @@
<Folder name="widgets"> <Folder name="widgets">
<File path="src\dlangui\widgets\controls.d" /> <File path="src\dlangui\widgets\controls.d" />
<File path="src\dlangui\widgets\layouts.d" /> <File path="src\dlangui\widgets\layouts.d" />
<File path="src\dlangui\widgets\lists.d" />
<File path="src\dlangui\widgets\styles.d" /> <File path="src\dlangui\widgets\styles.d" />
<File path="src\dlangui\widgets\widget.d" /> <File path="src\dlangui\widgets\widget.d" />
</Folder> </Folder>

View File

@ -16,7 +16,7 @@ class ListWidget : WidgetGroup {
/// returns linear layout orientation (Vertical, Horizontal) /// returns linear layout orientation (Vertical, Horizontal)
@property Orientation orientation() { return _orientation; } @property Orientation orientation() { return _orientation; }
/// sets linear layout orientation /// sets linear layout orientation
@property LinearLayout orientation(Orientation value) { @property ListWidget orientation(Orientation value) {
_orientation = value; _orientation = value;
_scrollbar.orientation = value; _scrollbar.orientation = value;
requestLayout(); requestLayout();
@ -24,7 +24,12 @@ class ListWidget : WidgetGroup {
} }
protected Rect[] _itemRects; protected Rect[] _itemRects;
protected Point[] _itemSizes;
protected bool _needScrollbar;
protected Point _sbsz; // scrollbar size
protected ScrollBar _scrollbar; protected ScrollBar _scrollbar;
protected int _lastMeasureWidth;
protected int _lastMeasureHeight;
protected ListAdapter _adapter; protected ListAdapter _adapter;
/// get adapter /// get adapter
@ -59,6 +64,7 @@ class ListWidget : WidgetGroup {
_orientation = orientation; _orientation = orientation;
_scrollbar = new ScrollBar("listscroll", orientation); _scrollbar = new ScrollBar("listscroll", orientation);
_scrollbar.visibility = Visibility.Gone; _scrollbar.visibility = Visibility.Gone;
addChild(_scrollbar);
} }
/// 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).
@ -67,6 +73,8 @@ class ListWidget : WidgetGroup {
_measuredWidth = _measuredHeight = 0; _measuredWidth = _measuredHeight = 0;
return; return;
} }
if (_itemSizes.length < itemCount)
_itemSizes.length = itemCount;
Rect m = margins; Rect m = margins;
Rect p = padding; Rect p = padding;
// calc size constraints for children // calc size constraints for children
@ -76,16 +84,25 @@ class ListWidget : WidgetGroup {
pwidth -= m.left + m.right + p.left + p.right; pwidth -= m.left + m.right + p.left + p.right;
if (parentHeight != SIZE_UNSPECIFIED) if (parentHeight != SIZE_UNSPECIFIED)
pheight -= m.top + m.bottom + p.top + p.bottom; pheight -= m.top + m.bottom + p.top + p.bottom;
_scrollbar.visibility = Visibility.Visible;
_scrollbar.measure(pwidth, pheight); _scrollbar.measure(pwidth, pheight);
_lastMeasureWidth = pwidth;
_lastMeasureHeight = pheight;
int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight; int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight;
// measure children // measure children
Point sz; Point sz;
Point sbsz; _sbsz.clear;
for (int i = 0; i < itemCount; i++) { for (int i = 0; i < itemCount; i++) {
Widget w = itemWidget(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; continue;
}
w.measure(pwidth, pheight); w.measure(pwidth, pheight);
_itemSizes[i].x = w.measuredWidth;
_itemSizes[i].y = w.measuredHeight;
if (_orientation == Orientation.Vertical) { if (_orientation == Orientation.Vertical) {
// Vertical // Vertical
if (sz.x < w.measuredWidth) if (sz.x < w.measuredWidth)
@ -99,14 +116,13 @@ class ListWidget : WidgetGroup {
sz.x += w.measuredWidth; sz.x += w.measuredWidth;
} }
} }
bool needScrollbar;
if (_orientation == Orientation.Vertical) { if (_orientation == Orientation.Vertical) {
if (pheight != SIZE_UNSPECIFIED && sz.y > pheight) { if (pheight != SIZE_UNSPECIFIED && sz.y > pheight) {
// need scrollbar // need scrollbar
if (pwidth != SIZE_UNSPECIFIED) { if (pwidth != SIZE_UNSPECIFIED) {
pwidth -= sbsize; pwidth -= sbsize;
sbsz.x = sbsize; _sbsz.x = sbsize;
needScrollbar = true; _needScrollbar = true;
} }
} }
} else { } else {
@ -114,12 +130,12 @@ class ListWidget : WidgetGroup {
// need scrollbar // need scrollbar
if (pheight != SIZE_UNSPECIFIED) { if (pheight != SIZE_UNSPECIFIED) {
pheight -= sbsize; pheight -= sbsize;
sbsz.y = sbsize; _sbsz.y = sbsize;
needScrollbar = true; _needScrollbar = true;
} }
} }
} }
if (needScrollbar) { if (_needScrollbar) {
// recalculate with scrollbar // recalculate with scrollbar
sz.x = sz.y = 0; sz.x = sz.y = 0;
for (int i = 0; i < itemCount; i++) { for (int i = 0; i < itemCount; i++) {
@ -127,6 +143,8 @@ class ListWidget : WidgetGroup {
if (w is null || w.visibility == Visibility.Gone) if (w is null || w.visibility == Visibility.Gone)
continue; continue;
w.measure(pwidth, pheight); w.measure(pwidth, pheight);
_itemSizes[i].x = w.measuredWidth;
_itemSizes[i].y = w.measuredHeight;
if (_orientation == Orientation.Vertical) { if (_orientation == Orientation.Vertical) {
// Vertical // Vertical
if (sz.x < w.measuredWidth) 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). /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
@ -150,40 +168,64 @@ class ListWidget : WidgetGroup {
return; return;
} }
_pos = rc; _pos = rc;
applyMargins(rc); applyMargins(rc);
applyPadding(rc); applyPadding(rc);
if (_itemRects.length < itemCount) if (_itemRects.length < itemCount)
_itemRects.length = itemCount; _itemRects.length = itemCount;
Rect r; // measure again if client size has been changed
Point sz; if (_lastMeasureWidth != rc.width || _lastMeasureHeight != rc.height)
Point sbsz; measure(rc.width, rc.height);
int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight;
r = rc;
for (int i = 0; i < itemCount; i++) {
Widget w = itemWidget(i); // layout scrollbar
if (w is null || w.visibility == Visibility.Gone) 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; continue;
if (_orientation == Orientation.Vertical) { if (_orientation == Orientation.Vertical) {
w.measure(rc.width, SIZE_UNSPECIFIED);
// Vertical // Vertical
if (sz.x < w.measuredWidth) int w = rc.width;
sz.x = w.measuredWidth; int h = _itemSizes[i].y;
sz.y += w.measuredHeight; r.top = p;
r.bottom = r.bottom = p + h;
r.left = 0;
r.right = w;
_itemRects[i] = r;
p += h;
} else { } else {
// Horizontal // Horizontal
w.measure(pwidth, pheight); int h = rc.height;
if (sz.y < w.measuredHeight) int w = _itemSizes[i].x;
sz.y = w.measuredHeight; r.top = 0;
sz.x += w.measuredWidth; r.bottom = h;
r.left = p;
r.right = p + w;
_itemRects[i] = r;
p += w;
} }
} }
_needLayout = false; _needLayout = false;
} }
/// Draw widget at its position to buffer /// Draw widget at its position to buffer
override void onDraw(DrawBuf buf) { override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible) if (visibility != Visibility.Visible)
@ -193,11 +235,25 @@ class ListWidget : WidgetGroup {
applyMargins(rc); applyMargins(rc);
applyPadding(rc); applyPadding(rc);
ClipRectSaver(buf, rc); ClipRectSaver(buf, rc);
for (int i = 0; i < _children.count; i++) { // draw scrollbar
Widget item = _children.get(i); if (_needScrollbar)
if (item.visibility != Visibility.Visible) _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; continue;
item.onDraw(buf); 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);
} }
} }