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 glfwGetWindowSize(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 glViewport(x, y, width, height); 195 196 windowWidth = width; 197 windowHeight = height; 198 } 199 200 void onScroll(double hOffset, double vOffset) 201 { 202 mouseScroll = -cast(int)vOffset; 203 } 204 205 extern(C) static void getUnicode(GLFWwindow* w, uint unicode) 206 { 207 staticUnicode = unicode; 208 } 209 210 extern(C) static void getKey(GLFWwindow* w, int key, int scancode, int action, int mods) 211 { 212 if(action != GLFW_PRESS) { return; } 213 if(key == GLFW_KEY_ENTER) { staticUnicode = 0x0D; } 214 else if(key == GLFW_KEY_BACKSPACE) { staticUnicode = 0x08; } 215 } 216 217 private: 218 Window window; 219 int windowWidth; 220 int windowHeight; 221 222 bool checkState1 = false; 223 bool checkState2 = false; 224 bool checkState3 = true; 225 bool collapseState1 = true; 226 bool collapseState2 = false; 227 float sliderValue1 = 50.0; 228 float sliderValue2 = 30.0; 229 int scrollArea1 = 0; 230 int scrollArea2 = 0; 231 int scrollArea3 = 0; 232 int mouseScroll = 0; 233 234 char[] lastInfo; // last clicked element information 235 char[1024] buffer; // buffer to hold our text 236 237 static dchar staticUnicode; 238 // Buffer to store text input 239 char[128] textInputBuffer; 240 // Slice of textInputBuffer 241 char[] textEntered; 242 // Text entered last time the user the text input field. 243 string lastTextEntered; 244 } 245 246 int main(string[] args) 247 { 248 int width = 1024, height = 768; 249 250 auto window = createWindow("imgui", WindowMode.windowed, width, height); 251 252 GUI gui = GUI(window); 253 254 glfwSwapInterval(1); 255 256 string fontPath = thisExePath().dirName().buildPath("../").buildPath("DroidSans.ttf"); 257 258 enforce(imguiInit(fontPath)); 259 260 glClearColor(0.8f, 0.8f, 0.8f, 1.0f); 261 glEnable(GL_BLEND); 262 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 263 glDisable(GL_DEPTH_TEST); 264 265 while (!glfwWindowShouldClose(window.window)) 266 { 267 gui.render(); 268 269 /* Swap front and back buffers. */ 270 window.swap_buffers(); 271 272 /* Poll for and process events. */ 273 glfwPollEvents(); 274 275 if (window.is_key_down(GLFW_KEY_ESCAPE)) 276 glfwSetWindowShouldClose(window.window, true); 277 } 278 279 // Clean UI 280 imguiDestroy(); 281 282 return 0; 283 }