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 20 private ImGuiWindowClass* windowClass; 21 22 /** 23 A Widget 24 */ 25 abstract class Window { 26 private: 27 string name_; 28 bool visible = true; 29 bool disabled; 30 31 protected: 32 bool onlyOne; 33 ImGuiWindowFlags flags; 34 35 abstract void onUpdate(); 36 37 void onBeginUpdate(int id) { 38 igSetNextWindowClass(windowClass); 39 igBegin( 40 (name~"##"~id.text).toStringz, 41 &visible, 42 flags | ImGuiWindowFlags.NoDecoration 43 ); 44 } 45 46 void onEndUpdate() { 47 igEnd(); 48 } 49 50 void onClose() { } 51 52 public: 53 54 /** 55 Constructs a frame 56 */ 57 this(string name) { 58 this.name_ = name; 59 this.restore(); 60 } 61 62 final void close() { 63 this.visible = false; 64 } 65 66 final string name() { 67 return name_; 68 } 69 70 /** 71 Draws the frame 72 */ 73 final void update(int id) { 74 igPushItemFlag(ImGuiItemFlags.Disabled, disabled); 75 this.onBeginUpdate(id); 76 this.onUpdate(); 77 this.onEndUpdate(); 78 igPopItemFlag(); 79 80 if (disabled && !visible) visible = true; 81 } 82 83 ImVec2 getPosition() { 84 ImVec2 pos; 85 igGetWindowPos(&pos); 86 return pos; 87 } 88 89 void disable() { 90 this.flags = ImGuiWindowFlags.NoDocking | 91 ImGuiWindowFlags.NoCollapse | 92 ImGuiWindowFlags.NoNav | 93 ImGuiWindowFlags.NoMove | 94 ImGuiWindowFlags.NoScrollWithMouse | 95 ImGuiWindowFlags.NoScrollbar; 96 disabled = true; 97 } 98 99 void restore() { 100 disabled = false; 101 this.flags = ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoSavedSettings; 102 103 windowClass = ImGuiWindowClass_ImGuiWindowClass(); 104 windowClass.ViewportFlagsOverrideClear = ImGuiViewportFlags.NoDecoration | ImGuiViewportFlags.NoTaskBarIcon; 105 windowClass.ViewportFlagsOverrideSet = ImGuiViewportFlags.NoAutoMerge; 106 } 107 } 108 109 private { 110 Window[] windowStack; 111 Window[] windowList; 112 } 113 114 /** 115 Pushes window to stack 116 */ 117 void incPushWindow(Window window) { 118 119 // Only allow one instance of the window 120 if (window.onlyOne) { 121 foreach(win; windowStack) { 122 if (win.name == window.name) return; 123 } 124 } 125 126 if (windowStack.length > 0) { 127 windowStack[$-1].disable(); 128 } 129 130 windowStack ~= window; 131 } 132 133 /** 134 Pushes window to stack 135 */ 136 void incPushWindowList(Window window) { 137 138 // Only allow one instance of the window 139 if (window.onlyOne) { 140 foreach(win; windowList) { 141 if (win.name == window.name) return; 142 } 143 } 144 145 windowList ~= window; 146 } 147 148 /** 149 Pop window from Window List 150 */ 151 void incPopWindowList(Window window) { 152 import std.algorithm.searching : countUntil; 153 import std.algorithm.mutation : remove; 154 155 ptrdiff_t i = windowList.countUntil(window); 156 if (i != -1) { 157 if (windowList.length == 1) windowList.length = 0; 158 else windowList = windowList.remove(i); 159 } 160 } 161 162 /** 163 Pops a window 164 */ 165 void incPopWindow() { 166 windowStack[$-1].onClose(); 167 windowStack.length--; 168 if (windowStack.length > 0) windowStack[$-1].restore(); 169 } 170 171 /** 172 Update windows 173 */ 174 void incUpdateWindows() { 175 int id = 0; 176 foreach(window; windowStack) { 177 window.update(id++); 178 if (!window.visible) incPopWindow(); 179 } 180 181 Window[] closedWindows; 182 foreach(window; windowList) { 183 window.update(id++); 184 closedWindows ~= window; 185 } 186 187 foreach(window; closedWindows) { 188 if (!window.visible) incPopWindowList(window); 189 } 190 } 191 192 /** 193 Gets top window 194 */ 195 Window incGetTopWindow() { 196 return windowStack.length > 0 ? windowStack[$-1] : null; 197 }