1 module rpui.widgets.button.transforms_system;
2 
3 import std.container.array;
4 import std.math;
5 
6 import rpui.events;
7 import rpui.widgets.button.widget;
8 import rpui.render.components_factory;
9 import rpui.render.components;
10 import rpui.render.transforms;
11 import rpui.theme;
12 import rpui.widgets.button.render_system;
13 import rpui.math;
14 import rpui.primitives;
15 import rpui.widget;
16 
17 struct RenderTransforms {
18     HorizontalChainTransforms background;
19     HorizontalChainTransforms focusGlow;
20     UiTextTransforms captionText;
21     Array!QuadTransforms icons;
22 }
23 
24 final class ButtonTransformsSystem : TransformsSystem {
25     private RenderTransforms* transforms;
26     private Button widget;
27     private Theme theme;
28     private RenderData* renderData;
29 
30     this(Button widget, RenderData* renderData, RenderTransforms* transforms) {
31         this.widget = widget;
32         this.theme = widget.view.theme;
33         this.renderData = renderData;
34         this.transforms = transforms;
35     }
36 
37     override void onProgress(in ProgressEvent event) {
38         updateBackground();
39         updateText();
40         updateIcons();
41     }
42 
43     private void updateBackground() {
44         transforms.background = updateHorizontalChainTransforms(
45             renderData.background.widths,
46             widget.view.cameraView,
47             widget.absolutePosition,
48             widget.size,
49             widget.partDraws
50         );
51 
52         if (widget.focusable && widget.isFocused) {
53             transforms.focusGlow = updateHorizontalChainTransforms(
54                 renderData.background.widths,
55                 widget.view.cameraView,
56                 widget.absolutePosition + widget.measure.focusOffsets,
57                 widget.size + vec2(widget.measure.focusResize),
58                 widget.partDraws
59             );
60         }
61     }
62 
63     private void updateText() {
64         if (widget.caption == "") {
65             widget.measure.textWidth = 0;
66             return;
67         }
68 
69         const textBoxSize = widget.size - vec2(widget.measure.iconsAreaSize, 0);
70         auto textPosition = vec2(widget.measure.iconsAreaSize, 0) + widget.absolutePosition;
71 
72         if (widget.textAlign == Align.left) {
73             textPosition.x += widget.measure.textLeftMargin;
74         }
75         else if (widget.textAlign == Align.right) {
76             textPosition.x -= widget.measure.textRightMargin;
77         }
78 
79         if (widget.partDraws == Widget.PartDraws.left || widget.partDraws == Widget.PartDraws.right) {
80             textPosition.x -= 1;
81         }
82 
83         with (renderData.captionText.attrs[widget.state]) {
84             caption = widget.caption;
85             textAlign = widget.textAlign;
86             textVerticalAlign = widget.textVerticalAlign;
87         }
88 
89         transforms.captionText = updateUiTextTransforms(
90             &renderData.captionText.render,
91             &theme.regularFont,
92             transforms.captionText,
93             renderData.captionText.attrs[widget.state],
94             widget.view.cameraView,
95             textPosition,
96             textBoxSize
97         );
98 
99         widget.measure.textWidth = transforms.captionText.size.x;
100     }
101 
102     private void updateIcons() {
103         with (widget) {
104             measure.iconsAreaSize = 0;
105 
106             const iconSize = view.resources.icons.getIconsConfig(iconsGroup).size;
107             const iconVerticalOffset = round((size.y - iconSize.y) / 2.0f);
108             float iconLastOffset = 0;
109             int counter = 0;
110 
111             for (int i = 0; i < widget.icons.length; ++i) {
112                 const iconOffset = iconLastOffset;
113 
114                 iconLastOffset = iconOffset + iconSize.x + measure.iconGaps;
115                 counter++;
116                 const offset = measure.iconOffsets + vec2(iconOffset, iconVerticalOffset);
117 
118                 const transform = updateQuadTransforms(
119                     view.cameraView,
120                     absolutePosition + offset,
121                     iconSize
122                 );
123                 transforms.icons[i] = transform;
124             }
125 
126             if (icons.length > 0) {
127                 measure.iconsAreaSize += iconLastOffset - measure.iconGaps * 2;
128             }
129         }
130     }
131 }