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.widgets.titlebar;
8 import bindbc.sdl;
9 import bindbc.imgui;
10 import creator.core;
11 import creator.widgets;
12 import creator.utils.link;
13 import std.string;
14 import app : incUpdateNoEv;
15 import i18n;
16 
17 private {
18     bool incUseNativeTitlebar;
19 
20     extern(C) SDL_HitTestResult _incHitTestCallback(SDL_Window* win, const(SDL_Point)* area, void* data) nothrow {
21         int winWidth, winHeight;
22         SDL_GetWindowSize(win, &winWidth, &winHeight);
23         
24         // GET PROPER RESIZE AREA
25         enum RESIZE_AREA = 4;
26         enum RESIZE_AREAC = RESIZE_AREA*2;
27 
28         // Resize top
29         if (area.x < RESIZE_AREAC && area.y < RESIZE_AREAC) return SDL_HitTestResult.SDL_HITTEST_RESIZE_TOPLEFT;
30         if (area.x > winWidth-RESIZE_AREAC && area.y < RESIZE_AREAC) return SDL_HitTestResult.SDL_HITTEST_RESIZE_TOPRIGHT;
31         if (area.x < RESIZE_AREA) return SDL_HitTestResult.SDL_HITTEST_RESIZE_LEFT;
32         if (area.y < RESIZE_AREA) return SDL_HitTestResult.SDL_HITTEST_RESIZE_TOP;
33 
34         // Title bar
35         if (area.y < 22 && area.x < winWidth-128) return SDL_HitTestResult.SDL_HITTEST_DRAGGABLE;
36 
37         if (area.x < RESIZE_AREAC && area.y > winHeight-RESIZE_AREAC) return SDL_HitTestResult.SDL_HITTEST_RESIZE_BOTTOMLEFT;
38         if (area.x > winWidth-RESIZE_AREAC && area.y > winHeight-RESIZE_AREAC) return SDL_HitTestResult.SDL_HITTEST_RESIZE_BOTTOMRIGHT;
39         if (area.x > winWidth-RESIZE_AREA) return SDL_HitTestResult.SDL_HITTEST_RESIZE_RIGHT;
40         if (area.y > winHeight-RESIZE_AREA) return SDL_HitTestResult.SDL_HITTEST_RESIZE_BOTTOM;
41 
42         return SDL_HitTestResult.SDL_HITTEST_NORMAL;
43     }
44 }
45 
46 /**
47     Whether the native titlebar can be used
48 */
49 bool incCanUseAppTitlebar = true;
50 
51 /**
52     Gets whether to use the native titlebar
53 */
54 bool incGetUseNativeTitlebar() {
55     return incCanUseAppTitlebar && incUseNativeTitlebar;
56 }
57 
58 /**
59     Set whether to use the native titlebar
60 */
61 void incSetUseNativeTitlebar(bool value) {
62     if (!incCanUseAppTitlebar) return;
63     incUseNativeTitlebar = value;
64     incApplyTitlebar(incGetWindowPtr());
65 }
66 
67 /**
68     Applies titlebar settings to a window
69 */
70 void incApplyTitlebar(void* window) {
71     if (!incUseNativeTitlebar) {
72         SDL_SetWindowBordered(cast(SDL_Window*)window, cast(SDL_bool)false);
73         SDL_SetWindowHitTest(cast(SDL_Window*)window, &_incHitTestCallback, null);
74     } else {
75         SDL_SetWindowBordered(cast(SDL_Window*)window, cast(SDL_bool)true);
76         SDL_SetWindowHitTest(cast(SDL_Window*)window, null, null);
77     }
78 }
79 
80 /**
81     Draws the custom titlebar
82 */
83 void incTitlebar(string title) {
84     auto flags = 
85         ImGuiWindowFlags.NoSavedSettings |
86         ImGuiWindowFlags.NoScrollbar |
87         ImGuiWindowFlags.MenuBar;
88     
89     SDL_Window* window = incGetWindowPtr();
90 
91     if (incGetDarkMode()) igPushStyleColor(ImGuiCol.MenuBarBg, ImVec4(0.1, 0.1, 0.1, 1));
92     else  igPushStyleColor(ImGuiCol.MenuBarBg, ImVec4(0.9, 0.9, 0.9, 1));
93     igPushStyleVar(ImGuiStyleVar.FramePadding, ImVec2(0, 4*incGetUIScale()));
94         if (igBeginViewportSideBar("##Titlebar", igGetMainViewport(), ImGuiDir.Up, 22*incGetUIScale(), flags)) {
95             if (igBeginMenuBar()) {
96                 ImVec2 avail;
97                 igGetContentRegionAvail(&avail);
98                 igImage(
99                     cast(void*)incGetLogo(), 
100                     ImVec2(avail.y*2, avail.y*2), 
101                     ImVec2(0, 0), ImVec2(1, 1), 
102                     ImVec4(1, 1, 1, 1), 
103                     ImVec4(0, 0, 0, 0)
104                 );
105                 
106                 debug {
107                     igText((title~_(" (Debug Mode)")).toStringz);
108                 } else {
109                     igText(title.toStringz);
110                 }
111 
112                 // :)
113                 if (isTransMonthOfVisibility) {
114                     igSeparator();
115                     ImVec4 a = ImVec4(85.0/255.0, 205.0/255.0, 252.0/255.0, 255);
116                     ImVec4 b;
117                     ImVec4 c;
118                     igColorConvertU32ToFloat4(&b, 0xF7A8B8FF);
119                     igColorConvertU32ToFloat4(&c, 0xFFFFFFFF);
120                     ImVec4[] transColors = [a, b, c, b];
121                     
122                     // A call for the human rights of transgender people to be respected
123                     // it is shown in the custom titlebar every transgender awareness month.
124                     foreach(i, ic; _("Trans Rights!")) {
125                         igTextColored(transColors[i%transColors.length], [ic, '\0'].ptr);
126                         igSameLine(0, 0);
127                     }
128                 }
129                 
130                 incDummy(ImVec2(-((16*4*incGetUIScale())+8), 0));
131                 igPushFont(incIconFont());
132                     auto state = igGetStateStorage();
133 
134                     igTextColored(
135                         ImGuiStorage_GetBool(state, igGetID("##MINIMIZE")) ? 
136                             (incGetDarkMode() ? ImVec4(1, 1, 1, 1) : ImVec4(.3, .3, .3, 1)) : 
137                             ImVec4(.5, .5, .5, 1), 
138                         ""
139                     );
140                     if (igIsItemClicked()) {
141                         SDL_MinimizeWindow(window);
142                     }
143                     if(igIsItemHovered()) {
144                         ImGuiStorage_SetBool(state, igGetID("##MINIMIZE"), true);
145                     } else {
146                         ImGuiStorage_SetBool(state, igGetID("##MINIMIZE"), false);
147                     }
148 
149                     bool isMaximized = (SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED) > 0;
150                     
151                     igTextColored(
152                         ImGuiStorage_GetBool(state, igGetID("##MAXIMIZE")) ? 
153                             (incGetDarkMode() ? ImVec4(1, 1, 1, 1) : ImVec4(.3, .3, .3, 1)) : 
154                             ImVec4(.5, .5, .5, 1), 
155                         isMaximized ? "" : ""
156                     );
157                     if (igIsItemClicked()) {
158                         if (!isMaximized) SDL_MaximizeWindow(window);
159                         else SDL_RestoreWindow(window);
160                     }
161                     if(igIsItemHovered()) {
162                         ImGuiStorage_SetBool(state, igGetID("##MAXIMIZE"), true);
163                     } else {
164                         ImGuiStorage_SetBool(state, igGetID("##MAXIMIZE"), false);
165                     }
166                     
167                     igTextColored(
168                         ImGuiStorage_GetBool(state, igGetID("##EXIT")) ? 
169                             ImVec4(1, .1, .1, 1) : 
170                             ImVec4(.5, .5, .5, 1), 
171                         ""
172                     );
173                     if (igIsItemClicked()) {
174                         incExit();
175                     }
176                     if(igIsItemHovered()) {
177                         ImGuiStorage_SetBool(state, igGetID("##EXIT"), true);
178                     } else {
179                         ImGuiStorage_SetBool(state, igGetID("##EXIT"), false);
180                     }
181                 igPopFont();
182 
183                 igEndMenuBar();
184             }
185                 
186             igEnd();
187         }
188     igPopStyleColor();
189     igPopStyleVar();
190 }