From 03eb2c7b659d7ea0616889ade0846e53f41eb0b4 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Fri, 7 Mar 2014 18:52:50 +0400 Subject: [PATCH] Linear layout - in progress --- dlanguilib.visualdproj | 1 + src/dlangui/all.d | 8 ++ src/dlangui/widgets/layouts.d | 164 ++++++++++++++++++++++++++++++++++ src/dlangui/widgets/widget.d | 38 ++++---- 4 files changed, 192 insertions(+), 19 deletions(-) create mode 100644 src/dlangui/all.d create mode 100644 src/dlangui/widgets/layouts.d diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index 9a0e3bae..ccc444cb 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -272,6 +272,7 @@ + diff --git a/src/dlangui/all.d b/src/dlangui/all.d new file mode 100644 index 00000000..413e62d3 --- /dev/null +++ b/src/dlangui/all.d @@ -0,0 +1,8 @@ +module dlangui.all; + +public import dlangui.platforms.common.platform; +public import dlangui.graphics.images; +public import dlangui.widgets.widget; +public import dlangui.widgets.controls; +public import dlangui.core.logger; +public import dlangui.graphics.fonts; diff --git a/src/dlangui/widgets/layouts.d b/src/dlangui/widgets/layouts.d new file mode 100644 index 00000000..1463209a --- /dev/null +++ b/src/dlangui/widgets/layouts.d @@ -0,0 +1,164 @@ +module dlangui.widgets.layouts; + +import dlangui.widgets.widget; + +enum Orientation : ubyte { + Vertical, + Horizontal +} + +class LinearLayout : 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; requestLayout(); return this; } + + /// 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; + // measure children + int contentWidth = 0; + int contentHeight = 0; + if (orientation == Orientation.Vertical) { + // Vertical + int max = 0; + int total = 0; + for (int i = 0; i < _children.count; i++) { + Widget item = _children.get(i); + if (item.visibility == Visibility.Gone) + continue; + item.measure(pwidth, pheight); + if (max < item.measuredWidth) + max = item.measuredWidth; + total += item.measuredHeight; + } + contentWidth = max; + contentHeight = total; + } else { + // Horizontal + int max = 0; + int total = 0; + for (int i = 0; i < _children.count; i++) { + Widget item = _children.get(i); + if (item.visibility == Visibility.Gone) + continue; + item.measure(pwidth, pheight); + if (max < item.measuredHeight) + max = item.measuredHeight; + total += item.measuredWidth; + } + contentWidth = total; + contentHeight = max; + } + measuredContent(parentWidth, parentHeight, contentWidth, contentHeight); + } + + /// 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); + int contentWidth = 0; + int contentHeight = 0; + if (orientation == Orientation.Vertical) { + // Vertical + int position = 0; + int totalSize = 0; + int delta = 0; + int resizableSize = 0; + int resizableWeight = 0; + int nonresizableSize = 0; + int nonresizableWeight = 0; + int maxItem = 0; // max item dimention + // calc total size + int visibleCount = 0; + for (int i = 0; i < _children.count; i++) { + Widget item = _children.get(i); + if (item.visibility == Visibility.Gone) + continue; + visibleCount++; + totalSize += item.measuredHeight; + if (maxItem < item.measuredWidth) + maxItem = item.measuredWidth; + int weight = item.layoutWeight; + if (item.layoutHeight == FILL_PARENT) { + resizableWeight += weight; + resizableSize += item.measuredHeight; + } else { + nonresizableWeight += weight; + nonresizableSize += item.measuredHeight; + } + } + if (layoutWidth == WRAP_CONTENT && maxItem < rc.width) + contentWidth = maxItem; + else + contentWidth = rc.width; + if (layoutHeight == FILL_PARENT || totalSize > rc.height) + delta = rc.height - totalSize; // total space to add to fit + bool needForceResize = false; + bool needResize = false; + int scaleFactor = 10000; // per weight unit + if (delta != 0 && visibleCount > 0) { + // need resize of some children + needResize = true; + needForceResize = delta < 0 || resizableSize < delta; // do we need resize non-FILL_PARENT items? + if (needForceResize) + scaleFactor = 10000 * rc.height / (resizableSize + nonresizableSize) / (nonresizableWeight + resizableWeight); + else + scaleFactor = 10000 * rc.height / (rc.height - delta) / resizableWeight; + } + for (int i = 0; i < _children.count; i++) { + Widget item = _children.get(i); + if (item.visibility == Visibility.Gone) + continue; + int weight = item.layoutWeight; + if (item.layoutHeight == FILL_PARENT) { + resizableWeight += weight; + resizableSize += item.measuredHeight; + } else { + nonresizableWeight += weight; + nonresizableSize += item.measuredHeight; + } + } + for (int i = 0; i < _children.count; i++) { + Widget item = _children.get(i); + if (item.visibility == Visibility.Gone) + continue; + int layoutSize = item.layoutHeight; + totalWeight += item.measuredHeight; + int weight = item.layoutWeight; + if (layoutSize) { + resizableWeight += weight; + resizableSize += item.measuredHeight; + } + } + } else { + // Horizontal + } + _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); + // TODO + _needDraw = false; + } + +} diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index a07f09f5..e5449832 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -194,11 +194,6 @@ class Widget { _needDraw = true; } - /// 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); - } - /// helper function for implement measure() when widget's content dimensions are known protected void measuredContent(int parentWidth, int parentHeight, int contentWidth, int contentHeight) { if (visibility == Visibility.Gone) { @@ -232,6 +227,11 @@ class Widget { _measuredHeight = dy; } + /// 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); + } + /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). void layout(Rect rc) { if (visibility == Visibility.Gone) { @@ -240,7 +240,19 @@ class Widget { _pos = rc; _needLayout = false; } - /// applies margins to rectangle + /// Draw widget at its position to buffer + void onDraw(DrawBuf buf) { + if (visibility != Visibility.Visible) + return; + Rect rc = _pos; + applyMargins(rc); + DrawableRef bg = style.backgroundDrawable; + bg.drawTo(buf, rc); + applyPadding(rc); + _needDraw = false; + } + + /// Helper function: applies margins to rectangle void applyMargins(ref Rect rc) { Rect m = margins; rc.left += m.left; @@ -248,7 +260,7 @@ class Widget { rc.bottom -= m.bottom; rc.right -= m.right; } - /// applies padding to rectangle + /// Helper function: applies padding to rectangle void applyPadding(ref Rect rc) { Rect m = padding; rc.left += m.left; @@ -256,18 +268,6 @@ class Widget { rc.bottom -= m.bottom; rc.right -= m.right; } - /// Draw widget at its position to buffer - void onDraw(DrawBuf buf) { - if (visibility != Visibility.Visible) - return; - Rect rc = _pos; - applyMargins(rc); - buf.fillRect(_pos, backgroundColor); - DrawableRef bg = style.backgroundDrawable; - bg.drawTo(buf, rc); - applyPadding(rc); - _needDraw = false; - } /// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc. void applyAlign(ref Rect rc, Point sz) { Align va = valign;