feat: Added full-screen views for use with subcommands in the future

This commit is contained in:
WerWolv
2025-07-30 17:42:56 +02:00
parent 2c3d8d4c0b
commit 4c89a79dc3
7 changed files with 132 additions and 78 deletions

View File

@@ -580,7 +580,10 @@ EXPORT_MODULE namespace hex {
namespace impl {
void add(std::unique_ptr<View> &&view);
void setFullScreenView(std::unique_ptr<View> &&view);
const std::map<UnlocalizedString, std::unique_ptr<View>>& getEntries();
const std::unique_ptr<View>& getFullScreenView();
}
@@ -595,6 +598,17 @@ EXPORT_MODULE namespace hex {
return impl::add(std::make_unique<T>(std::forward<Args>(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<std::derived_from<View> T, typename... Args>
void setFullScreenView(Args &&...args) {
return impl::setFullScreenView(std::make_unique<T>(std::forward<Args>(args)...));
}
/**
* @brief Gets a view by its unlocalized name
* @param unlocalizedName The unlocalized name of the view

View File

@@ -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();
}
};
}

View File

@@ -720,10 +720,19 @@ namespace hex {
}
void add(std::unique_ptr<View> &&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<std::unique_ptr<View>> s_fullscreenView;
const std::unique_ptr<View>& getFullScreenView() {
return *s_fullscreenView;
}
void setFullScreenView(std::unique_ptr<View> &&view) {
s_fullscreenView = std::move(view);
}
}

View File

@@ -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);

View File

@@ -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<bool>("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<bool>("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();

View File

@@ -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();
}