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 
73     struct ItemData {
74         dstring title;
75         int payload;
76     }
77 
78     Array!ItemData listData;
79 
80     int a = 0;
81 
82     this(View view, in string laytoutFileName, in string shortcutsFileName) {
83         super(view, laytoutFileName, shortcutsFileName);
84     }
85 
86     override void onCreate() {
87         okButton.events.subscribe!KeyPressedEvent(delegate(in event) {
88             writeln("Handle OkButton Key Pressed Event", event.key);
89         });
90 
91         okButton.isEnabled = true;
92         openglCanvas.canvasRenderer = new OpenGLRenderer();
93     }
94 
95     private void bindData() {
96         listWithData.bindData(listData, function(ItemData data) {
97             auto listItem = new ListMenuItem();
98             listItem.caption = data.title;
99             listItem.events.subscribe!ClickEvent(delegate(in event) {
100                 writeln("List item clicked; payload is: ", data.payload);
101             });
102             return listItem;
103         });
104     }
105 
106     @onClickListener("addListItemButton")
107     void onAddListItemButton() {
108         listData.insert(ItemData("Item index: " ~ to!dstring(listData.length), a));
109         bindData();
110     }
111 
112     @onClickListener("removeListItemButton")
113     void onRemoveListItemButton() {
114         if (!listData.empty) {
115             listData.removeBack(1);
116             bindData();
117         }
118     }
119 
120     @onClickListener("okButton")
121     void onOkButtonClick() {
122         writeln("Hello world! a = ", a);
123         a += 1;
124     }
125 
126     @onClickListener("okButton")
127     void onOkButtonClick2() {
128         okButton.caption = "YAY!";
129         myButton.caption = "WORKS!";
130         buttons[2].caption = "YES!";
131     }
132 
133     @shortcut("TestGroup.cancel")
134     void someShortcutAction() {
135         writeln("Wow! shortcut was executed!");
136     }
137 
138     @onClickListener("closeButton")
139     @onClickListener("cancelButton")
140     void onCancelButtonClick() {
141         writeln("Close!");
142     }
143 
144     @onClickListener("testMenuItem")
145     @onClickListener("testMenuItem2")
146     @onClickListener("openDialogButton")
147     void onOpenDialogButtonClick() {
148         testDialog.open();
149     }
150 
151     @onClickListener("closeDialogButton")
152     void onCloseDialogButtonClick() {
153         testDialog.close();
154     }
155 }
156 
157 final class OpenGLRenderer : CanvasRenderer {
158     struct Geometry {
159         Buffer indicesBuffer;
160         Buffer verticesBuffer;
161         Buffer texCoordsBuffer;
162 
163         VAO vao;
164     }
165 
166     private Geometry sprite;
167     private Texture2D spriteTexture;
168     private ShaderProgram transformShader;
169     private Transform2D spriteTransform;
170     private mat4 spriteModelMatrix;
171     private mat4 spriteMVPMatrix;
172     private Widget widget;
173 
174     override void onCreate(Widget widget) {
175         createSprite();
176         createTexture();
177         createShaders();
178 
179         this.widget = widget;
180     }
181 
182     override void onDestroy() {
183         deleteBuffer(sprite.indicesBuffer);
184         deleteBuffer(sprite.verticesBuffer);
185         deleteBuffer(sprite.texCoordsBuffer);
186         deleteTexture2D(spriteTexture);
187         deleteShaderProgram(transformShader);
188     }
189 
190     private void createSprite() {
191         sprite.indicesBuffer = createIndicesBuffer(quadIndices);
192         sprite.verticesBuffer = createVector2fBuffer(centeredQuadVertices);
193         sprite.texCoordsBuffer = createVector2fBuffer(quadTexCoords);
194 
195         sprite.vao = createVAO();
196         bindVAO(sprite.vao);
197         createVector2fVAO(sprite.verticesBuffer, inAttrPosition);
198         createVector2fVAO(sprite.texCoordsBuffer, inAttrTextCoords);
199     }
200 
201     private void createTexture() {
202         const Texture2DParameters params = {
203             minFilter: true,
204             magFilter: true
205         };
206         spriteTexture = createTexture2DFromFile(buildPath("res", "test.jpg"), params);
207     }
208 
209     private void createShaders() {
210         const vertexSource = readText(buildPath("res", "shaders", "transform_vertex.glsl"));
211         const vertexShader = createShader("transform vertex shader", ShaderType.vertex, vertexSource);
212 
213         const fragmentSource = readText(buildPath("res", "shaders", "texture_fragment.glsl"));
214         const fragmentShader = createShader("transform fragment shader", ShaderType.fragment, fragmentSource);
215 
216         transformShader = createShaderProgram("transform program", [vertexShader, fragmentShader]);
217     }
218 
219     override void onRender() {
220         bindShaderProgram(transformShader);
221         setShaderProgramUniformMatrix(transformShader, "MVP", spriteMVPMatrix);
222         setShaderProgramUniformTexture(transformShader, "texture", spriteTexture, 0);
223 
224         bindVAO(sprite.vao);
225         bindIndices(sprite.indicesBuffer);
226         renderIndexedGeometry(cast(uint) quadIndices.length, GL_TRIANGLE_STRIP);
227     }
228 
229     override void onProgress(in ProgressEvent event) {
230         assert(widget !is null);
231         assert(widget.view !is null);
232 
233         const screenCameraView = widget.view.cameraView;
234         spriteTransform.position = vec2(
235             screenCameraView.viewportWidth / 2,
236             screenCameraView.viewportHeight / 2
237         );
238         spriteTransform.scaling = vec2(430.0f, 600.0f);
239         spriteTransform.rotation += 0.025f * event.deltaTime;
240 
241         spriteModelMatrix = create2DModelMatrix(spriteTransform);
242         spriteMVPMatrix = screenCameraView.mvpMatrix * spriteModelMatrix;
243     }
244 }