mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-27 23:37:05 -05:00
Currently, interactions with the user interface, like changing providers, opening menus or even resizing windows, take the focus away from the main views. This PR resets focus to the child (if view has no children then the view's window itself is used) of the view that had focus before the interaction took place. It was tested by interacting with menus, changing providers, using toolbar icons, using command palette, resizing windows or widgets of the view itself that are not children windows of the main view (e.g. running a pattern and having focus return to the pattern editor when evaluation ends. or using the icons in the hex editor) and also by selecting the main view itself. To clarify this last item, if you click on the view tab (not the provider tab but the view tab itself) the focus will be restored to the child that had focused before the tab was clicked There is no attempt to recover the active status of widgets within the window but it can be easily recovered by clicking the Tab key once. Some views, like the pattern data view, can set other views to focus depending on where they are clicked. The implementation saves the the child sub-window in a pointer of the view and is only changed if another child is given focus. Then various UI interactions are detected with care not to change focus while the interaction occurs. The end of the interaction is detected by checking if undesired items are the ones that have focus (these undesired values only occur when the UI interaction ends) and if they are, then the focus is restored to the window that is stored in the view pointer.
222 lines
7.1 KiB
C++
222 lines
7.1 KiB
C++
#pragma once
|
|
|
|
#include <hex.hpp>
|
|
|
|
#include <imgui.h>
|
|
#include <hex/ui/imgui_imhex_extensions.h>
|
|
|
|
#include <hex/api/shortcut_manager.hpp>
|
|
#include <hex/api/localization_manager.hpp>
|
|
|
|
#include <hex/providers/provider_data.hpp>
|
|
|
|
#include <hex/helpers/scaling.hpp>
|
|
|
|
#include <map>
|
|
#include <string>
|
|
|
|
namespace hex {
|
|
|
|
class View {
|
|
explicit View(UnlocalizedString unlocalizedName, const char *icon);
|
|
public:
|
|
virtual ~View() = default;
|
|
|
|
/**
|
|
* @brief Draws the view
|
|
* @note Do not override this method. Override drawContent() instead
|
|
*/
|
|
virtual void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) = 0;
|
|
|
|
/**
|
|
* @brief Draws the content of the view
|
|
*/
|
|
virtual void drawContent() = 0;
|
|
|
|
/**
|
|
* @brief Draws content that should always be visible, even if the view is not open
|
|
*/
|
|
virtual void drawAlwaysVisibleContent() { }
|
|
|
|
/**
|
|
* @brief Whether or not the view window should be drawn
|
|
* @return True if the view window should be drawn, false otherwise
|
|
*/
|
|
[[nodiscard]] virtual bool shouldDraw() const;
|
|
|
|
/**
|
|
* @brief Whether or not the entire view should be processed
|
|
* If this returns false, the view will not be drawn and no shortcuts will be handled. This includes things
|
|
* drawn in the drawAlwaysVisibleContent() function.
|
|
* @return True if the view should be processed, false otherwise
|
|
*/
|
|
[[nodiscard]] virtual bool shouldProcess() const;
|
|
|
|
/**
|
|
* @brief Whether or not the view should have an entry in the view menu
|
|
* @return True if the view should have an entry in the view menu, false otherwise
|
|
*/
|
|
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
|
|
|
|
/**
|
|
* @brief Gets the minimum size of the view window
|
|
* @return The minimum size of the view window
|
|
*/
|
|
[[nodiscard]] virtual ImVec2 getMinSize() const;
|
|
|
|
/**
|
|
* @brief Gets the maximum size of the view window
|
|
* @return The maximum size of the view window
|
|
*/
|
|
[[nodiscard]] virtual ImVec2 getMaxSize() const;
|
|
|
|
/**
|
|
* @brief Gets additional window flags for the view window
|
|
* @return Additional window flags for the view window
|
|
*/
|
|
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
|
|
|
|
/**
|
|
* @brief Returns a view whose menu items should be additionally visible when this view is focused
|
|
* @return
|
|
*/
|
|
[[nodiscard]] virtual View* getMenuItemInheritView() const { return nullptr; }
|
|
|
|
|
|
[[nodiscard]] const char *getIcon() const { return m_icon; }
|
|
[[nodiscard]] const UnlocalizedString& getUnlocalizedName() const;
|
|
[[nodiscard]] std::string getName() const;
|
|
|
|
[[nodiscard]] virtual bool shouldDefaultFocus() const { return false; }
|
|
[[nodiscard]] virtual bool shouldStoreWindowState() const { return true; }
|
|
|
|
[[nodiscard]] bool &getWindowOpenState();
|
|
[[nodiscard]] const bool &getWindowOpenState() const;
|
|
|
|
[[nodiscard]] bool isFocused() const { return m_focused; }
|
|
|
|
[[nodiscard]] static std::string toWindowName(const UnlocalizedString &unlocalizedName);
|
|
[[nodiscard]] static const View* getLastFocusedView();
|
|
static void discardNavigationRequests();
|
|
|
|
void bringToFront();
|
|
|
|
[[nodiscard]] bool didWindowJustOpen();
|
|
void setWindowJustOpened(bool state);
|
|
|
|
[[nodiscard]] bool didWindowJustClose();
|
|
void setWindowJustClosed(bool state);
|
|
|
|
void trackViewState();
|
|
void setFocused(bool focused);
|
|
|
|
protected:
|
|
/**
|
|
* @brief Called when this view is opened (i.e. made visible).
|
|
*/
|
|
virtual void onOpen() {}
|
|
|
|
/**
|
|
* @brief Called when this view is closed (i.e. made invisible).
|
|
*/
|
|
virtual void onClose() {}
|
|
|
|
public:
|
|
class Window;
|
|
class Special;
|
|
class Floating;
|
|
class Scrolling;
|
|
class Modal;
|
|
class FullScreen;
|
|
|
|
private:
|
|
UnlocalizedString m_unlocalizedViewName;
|
|
bool m_windowOpen = false, m_prevWindowOpen = false;
|
|
std::map<Shortcut, ShortcutManager::ShortcutEntry> m_shortcuts;
|
|
bool m_windowJustOpened = false, m_windowJustClosed = false;
|
|
const char *m_icon;
|
|
bool m_focused = false;
|
|
|
|
friend class ShortcutManager;
|
|
};
|
|
|
|
|
|
/**
|
|
* @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), m_focusedSubWindow(nullptr) {}
|
|
|
|
/**
|
|
* @brief Draws help text for the view
|
|
*/
|
|
virtual void drawHelpText() = 0;
|
|
|
|
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) override;
|
|
|
|
virtual bool allowScroll() const {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A view that doesn't handle any window creation and just draws its content.
|
|
* This should be used if you intend to draw your own special window
|
|
*/
|
|
class View::Special : public View {
|
|
public:
|
|
explicit Special(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName), "") {}
|
|
|
|
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
|
|
};
|
|
|
|
/**
|
|
* @brief A view that draws a floating window. These are the same as regular windows but cannot be docked
|
|
*/
|
|
class View::Floating : public View::Window {
|
|
public:
|
|
explicit Floating(UnlocalizedString unlocalizedName, const char *icon) : Window(std::move(unlocalizedName), icon) {}
|
|
|
|
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
|
|
|
|
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
|
};
|
|
|
|
/**
|
|
* @brief A view that draws all its content at once without any scrolling being done by the window itself
|
|
*/
|
|
class View::Scrolling : public View::Window {
|
|
public:
|
|
explicit Scrolling(UnlocalizedString unlocalizedName, const char *icon) : Window(std::move(unlocalizedName), icon) {}
|
|
|
|
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
|
|
|
|
bool allowScroll() const final {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A view that draws a modal window. The window will always be drawn on top and will block input to other windows
|
|
*/
|
|
class View::Modal : public View {
|
|
public:
|
|
explicit Modal(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {}
|
|
|
|
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
|
|
|
|
[[nodiscard]] virtual bool hasCloseButton() const { return true; }
|
|
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
|
};
|
|
|
|
class View::FullScreen : public View {
|
|
public:
|
|
explicit FullScreen() : View("FullScreen", "") {}
|
|
|
|
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
|
|
};
|
|
|
|
}
|