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 99 version (InBranding) { 100 igImage( 101 cast(void*)incGetLogo(), 102 ImVec2(avail.y*2, avail.y*2), 103 ImVec2(0, 0), ImVec2(1, 1), 104 ImVec4(1, 1, 1, 1), 105 ImVec4(0, 0, 0, 0) 106 ); 107 108 debug { 109 igText((title~_(" (Debug Mode)")).toStringz); 110 } else { 111 igText(title.toStringz); 112 } 113 } else { 114 igText((title~_(" (Unsupported)")).toStringz); 115 } 116 117 // :) 118 if (isTransMonthOfVisibility) { 119 igSeparator(); 120 ImVec4 a = ImVec4(85.0/255.0, 205.0/255.0, 252.0/255.0, 255); 121 ImVec4 b; 122 ImVec4 c; 123 igColorConvertU32ToFloat4(&b, 0xF7A8B8FF); 124 igColorConvertU32ToFloat4(&c, 0xFFFFFFFF); 125 ImVec4[] transColors = [a, b, c, b]; 126 127 // A call for the human rights of transgender people to be respected 128 // it is shown in the custom titlebar every transgender awareness month. 129 foreach(i, ic; _("Trans Rights!")) { 130 igTextColored(transColors[i%transColors.length], [ic, '\0'].ptr); 131 igSameLine(0, 0); 132 } 133 } 134 135 incDummy(ImVec2(-((16*4*incGetUIScale())+8), 0)); 136 igPushFont(incIconFont()); 137 auto state = igGetStateStorage(); 138 139 igTextColored( 140 ImGuiStorage_GetBool(state, igGetID("##MINIMIZE")) ? 141 (incGetDarkMode() ? ImVec4(1, 1, 1, 1) : ImVec4(.3, .3, .3, 1)) : 142 ImVec4(.5, .5, .5, 1), 143 "" 144 ); 145 if (igIsItemClicked()) { 146 SDL_MinimizeWindow(window); 147 } 148 if(igIsItemHovered()) { 149 ImGuiStorage_SetBool(state, igGetID("##MINIMIZE"), true); 150 } else { 151 ImGuiStorage_SetBool(state, igGetID("##MINIMIZE"), false); 152 } 153 154 bool isMaximized = (SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED) > 0; 155 156 igTextColored( 157 ImGuiStorage_GetBool(state, igGetID("##MAXIMIZE")) ? 158 (incGetDarkMode() ? ImVec4(1, 1, 1, 1) : ImVec4(.3, .3, .3, 1)) : 159 ImVec4(.5, .5, .5, 1), 160 isMaximized ? "" : "" 161 ); 162 if (igIsItemClicked()) { 163 if (!isMaximized) SDL_MaximizeWindow(window); 164 else SDL_RestoreWindow(window); 165 } 166 if(igIsItemHovered()) { 167 ImGuiStorage_SetBool(state, igGetID("##MAXIMIZE"), true); 168 } else { 169 ImGuiStorage_SetBool(state, igGetID("##MAXIMIZE"), false); 170 } 171 172 igTextColored( 173 ImGuiStorage_GetBool(state, igGetID("##EXIT")) ? 174 ImVec4(1, .1, .1, 1) : 175 ImVec4(.5, .5, .5, 1), 176 "" 177 ); 178 if (igIsItemClicked()) { 179 incExit(); 180 } 181 if(igIsItemHovered()) { 182 ImGuiStorage_SetBool(state, igGetID("##EXIT"), true); 183 } else { 184 ImGuiStorage_SetBool(state, igGetID("##EXIT"), false); 185 } 186 igPopFont(); 187 188 igEndMenuBar(); 189 } 190 191 igEnd(); 192 } 193 igPopStyleColor(); 194 igPopStyleVar(); 195 }