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 }