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 }