1 module rpui.widgets.stack_layout.stack_locator;
2 
3 import std.math;
4 
5 import rpui.widget;
6 import rpui.primitives;
7 import rpui.math;
8 
9 struct StackLocator {
10     Widget holder;
11     Orientation orientation = Orientation.vertical;
12 
13     private vec2 maxSize = vec2(0, 0);
14     private vec2 lastWidgetPosition = vec2(0, 0);
15     private Widget lastWidgetInStack = null;
16 
17     void attach(Widget widget) {
18         holder = widget;
19         holder.widthType = Widget.SizeType.wrapContent;
20         holder.heightType = Widget.SizeType.wrapContent;
21         setDecorator();
22     }
23 
24     private void setDecorator() {
25         holder.children.decorateWidgets(delegate(Widget widget) {
26             Widget cell = new Widget();
27             cell.associatedWidget = widget;
28             cell.skipFocus = true;
29             return cell;
30         });
31     }
32 
33     void updateWidgetsPosition() {
34         with (holder) {
35             startWidgetsPositioning();
36 
37             foreach (Widget cell; children) {
38                 pushWidgetPosition(cell);
39             }
40         }
41     }
42 
43     void startWidgetsPositioning() {
44         lastWidgetPosition = vec2(0, 0);
45         lastWidgetInStack = null;
46     }
47 
48     void pushWidgetPosition(Widget cell) {
49         if (!cell.associatedWidget.isVisible) {
50             return;
51         }
52 
53         with (holder) {
54             lastWidgetInStack = cell.firstWidget;
55 
56             if (orientation == Orientation.vertical) {
57                 cell.widthType = SizeType.matchParent;
58                 cell.size.y = lastWidgetInStack.outerSize.y;
59                 cell.position.y = lastWidgetPosition.y;
60                 cell.updateSize();
61             } else {
62                 cell.size.x = lastWidgetInStack.outerSize.x;
63                 cell.heightType = SizeType.matchParent;
64                 cell.position.x = lastWidgetPosition.x;
65                 cell.updateSize();
66             }
67 
68             lastWidgetPosition += lastWidgetInStack.size + lastWidgetInStack.outerOffsetEnd;
69 
70             if (lastWidgetInStack.widthType != SizeType.matchParent) {
71                 maxSize.x = fmax(maxSize.x, lastWidgetInStack.outerSize.x);
72             }
73 
74             if (lastWidgetInStack.heightType != SizeType.matchParent) {
75                 maxSize.y = fmax(maxSize.y, lastWidgetInStack.outerSize.y);
76             }
77         }
78     }
79 
80     void updateSize() {
81         with (holder) {
82             if (orientation == Orientation.vertical) {
83                 if (widthType == SizeType.wrapContent) {
84                     size.x = maxSize.x > innerSize.x ? maxSize.x : innerSize.x;
85                 }
86 
87                 if (heightType == SizeType.wrapContent) {
88                     if (lastWidgetInStack !is null) {
89                         size.y = lastWidgetPosition.y + lastWidgetInStack.outerOffset.bottom + innerOffsetSize.y;
90                     } else {
91                         // TODO(Andrey): why *2 ?
92                         size.y = innerOffsetSize.y * 2;
93                     }
94                 }
95             }
96 
97             if (orientation == Orientation.horizontal) {
98                 if (heightType == SizeType.wrapContent) {
99                     size.y = maxSize.y > innerSize.y ? maxSize.y : innerSize.y;
100                 }
101 
102                 if (widthType == SizeType.wrapContent) {
103                     if (lastWidgetInStack !is null) {
104                         size.x = lastWidgetPosition.x + lastWidgetInStack.outerOffset.right + innerOffsetSize.x;
105                     }
106                 }
107             }
108         }
109     }
110 }