diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index 21187060..e4de8b01 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -513,6 +513,55 @@ struct Ref(T) { // if (T is RefCountedObject) } +/** + This struct allows to not execute some code if some variables was not changed since the last check. + Used for optimizations. + + Reference types, arrays and pointers are compared by reference. + */ +struct CalcSaver(Params...) { + import std.typecons : Tuple; + Tuple!Params values; + + bool check(Params args) { + bool changed; + foreach (i, arg; args) { + if (values[i] !is arg) { + values[i] = arg; + changed = true; + } + } + return changed; + } +} + +/// +unittest { + + class A { } + + CalcSaver!(uint, double[], A) saver; + + uint x = 5; + double[] arr = [1, 2, 3]; + A a = new A(); + + assert(saver.check(x, arr, a)); + // values are not changing + assert(!saver.check(x, arr, a)); + assert(!saver.check(x, arr, a)); + assert(!saver.check(x, arr, a)); + assert(!saver.check(x, arr, a)); + + x = 8; + arr ~= 25; + a = new A(); + // values are changed + assert(saver.check(x, arr, a)); + assert(!saver.check(x, arr, a)); +} + + //================================================================================ // some utility functions diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 947ac60b..18d54d0b 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -115,20 +115,26 @@ class TextWidget : Widget { return this; } - override void measure(int parentWidth, int parentHeight) { + private CalcSaver!(Font, dstring, uint, uint) _measureSaver; + + override void measure(int parentWidth, int parentHeight) { FontRef font = font(); - //auto measureStart = std.datetime.Clock.currAppTick; - Point sz; - if (maxLines == 1) { - sz = font.textSize(text, MAX_WIDTH_UNSPECIFIED, 4, 0, textFlags); - } else { - sz = font.measureMultilineText(text,maxLines,parentWidth-margins.left-margins.right-padding.left-padding.right, 4, 0, textFlags); + uint w = (maxLines == 1) ? MAX_WIDTH_UNSPECIFIED : + parentWidth - margins.left - margins.right - padding.left - padding.right; + uint flags = textFlags; + + // optimization: do not measure if nothing changed + if (_measureSaver.check(font.get, text, w, flags) || _needLayout) { + Point sz; + if (maxLines == 1) { + sz = font.textSize(text, w, 4, 0, flags); + } else { + sz = font.measureMultilineText(text, maxLines, w, 4, 0, flags); + } + // it's not very correct, but in such simple widget it doesn't make issues + measuredContent(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED, sz.x, sz.y); + _needLayout = false; } - //auto measureEnd = std.datetime.Clock.currAppTick; - //auto duration = measureEnd - measureStart; - //if (duration.length > 10) - // Log.d("TextWidget measureText took ", duration.length, " ticks"); - measuredContent(parentWidth, parentHeight, sz.x, sz.y); } override void onDraw(DrawBuf buf) { diff --git a/src/dlangui/widgets/layouts.d b/src/dlangui/widgets/layouts.d index 9d5b8f06..57c906a2 100644 --- a/src/dlangui/widgets/layouts.d +++ b/src/dlangui/widgets/layouts.d @@ -643,7 +643,7 @@ class FrameLayout : WidgetGroupDefaultDrawing { applyPadding(rc); for (int i = 0; i < _children.count; i++) { Widget item = _children.get(i); - if (item.visibility != Visibility.Gone) { + if (item.visibility == Visibility.Visible) { item.layout(rc); } } @@ -657,6 +657,7 @@ class FrameLayout : WidgetGroupDefaultDrawing { Widget item = _children.get(i); if (item.compareId(ID)) { item.visibility = Visibility.Visible; + item.requestLayout(); foundWidget = item; found = true; } else {