1 module rpui.widgets.checkbox.renderer;
2 
3 import rpui.math;
4 import rpui.theme;
5 import rpui.events;
6 import rpui.widget;
7 import rpui.widgets.checkbox.widget;
8 import rpui.render.components;
9 import rpui.render.components_factory;
10 import rpui.render.renderer;
11 import rpui.render.transforms;
12 
13 final class CheckboxRenderer : Renderer {
14     private StatefulUiText text;
15     private StatefulTexAtlasTextureQuad checkedBox;
16     private StatefulTexAtlasTextureQuad uncheckedBox;
17     private TexAtlasTextureQuad focusGlow;
18     private QuadTransforms boxTransforms;
19     private QuadTransforms focusGlowTransforms;
20     private UiTextTransforms textTransforms;
21     private Checkbox widget;
22     private Theme theme;
23     private vec2 focusOffsets;
24 
25     private inout(State) getTextState() inout {
26         return widget.isEnter ? State.enter : State.leave;
27     }
28 
29     private void updateState() {
30         text.state = getTextState();
31         checkedBox.state = getTextState();
32         uncheckedBox.state = getTextState();
33     }
34 
35     override void onCreate(Widget widget, in string style) {
36         this.theme = widget.view.theme;
37         this.widget = cast(Checkbox) widget;
38 
39         text = createStatefulUiTextFromRdpl(
40             theme,
41             style,
42             "Text",
43             [State.leave, State.enter]
44         );
45 
46         checkedBox = createStatefulTexAtlasTextureQuadFromRdpl(
47             theme,
48             style,
49             "checkedBox",
50             [State.leave, State.enter]
51         );
52 
53         uncheckedBox = createStatefulTexAtlasTextureQuadFromRdpl(
54             theme,
55             style,
56             "uncheckedBox",
57             [State.leave, State.enter]
58         );
59 
60         focusGlow = createTexAtlasTextureQuadFromRdpl(
61             theme,
62             style,
63             "Focus.glow"
64         );
65 
66         focusOffsets = theme.tree.data.getVec2f(style ~ ".Focus.offsets");
67     }
68 
69     override void onRender() {
70         updateState();
71         renderUiText(theme, text, textTransforms);
72 
73         if (widget.checked) {
74             renderTexAtlasQuad(theme, checkedBox, boxTransforms);
75         } else {
76             renderTexAtlasQuad(theme, uncheckedBox, boxTransforms);
77         }
78 
79         if (widget.isFocused) {
80             renderTexAtlasQuad(theme, focusGlow, focusGlowTransforms);
81         }
82     }
83 
84     override void onProgress(in ProgressEvent event) {
85         updateText();
86         updateBox();
87     }
88 
89     private void updateText() {
90         UiTextAttributes* textAttrs = &text.attrs[getTextState()];
91 
92         with (textAttrs) {
93             caption = widget.caption;
94             textAlign = widget.textAlign;
95             textVerticalAlign = widget.textVerticalAlign;
96         }
97 
98         textTransforms = updateUiTextTransforms(
99             &text.render,
100             &theme.regularFont,
101             textTransforms,
102             *textAttrs,
103             widget.view.cameraView,
104             widget.absolutePosition + widget.innerOffsetStart,
105             widget.size
106         );
107 
108         widget.measure.textWidth = textTransforms.size.x + textAttrs.offset.x;
109         widget.measure.lineHeight = textTransforms.size.y + textAttrs.offset.y;
110     }
111 
112     private void updateBox() {
113         boxTransforms = updateQuadTransforms(
114             widget.view.cameraView,
115             widget.absolutePosition,
116             uncheckedBox.texCoords[State.leave].originalTexCoords.size
117         );
118 
119         const focusPos = widget.absolutePosition + focusOffsets;
120 
121         focusGlowTransforms = updateQuadTransforms(
122             widget.view.cameraView,
123             focusPos,
124             focusGlow.texCoords.originalTexCoords.size
125         );
126     }
127 }