diff --git a/lib/libimhex/include/hex/ui/view.hpp b/lib/libimhex/include/hex/ui/view.hpp index 41af0876f..d373c60a4 100644 --- a/lib/libimhex/include/hex/ui/view.hpp +++ b/lib/libimhex/include/hex/ui/view.hpp @@ -145,8 +145,9 @@ namespace hex { * @brief A view that draws a regular window. This should be the default for most views */ class View::Window : public View { + ImGuiWindow *m_focusedSubWindow; public: - explicit Window(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {} + explicit Window(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon), m_focusedSubWindow(nullptr) {} /** * @brief Draws help text for the view diff --git a/lib/libimhex/source/ui/view.cpp b/lib/libimhex/source/ui/view.cpp index b524c953b..325bb0b31 100644 --- a/lib/libimhex/source/ui/view.cpp +++ b/lib/libimhex/source/ui/view.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include @@ -120,11 +120,73 @@ namespace hex { void View::Window::draw(ImGuiWindowFlags extraFlags) { if (this->shouldDraw()) { + const auto title = fmt::format("{} {}", this->getIcon(), View::toWindowName(this->getUnlocalizedName())); + + const ImGuiContext& g = *ImGui::GetCurrentContext(); + bool foundTopFocused = false; + ImGuiWindow *imguiFocusedWindow = nullptr; + ImGuiWindow *focusedSubWindow = nullptr; + + if (g.NavWindow != nullptr) { + imguiFocusedWindow = g.NavWindow; + foundTopFocused = true; + } + for (auto focusedWindow: g.WindowsFocusOrder | std::views::reverse) { + if (focusedWindow == nullptr || !focusedWindow->WasActive) + continue; + std::string focusedWindowName = focusedWindow->Name; + if (!foundTopFocused) { + imguiFocusedWindow = focusedWindow; + foundTopFocused = true; + } + if (imguiFocusedWindow == nullptr || !focusedWindowName.contains("###hex.builtin.view.")) + continue; + if (auto focusedChild = focusedWindow->NavLastChildNavWindow; focusedChild != nullptr) + focusedSubWindow = focusedChild; + else if (focusedWindow == focusedWindow->RootWindow) + focusedSubWindow = focusedWindow; + + break; + } + + std::string imguiFocusedWindowName = "NULL"; + if (imguiFocusedWindow != nullptr) + imguiFocusedWindowName.assign(imguiFocusedWindow->Name); + + std::string focusedSubWindowName; + if (focusedSubWindow != nullptr || m_focusedSubWindow != nullptr) { + focusedSubWindowName = focusedSubWindow != nullptr ? focusedSubWindow->Name : m_focusedSubWindow->Name; + if (focusedSubWindow != nullptr && m_focusedSubWindow != nullptr) { + std::string_view windowName = m_focusedSubWindow->Name; + auto stringsVector = wolv::util::splitString(focusedSubWindowName, "/"); + if (stringsVector.back().contains("resize") || (focusedSubWindow == focusedSubWindow->RootWindow && windowName.starts_with(focusedSubWindowName))) + focusedSubWindowName = windowName; + else + m_focusedSubWindow = focusedSubWindow; + } else if (focusedSubWindow != nullptr) + m_focusedSubWindow = focusedSubWindow; + + bool windowAlreadyFocused = focusedSubWindowName == imguiFocusedWindowName; + bool titleFocused = focusedSubWindowName.starts_with(title); + + if (titleFocused && !windowAlreadyFocused) { + + bool windowMayNeedFocus = focusedSubWindowName.starts_with(imguiFocusedWindowName); + std::string activeName = g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"; + + if ((activeName == "NULL" || windowMayNeedFocus) && (imguiFocusedWindowName == "##MainMenuBar" || imguiFocusedWindowName.starts_with("ImHexDockSpace") || imguiFocusedWindowName.contains("###hex.builtin.view."))) { + if (m_focusedSubWindow == m_focusedSubWindow->RootWindow) + ImGui::FocusWindow(m_focusedSubWindow, ImGuiFocusRequestFlags_RestoreFocusedChild); + else + ImGui::FocusWindow(m_focusedSubWindow, ImGuiFocusRequestFlags_None); + } + } + } + if (!allowScroll()) extraFlags |= ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize()); - const auto title = fmt::format("{} {}", this->getIcon(), View::toWindowName(this->getUnlocalizedName())); if (ImGui::Begin(title.c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | extraFlags | this->getWindowFlags())) { TutorialManager::setLastItemInteractiveHelpPopup([this]{ this->drawHelpText(); }); this->drawContent();