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 }