1 /* 2 Copyright © 2020, Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module creator.windows; 8 import creator.core; 9 import bindbc.imgui; 10 import std.string; 11 import std.conv; 12 import creator.widgets.titlebar; 13 import i18n; 14 15 public import creator.windows.about; 16 public import creator.windows.settings; 17 public import creator.windows.texviewer; 18 public import creator.windows.notice; 19 public import creator.windows.paramprop; 20 public import creator.windows.paramaxes; 21 public import creator.windows.trkbind; 22 23 private ImGuiWindowClass* windowClass; 24 25 private uint spawnCount = 0; 26 27 /** 28 A Widget 29 */ 30 abstract class Window { 31 private: 32 string name_; 33 bool visible = true; 34 bool disabled; 35 int spawnedId; 36 const(char)* imName; 37 38 protected: 39 bool onlyOne; 40 ImGuiWindowFlags flags; 41 42 abstract void onUpdate(); 43 44 void onBeginUpdate() { 45 if (imName is null) this.setTitle(name); 46 igSetNextWindowClass(windowClass); 47 igBegin( 48 imName, 49 &visible, 50 flags | ImGuiWindowFlags.NoDecoration 51 ); 52 } 53 54 void onEndUpdate() { 55 igEnd(); 56 } 57 58 void onClose() { } 59 60 public: 61 62 63 /** 64 Constructs a frame 65 */ 66 this(string name) { 67 this.name_ = name; 68 this.restore(); 69 } 70 71 final void close() { 72 this.visible = false; 73 } 74 75 final string name() { 76 return name_; 77 } 78 79 final void setTitle(string title) { 80 this.name_ = title; 81 imName = "%s###%s".format(name_, spawnedId).toStringz; 82 } 83 84 /** 85 Draws the frame 86 */ 87 final void update() { 88 igPushItemFlag(ImGuiItemFlags.Disabled, disabled); 89 this.onBeginUpdate(); 90 this.onUpdate(); 91 this.onEndUpdate(); 92 igPopItemFlag(); 93 94 if (disabled && !visible) visible = true; 95 } 96 97 ImVec2 getPosition() { 98 ImVec2 pos; 99 igGetWindowPos(&pos); 100 return pos; 101 } 102 103 void disable() { 104 this.flags = ImGuiWindowFlags.NoDocking | 105 ImGuiWindowFlags.NoCollapse | 106 ImGuiWindowFlags.NoNav | 107 ImGuiWindowFlags.NoMove | 108 ImGuiWindowFlags.NoScrollWithMouse | 109 ImGuiWindowFlags.NoScrollbar; 110 disabled = true; 111 } 112 113 void restore() { 114 disabled = false; 115 this.flags = ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoSavedSettings; 116 117 windowClass = ImGuiWindowClass_ImGuiWindowClass(); 118 windowClass.ViewportFlagsOverrideClear = ImGuiViewportFlags.NoDecoration | ImGuiViewportFlags.NoTaskBarIcon; 119 windowClass.ViewportFlagsOverrideSet = ImGuiViewportFlags.NoAutoMerge; 120 } 121 } 122 123 private { 124 Window[] windowStack; 125 Window[] windowList; 126 } 127 128 /** 129 Pushes window to stack 130 */ 131 void incPushWindow(Window window) { 132 window.spawnedId = spawnCount++; 133 134 // Only allow one instance of the window 135 if (window.onlyOne) { 136 foreach(win; windowStack) { 137 if (win.name == window.name) return; 138 } 139 } 140 141 if (windowStack.length > 0) { 142 windowStack[$-1].disable(); 143 } 144 145 windowStack ~= window; 146 } 147 148 /** 149 Pushes window to stack 150 */ 151 void incPushWindowList(Window window) { 152 window.spawnedId = spawnCount++; 153 154 // Only allow one instance of the window 155 if (window.onlyOne) { 156 foreach(win; windowList) { 157 if (win.name == window.name) return; 158 } 159 } 160 161 windowList ~= window; 162 } 163 164 /** 165 Pop window from Window List 166 */ 167 void incPopWindowList(Window window) { 168 import std.algorithm.searching : countUntil; 169 import std.algorithm.mutation : remove; 170 171 ptrdiff_t i = windowList.countUntil(window); 172 if (i != -1) { 173 if (windowList.length == 1) windowList.length = 0; 174 else windowList = windowList.remove(i); 175 } 176 } 177 178 /** 179 Pop window from Window List 180 */ 181 void incPopWindowListAll() { 182 foreach(window; windowList) { 183 window.onClose(); 184 window.visible = false; 185 } 186 windowList.length = 0; 187 } 188 189 /** 190 Pops a window 191 */ 192 void incPopWindow() { 193 windowStack[$-1].onClose(); 194 windowStack.length--; 195 if (windowStack.length > 0) windowStack[$-1].restore(); 196 } 197 198 /** 199 Update windows 200 */ 201 void incUpdateWindows() { 202 int id = 0; 203 foreach(window; windowStack) { 204 window.update(); 205 if (!window.visible) incPopWindow(); 206 } 207 208 Window[] closedWindows; 209 foreach(window; windowList) { 210 window.update(); 211 if (!window.visible) closedWindows ~= window; 212 } 213 214 foreach(window; closedWindows) { 215 incPopWindowList(window); 216 } 217 } 218 219 /** 220 Gets top window 221 */ 222 Window incGetTopWindow() { 223 return windowStack.length > 0 ? windowStack[$-1] : null; 224 }