From 4c89a79dc30b68ef88bc608c5d06523f220acc6c Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 30 Jul 2025 17:42:56 +0200 Subject: [PATCH] feat: Added full-screen views for use with subcommands in the future --- lib/external/libwolv | 2 +- .../include/hex/api/content_registry.hpp | 14 +++ lib/libimhex/include/hex/ui/view.hpp | 14 ++- lib/libimhex/source/api/content_registry.cpp | 15 +++- main/gui/source/window/window.cpp | 88 ++++++++++--------- .../builtin/source/content/welcome_screen.cpp | 47 +++++----- .../source/content/window_decoration.cpp | 30 ++++--- 7 files changed, 132 insertions(+), 78 deletions(-) diff --git a/lib/external/libwolv b/lib/external/libwolv index 68e548eaa..95efb87f5 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit 68e548eaa93f1b2a645307e98fd2cbeaa5aef093 +Subproject commit 95efb87f5d17807daaba53f8fcc4618136cdae65 diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 6f2e1f8f4..3f2e5616c 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -580,7 +580,10 @@ EXPORT_MODULE namespace hex { namespace impl { void add(std::unique_ptr &&view); + void setFullScreenView(std::unique_ptr &&view); + const std::map>& getEntries(); + const std::unique_ptr& getFullScreenView(); } @@ -595,6 +598,17 @@ EXPORT_MODULE namespace hex { return impl::add(std::make_unique(std::forward(args)...)); } + /** + * @brief Sets a view as a full-screen view. This will cause the view to take up the entire ImHex window + * @tparam T The custom view class that extends View + * @tparam Args Arguments types + * @param args Arguments passed to the constructor of the view + */ + template T, typename... Args> + void setFullScreenView(Args &&...args) { + return impl::setFullScreenView(std::make_unique(std::forward(args)...)); + } + /** * @brief Gets a view by its unlocalized name * @param unlocalizedName The unlocalized name of the view diff --git a/lib/libimhex/include/hex/ui/view.hpp b/lib/libimhex/include/hex/ui/view.hpp index abbbf2d37..b21657897 100644 --- a/lib/libimhex/include/hex/ui/view.hpp +++ b/lib/libimhex/include/hex/ui/view.hpp @@ -119,6 +119,7 @@ namespace hex { class Special; class Floating; class Modal; + class FullScreen; private: UnlocalizedString m_unlocalizedViewName; @@ -142,7 +143,8 @@ namespace hex { void draw() final { if (this->shouldDraw()) { ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize()); - if (ImGui::Begin(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | this->getWindowFlags())) { + const auto title = hex::format("{} {}", this->getIcon(), View::toWindowName(this->getUnlocalizedName())); + if (ImGui::Begin(title.c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | this->getWindowFlags())) { this->drawContent(); } ImGui::End(); @@ -206,4 +208,14 @@ namespace hex { [[nodiscard]] bool shouldStoreWindowState() const override { return false; } }; + class View::FullScreen : public View { + public: + explicit FullScreen() : View("FullScreen", "") {} + + void draw() final { + this->drawContent(); + this->drawAlwaysVisibleContent(); + } + }; + } \ No newline at end of file diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 3a233b8c6..b83c9a334 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -720,10 +720,19 @@ namespace hex { } void add(std::unique_ptr &&view) { - log::debug("Registered new view: {}", view->getUnlocalizedName().get()); + log::debug("Registered new view: {}", view->getUnlocalizedName().get()); - s_views->emplace(view->getUnlocalizedName(), std::move(view)); - } + s_views->emplace(view->getUnlocalizedName(), std::move(view)); + } + + static AutoReset> s_fullscreenView; + const std::unique_ptr& getFullScreenView() { + return *s_fullscreenView; + } + + void setFullScreenView(std::unique_ptr &&view) { + s_fullscreenView = std::move(view); + } } diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index 6ab98e0e0..351f324ca 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -740,66 +740,70 @@ namespace hex { ShortcutManager::resetLastActivatedMenu(); - // Loop through all views and draw them - for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) { - ImGui::GetCurrentContext()->NextWindowData.ClearFlags(); + if (const auto &fullScreenView = ContentRegistry::Views::impl::getFullScreenView(); fullScreenView == nullptr) { - // Draw always visible views - view->drawAlwaysVisibleContent(); + // Loop through all views and draw them + for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) { + ImGui::GetCurrentContext()->NextWindowData.ClearFlags(); - // Skip views that shouldn't be processed currently - if (!view->shouldProcess()) - continue; + // Draw always visible views + view->drawAlwaysVisibleContent(); - const auto openViewCount = std::ranges::count_if(ContentRegistry::Views::impl::getEntries(), [](const auto &entry) { - const auto &[unlocalizedName, openView] = entry; + // Skip views that shouldn't be processed currently + if (!view->shouldProcess()) + continue; - return openView->hasViewMenuItemEntry() && openView->shouldProcess(); - }); + const auto openViewCount = std::ranges::count_if(ContentRegistry::Views::impl::getEntries(), [](const auto &entry) { + const auto &[unlocalizedName, openView] = entry; - ImGuiWindowClass windowClass = {}; + return openView->hasViewMenuItemEntry() && openView->shouldProcess(); + }); - windowClass.DockNodeFlagsOverrideSet |= ImGuiDockNodeFlags_NoCloseButton; + ImGuiWindowClass windowClass = {}; - if (openViewCount <= 1 || LayoutManager::isLayoutLocked()) - windowClass.DockNodeFlagsOverrideSet |= ImGuiDockNodeFlags_NoTabBar; + windowClass.DockNodeFlagsOverrideSet |= ImGuiDockNodeFlags_NoCloseButton; - ImGui::SetNextWindowClass(&windowClass); + if (openViewCount <= 1 || LayoutManager::isLayoutLocked()) + windowClass.DockNodeFlagsOverrideSet |= ImGuiDockNodeFlags_NoTabBar; - auto window = ImGui::FindWindowByName(view->getName().c_str()); - if (window != nullptr && window->DockNode == nullptr) - ImGui::SetNextWindowBgAlpha(1.0F); + ImGui::SetNextWindowClass(&windowClass); - // Draw view - view->draw(); - view->trackViewOpenState(); + auto window = ImGui::FindWindowByName(view->getName().c_str()); + if (window != nullptr && window->DockNode == nullptr) + ImGui::SetNextWindowBgAlpha(1.0F); - if (view->getWindowOpenState()) { - // Get the currently focused view - if (window != nullptr && (window->Flags & ImGuiWindowFlags_Popup) != ImGuiWindowFlags_Popup) { - auto windowName = View::toWindowName(name); - ImGui::Begin(windowName.c_str()); + // Draw view + view->draw(); + view->trackViewOpenState(); - // Detect if the window is focused - const bool focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy); - view->setFocused(focused); + if (view->getWindowOpenState()) { + // Get the currently focused view + if (window != nullptr && (window->Flags & ImGuiWindowFlags_Popup) != ImGuiWindowFlags_Popup) { + auto windowName = View::toWindowName(name); + ImGui::Begin(windowName.c_str()); - // Dock the window if it's not already docked - if (view->didWindowJustOpen() && !ImGui::IsWindowDocked()) { - ImGui::DockBuilderDockWindow(windowName.c_str(), ImHexApi::System::getMainDockSpaceId()); - EventViewOpened::post(view.get()); + // Detect if the window is focused + const bool focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy); + view->setFocused(focused); + + // Dock the window if it's not already docked + if (view->didWindowJustOpen() && !ImGui::IsWindowDocked()) { + ImGui::DockBuilderDockWindow(windowName.c_str(), ImHexApi::System::getMainDockSpaceId()); + EventViewOpened::post(view.get()); + } + + // Pass on currently pressed keys to the shortcut handler + for (const auto &key : m_pressedKeys) { + ShortcutManager::process(view.get(), io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl, io.KeyAlt, io.KeyShift, io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeySuper, focused, key); + } + + ImGui::End(); } - - // Pass on currently pressed keys to the shortcut handler - for (const auto &key : m_pressedKeys) { - ShortcutManager::process(view.get(), io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl, io.KeyAlt, io.KeyShift, io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeySuper, focused, key); - } - - ImGui::End(); } } } + // Handle global shortcuts for (const auto &key : m_pressedKeys) { ShortcutManager::processGlobals(io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl, io.KeyAlt, io.KeyShift, io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeySuper, key); diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 9844e946f..a05e9f2ff 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -502,33 +502,38 @@ namespace hex::plugin::builtin { if (ImGui::Begin("Welcome Screen", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) { ImGui::BringWindowToDisplayBack(ImGui::GetCurrentWindowRead()); - drawWelcomeScreenBackground(); + if (const auto &fullScreenView = ContentRegistry::Views::impl::getFullScreenView(); fullScreenView != nullptr) { + fullScreenView->draw(); + } else { + drawWelcomeScreenBackground(); - if (s_simplifiedWelcomeScreen) - drawWelcomeScreenContentSimplified(); - else - drawWelcomeScreenContentFull(); + if (s_simplifiedWelcomeScreen) + drawWelcomeScreenContentSimplified(); + else + drawWelcomeScreenContentFull(); + + static bool hovered = false; + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, hovered ? 1.0F : 0.3F); + { + const ImVec2 windowSize = { 150_scaled, ImGui::GetTextLineHeightWithSpacing() * 3.5F }; + ImGui::SetCursorScreenPos(ImGui::GetWindowPos() + ImGui::GetWindowSize() - windowSize - ImGui::GetStyle().WindowPadding); + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg)); + if (ImGuiExt::BeginSubWindow("hex.builtin.welcome.header.quick_settings"_lang, nullptr, windowSize, ImGuiChildFlags_AutoResizeY)) { + if (ImGuiExt::ToggleSwitch("hex.builtin.welcome.quick_settings.simplified"_lang, &s_simplifiedWelcomeScreen)) { + ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.simplified_welcome_screen", s_simplifiedWelcomeScreen); + WorkspaceManager::switchWorkspace(s_simplifiedWelcomeScreen ? "Minimal" : "Default"); + } - static bool hovered = false; - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, hovered ? 1.0F : 0.3F); - { - const ImVec2 windowSize = { 150_scaled, ImGui::GetTextLineHeightWithSpacing() * 3.5F }; - ImGui::SetCursorScreenPos(ImGui::GetWindowPos() + ImGui::GetWindowSize() - windowSize - ImGui::GetStyle().WindowPadding); - ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg)); - if (ImGuiExt::BeginSubWindow("hex.builtin.welcome.header.quick_settings"_lang, nullptr, windowSize, ImGuiChildFlags_AutoResizeY)) { - if (ImGuiExt::ToggleSwitch("hex.builtin.welcome.quick_settings.simplified"_lang, &s_simplifiedWelcomeScreen)) { - ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.simplified_welcome_screen", s_simplifiedWelcomeScreen); - WorkspaceManager::switchWorkspace(s_simplifiedWelcomeScreen ? "Minimal" : "Default"); } + ImGuiExt::EndSubWindow(); + + ImGui::PopStyleColor(); + hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } - ImGuiExt::EndSubWindow(); - - ImGui::PopStyleColor(); - hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); - + ImGui::PopStyleVar(); } - ImGui::PopStyleVar(); + } ImGui::End(); ImGui::PopStyleVar(); diff --git a/plugins/builtin/source/content/window_decoration.cpp b/plugins/builtin/source/content/window_decoration.cpp index dd1f91448..f856cfbc9 100644 --- a/plugins/builtin/source/content/window_decoration.cpp +++ b/plugins/builtin/source/content/window_decoration.cpp @@ -495,7 +495,12 @@ namespace hex::plugin::builtin { ImGui::EndPopup(); } - drawMenu(); + + { + ImGui::BeginDisabled(ContentRegistry::Views::impl::getFullScreenView() != nullptr); + drawMenu(); + ImGui::EndDisabled(); + } menu::endMainMenuBar(); } menu::enableNativeMenuBar(false); @@ -541,18 +546,23 @@ namespace hex::plugin::builtin { ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F); if (ImGui::BeginMenuBar()) { drawTitleBarBackDrop(); - for (const auto &callback : ContentRegistry::Interface::impl::getToolbarItems()) { - callback(); - ImGui::SameLine(); - } - if (auto provider = ImHexApi::Provider::get(); provider != nullptr) { - ImGui::BeginDisabled(TaskManager::getRunningTaskCount() > 0); - if (ImGui::CloseButton(ImGui::GetID("ProviderCloseButton"), ImGui::GetCursorScreenPos() + ImVec2(ImGui::GetContentRegionAvail().x - 17_scaled, 3_scaled))) { - ImHexApi::Provider::remove(provider); + ImGui::BeginDisabled(ContentRegistry::Views::impl::getFullScreenView() != nullptr); + { + for (const auto &callback : ContentRegistry::Interface::impl::getToolbarItems()) { + callback(); + ImGui::SameLine(); + } + + if (auto provider = ImHexApi::Provider::get(); provider != nullptr) { + ImGui::BeginDisabled(TaskManager::getRunningTaskCount() > 0); + if (ImGui::CloseButton(ImGui::GetID("ProviderCloseButton"), ImGui::GetCursorScreenPos() + ImVec2(ImGui::GetContentRegionAvail().x - 17_scaled, 3_scaled))) { + ImHexApi::Provider::remove(provider); + } + ImGui::EndDisabled(); } - ImGui::EndDisabled(); } + ImGui::EndDisabled(); ImGui::EndMenuBar(); }