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 }