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 }