1 module rpui.widgets.panel.transforms_system;
2 
3 import rpui.events;
4 import rpui.theme;
5 import rpui.primitives;
6 import rpui.widgets.panel.widget;
7 import rpui.widgets.panel.render_system;
8 import rpui.render.transforms;
9 import rpui.render.components;
10 
11 import gapi.transform;
12 import gapi.vec;
13 
14 struct RenderTransforms {
15     QuadTransforms background;
16     QuadTransforms splitInner;
17     QuadTransforms splitOuter;
18     HorizontalChainTransforms horizontalScrollButton;
19     HorizontalChainTransforms verticalScrollButton;
20     QuadTransforms headerBackground;
21     QuadTransforms headerMark;
22     UiTextTransforms headerText;
23 }
24 
25 struct SplitTransforms {
26     vec2 size;
27     vec2 innerPosition;
28     vec2 outerPosition;
29 }
30 
31 final class PanelTransformsSystem : TransformsSystem {
32     private RenderTransforms* transforms;
33     private Panel widget;
34     private RenderData* renderData;
35     private Theme theme;
36 
37     this(Panel widget, RenderData* renderData, RenderTransforms* transforms) {
38         this.renderData = renderData;
39         this.transforms = transforms;
40         this.theme = widget.view.theme;
41         this.widget = widget;
42     }
43 
44     override void onProgress(in ProgressEvent event) {
45         updateBackgroundTransforms();
46         updateHeaderTransforms();
47         updateSplitTransforms();
48         updateScrollButtonsTransforms();
49     }
50 
51     private void updateBackgroundTransforms() {
52         transforms.background = updateQuadTransforms(
53             widget.view.cameraView,
54             widget.absolutePosition,
55             widget.size
56         );
57     }
58 
59     private void updateHeaderTransforms() {
60         vec2 textPosition;
61         const headerSize = vec2(widget.size.x, widget.measure.headerHeight);
62 
63         if (widget.userCanHide) {
64             transforms.headerBackground = updateQuadTransforms(
65                 widget.view.cameraView,
66                 widget.absolutePosition,
67                 headerSize
68             );
69 
70             transforms.headerMark = updateQuadTransforms(
71                 widget.view.cameraView,
72                 widget.absolutePosition + renderData.headerMarkPosition,
73                 renderData.headerMarkSize
74             );
75 
76             textPosition = widget.absolutePosition +
77                 vec2(renderData.headerMarkPosition.x + renderData.headerMarkSize.x, 0);
78         } else {
79             textPosition = widget.absolutePosition + vec2(renderData.headerMarkPosition.x, 0);
80         }
81 
82         with (renderData.headerText.attrs[widget.headerState]) {
83             caption = widget.caption;
84         }
85 
86         transforms.headerText = updateUiTextTransforms(
87             &renderData.headerText.render,
88             &theme.regularFont,
89             transforms.headerText,
90             renderData.headerText.attrs[widget.headerState],
91             widget.view.cameraView,
92             textPosition,
93             headerSize
94         );
95     }
96 
97     private void updateSplitTransforms() {
98         // if (!widget.userCanResize && !widget.showSplit)
99             // return;
100 
101         const splitTransforms = getSplitTransforms();
102 
103         transforms.splitInner = updateQuadTransforms(
104             widget.view.cameraView,
105             splitTransforms.innerPosition,
106             splitTransforms.size
107         );
108 
109         transforms.splitOuter = updateQuadTransforms(
110             widget.view.cameraView,
111             splitTransforms.outerPosition,
112             splitTransforms.size
113         );
114 
115         widget.split.cursorRangeRect = Rect(
116             splitTransforms.outerPosition,
117             splitTransforms.size
118         );
119     }
120 
121     private SplitTransforms getSplitTransforms() {
122         vec2 size;
123         vec2 innerPosition;
124         vec2 outerPosition;
125 
126         const thickness = widget.split.thickness;
127 
128         switch (widget.splitRegionAlign) {
129             case RegionAlign.top:
130                 outerPosition = widget.absolutePosition + vec2(0, widget.size.y - thickness);
131                 innerPosition = outerPosition - vec2(0, thickness);
132                 size = vec2(widget.size.x, thickness);
133                 break;
134 
135             case RegionAlign.bottom:
136                 outerPosition = widget.absolutePosition;
137                 innerPosition = outerPosition + vec2(0, thickness);
138                 size = vec2(widget.size.x, thickness);
139                 break;
140 
141             case RegionAlign.left:
142                 outerPosition = widget.absolutePosition + vec2(widget.size.x - thickness, 0);
143                 innerPosition = outerPosition - vec2(thickness, 0);
144                 size = vec2(thickness, widget.size.y);
145                 break;
146 
147             case RegionAlign.right:
148                 outerPosition = widget.absolutePosition;
149                 innerPosition = outerPosition + vec2(thickness, 0);
150                 size = vec2(thickness, widget.size.y);
151                 break;
152 
153             default:
154                 return SplitTransforms();
155         }
156 
157         return SplitTransforms(size, innerPosition, outerPosition);
158     }
159 
160     private void updateScrollButtonsTransforms() {
161         transforms.horizontalScrollButton = updateHorizontalChainTransforms(
162             renderData.horizontalScrollButton.widths,
163             widget.view.cameraView,
164             widget.absolutePosition + widget.horizontalScrollButton.buttonOffset,
165             vec2(
166                 widget.horizontalScrollButton.buttonSize,
167                 widget.measure.horizontalScrollRegionWidth
168             )
169         );
170 
171         transforms.verticalScrollButton = updateVerticalChainTransforms(
172             renderData.verticalScrollButton.widths,
173             widget.view.cameraView,
174             widget.absolutePosition + widget.verticalScrollButton.buttonOffset,
175             vec2(
176                 widget.measure.verticalScrollRegionWidth,
177                 widget.verticalScrollButton.buttonSize
178             )
179         );
180     }
181 }