1 module rpui.widgets.text_input.render_system;
2 
3 import std.container.array;
4 
5 import rpui.widgets.text_input.widget;
6 import rpui.widgets.text_input.transforms_system;
7 import rpui.render.components_factory;
8 import rpui.render.components;
9 import rpui.render.renderer;
10 import rpui.theme;
11 import rpui.math;
12 import rpui.primitives;
13 
14 import gapi.texture;
15 
16 struct RenderData {
17     StatefulChain background;
18     Chain focusGlow;
19     TexAtlasTextureQuad carriage;
20     StatefulTexAtlasTextureQuad leftArrow;
21     StatefulTexAtlasTextureQuad rightArrow;
22     StatefulUiText text;
23     StatefulUiText prefix;
24     StatefulUiText postfix;
25     Geometry selectRegion;
26     vec4 selectRegionColor;
27     vec4 selectedTextColor;
28 }
29 
30 final class TextInputRenderSystem : RenderSystem {
31     private TextInput widget;
32     private Theme theme;
33     private RenderTransforms* transforms;
34     private RenderData* renderData;
35 
36     this(TextInput widget, RenderData* renderData, RenderTransforms* transforms) {
37         this.widget = widget;
38         this.theme = widget.view.theme;
39         this.transforms = transforms;
40         this.renderData = renderData;
41     }
42 
43     override void onRender() {
44         renderBackground();
45         renderPrefix();
46         renderPostfix();
47         pushScissor();
48         renderText();
49         renderSoftPostfix();
50         renderSelectRegion();
51         renderSelectedText();
52         widget.view.popScissor();
53         renderArrows();
54         renderCarriage();
55     }
56 
57     private void pushScissor() {
58         with (widget) {
59             Rect scissor;
60 
61             const leftMargin = measure.textLeftMargin + widget.measure.prefixWidth;
62             const rightMargin = measure.textRightMargin + widget.measure.postfixWidth;
63 
64             scissor.point = vec2(
65                 absolutePosition.x + leftMargin,
66                 absolutePosition.y
67             );
68             scissor.size = vec2(
69                 size.x - leftMargin - rightMargin,
70                 size.y
71             );
72 
73             view.pushScissor(scissor);
74         }
75     }
76 
77     private void renderBackground() {
78         renderData.background.state = widget.state;
79 
80         renderHorizontalChain(
81             theme,
82             renderData.background,
83             transforms.background,
84             widget.partDraws
85         );
86 
87         if (widget.focusable && widget.isFocused) {
88             renderHorizontalChain(
89                 theme,
90                 renderData.focusGlow,
91                 transforms.focusGlow,
92                 widget.partDraws
93             );
94         }
95     }
96 
97     private void renderArrows() {
98         if (!widget.isNumberMode())
99             return;
100 
101         renderTexAtlasQuad(
102             theme,
103             renderData.leftArrow,
104             transforms.leftArrow
105         );
106 
107         renderTexAtlasQuad(
108             theme,
109             renderData.rightArrow,
110             transforms.rightArrow
111         );
112     }
113 
114     private void renderCarriage() {
115         if (!widget.isFocused)
116             return;
117 
118         if (widget.editComponent.carriage.visible) {
119             renderTexAtlasQuad(
120                 theme,
121                 renderData.carriage,
122                 transforms.carriage
123             );
124         }
125     }
126 
127     private void renderPrefix() {
128         if (widget.prefix != "") {
129             renderData.prefix.state = widget.state;
130             renderUiText(theme, renderData.prefix, transforms.prefix);
131         }
132     }
133 
134     private void renderPostfix() {
135         if (widget.postfix != "" && !widget.softPostfix) {
136             renderData.postfix.state = widget.state;
137             renderUiText(theme, renderData.postfix, transforms.postfix);
138         }
139     }
140 
141     private void renderSoftPostfix() {
142         if (widget.postfix != "" && widget.softPostfix) {
143             renderData.postfix.state = widget.state;
144             renderUiText(theme, renderData.postfix, transforms.postfix);
145         }
146     }
147 
148     private void renderText() {
149         renderData.text.state = widget.state;
150         renderUiText(theme, renderData.text, transforms.text);
151     }
152 
153     private void renderSelectedText() {
154         if (!widget.editComponent.selectRegion.textIsSelected())
155             return;
156 
157         const scissor = Rect(
158             widget.editComponent.selectRegion.absolutePosition,
159             widget.editComponent.selectRegion.size
160         );
161 
162         widget.view.pushScissor(scissor);
163         auto attrs = renderData.text.attrs[widget.state];
164         attrs.color = renderData.selectedTextColor;
165 
166         renderUiText(
167             theme,
168             renderData.text.render,
169             attrs,
170             transforms.text
171         );
172 
173         widget.view.popScissor();
174     }
175 
176     private void renderSelectRegion() {
177         if (!widget.editComponent.selectRegion.textIsSelected())
178             return;
179 
180         renderColorQuad(
181             theme,
182             renderData.selectRegion,
183             renderData.selectRegionColor,
184             transforms.selectRegion
185         );
186     }
187 }