1 module rpui.widgets.panel.render_system;
2 
3 import rpui.theme;
4 import rpui.widgets.panel.widget;
5 import rpui.widgets.panel.transforms_system;
6 
7 import gapi.texture;
8 import gapi.vec;
9 import gapi.geometry;
10 import rpui.primitives;
11 import rpui.render.components;
12 import rpui.render.components_factory;
13 import rpui.render.renderer;
14 
15 enum SplitColor {
16     darkInner,
17     darkOuter,
18     lightInner,
19     lightOuter,
20 }
21 
22 struct RenderData {
23     vec4[Panel.Background] backgroundColors;
24     vec4[SplitColor] splitColors;
25     Texture2DCoords headerOpenMarkTexCoords;
26     Texture2DCoords headerCloseMarkTexCoords;
27     vec2 headerMarkSize;
28     vec2 headerMarkPosition;
29 
30     Geometry background;
31     Geometry splitInner;
32     Geometry splitOuter;
33     StatefulChain horizontalScrollButton;
34     StatefulChain verticalScrollButton;
35     StatefulTexAtlasTextureQuad headerBackground;
36     TextureQuad headerMark;
37     StatefulUiText headerText;
38 }
39 
40 final class PanelRenderSystem : RenderSystem {
41     private Panel widget;
42     private Theme theme;
43     private RenderTransforms* transforms;
44     private RenderData* renderData;
45 
46     this(Panel widget, RenderData* renderData, RenderTransforms* transforms) {
47         this.widget = widget;
48         this.theme = widget.view.theme;
49         this.transforms = transforms;
50         this.renderData = renderData;
51     }
52 
53     override void onRender() {
54         renderBackground();
55         renderHeader();
56 
57         if (!widget.isOpen) {
58             renderSplit();
59             return;
60         }
61 
62         widget.renderChildren();
63         renderSplit();
64         renderScrollButtons();
65     }
66 
67     private void renderBackground() {
68         if (widget.background == Panel.Background.transparent) {
69             return;
70         }
71 
72         renderColorQuad(
73             theme,
74             renderData.background,
75             renderData.backgroundColors[widget.background],
76             transforms.background
77         );
78     }
79 
80     private void renderScrollButtons() {
81         if (widget.horizontalScrollButton.visible) {
82             renderHorizontalChain(
83                 theme,
84                 renderData.horizontalScrollButton.parts,
85                 renderData.horizontalScrollButton.texCoords[widget.horizontalScrollButton.state],
86                 transforms.horizontalScrollButton
87             );
88         }
89 
90         if (widget.verticalScrollButton.visible) {
91             renderVerticalChain(
92                 theme,
93                 renderData.verticalScrollButton.parts,
94                 renderData.verticalScrollButton.texCoords[widget.verticalScrollButton.state],
95                 transforms.verticalScrollButton
96             );
97         }
98     }
99 
100     private void renderSplit() {
101         if (!widget.showSplit)
102             return;
103 
104         const innerColor = widget.darkSplit
105             ? renderData.splitColors[SplitColor.darkInner]
106             : renderData.splitColors[SplitColor.lightInner];
107 
108         const outerColor = widget.darkSplit
109             ? renderData.splitColors[SplitColor.darkOuter]
110             : renderData.splitColors[SplitColor.lightOuter];
111 
112         renderColorQuad(
113             theme,
114             renderData.splitInner,
115             innerColor,
116             transforms.splitInner
117         );
118 
119         renderColorQuad(
120             theme,
121             renderData.splitOuter,
122             outerColor,
123             transforms.splitOuter
124         );
125     }
126 
127     private void renderHeader() {
128         if (widget.userCanHide) {
129             renderTexAtlasQuad(
130                 theme,
131                 renderData.headerBackground.geometry,
132                 renderData.headerBackground.texture,
133                 renderData.headerBackground.texCoords[widget.headerState].normilizedTexCoords,
134                 transforms.headerBackground
135             );
136 
137             Texture2DCoords markTexCoords;
138 
139             if (widget.isOpen) {
140                 markTexCoords = renderData.headerOpenMarkTexCoords;
141             } else {
142                 markTexCoords = renderData.headerCloseMarkTexCoords;
143             }
144 
145             renderTexAtlasQuad(
146                 theme,
147                 renderData.headerMark.geometry,
148                 renderData.headerMark.texture,
149                 markTexCoords,
150                 transforms.headerMark
151             );
152         }
153 
154         renderUiText(
155             theme,
156             renderData.headerText.render,
157             renderData.headerText.attrs[widget.headerState],
158             transforms.headerText,
159         );
160     }
161 }