imgui_fullscreen.h (16678B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0) 3 4 #pragma once 5 6 #include "common/types.h" 7 8 #include "IconsFontAwesome5.h" 9 #include "imgui.h" 10 #include "imgui_internal.h" 11 12 #include <functional> 13 #include <memory> 14 #include <optional> 15 #include <span> 16 #include <string> 17 #include <string_view> 18 #include <utility> 19 #include <vector> 20 21 class RGBA8Image; 22 class GPUTexture; 23 class SmallStringBase; 24 25 namespace ImGuiFullscreen { 26 #define HEX_TO_IMVEC4(hex, alpha) \ 27 ImVec4(static_cast<float>((hex >> 16) & 0xFFu) / 255.0f, static_cast<float>((hex >> 8) & 0xFFu) / 255.0f, \ 28 static_cast<float>(hex & 0xFFu) / 255.0f, static_cast<float>(alpha) / 255.0f) 29 30 static constexpr float LAYOUT_SCREEN_WIDTH = 1280.0f; 31 static constexpr float LAYOUT_SCREEN_HEIGHT = 720.0f; 32 static constexpr float LAYOUT_LARGE_FONT_SIZE = 26.0f; 33 static constexpr float LAYOUT_MEDIUM_FONT_SIZE = 16.0f; 34 static constexpr float LAYOUT_SMALL_FONT_SIZE = 10.0f; 35 static constexpr float LAYOUT_MENU_BUTTON_HEIGHT = 50.0f; 36 static constexpr float LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY = 26.0f; 37 static constexpr float LAYOUT_MENU_BUTTON_X_PADDING = 15.0f; 38 static constexpr float LAYOUT_MENU_BUTTON_Y_PADDING = 10.0f; 39 static constexpr float LAYOUT_MENU_WINDOW_X_PADDING = 12.0f; 40 static constexpr float LAYOUT_FOOTER_PADDING = 10.0f; 41 static constexpr float LAYOUT_FOOTER_HEIGHT = LAYOUT_MEDIUM_FONT_SIZE + LAYOUT_FOOTER_PADDING * 2.0f; 42 static constexpr float LAYOUT_HORIZONTAL_MENU_HEIGHT = 320.0f; 43 static constexpr float LAYOUT_HORIZONTAL_MENU_PADDING = 30.0f; 44 static constexpr float LAYOUT_HORIZONTAL_MENU_ITEM_WIDTH = 250.0f; 45 46 extern ImFont* g_standard_font; 47 extern ImFont* g_medium_font; 48 extern ImFont* g_large_font; 49 50 extern float g_layout_scale; 51 extern float g_rcp_layout_scale; 52 extern float g_layout_padding_left; 53 extern float g_layout_padding_top; 54 55 extern ImVec4 UIBackgroundColor; 56 extern ImVec4 UIBackgroundTextColor; 57 extern ImVec4 UIBackgroundLineColor; 58 extern ImVec4 UIBackgroundHighlightColor; 59 extern ImVec4 UIPopupBackgroundColor; 60 extern ImVec4 UIDisabledColor; 61 extern ImVec4 UIPrimaryColor; 62 extern ImVec4 UIPrimaryLightColor; 63 extern ImVec4 UIPrimaryDarkColor; 64 extern ImVec4 UIPrimaryTextColor; 65 extern ImVec4 UITextHighlightColor; 66 extern ImVec4 UIPrimaryLineColor; 67 extern ImVec4 UISecondaryColor; 68 extern ImVec4 UISecondaryWeakColor; // Not currently used. 69 extern ImVec4 UISecondaryStrongColor; 70 extern ImVec4 UISecondaryTextColor; 71 72 ALWAYS_INLINE static float LayoutScale(float v) 73 { 74 return ImCeil(g_layout_scale * v); 75 } 76 77 ALWAYS_INLINE static ImVec2 LayoutScale(const ImVec2& v) 78 { 79 return ImVec2(ImCeil(v.x * g_layout_scale), ImCeil(v.y * g_layout_scale)); 80 } 81 82 ALWAYS_INLINE static ImVec2 LayoutScale(float x, float y) 83 { 84 return ImVec2(ImCeil(x * g_layout_scale), ImCeil(y * g_layout_scale)); 85 } 86 87 ALWAYS_INLINE static float LayoutUnscale(float v) 88 { 89 return ImCeil(g_rcp_layout_scale * v); 90 } 91 ALWAYS_INLINE static ImVec2 LayoutUnscale(const ImVec2& v) 92 { 93 return ImVec2(ImCeil(v.x * g_rcp_layout_scale), ImCeil(v.y * g_rcp_layout_scale)); 94 } 95 ALWAYS_INLINE static ImVec2 LayoutUnscale(float x, float y) 96 { 97 return ImVec2(ImCeil(x * g_rcp_layout_scale), ImCeil(y * g_rcp_layout_scale)); 98 } 99 100 ALWAYS_INLINE static ImVec4 ModAlpha(const ImVec4& v, float a) 101 { 102 return ImVec4(v.x, v.y, v.z, a); 103 } 104 105 ALWAYS_INLINE static ImVec4 MulAlpha(const ImVec4& v, float a) 106 { 107 return ImVec4(v.x, v.y, v.z, v.w * a); 108 } 109 110 ALWAYS_INLINE static std::string_view RemoveHash(std::string_view s) 111 { 112 const std::string_view::size_type pos = s.find('#'); 113 return (pos != std::string_view::npos) ? s.substr(0, pos) : s; 114 } 115 116 /// Centers an image within the specified bounds, scaling up or down as needed. 117 ImRect CenterImage(const ImVec2& fit_size, const ImVec2& image_size); 118 ImRect CenterImage(const ImRect& fit_rect, const ImVec2& image_size); 119 120 /// Initializes, setting up any state. 121 bool Initialize(const char* placeholder_image_path); 122 123 void SetTheme(bool light); 124 void SetFonts(ImFont* standard_font, ImFont* medium_font, ImFont* large_font); 125 bool UpdateLayoutScale(); 126 127 /// Shuts down, clearing all state. 128 void Shutdown(); 129 130 /// Texture cache. 131 const std::shared_ptr<GPUTexture>& GetPlaceholderTexture(); 132 std::unique_ptr<GPUTexture> CreateTextureFromImage(const RGBA8Image& image); 133 std::shared_ptr<GPUTexture> LoadTexture(std::string_view path); 134 GPUTexture* GetCachedTexture(std::string_view name); 135 GPUTexture* GetCachedTextureAsync(std::string_view name); 136 bool InvalidateCachedTexture(const std::string& path); 137 void UploadAsyncTextures(); 138 139 void BeginLayout(); 140 void EndLayout(); 141 142 void PushResetLayout(); 143 void PopResetLayout(); 144 145 enum class FocusResetType : u8 146 { 147 None, 148 PopupOpened, 149 PopupClosed, 150 ViewChanged, 151 Other, 152 }; 153 void QueueResetFocus(FocusResetType type); 154 bool ResetFocusHere(); 155 bool IsFocusResetQueued(); 156 bool IsFocusResetFromWindowChange(); 157 FocusResetType GetQueuedFocusResetType(); 158 void ForceKeyNavEnabled(); 159 160 bool WantsToCloseMenu(); 161 void ResetCloseMenuIfNeeded(); 162 163 void PushPrimaryColor(); 164 void PopPrimaryColor(); 165 166 void DrawWindowTitle(const char* title); 167 168 bool BeginFullscreenColumns(const char* title = nullptr, float pos_y = 0.0f, bool expand_to_screen_width = false, 169 bool footer = false); 170 void EndFullscreenColumns(); 171 172 bool BeginFullscreenColumnWindow(float start, float end, const char* name, 173 const ImVec4& background = UIBackgroundColor); 174 void EndFullscreenColumnWindow(); 175 176 bool BeginFullscreenWindow(float left, float top, float width, float height, const char* name, 177 const ImVec4& background = HEX_TO_IMVEC4(0x212121, 0xFF), float rounding = 0.0f, 178 const ImVec2& padding = ImVec2(), ImGuiWindowFlags flags = 0); 179 bool BeginFullscreenWindow(const ImVec2& position, const ImVec2& size, const char* name, 180 const ImVec4& background = HEX_TO_IMVEC4(0x212121, 0xFF), float rounding = 0.0f, 181 const ImVec2& padding = ImVec2(), ImGuiWindowFlags flags = 0); 182 void EndFullscreenWindow(); 183 184 bool IsGamepadInputSource(); 185 void CreateFooterTextString(SmallStringBase& dest, std::span<const std::pair<const char*, std::string_view>> items); 186 void SetFullscreenFooterText(std::string_view text); 187 void SetFullscreenFooterText(std::span<const std::pair<const char*, std::string_view>> items); 188 void DrawFullscreenFooter(); 189 190 void PrerenderMenuButtonBorder(); 191 void BeginMenuButtons(u32 num_items = 0, float y_align = 0.0f, float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, 192 float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING, float item_height = LAYOUT_MENU_BUTTON_HEIGHT); 193 void EndMenuButtons(); 194 void GetMenuButtonFrameBounds(float height, ImVec2* pos, ImVec2* size); 195 bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool* visible, bool* hovered, ImVec2* min, 196 ImVec2* max, ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f); 197 void DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max, ImU32 fill_col, bool border = true, 198 float rounding = 0.0f); 199 void ResetMenuButtonFrame(); 200 void MenuHeading(const char* title, bool draw_line = true); 201 bool MenuHeadingButton(const char* title, const char* value = nullptr, bool enabled = true, bool draw_line = true); 202 bool ActiveButton(const char* title, bool is_active, bool enabled = true, 203 float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); 204 bool DefaultActiveButton(const char* title, bool is_active, bool enabled = true, 205 float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); 206 bool ActiveButtonWithRightText(const char* title, const char* right_title, bool is_active, bool enabled = true, 207 float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); 208 bool MenuButton(const char* title, const char* summary, bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, 209 ImFont* font = g_large_font, ImFont* summary_font = g_medium_font); 210 bool MenuButtonWithoutSummary(const char* title, bool enabled = true, 211 float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font, 212 const ImVec2& text_align = ImVec2(0.0f, 0.0f)); 213 bool MenuButtonWithValue(const char* title, const char* summary, const char* value, bool enabled = true, 214 float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, 215 ImFont* summary_font = g_medium_font); 216 bool MenuImageButton(const char* title, const char* summary, ImTextureID user_texture_id, const ImVec2& image_size, 217 bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, 218 const ImVec2& uv0 = ImVec2(0.0f, 0.0f), const ImVec2& uv1 = ImVec2(1.0f, 1.0f), 219 ImFont* font = g_large_font, ImFont* summary_font = g_medium_font); 220 bool FloatingButton(const char* text, float x, float y, float width = -1.0f, 221 float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, float anchor_x = 0.0f, float anchor_y = 0.0f, 222 bool enabled = true, ImFont* font = g_large_font, ImVec2* out_position = nullptr, 223 bool repeat_button = false); 224 bool ToggleButton(const char* title, const char* summary, bool* v, bool enabled = true, 225 float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, 226 ImFont* summary_font = g_medium_font); 227 bool ThreeWayToggleButton(const char* title, const char* summary, std::optional<bool>* v, bool enabled = true, 228 float height = LAYOUT_MENU_BUTTON_HEIGHT, ImFont* font = g_large_font, 229 ImFont* summary_font = g_medium_font); 230 bool RangeButton(const char* title, const char* summary, s32* value, s32 min, s32 max, s32 increment, 231 const char* format = "%d", bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, 232 ImFont* font = g_large_font, ImFont* summary_font = g_medium_font, const char* ok_text = "OK"); 233 bool RangeButton(const char* title, const char* summary, float* value, float min, float max, float increment, 234 const char* format = "%f", bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, 235 ImFont* font = g_large_font, ImFont* summary_font = g_medium_font, const char* ok_text = "OK"); 236 bool EnumChoiceButtonImpl(const char* title, const char* summary, s32* value_pointer, 237 const char* (*to_display_name_function)(s32 value, void* opaque), void* opaque, u32 count, 238 bool enabled, float height, ImFont* font, ImFont* summary_font); 239 240 template<typename DataType, typename CountType> 241 ALWAYS_INLINE static bool EnumChoiceButton(const char* title, const char* summary, DataType* value_pointer, 242 const char* (*to_display_name_function)(DataType value), CountType count, 243 bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT, 244 ImFont* font = g_large_font, ImFont* summary_font = g_medium_font) 245 { 246 s32 value = static_cast<s32>(*value_pointer); 247 auto to_display_name_wrapper = [](s32 value, void* opaque) -> const char* { 248 return (*static_cast<decltype(to_display_name_function)*>(opaque))(static_cast<DataType>(value)); 249 }; 250 251 if (EnumChoiceButtonImpl(title, summary, &value, to_display_name_wrapper, &to_display_name_function, 252 static_cast<u32>(count), enabled, height, font, summary_font)) 253 { 254 *value_pointer = static_cast<DataType>(value); 255 return true; 256 } 257 else 258 { 259 return false; 260 } 261 } 262 263 void DrawShadowedText(ImDrawList* dl, ImFont* font, const ImVec2& pos, u32 col, const char* text, 264 const char* text_end = nullptr, float wrap_width = 0.0f); 265 266 void BeginNavBar(float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING); 267 void EndNavBar(); 268 void NavTitle(const char* title, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); 269 void RightAlignNavButtons(u32 num_items = 0, float item_width = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, 270 float item_height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); 271 bool NavButton(const char* title, bool is_active, bool enabled = true, float width = -1.0f, 272 float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); 273 bool NavTab(const char* title, bool is_active, bool enabled, float width, float height, const ImVec4& background, 274 ImFont* font = g_large_font); 275 276 bool BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, u32 num_items); 277 void EndHorizontalMenu(); 278 bool HorizontalMenuItem(GPUTexture* icon, const char* title, const char* description); 279 280 using FileSelectorCallback = std::function<void(const std::string& path)>; 281 using FileSelectorFilters = std::vector<std::string>; 282 bool IsFileSelectorOpen(); 283 void OpenFileSelector(std::string_view title, bool select_directory, FileSelectorCallback callback, 284 FileSelectorFilters filters = FileSelectorFilters(), 285 std::string initial_directory = std::string()); 286 void CloseFileSelector(); 287 288 using ChoiceDialogCallback = std::function<void(s32 index, const std::string& title, bool checked)>; 289 using ChoiceDialogOptions = std::vector<std::pair<std::string, bool>>; 290 bool IsChoiceDialogOpen(); 291 void OpenChoiceDialog(std::string_view title, bool checkable, ChoiceDialogOptions options, 292 ChoiceDialogCallback callback); 293 void CloseChoiceDialog(); 294 295 using InputStringDialogCallback = std::function<void(std::string text)>; 296 bool IsInputDialogOpen(); 297 void OpenInputStringDialog(std::string title, std::string message, std::string caption, std::string ok_button_text, 298 InputStringDialogCallback callback); 299 void CloseInputDialog(); 300 301 using ConfirmMessageDialogCallback = std::function<void(bool)>; 302 using InfoMessageDialogCallback = std::function<void()>; 303 using MessageDialogCallback = std::function<void(s32)>; 304 bool IsMessageBoxDialogOpen(); 305 void OpenConfirmMessageDialog(std::string title, std::string message, ConfirmMessageDialogCallback callback, 306 std::string yes_button_text = ICON_FA_CHECK " Yes", 307 std::string no_button_text = ICON_FA_TIMES " No"); 308 void OpenInfoMessageDialog(std::string title, std::string message, InfoMessageDialogCallback callback = {}, 309 std::string button_text = ICON_FA_WINDOW_CLOSE " Close"); 310 void OpenMessageDialog(std::string title, std::string message, MessageDialogCallback callback, 311 std::string first_button_text, std::string second_button_text, std::string third_button_text); 312 void CloseMessageDialog(); 313 314 float GetNotificationVerticalPosition(); 315 float GetNotificationVerticalDirection(); 316 void SetNotificationVerticalPosition(float position, float direction); 317 318 void OpenBackgroundProgressDialog(const char* str_id, std::string message, s32 min, s32 max, s32 value); 319 void UpdateBackgroundProgressDialog(const char* str_id, std::string message, s32 min, s32 max, s32 value); 320 void CloseBackgroundProgressDialog(const char* str_id); 321 322 void AddNotification(std::string key, float duration, std::string title, std::string text, std::string image_path); 323 void ClearNotifications(); 324 325 void ShowToast(std::string title, std::string message, float duration = 10.0f); 326 void ClearToast(); 327 328 // Message callbacks. 329 void GetChoiceDialogHelpText(SmallStringBase& dest); 330 void GetFileSelectorHelpText(SmallStringBase& dest); 331 void GetInputDialogHelpText(SmallStringBase& dest); 332 } // namespace ImGuiFullscreen 333 334 // Host UI triggers from Big Picture mode. 335 namespace Host { 336 /// Returns true if native file dialogs should be preferred over Big Picture. 337 bool ShouldPreferHostFileSelector(); 338 339 /// Opens a file selector dialog. 340 using FileSelectorCallback = std::function<void(const std::string& path)>; 341 using FileSelectorFilters = std::vector<std::string>; 342 void OpenHostFileSelectorAsync(std::string_view title, bool select_directory, FileSelectorCallback callback, 343 FileSelectorFilters filters = FileSelectorFilters(), 344 std::string_view initial_directory = std::string_view()); 345 } // namespace Host