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         with (holder) {
50             lastWidgetInStack = cell.firstWidget;
51 
52             if (orientation == Orientation.vertical) {
53                 cell.widthType = SizeType.matchParent;
54                 cell.size.y = lastWidgetInStack.outerSize.y;
55                 cell.position.y = lastWidgetPosition.y;
56                 cell.updateSize();
57             } else {
58                 cell.size.x = lastWidgetInStack.outerSize.x;
59                 cell.heightType = SizeType.matchParent;
60                 cell.position.x = lastWidgetPosition.x;
61                 cell.updateSize();
62             }
63 
64             lastWidgetPosition += lastWidgetInStack.size + lastWidgetInStack.outerOffsetEnd;
65 
66             if (lastWidgetInStack.widthType != SizeType.matchParent) {
67                 maxSize.x = fmax(maxSize.x, lastWidgetInStack.outerSize.x);
68             }
69 
70             if (lastWidgetInStack.heightType != SizeType.matchParent) {
71                 maxSize.y = fmax(maxSize.y, lastWidgetInStack.outerSize.y);
72             }
73         }
74     }
75 
76     void updateSize() {
77         with (holder) {
78             if (orientation == Orientation.vertical) {
79                 if (widthType == SizeType.wrapContent) {
80                     size.x = maxSize.x > innerSize.x ? maxSize.x : innerSize.x;
81                 }
82 
83                 if (heightType == SizeType.wrapContent) {
84                     if (lastWidgetInStack !is null) {
85                         size.y = lastWidgetPosition.y + lastWidgetInStack.outerOffset.bottom + innerOffsetSize.y;
86                     } else {
87                         // TODO(Andrey): why *2 ?
88                         size.y = innerOffsetSize.y * 2;
89                     }
90                 }
91             }
92 
93             if (orientation == Orientation.horizontal) {
94                 if (heightType == SizeType.wrapContent) {
95                     size.y = maxSize.y > innerSize.y ? maxSize.y : innerSize.y;
96                 }
97 
98                 if (widthType == SizeType.wrapContent) {
99                     if (lastWidgetInStack !is null) {
100                         size.x = lastWidgetPosition.x + lastWidgetInStack.outerOffset.right + innerOffsetSize.x;
101                     }
102                 }
103             }
104         }
105     }
106 }