1 module demo; 2 3 import std.exception; 4 import std.file; 5 import std.path; 6 import std.stdio; 7 import std..string; 8 9 import deimos.glfw.glfw3; 10 11 import glad.gl.enums; 12 import glad.gl.ext; 13 import glad.gl.funcs; 14 import glad.gl.loader; 15 import glad.gl.types; 16 17 import glwtf.input; 18 import glwtf.window; 19 20 import imgui; 21 22 import window; 23 24 struct GUI 25 { 26 this(Window window) 27 { 28 this.window = window; 29 30 window.on_scroll.strongConnect(&onScroll); 31 32 int width; 33 int height; 34 glfwGetFramebufferSize(window.window, &width, &height); 35 36 // trigger initial viewport transform. 37 onWindowResize(width, height); 38 39 window.on_resize.strongConnect(&onWindowResize); 40 41 // Not really needed, but makes it obvious what we're doing 42 textEntered = textInputBuffer[0 .. 0]; 43 44 glfwSetCharCallback(window.window, &getUnicode); 45 glfwSetKeyCallback(window.window, &getKey); 46 } 47 48 void render() 49 { 50 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 51 52 // Mouse states 53 ubyte mousebutton = 0; 54 double mouseX; 55 double mouseY; 56 glfwGetCursorPos(window.window, &mouseX, &mouseY); 57 58 const scrollAreaWidth = windowWidth / 4; 59 const scrollAreaHeight = windowHeight - 20; 60 61 int mousex = cast(int)mouseX; 62 int mousey = cast(int)mouseY; 63 64 mousey = windowHeight - mousey; 65 int leftButton = glfwGetMouseButton(window.window, GLFW_MOUSE_BUTTON_LEFT); 66 int rightButton = glfwGetMouseButton(window.window, GLFW_MOUSE_BUTTON_RIGHT); 67 int middleButton = glfwGetMouseButton(window.window, GLFW_MOUSE_BUTTON_MIDDLE); 68 69 if (leftButton == GLFW_PRESS) 70 mousebutton |= MouseButton.left; 71 72 imguiBeginFrame(mousex, mousey, mousebutton, mouseScroll, staticUnicode); 73 staticUnicode = 0; 74 75 if (mouseScroll != 0) 76 mouseScroll = 0; 77 78 imguiBeginScrollArea("Scroll area 1", 10, 10, scrollAreaWidth, scrollAreaHeight, &scrollArea1); 79 80 imguiSeparatorLine(); 81 imguiSeparator(); 82 83 imguiButton("Button"); 84 85 imguiButton("Disabled button", Enabled.no); 86 imguiItem("Item"); 87 imguiItem("Disabled item", Enabled.no); 88 89 if (imguiCheck("Checkbox", &checkState1)) 90 lastInfo = sformat(buffer, "Toggled the checkbox to: '%s'", checkState1 ? "On" : "Off"); 91 92 // should not be clickable 93 enforce(!imguiCheck("Inactive disabled checkbox", &checkState2, Enabled.no)); 94 95 enforce(!imguiCheck("Inactive enabled checkbox", &checkState3, Enabled.no)); 96 97 if(imguiTextInput("Text input:", textInputBuffer, textEntered)) 98 { 99 lastTextEntered = textEntered.idup; 100 textEntered = textInputBuffer[0 .. 0]; 101 } 102 imguiLabel("Entered text: " ~ lastTextEntered); 103 104 if (imguiCollapse("Collapse", "subtext", &collapseState1)) 105 lastInfo = sformat(buffer, "subtext changed to: '%s'", collapseState1 ? "Maximized" : "Minimized"); 106 107 if (collapseState1) 108 { 109 imguiIndent(); 110 imguiLabel("Collapsable element"); 111 imguiUnindent(); 112 } 113 114 // should not be clickable 115 enforce(!imguiCollapse("Disabled collapse", "subtext", &collapseState2, Enabled.no)); 116 117 imguiLabel("Label"); 118 imguiValue("Value"); 119 120 imguiLabel("Unicode characters"); 121 imguiValue("é ř ť ý ú í ó á š ď ĺ ľ ž č ň"); 122 123 if (imguiSlider("Slider", &sliderValue1, 0.0, 100.0, 1.0f)) 124 lastInfo = sformat(buffer, "Slider clicked, current value is: '%s'", sliderValue1); 125 126 // should not be clickable 127 enforce(!imguiSlider("Disabled slider", &sliderValue2, 0.0, 100.0, 1.0f, Enabled.no)); 128 129 imguiIndent(); 130 imguiLabel("Indented"); 131 imguiUnindent(); 132 imguiLabel("Unindented"); 133 134 imguiEndScrollArea(); 135 136 imguiBeginScrollArea("Scroll area 2", 20 + (1 * scrollAreaWidth), 10, scrollAreaWidth, scrollAreaHeight, &scrollArea2); 137 imguiSeparatorLine(); 138 imguiSeparator(); 139 140 foreach (i; 0 .. 100) 141 imguiLabel("A wall of text"); 142 143 imguiEndScrollArea(); 144 145 imguiBeginScrollArea("Scroll area 3", 30 + (2 * scrollAreaWidth), 10, scrollAreaWidth, scrollAreaHeight, &scrollArea3); 146 imguiLabel(lastInfo); 147 imguiEndScrollArea(); 148 149 imguiEndFrame(); 150 151 const graphicsXPos = 40 + (3 * scrollAreaWidth); 152 153 imguiDrawText(graphicsXPos, scrollAreaHeight, TextAlign.left, "Free text", RGBA(32, 192, 32, 192)); 154 imguiDrawText(graphicsXPos + 100, windowHeight - 40, TextAlign.right, "Free text", RGBA(32, 32, 192, 192)); 155 imguiDrawText(graphicsXPos + 50, windowHeight - 60, TextAlign.center, "Free text", RGBA(192, 32, 32, 192)); 156 157 imguiDrawLine(graphicsXPos, windowHeight - 80, graphicsXPos + 100, windowHeight - 60, 1.0f, RGBA(32, 192, 32, 192)); 158 imguiDrawLine(graphicsXPos, windowHeight - 100, graphicsXPos + 100, windowHeight - 80, 2.0, RGBA(32, 32, 192, 192)); 159 imguiDrawLine(graphicsXPos, windowHeight - 120, graphicsXPos + 100, windowHeight - 100, 3.0, RGBA(192, 32, 32, 192)); 160 161 imguiDrawRoundedRect(graphicsXPos, windowHeight - 240, 100, 100, 5.0, RGBA(32, 192, 32, 192)); 162 imguiDrawRoundedRect(graphicsXPos, windowHeight - 350, 100, 100, 10.0, RGBA(32, 32, 192, 192)); 163 imguiDrawRoundedRect(graphicsXPos, windowHeight - 470, 100, 100, 20.0, RGBA(192, 32, 32, 192)); 164 165 imguiDrawRect(graphicsXPos, windowHeight - 590, 100, 100, RGBA(32, 192, 32, 192)); 166 imguiDrawRect(graphicsXPos, windowHeight - 710, 100, 100, RGBA(32, 32, 192, 192)); 167 imguiDrawRect(graphicsXPos, windowHeight - 830, 100, 100, RGBA(192, 32, 32, 192)); 168 169 imguiRender(windowWidth, windowHeight); 170 } 171 172 /** 173 This tells OpenGL what area of the available area we are 174 rendering to. In this case, we change it to match the 175 full available area. Without this function call resizing 176 the window would have no effect on the rendering. 177 */ 178 void onWindowResize(int width, int height) 179 { 180 // bottom-left position. 181 enum int x = 0; 182 enum int y = 0; 183 184 /** 185 This function defines the current viewport transform. 186 It defines as a region of the window, specified by the 187 bottom-left position and a width/height. 188 189 Note about the viewport transform: 190 It is the process of transforming vertex data from normalized 191 device coordinate space to window space. It specifies the 192 viewable region of a window. 193 */ 194 glfwGetFramebufferSize(window.window, &width, &height); 195 glViewport(x, y, width, height); 196 197 windowWidth = width; 198 windowHeight = height; 199 } 200 201 void onScroll(double hOffset, double vOffset) 202 { 203 mouseScroll = -cast(int)vOffset; 204 } 205 206 extern(C) static void getUnicode(GLFWwindow* w, uint unicode) 207 { 208 staticUnicode = unicode; 209 } 210 211 extern(C) static void getKey(GLFWwindow* w, int key, int scancode, int action, int mods) 212 { 213 if(action != GLFW_PRESS) { return; } 214 if(key == GLFW_KEY_ENTER) { staticUnicode = 0x0D; } 215 else if(key == GLFW_KEY_BACKSPACE) { staticUnicode = 0x08; } 216 } 217 218 private: 219 Window window; 220 int windowWidth; 221 int windowHeight; 222 223 bool checkState1 = false; 224 bool checkState2 = false; 225 bool checkState3 = true; 226 bool collapseState1 = true; 227 bool collapseState2 = false; 228 float sliderValue1 = 50.0; 229 float sliderValue2 = 30.0; 230 int scrollArea1 = 0; 231 int scrollArea2 = 0; 232 int scrollArea3 = 0; 233 int mouseScroll = 0; 234 235 char[] lastInfo; // last clicked element information 236 char[1024] buffer; // buffer to hold our text 237 238 static dchar staticUnicode; 239 // Buffer to store text input 240 char[128] textInputBuffer; 241 // Slice of textInputBuffer 242 char[] textEntered; 243 // Text entered last time the user the text input field. 244 string lastTextEntered; 245 } 246 247 int main(string[] args) 248 { 249 int width = 1024, height = 768; 250 251 auto window = createWindow("imgui", WindowMode.windowed, width, height); 252 253 GUI gui = GUI(window); 254 255 glfwSwapInterval(1); 256 257 string fontPath = thisExePath().dirName().buildPath("../").buildPath("DroidSans.ttf"); 258 259 enforce(imguiInit(fontPath)); 260 261 glClearColor(0.8f, 0.8f, 0.8f, 1.0f); 262 glEnable(GL_BLEND); 263 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 264 glDisable(GL_DEPTH_TEST); 265 266 while (!glfwWindowShouldClose(window.window)) 267 { 268 gui.render(); 269 270 /* Swap front and back buffers. */ 271 window.swap_buffers(); 272 273 /* Poll for and process events. */ 274 glfwPollEvents(); 275 276 if (window.is_key_down(GLFW_KEY_ESCAPE)) 277 glfwSetWindowShouldClose(window.window, true); 278 } 279 280 // Clean UI 281 imguiDestroy(); 282 283 return 0; 284 }