mirror of https://github.com/buggins/dlangui.git
fix linear layout implementation
This commit is contained in:
parent
3661f7f9fb
commit
1341bb6e71
|
@ -27,9 +27,20 @@ extern (C) int UIAppMain(string[] args) {
|
|||
|
||||
// create window
|
||||
Window window = Platform.instance().createWindow("My Window", null);
|
||||
Widget myWidget = (new Button()).textColor(0x40FF4000);
|
||||
myWidget.text = "Some strange text string. 1234567890";
|
||||
window.mainWidget = myWidget;
|
||||
LinearLayout layout = new LinearLayout();
|
||||
layout.addChild((new TextWidget()).textColor(0x00802000).text("Text widget 0"));
|
||||
layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
|
||||
layout.addChild((new Button()).textColor(0x40FF4000).text("Button1"));
|
||||
layout.addChild((new Button()).textColor(0x000000FF).text("Button2"));
|
||||
layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
|
||||
layout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)));
|
||||
layout.addChild((new TextWidget()).textColor(0xFF4000).text("Text widget2").padding(Rect(5,5,5,5)).margins(Rect(5,5,5,5)).backgroundColor(0xA0A0A0));
|
||||
layout.addChild((new Button()).textColor(0x000000FF).text("Button3").layoutHeight(FILL_PARENT));
|
||||
layout.addChild((new TextWidget()).textColor(0x004000).text("Text widget3 with very long text"));
|
||||
|
||||
layout.layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT);
|
||||
|
||||
window.mainWidget = layout;
|
||||
window.show();
|
||||
window.windowCaption = "New Window Caption";
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
module dlangui.all;
|
||||
|
||||
public import dlangui.core.logger;
|
||||
public import dlangui.core.types;
|
||||
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.widgets.layouts;
|
||||
public import dlangui.graphics.fonts;
|
||||
|
|
|
@ -4,16 +4,20 @@ import dlangui.widgets.widget;
|
|||
|
||||
/// static text widget
|
||||
class TextWidget : Widget {
|
||||
this(string ID = null) {
|
||||
super(ID);
|
||||
styleId = "TEXT";
|
||||
}
|
||||
protected dstring _text;
|
||||
/// get widget text
|
||||
override @property dstring text() { return _text; }
|
||||
/// set text to show
|
||||
override @property void text(dstring s) {
|
||||
override @property Widget text(dstring s) {
|
||||
_text = s;
|
||||
requestLayout();
|
||||
return this;
|
||||
}
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
_measuredWidth = _measuredHeight = 0;
|
||||
FontRef font = font();
|
||||
Point sz = font.textSize(text);
|
||||
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
||||
|
@ -24,8 +28,8 @@ class TextWidget : Widget {
|
|||
super.onDraw(buf);
|
||||
Rect rc = _pos;
|
||||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
ClipRectSaver(buf, rc);
|
||||
applyPadding(rc);
|
||||
FontRef font = font();
|
||||
Point sz = font.textSize(text);
|
||||
applyAlign(rc, sz);
|
||||
|
@ -39,6 +43,10 @@ class ImageWidget : Widget {
|
|||
protected string _drawableId;
|
||||
protected DrawableRef _drawable;
|
||||
|
||||
this(string ID = null) {
|
||||
super(ID);
|
||||
}
|
||||
|
||||
/// get drawable image id
|
||||
@property string drawableId() { return _drawableId; }
|
||||
/// set drawable image id
|
||||
|
@ -79,8 +87,8 @@ class ImageWidget : Widget {
|
|||
super.onDraw(buf);
|
||||
Rect rc = _pos;
|
||||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
ClipRectSaver(buf, rc);
|
||||
applyPadding(rc);
|
||||
DrawableRef img = drawable;
|
||||
if (!img.isNull) {
|
||||
Point sz;
|
||||
|
@ -95,16 +103,15 @@ class ImageWidget : Widget {
|
|||
class Button : Widget {
|
||||
protected dstring _text;
|
||||
override @property dstring text() { return _text; }
|
||||
override @property void text(dstring s) { _text = s; }
|
||||
this() {
|
||||
override @property Widget text(dstring s) { _text = s; requestLayout(); return this; }
|
||||
this(string ID = null) {
|
||||
super(ID);
|
||||
styleId = "BUTTON";
|
||||
}
|
||||
override void measure(int width, int height) {
|
||||
_measuredWidth = _measuredHeight = 0;
|
||||
}
|
||||
override void layout(Rect rc) {
|
||||
_pos = rc;
|
||||
_needLayout = false;
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
FontRef font = font();
|
||||
Point sz = font.textSize(text);
|
||||
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
||||
}
|
||||
override void onDraw(DrawBuf buf) {
|
||||
super.onDraw(buf);
|
||||
|
|
|
@ -74,7 +74,6 @@ class LinearLayout : WidgetGroup {
|
|||
int contentHeight = 0;
|
||||
if (orientation == Orientation.Vertical) {
|
||||
// Vertical
|
||||
int position = 0;
|
||||
int totalSize = 0;
|
||||
int delta = 0;
|
||||
int resizableSize = 0;
|
||||
|
@ -89,16 +88,17 @@ class LinearLayout : WidgetGroup {
|
|||
if (item.visibility == Visibility.Gone)
|
||||
continue;
|
||||
visibleCount++;
|
||||
totalSize += item.measuredHeight;
|
||||
int weight = item.layoutWeight;
|
||||
int size = item.measuredHeight;
|
||||
totalSize += size;
|
||||
if (maxItem < item.measuredWidth)
|
||||
maxItem = item.measuredWidth;
|
||||
int weight = item.layoutWeight;
|
||||
if (item.layoutHeight == FILL_PARENT) {
|
||||
resizableWeight += weight;
|
||||
resizableSize += item.measuredHeight;
|
||||
resizableSize += size * weight;
|
||||
} else {
|
||||
nonresizableWeight += weight;
|
||||
nonresizableSize += item.measuredHeight;
|
||||
nonresizableSize += size * weight;
|
||||
}
|
||||
}
|
||||
if (layoutWidth == WRAP_CONTENT && maxItem < rc.width)
|
||||
|
@ -107,42 +107,59 @@ class LinearLayout : WidgetGroup {
|
|||
contentWidth = rc.width;
|
||||
if (layoutHeight == FILL_PARENT || totalSize > rc.height)
|
||||
delta = rc.height - totalSize; // total space to add to fit
|
||||
// calculate resize options and scale
|
||||
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?
|
||||
// resize all if need to shrink or only resizable are too small to correct delta
|
||||
needForceResize = delta < 0 || resizableWeight == 0; // || resizableSize * 2 / 3 < delta; // do we need resize non-FILL_PARENT items?
|
||||
// calculate scale factor: weight / delta * 10000
|
||||
if (needForceResize)
|
||||
scaleFactor = 10000 * rc.height / (resizableSize + nonresizableSize) / (nonresizableWeight + resizableWeight);
|
||||
scaleFactor = 10000 * delta / (nonresizableSize + resizableSize);
|
||||
else
|
||||
scaleFactor = 10000 * rc.height / (rc.height - delta) / resizableWeight;
|
||||
scaleFactor = 10000 * delta / resizableSize;
|
||||
}
|
||||
//Log.d("VerticalLayout delta=", delta, ", nonres=", nonresizableWeight, ", res=", resizableWeight, ", scale=", scaleFactor);
|
||||
// find last resized - to allow fill space 1 pixel accurate
|
||||
Widget lastResized = null;
|
||||
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;
|
||||
if (item.layoutHeight == FILL_PARENT || needForceResize) {
|
||||
lastResized = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
// final resize and layout of children
|
||||
int position = 0;
|
||||
int deltaTotal = 0;
|
||||
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;
|
||||
int size = item.measuredHeight;
|
||||
if (needResize && (layoutSize == FILL_PARENT || needForceResize)) {
|
||||
// do resize
|
||||
int correction = scaleFactor * weight * size / 10000;
|
||||
deltaTotal += correction;
|
||||
// for last resized, apply additional correction to resolve calculation inaccuracy
|
||||
if (item == lastResized) {
|
||||
correction += delta - deltaTotal;
|
||||
}
|
||||
size += correction;
|
||||
}
|
||||
// apply size
|
||||
Rect childRect = rc;
|
||||
childRect.top += position;
|
||||
childRect.bottom = childRect.top + size;
|
||||
childRect.right = childRect.left + contentWidth;
|
||||
item.layout(childRect);
|
||||
position += size;
|
||||
}
|
||||
} else {
|
||||
// Horizontal
|
||||
|
@ -157,8 +174,13 @@ class LinearLayout : WidgetGroup {
|
|||
Rect rc = _pos;
|
||||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
// TODO
|
||||
_needDraw = false;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -447,6 +447,29 @@ class Theme : Style {
|
|||
return style;
|
||||
}
|
||||
|
||||
// ================================================
|
||||
// override to avoid infinite recursion
|
||||
/// font size
|
||||
@property override string backgroundImageId() const {
|
||||
return _backgroundImageId;
|
||||
}
|
||||
/// minimal width constraint, 0 if limit is not set
|
||||
@property override uint minWidth() const {
|
||||
return _minWidth;
|
||||
}
|
||||
/// max width constraint, returns SIZE_UNSPECIFIED if limit is not set
|
||||
@property override uint maxWidth() const {
|
||||
return _maxWidth;
|
||||
}
|
||||
/// minimal height constraint, 0 if limit is not set
|
||||
@property override uint minHeight() const {
|
||||
return _minHeight;
|
||||
}
|
||||
/// max height constraint, SIZE_UNSPECIFIED if limit is not set
|
||||
@property override uint maxHeight() const {
|
||||
return _maxHeight;
|
||||
}
|
||||
|
||||
/// create new named style
|
||||
override Style createSubstyle(string id) {
|
||||
Style style = new Style(this, id);
|
||||
|
@ -470,6 +493,6 @@ private __gshared Theme _currentTheme;
|
|||
|
||||
static this() {
|
||||
_currentTheme = new Theme("default");
|
||||
Style button = _currentTheme.createSubstyle("BUTTON").backgroundImageId("btn_default_normal");
|
||||
button.alignment(Align.Center);
|
||||
Style button = _currentTheme.createSubstyle("BUTTON").backgroundImageId("btn_default_normal").alignment(Align.Center);
|
||||
Style text = _currentTheme.createSubstyle("TEXT").margins(Rect(3,3,3,3)).padding(Rect(3,3,3,3));
|
||||
}
|
||||
|
|
|
@ -37,17 +37,16 @@ class Widget {
|
|||
/// height measured by measure()
|
||||
protected int _measuredHeight;
|
||||
/// true to force layout
|
||||
protected bool _needLayout;
|
||||
protected bool _needLayout = true;
|
||||
/// true to force redraw
|
||||
protected bool _needDraw;
|
||||
protected bool _needDraw = true;
|
||||
/// parent widget
|
||||
protected Widget _parent;
|
||||
/// window (to be used for top level widgets only!)
|
||||
protected Window _window;
|
||||
|
||||
this() {
|
||||
_needLayout = true;
|
||||
_needDraw = true;
|
||||
this(string ID = null) {
|
||||
_id = id;
|
||||
}
|
||||
|
||||
/// accessor to style - by lookup in theme by styleId (if style id is not set, theme base style will be used).
|
||||
|
@ -82,7 +81,20 @@ class Widget {
|
|||
/// set margins for widget - override one from style
|
||||
@property Widget margins(Rect rc) { ownStyle.margins = rc; return this; }
|
||||
/// get padding (between background bounds and content of widget)
|
||||
@property Rect padding() const { return style.padding; }
|
||||
@property Rect padding() const {
|
||||
// get max padding from style padding and background drawable padding
|
||||
Rect p = style.padding;
|
||||
Rect dp = style.backgroundDrawable.padding;
|
||||
if (p.left < dp.left)
|
||||
p.left = dp.left;
|
||||
if (p.right < dp.right)
|
||||
p.right = dp.right;
|
||||
if (p.top < dp.top)
|
||||
p.top = dp.top;
|
||||
if (p.bottom < dp.bottom)
|
||||
p.bottom = dp.bottom;
|
||||
return p;
|
||||
}
|
||||
/// set padding for widget - override one from style
|
||||
@property Widget padding(Rect rc) { ownStyle.padding = rc; return this; }
|
||||
/// returns background color
|
||||
|
@ -127,7 +139,7 @@ class Widget {
|
|||
/// returns widget content text (override to support this)
|
||||
@property dstring text() { return ""; }
|
||||
/// sets widget content text (override to support this)
|
||||
@property void text(dstring s) { }
|
||||
@property Widget text(dstring s) { return this; }
|
||||
|
||||
//==================================================================
|
||||
// Layout and drawing related methods
|
||||
|
|
Loading…
Reference in New Issue