1 module main;
2 
3 import std.stdio;
4 import std.path;
5 import std.file;
6 import std.container.array;
7 import std.conv;
8 import core.memory;
9 
10 import rpui.application;
11 import rpui.events;
12 import rpui.widget_events;
13 import rpui.view;
14 import rpui.view_component;
15 import rpui.widget;
16 import rpui.widgets.button.widget;
17 import rpui.widgets.panel.widget;
18 import rpui.widgets.dialog.widget;
19 import rpui.widgets.canvas.widget;
20 import rpui.widgets.list_menu.widget;
21 import rpui.widgets.list_menu_item.widget;
22 
23 import gapi.vec;
24 import gapi.camera;
25 import gapi.geometry;
26 import gapi.geometry_quad;
27 import gapi.shader;
28 import gapi.texture;
29 import gapi.transform;
30 import gapi.shader_uniform;
31 import gapi.opengl;
32 
33 void main() {
34     auto app = new TestApplication();
35     app.run();
36 }
37 
38 final class TestApplication : Application {
39     private View rootView;
40     private MyViewComponent viewComponent;
41 
42     override void onProgress(in ProgressEvent event) {
43         viewComponent.onProgress(event);
44         rootView.onProgress(event);
45     }
46 
47     override void onRender() {
48         rootView.onRender();
49     }
50 
51     override void onCreate() {
52         auto viewResources = createViewResources("light");
53         viewResources.strings.setLocale("en");
54         viewResources.strings.addStrings("test_view.rdl");
55 
56         rootView = new View(windowData.window, "light", cursorManager, viewResources);
57         events.join(rootView.events);
58         events.subscribe(rootView);
59 
60         viewComponent = ViewComponent.createFromFileWithShortcuts!(MyViewComponent)(rootView, "test.rdl");
61     }
62 }
63 
64 final class MyViewComponent : ViewComponent {
65     @bindWidget Button okButton;
66     @bindWidget Panel testPanel;
67     @bindWidget("cancelButton") Button myButton;
68     @bindWidget Dialog testDialog;
69     @bindGroupWidgets Button[3] buttons;
70     @bindWidget Canvas openglCanvas;
71     @bindWidget ListMenu listWithData;
72     @bindWidget ListMenu dropListWithData;
73 
74     struct ItemData {
75         dstring title;
76         int payload;
77     }
78 
79     Array!ItemData listData;
80 
81     int a = 0;
82 
83     this(View view, in string laytoutFileName, in string shortcutsFileName) {
84         super(view, laytoutFileName, shortcutsFileName);
85     }
86 
87     override void onCreate() {
88         okButton.events.subscribe!KeyPressedEvent(delegate(in event) {
89             writeln("Handle OkButton Key Pressed Event", event.key);
90         });
91 
92         okButton.isEnabled = true;
93         openglCanvas.canvasRenderer = new OpenGLRenderer();
94     }
95 
96     private void bindData() {
97         listWithData.bindData(listData, delegate(ItemData data) {
98             auto listItem = new ListMenuItem();
99             listItem.caption = data.title;
100             listItem.events.subscribe!ClickEvent(delegate(in event) {
101                 writeln("List item clicked; payload is: ", data.payload);
102             });
103             return listItem;
104         });
105 
106         dropListWithData.bindData(listData, delegate(ItemData data) {
107             auto listItem = new ListMenuItem();
108             listItem.caption = data.title;
109             listItem.events.subscribe!ClickEvent(delegate(in event) {
110                 writeln("List item clicked; payload is: ", data.payload);
111             });
112             return listItem;
113         });
114     }
115 
116     @onClickListener("addListItemButton")
117     void onAddListItemButton() {
118         listData.insert(ItemData("Item index: " ~ to!dstring(listData.length), a));
119         bindData();
120     }
121 
122     @onClickListener("menuItem1")
123     void onMenuItem1Click() {
124         writeln("MenuItem1 clicked");
125     }
126 
127     @onClickListener("menuItem2")
128     void onMenuItem2Click() {
129         writeln("MenuItem2 clicked");
130     }
131 
132     @onClickListener("removeListItemButton")
133     void onRemoveListItemButton() {
134         if (!listData.empty) {
135             listData.removeBack(1);
136             bindData();
137         }
138     }
139 
140     @onClickListener("okButton")
141     void onOkButtonClick() {
142         writeln("Hello world! a = ", a);
143         a += 1;
144     }
145 
146     @onClickListener("okButton")
147     void onOkButtonClick2() {
148         okButton.caption = "YAY!";
149         myButton.caption = "WORKS!";
150         buttons[2].caption = "YES!";
151     }
152 
153     @shortcut("TestGroup.cancel")
154     void someShortcutAction() {
155         writeln("Wow! shortcut was executed!");
156     }
157 
158     @shortcut("Ctrl+U", false)
159     void someShortcutAction2() {
160         writeln("Manual set chortcut");
161     }
162 
163     @onClickListener("closeButton")
164     @onClickListener("cancelButton")
165     void onCancelButtonClick() {
166         writeln("Close!");
167     }
168 
169     @onClickListener("testMenuItem")
170     @onClickListener("testMenuItem2")
171     @onClickListener("openDialogButton")
172     void onOpenDialogButtonClick() {
173         testDialog.open();
174     }
175 
176     @onClickListener("closeDialogButton")
177     void onCloseDialogButtonClick() {
178         testDialog.close();
179     }
180 }
181 
182 final class OpenGLRenderer : CanvasRenderer {
183     struct Geometry {
184         Buffer indicesBuffer;
185         Buffer verticesBuffer;
186         Buffer texCoordsBuffer;
187 
188         VAO vao;
189     }
190 
191     private Geometry sprite;
192     private Texture2D spriteTexture;
193     private ShaderProgram transformShader;
194     private Transform2D spriteTransform;
195     private mat4 spriteModelMatrix;
196     private mat4 spriteMVPMatrix;
197     private Widget widget;
198 
199     override void onCreate(Widget widget) {
200         createSprite();
201         createTexture();
202         createShaders();
203 
204         this.widget = widget;
205     }
206 
207     override void onDestroy() {
208         deleteBuffer(sprite.indicesBuffer);
209         deleteBuffer(sprite.verticesBuffer);
210         deleteBuffer(sprite.texCoordsBuffer);
211         deleteTexture2D(spriteTexture);
212         deleteShaderProgram(transformShader);
213     }
214 
215     private void createSprite() {
216         sprite.indicesBuffer = createIndicesBuffer(quadIndices);
217         sprite.verticesBuffer = createVector2fBuffer(centeredQuadVertices);
218         sprite.texCoordsBuffer = createVector2fBuffer(quadTexCoords);
219 
220         sprite.vao = createVAO();
221         bindVAO(sprite.vao);
222         createVector2fVAO(sprite.verticesBuffer, inAttrPosition);
223         createVector2fVAO(sprite.texCoordsBuffer, inAttrTextCoords);
224     }
225 
226     private void createTexture() {
227         const Texture2DParameters params = {
228             minFilter: true,
229             magFilter: true
230         };
231         spriteTexture = createTexture2DFromFile(buildPath("res", "test.jpg"), params);
232     }
233 
234     private void createShaders() {
235         const vertexSource = readText(buildPath("res", "shaders", "transform_vertex.glsl"));
236         const vertexShader = createShader("transform vertex shader", ShaderType.vertex, vertexSource);
237 
238         const fragmentSource = readText(buildPath("res", "shaders", "texture_fragment.glsl"));
239         const fragmentShader = createShader("transform fragment shader", ShaderType.fragment, fragmentSource);
240 
241         transformShader = createShaderProgram("transform program", [vertexShader, fragmentShader]);
242     }
243 
244     override void onRender() {
245         bindShaderProgram(transformShader);
246         setShaderProgramUniformMatrix(transformShader, "MVP", spriteMVPMatrix);
247         setShaderProgramUniformTexture(transformShader, "utexture", spriteTexture, 0);
248 
249         bindVAO(sprite.vao);
250         bindIndices(sprite.indicesBuffer);
251         renderIndexedGeometry(cast(uint) quadIndices.length, GL_TRIANGLE_STRIP);
252     }
253 
254     override void onProgress(in ProgressEvent event) {
255         assert(widget !is null);
256         assert(widget.view !is null);
257 
258         const screenCameraView = widget.view.cameraView;
259         spriteTransform.position = vec2(
260             screenCameraView.viewportWidth / 2,
261             screenCameraView.viewportHeight / 2
262         );
263         spriteTransform.scaling = vec2(430.0f, 600.0f);
264         spriteTransform.rotation += 0.025f * event.deltaTime;
265 
266         spriteModelMatrix = create2DModelMatrix(spriteTransform);
267         spriteMVPMatrix = screenCameraView.mvpMatrix * spriteModelMatrix;
268     }
269 }