diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-01-12 10:11:19 -0700 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-02-05 13:42:52 -0500 |
| commit | 97ac519092fc87e27c49ab21aafb41b77f40dc03 (patch) | |
| tree | 33d1a72b835a73c25868cb170106f865d9d54430 | |
| parent | efa49ca6d23530b5e1ececccea4a2dc0bbe3406b (diff) | |
Sidebar improvements
| -rw-r--r-- | binaryninjacore.h | 2 | ||||
| -rw-r--r-- | ui/globalarea.h | 67 | ||||
| -rw-r--r-- | ui/logview.h | 27 | ||||
| -rw-r--r-- | ui/memorymap.h | 5 | ||||
| -rw-r--r-- | ui/minigraph.h | 6 | ||||
| -rw-r--r-- | ui/pane.h | 2 | ||||
| -rw-r--r-- | ui/scriptingconsole.h | 16 | ||||
| -rw-r--r-- | ui/searchresult.h | 49 | ||||
| -rw-r--r-- | ui/sidebar.h | 347 | ||||
| -rw-r--r-- | ui/sidebarcontainer.h | 162 | ||||
| -rw-r--r-- | ui/sidebaricons.h | 107 | ||||
| -rw-r--r-- | ui/sidebarwidget.h | 225 | ||||
| -rw-r--r-- | ui/splitter.h | 123 | ||||
| -rw-r--r-- | ui/stackview.h | 1 | ||||
| -rw-r--r-- | ui/stringsview.h | 5 | ||||
| -rw-r--r-- | ui/tabwidget.h | 8 | ||||
| -rw-r--r-- | ui/typebrowser.h | 7 | ||||
| -rw-r--r-- | ui/typeview.h | 4 | ||||
| -rw-r--r-- | ui/uicontext.h | 5 | ||||
| -rw-r--r-- | ui/variablelist.h | 1 | ||||
| -rw-r--r-- | ui/xreflist.h | 6 |
21 files changed, 868 insertions, 307 deletions
diff --git a/binaryninjacore.h b/binaryninjacore.h index 29d1cf29..9090fdd5 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1906,7 +1906,7 @@ extern "C" SidebarBackgroundColor, SidebarInactiveIconColor, SidebarActiveIconColor, - SidebarHeaderBackgroundColor, + SidebarHeaderBackgroundColor, // Deprecated, has no effect (paints as QPalette::Window) SidebarHeaderTextColor, SidebarWidgetBackgroundColor, diff --git a/ui/globalarea.h b/ui/globalarea.h index 098f209f..f040b802 100644 --- a/ui/globalarea.h +++ b/ui/globalarea.h @@ -4,6 +4,7 @@ #include "theme.h" #include "viewframe.h" #include "tabwidget.h" +#include "sidebar.h" /*! @@ -12,30 +13,15 @@ */ /*! - \ingroup globalarea + \deprecated Use `SidebarWidget` with `SidebarContextSensitivity::Global` instead */ -class BINARYNINJAUIAPI GlobalAreaWidget : public QWidget +class BINARYNINJAUIAPI GlobalAreaWidget : public SidebarWidget { Q_OBJECT - protected: - QString m_title; - UIActionHandler m_actionHandler; - ContextMenuManager* m_contextMenuManager = nullptr; - Menu* m_menu = nullptr; - - public: +public: GlobalAreaWidget(const QString& title); - - const QString& title() const { return m_title; } - - virtual void notifyFontChanged() {} - virtual void notifyOffsetChanged(uint64_t /*offset*/) {} - virtual void notifyThemeChanged() {} - virtual void notifyViewChanged(ViewFrame* /*frame*/) {} - virtual void notifyViewLocationChanged(View* /*view*/, const ViewLocation& /*viewLocation*/) {} - virtual void focus(); }; /*! @@ -93,35 +79,22 @@ class BINARYNINJAUIAPI CloseButton : public QWidget \ingroup globalarea */ -class BINARYNINJAUIAPI GlobalArea : public QWidget +class BINARYNINJAUIAPI GlobalArea : public QObject { Q_OBJECT - SplitTabWidget* m_tabs; - DockableTabCollection* m_collection; - QSplitter* m_parentSplitter = nullptr; - std::optional<QList<int>> m_pendingParentSplitterSizes, m_savedParentSplitterSizes; - + Sidebar* m_sidebar; static std::vector<std::function<GlobalAreaWidget*(UIContext*)>> m_widgetFactories; QString actionNameForWidget(const QString& title); - static QVariant sizesToVariant(const QList<int>& sizes); - static std::optional<QList<int>> variantToSizes(const QVariant& variant); - public: - GlobalArea(); - void setSplitter(QSplitter* splitter); +public: + GlobalArea(QWidget* owner, Sidebar* sidebar); void addWidget(GlobalAreaWidget* widget, bool canClose = false); static void addWidget(const std::function<GlobalAreaWidget*(UIContext*)>& createWidget); void initRegisteredWidgets(UIContext* context); - - void updateFonts(); - void updateTheme(); - void updateViewLocation(View* view, const ViewLocation& viewLocation); - void viewChanged(ViewFrame* frame); - bool isWidgetVisible(const QString& title); bool toggleVisible(); @@ -130,11 +103,6 @@ class BINARYNINJAUIAPI GlobalArea : public QWidget GlobalAreaWidget* widget(const QString& title); void closeTab(QWidget* widget); - void saveSizes(const QSettings& settings, const QString& windowStateName); - void saveState(const QSettings& settings, const QString& windowStateName); - void restoreSizes(const QSettings& settings, const QString& windowStateName); - void restoreState(const QSettings& settings, const QString& windowStateName); - static GlobalArea* current() { UIContext* context = UIContext::activeContext(); @@ -235,12 +203,17 @@ class BINARYNINJAUIAPI GlobalArea : public QWidget return false; }; } +}; - Q_SIGNALS: - void widgetClosed(GlobalAreaWidget* widget); - - private Q_SLOTS: - void currentChanged(QWidget* widget); - void tabClosed(QWidget* widget); - void hideButtonClicked(); +/*! + \ingroup scriptingconsole +*/ +class BINARYNINJAUIAPI GlobalAreaCompatibilitySidebarWidgetType : public SidebarWidgetType +{ +public: + GlobalAreaCompatibilitySidebarWidgetType(); + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftBottom; } + SidebarContextSensitivity contextSensitivity() const override { return GlobalSidebarContext; } + bool alwaysShowTabs() const override { return true; } + bool hideIfNoContent() const override { return true; } }; diff --git a/ui/logview.h b/ui/logview.h index aff78562..3d0ce4cd 100644 --- a/ui/logview.h +++ b/ui/logview.h @@ -20,6 +20,7 @@ #include "action.h" #include "globalarea.h" #include "render.h" +#include "filter.h" #define LOG_UPDATE_INTERVAL 100 @@ -223,7 +224,7 @@ class BINARYNINJAUIAPI LogViewComboBox : public QComboBox \ingroup logview */ -class BINARYNINJAUIAPI LogView : public GlobalAreaWidget +class BINARYNINJAUIAPI LogView : public SidebarWidget, public FilterTarget { Q_OBJECT @@ -236,7 +237,7 @@ class BINARYNINJAUIAPI LogView : public GlobalAreaWidget QTimer* m_updateTimer; LogViewComboBox* m_comboBox; - QLineEdit* m_lineEdit; + FilteredView* m_filteredView; QWidget* m_filterWidget; RenderContext m_render; @@ -262,10 +263,18 @@ class BINARYNINJAUIAPI LogView : public GlobalAreaWidget void focus() override; LogListModel* model() { return m_listModel; } - void updateFilter(const QString& filterText); + void setFilter(const std::string& filter) override; LoggingScope getScope() const { return m_model->getScope(); } void setScope(LoggingScope scope) { m_model->setScope(scope); } + QWidget* headerWidget() override { return m_filterWidget; } + + void scrollToFirstItem() override; + void scrollToCurrentItem() override; + void selectFirstItem() override; + void activateFirstItem() override {} + void closeFilter() override; + // std::pair<size_t, size_t> GetSelectionIndexAndOffsetFromPosition(const QPoint& position) const; // virtual void mousePressEvent(QMouseEvent* event) override; // virtual void mouseReleaseEvent(QMouseEvent* event) override; @@ -326,3 +335,15 @@ class BINARYNINJAUIAPI LogStatus : public QWidget public Q_SLOTS: void clicked(bool error); }; + +/*! + + \ingroup logview +*/ +class BINARYNINJAUIAPI LogViewSidebarWidgetType : public SidebarWidgetType +{ +public: + LogViewSidebarWidgetType(); + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::RightBottom; } + SidebarContextSensitivity contextSensitivity() const override { return GlobalSidebarContext; } +}; diff --git a/ui/memorymap.h b/ui/memorymap.h index 5ae7c6e4..98cbbd04 100644 --- a/ui/memorymap.h +++ b/ui/memorymap.h @@ -283,7 +283,10 @@ public: */ class BINARYNINJAUIAPI MemoryMapSidebarWidgetType : public SidebarWidgetType { - public: +public: MemoryMapSidebarWidgetType(); + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftContent; } SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; + virtual bool canUseAsPane(SplitPaneWidget*, BinaryViewRef) const override { return true; } + virtual Pane* createPane(SplitPaneWidget* panes, BinaryViewRef data) override; }; diff --git a/ui/minigraph.h b/ui/minigraph.h index 2dced4a9..27eb6ce1 100644 --- a/ui/minigraph.h +++ b/ui/minigraph.h @@ -29,7 +29,6 @@ class BINARYNINJAUIAPI MiniGraph : public SidebarWidget, public UIContextNotific ViewFrame* m_frame = nullptr; FlowGraphWidget* m_flowGraphWidget = nullptr; - QWidget* m_header = nullptr; bool m_popout; QRect m_miniRenderRect; @@ -43,7 +42,6 @@ class BINARYNINJAUIAPI MiniGraph : public SidebarWidget, public UIContextNotific // Called when popped out of sidebar virtual void OnViewChange(UIContext* context, ViewFrame* frame, const QString& type) override; - virtual QWidget* headerWidget() override { return m_header; } virtual QSize sizeHint() const override { return QSize(200, 200); } void setSource(ViewFrame* frame, FlowGraphWidget* graphView); @@ -70,5 +68,7 @@ class BINARYNINJAUIAPI MiniGraphSidebarWidgetType : public SidebarWidgetType public: MiniGraphSidebarWidgetType(); virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; - virtual bool isInReferenceArea() const override { return true; } + virtual SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftReference; } + virtual bool canUseAsPane(SplitPaneWidget*, BinaryViewRef) const override { return true; } + virtual Pane* createPane(SplitPaneWidget* pane, BinaryViewRef data) override; }; @@ -50,6 +50,7 @@ class BINARYNINJAUIAPI Pane : public QWidget virtual QString title() = 0; void closePane(); Pane* splitPane(Qt::Orientation orientation); + void splitPane(Pane* pane, Qt::Edge edge); void moveToNewWindow(); virtual void setIsSinglePane(bool isSinglePane); @@ -429,6 +430,7 @@ class BINARYNINJAUIAPI SplitPaneWidget : public QWidget void enumeratePanes(const std::function<void(Pane*)>& func); void enumerateViewPanes(const std::function<void(ViewPane*)>& func); + Pane* paneAt(const QPoint& pos); void createFeatureMap(); void recreateFeatureMaps(); diff --git a/ui/scriptingconsole.h b/ui/scriptingconsole.h index d9f7d814..0b59a189 100644 --- a/ui/scriptingconsole.h +++ b/ui/scriptingconsole.h @@ -147,7 +147,7 @@ class ScriptingConsoleWidget; /*! \ingroup scriptingconsole */ -class BINARYNINJAUIAPI ScriptingConsole : public GlobalAreaWidget, BinaryNinja::ScriptingOutputListener +class BINARYNINJAUIAPI ScriptingConsole : public SidebarWidget, BinaryNinja::ScriptingOutputListener { Q_OBJECT @@ -222,6 +222,18 @@ class BINARYNINJAUIAPI ScriptingConsole : public GlobalAreaWidget, BinaryNinja:: void moveDownInHistory(); std::vector<std::string> reverseSearch(const QString& text); - void closing(); + void closing() override; void runScriptFromFile(const std::string& filename); }; + +/*! + \ingroup scriptingconsole +*/ +class BINARYNINJAUIAPI ScriptingConsoleSidebarWidgetType : public SidebarWidgetType +{ +public: + ScriptingConsoleSidebarWidgetType(); + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftBottom; } + SidebarContextSensitivity contextSensitivity() const override { return GlobalSidebarContext; } + bool alwaysShowTabs() const override { return true; } +}; diff --git a/ui/searchresult.h b/ui/searchresult.h index c585d52c..07bedcd7 100644 --- a/ui/searchresult.h +++ b/ui/searchresult.h @@ -12,9 +12,10 @@ #include <QtWidgets/QProgressBar> #include <QtWidgets/QToolButton> #include "binaryninjaapi.h" -#include "dockhandler.h" #include "filter.h" #include "expandablegroup.h" +#include "sidebar.h" +#include "tabwidget.h" #define FIND_RESULT_LIST_UPDATE_INTERVAL 250 #define COLUMN_MIN_WIDTH_IN_CHAR 10 @@ -183,6 +184,7 @@ class BINARYNINJAUIAPI SearchResultTable : public QTableView BinaryNinja::FindParameters m_params; UIActionHandler m_actionHandler; QTimer* m_updateTimer; + bool m_ignoreColumnResize = true; int m_charWidth, m_charHeight; @@ -233,7 +235,7 @@ class SearchProgressBar; /*! \ingroup searchresult */ -class BINARYNINJAUIAPI SearchResultWidget : public QWidget +class BINARYNINJAUIAPI SearchResultWidget : public SidebarWidget { Q_OBJECT @@ -253,10 +255,10 @@ class BINARYNINJAUIAPI SearchResultWidget : public QWidget virtual void contextMenuEvent(QContextMenuEvent* event) override; public: - SearchResultWidget(BinaryViewRef data); + SearchResultWidget(BinaryViewRef data, const QString& title); ~SearchResultWidget(); - void notifyFontChanged(); + void notifyFontChanged() override; void startNewFind(const BinaryNinja::FindParameters& params); virtual QString getHeaderText(); @@ -299,3 +301,42 @@ class BINARYNINJAUIAPI SearchProgressBar : public QWidget void show(); bool isRunning() const { return m_running; } }; + +/*! + \ingroup searchresult +*/ +class BINARYNINJAUIAPI SearchResultHeaderWidget : public QWidget, public FilterTarget +{ + Q_OBJECT + + QLineEdit* m_search; + QComboBox* m_mode; + QCheckBox* m_caseInsensitive; + +public: + SearchResultHeaderWidget(); + + virtual void setFilter(const std::string&) override {} + virtual void scrollToFirstItem() override {} + virtual void scrollToCurrentItem() override {} + virtual void selectFirstItem() override {} + virtual void activateFirstItem() override; + +protected: + virtual void keyPressEvent(QKeyEvent* e) override; +}; + +/*! + \ingroup searchresult +*/ +class BINARYNINJAUIAPI SearchResultSidebarWidgetType : public SidebarWidgetType +{ +public: + SearchResultSidebarWidgetType(); + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::RightBottom; } + SidebarContextSensitivity contextSensitivity() const override { return PerViewTypeSidebarContext; } + bool alwaysShowTabs() const override { return true; } + virtual QString noWidgetMessage() const override { return "No search active"; } + virtual QWidget* headerWidget(SplitPaneWidget* panes, ViewFrame* frame, BinaryViewRef data) override; + virtual DockableTabStyle* tabStyle() const override { return new DefaultDockableTabStyle(); } +}; diff --git a/ui/sidebar.h b/ui/sidebar.h index 4f8825ed..59bf4d34 100644 --- a/ui/sidebar.h +++ b/ui/sidebar.h @@ -1,288 +1,155 @@ #pragma once -#include <QtWidgets/QWidget> -#include <QtWidgets/QLabel> -#include <QtWidgets/QStackedWidget> #include <QtWidgets/QSplitter> -#include <QtGui/QPicture> #include <QtCore/QSettings> -#include "theme.h" +#include "sidebarwidget.h" +#include "sidebarcontainer.h" +#include "sidebaricons.h" +#include "splitter.h" -class SidebarEntry; -class MainWindow; -class ContextMenuManager; -class SplitPaneWidget; - -/*! - - \defgroup sidebar Sidebar - \ingroup uiapi -*/ - -/*! - \ingroup sidebar -*/ -struct SidebarIcon -{ - QImage original; - QImage active; - QImage inactive; - - static SidebarIcon generate(const QImage& src); -}; - -/*! - \ingroup sidebar -*/ -class BINARYNINJAUIAPI SidebarWidget : public QWidget -{ - Q_OBJECT - - protected: - QString m_title; - UIActionHandler m_actionHandler; - ContextMenuManager* m_contextMenuManager = nullptr; - Menu* m_menu = nullptr; - - QTimer* m_updateTimer = nullptr; - - public: - SidebarWidget(const QString& title); - ~SidebarWidget() { closing(); } - const QString& title() const { return m_title; } - - void enableRefreshTimer(int interval); - void setRefreshQuiesce(bool enable); - virtual void notifyRefresh() {}; - - virtual void notifyFontChanged() {} - virtual void notifyOffsetChanged(uint64_t /*offset*/) {} - virtual void notifyThemeChanged(); - virtual void notifyViewChanged(ViewFrame* /*frame*/) {} - virtual void notifyViewLocationChanged(View* /*view*/, const ViewLocation& /*viewLocation*/) {} - virtual void focus(); - virtual void closing() {} - - virtual QWidget* headerWidget() { return nullptr; } -}; - -/*! - \ingroup sidebar -*/ -class BINARYNINJAUIAPI SidebarWidgetAndHeader : public QWidget -{ - Q_OBJECT - SidebarWidget* m_widget; - QWidget* m_header; - ViewFrame* m_frame; - - public: - SidebarWidgetAndHeader(SidebarWidget* widget, ViewFrame* frame); - - SidebarWidget* widget() const { return m_widget; } - QWidget* header() const { return m_header; } - ViewFrame* viewFrame() const { return m_frame; } - - void updateTheme(); - void updateFonts(); -}; - -/*! - \ingroup sidebar -*/ -class BINARYNINJAUIAPI SidebarHeaderTitle : public QLabel -{ - Q_OBJECT - - public: - SidebarHeaderTitle(const QString& name); -}; +class ViewFrame; /*! \ingroup sidebar */ -class BINARYNINJAUIAPI SidebarHeader : public QWidget +struct BINARYNINJAUIAPI SidebarMetrics { - Q_OBJECT - - public: - SidebarHeader(const QString& name, QWidget* rightSide = nullptr); + int iconWidth, iconHeight; + int paddingX, paddingY; + int separatorPadding; + int iconTotalWidth, iconTotalHeight; + int dragIconPadding; + int dropIconPadding; }; /*! \ingroup sidebar */ -class BINARYNINJAUIAPI SidebarInvalidContextWidget : public SidebarWidget +class BINARYNINJAUIAPI Sidebar : public QObject { Q_OBJECT - public: - SidebarInvalidContextWidget(const QString& title); - - private Q_SLOTS: - void openFile(); -}; - -/*! - \ingroup sidebar -*/ -class BINARYNINJAUIAPI SidebarWidgetType -{ - SidebarIcon m_icon; - QString m_name; - - public: - SidebarWidgetType(const QImage& icon, const QString& name); - virtual ~SidebarWidgetType() {} - - const SidebarIcon& icon() const { return m_icon; } - const QString& name() const { return m_name; } + struct SavedTypeOrderingInfo + { + QString typeName; + bool isDefaultArea; + }; - virtual bool isInReferenceArea() const { return false; } - virtual bool viewSensitive() const { return true; } - virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) = 0; - virtual SidebarWidget* createInvalidContextWidget(); + SidebarIconsWidget* m_left; + SidebarIconsWidget* m_right; + Splitter* m_parentSideSplitter = nullptr; + Splitter* m_parentExtendedSideSplitter = nullptr; + Splitter* m_parentBottomSplitter = nullptr; + Splitter* m_parentBottomSeparatorSplitter = nullptr; - void updateTheme(); -}; - -class ViewFrame; + SplitPaneWidget* m_panes = nullptr; + ViewFrame* m_frame = nullptr; + QString m_dataType; + BinaryViewRef m_data; -/*! - \ingroup sidebar -*/ -struct SidebarWidgetContainerState -{ - SidebarWidgetType* contentWidgetType; - SidebarWidgetType* referenceWidgetType; - QList<int> contentSplitterSizes; - QList<int> parentSplitterSizes; -}; + std::map<SplitPaneWidget*, std::map<QString, QVariantMap>> m_priorParentSideSplitterSizes; + std::map<SplitPaneWidget*, std::map<QString, QVariantMap>> m_priorParentExtendedSideSplitterSizes; + std::map<SplitPaneWidget*, std::map<QString, QVariantMap>> m_priorParentBottomSplitterSizes; + std::map<SplitPaneWidget*, std::map<QString, QVariantMap>> m_priorParentBottomSeparatorSplitterSizes; + std::map<SplitPaneWidget*, std::map<ViewFrame*, std::map<QString, std::pair<View*, ViewLocation>>>> + m_currentViewLocation; + std::set<SidebarWidgetType*> m_toggledWidgets; -/*! - \ingroup sidebar -*/ -class BINARYNINJAUIAPI SidebarWidgetContainer : public QWidget -{ - Q_OBJECT + static std::map<SidebarWidgetLocation, std::vector<SidebarWidgetType*>> m_types; + static std::map<SidebarWidgetLocation, std::vector<SavedTypeOrderingInfo>> m_savedTypeOrdering; + static std::set<Sidebar*> m_instances; + static std::set<SidebarWidgetType*> m_defaultTypes; + static std::optional<SidebarMetrics> m_metrics; - QSplitter* m_parentSplitter = nullptr; - QSplitter* m_contentSplitter; - QStackedWidget* m_contentStackedWidget; - QStackedWidget* m_referenceStackedWidget; - SplitPaneWidget* m_panes; - ViewFrame* m_frame; - QString m_dataType; - BinaryViewRef m_data; - SidebarWidgetType* m_contentActive = nullptr; - SidebarWidgetType* m_lastContentActive = nullptr; - SidebarWidgetType* m_referenceActive = nullptr; - SidebarWidgetType* m_pendingReferenceType = nullptr; - std::map<ViewFrame*, std::map<QString, std::map<SidebarWidgetType*, SidebarWidgetAndHeader*>>> m_widgets; - std::map<SplitPaneWidget*, std::map<QString, std::pair<SidebarWidgetType*, SidebarWidgetType*>>> m_priorWidgets; - std::map<SplitPaneWidget*, std::map<QString, QList<int>>> m_priorContentSplitterSizes; - std::map<SplitPaneWidget*, std::map<QString, QList<int>>> m_priorParentSplitterSizes; - std::optional<QList<int>> m_pendingContentSplitterSizes; - std::optional<QList<int>> m_pendingParentSplitterSizes; - std::map<ViewFrame*, std::map<QString, std::pair<View*, ViewLocation>>> m_currentViewLocation; +private Q_SLOTS: + void containerUpdated(); - void activateWidgetForType(SidebarWidgetType* type); - void deactivateWidgetForType(SidebarWidgetType* type); +public: + Sidebar(QWidget* parent); + virtual ~Sidebar(); - static QVariant sizesToVariant(const QList<int>& sizes); - static std::optional<QList<int>> variantToSizes(const QVariant& variant); + SidebarIconsWidget* left() const { return m_left; } + SidebarIconsWidget* right() const { return m_right; } + static SidebarWidgetLocation locationForType(SidebarWidgetType* type); + static SidebarLocation sideForLocation(SidebarWidgetLocation location); + static SidebarContainerLocation containerLocationForWidgetLocation(SidebarWidgetLocation location); + SidebarWidgetContainer* containerForLocation(SidebarWidgetLocation location) const; + static Qt::Orientation primaryOrientationForLocation(SidebarWidgetLocation location); + void forAllContainers(const std::function<void(SidebarWidgetContainer*)>& func) const; - public: - SidebarWidgetContainer(); + void setSplitters(Splitter* sideSplitter, Splitter* extendedSideSplitter, Splitter* bottomSplitter, + Splitter* bottomSeparatorSplitter); - void setSplitter(QSplitter* splitter); void setActiveContext(SplitPaneWidget* panes, ViewFrame* frame, const QString& dataType, BinaryViewRef data); void destroyContext(ViewFrame* frame); void destroyContext(SplitPaneWidget* panes); + void moveContextToContainer(SplitPaneWidget* panes, Sidebar* target); - bool isContentActive() const { return m_contentActive != nullptr; } - bool isActive(SidebarWidgetType* type) const { return m_contentActive == type || m_referenceActive == type; } - void activate(SidebarWidgetType* type); - void deactivate(SidebarWidgetType* type); + SplitPaneWidget* currentPanes(SidebarWidgetType* type = nullptr) const; + ViewFrame* currentFrame(SidebarWidgetType* type = nullptr) const; + const QString& currentDataType(SidebarWidgetType* type = nullptr) const; + BinaryViewRef currentData(SidebarWidgetType* type = nullptr) const; + std::optional<std::pair<View*, ViewLocation>> currentViewLocation() const; SidebarWidget* widget(SidebarWidgetType* type); SidebarWidget* widget(const QString& name); + SidebarWidgetAndHeader* widgetAndHeader(SidebarWidgetType* type); + SidebarWidgetAndHeader* widgetAndHeader(const QString& name); - virtual QSize sizeHint() const override; - - void updateTheme(); - void updateFonts(); - - void setDefaultReferenceType(SidebarWidgetType* type); - - void saveSizes(const QSettings& settings, const QString& windowStateName); - void saveState(const QSettings& settings, const QString& windowStateName); - void restoreSizes(const QSettings& settings, const QString& windowStateName); - void restoreState(const QSettings& settings, const QString& windowStateName); - - void updateViewLocation(View* view, const ViewLocation& viewLocation); - void viewChanged(); - - void toggleSidebar(); - - void moveContextToContainer( - SplitPaneWidget* panes, const std::vector<ViewFrame*>& frames, SidebarWidgetContainer* target); - - Q_SIGNALS: - void showContents(); - void hideContents(); -}; - -/*! - \ingroup sidebar -*/ -class BINARYNINJAUIAPI Sidebar : public QWidget -{ - Q_OBJECT - - SidebarWidgetType* m_hoverItem = nullptr; - SidebarWidgetContainer* m_currentContainer = nullptr; - - static std::vector<SidebarWidgetType*> m_contentTypes; - static std::vector<SidebarWidgetType*> m_referenceTypes; - static SidebarWidgetType* m_defaultContentType; - static SidebarWidgetType* m_defaultReferenceType; - - protected: - virtual void paintEvent(QPaintEvent* event) override; - virtual void mouseMoveEvent(QMouseEvent* event) override; - virtual void mousePressEvent(QMouseEvent* event) override; - virtual void leaveEvent(QEvent* event) override; - - public: - Sidebar(); - - SidebarWidgetContainer* container() const { return m_currentContainer; } - void setContainer(SidebarWidgetContainer* container); - void setActiveContext(SplitPaneWidget* panes, ViewFrame* frame, const QString& dataType, BinaryViewRef data); - - SidebarWidget* widget(SidebarWidgetType* type); - SidebarWidget* widget(const QString& name); + void addWidget(SidebarWidgetType* type, SidebarWidget* widget, bool canClose = false); + void addWidget(const QString& name, SidebarWidget* widget, bool canClose = false); + void removeWidget(SidebarWidgetType* type, SidebarWidget* widget); + void removeWidget(const QString& typeName, SidebarWidget* widget); + SidebarWidget* widgetWithTitle(SidebarWidgetType* type, const QString& title) const; + SidebarWidget* widgetWithTitle(const QString& typeName, const QString& title) const; + bool hasWidgetWithTitle(SidebarWidgetType* type, const QString& title) const; + bool hasWidgetWithTitle(const QString& typeName, const QString& title) const; + void focusWidgetWithTitle(SidebarWidgetType* type, const QString& title); + void focusWidgetWithTitle(const QString& typeName, const QString& title); void activate(SidebarWidgetType* type); void activate(const QString& name); + void activateDefaultTypes(); void deactivate(SidebarWidgetType* type); void deactivate(const QString& name); + void focus(SidebarWidgetType* type); + void focus(const QString& name); + void toggle(SidebarWidgetType* type); + void toggle(const QString& name); + bool isActive(SidebarWidgetType* type) const; + bool isActive(const QString& name) const; + bool isContentActive() const; + bool isSideContentActive() const; + bool isBottomContentActive() const; void updateTheme(); void updateFonts(); void toggleSidebar(); + void updateViewLocation(View* view, const ViewLocation& viewLocation); + void viewChanged(); + + void saveState(QSettings& settings, const QString& windowStateName, bool globalStateOnly = false); + QVariant saveActiveState(); + void restoreState(const QSettings& settings, const QString& windowStateName, bool globalStateOnly = false); + bool restoreActiveState(const QVariant& state); + static void addSidebarWidgetType(SidebarWidgetType* type); + static void moveSidebarWidgetType(SidebarWidgetType* type, SidebarWidgetLocation newLocation, size_t newIndex); static SidebarWidgetType* typeFromName(const QString& name); - static const std::vector<SidebarWidgetType*>& contentTypes() { return m_contentTypes; } - static const std::vector<SidebarWidgetType*>& referenceTypes() { return m_referenceTypes; } + static bool isTypeRegistered(const QString& name); + static std::vector<SidebarWidgetType*> types(); + static const std::vector<SidebarWidgetType*>& typesForLocation(SidebarWidgetLocation location); + static std::vector<SidebarWidgetType*> typesForContainerLocation(SidebarContainerLocation location); + static void initSavedTypeOrdering(); + static void saveTypeOrdering(); + + static SidebarMetrics metrics(); + static void refreshMetrics(); - static SidebarWidgetType* defaultContentType() { return m_defaultContentType; } - static SidebarWidgetType* defaultReferenceType() { return m_defaultReferenceType; } - static void setDefaultContentType(SidebarWidgetType* type) { m_defaultContentType = type; } - static void setDefaultReferenceType(SidebarWidgetType* type) { m_defaultReferenceType = type; } + static std::set<SidebarWidgetType*> defaultTypes() { return m_defaultTypes; } + static void setDefaultTypes(const std::set<SidebarWidgetType*>& types) { m_defaultTypes = types; } static Sidebar* current() { @@ -296,7 +163,7 @@ class BINARYNINJAUIAPI Sidebar : public QWidget static T* widget(SidebarWidgetType* type) { Sidebar* sidebar = current(); - if (!type || !sidebar || !sidebar->container() || !sidebar->container()->isActive(type)) + if (!type || !sidebar || !sidebar->isActive(type)) return (T*)nullptr; QWidget* widget = sidebar->widget(type); if (!widget) @@ -314,7 +181,7 @@ class BINARYNINJAUIAPI Sidebar : public QWidget static T* activateWidget(SidebarWidgetType* type) { Sidebar* sidebar = current(); - if (!type || !sidebar || !sidebar->container()) + if (!type || !sidebar) return (T*)nullptr; sidebar->activate(type); QWidget* widget = sidebar->widget(type); @@ -397,7 +264,7 @@ class BINARYNINJAUIAPI Sidebar : public QWidget if (!type || !ctxt.context) return (T*)nullptr; Sidebar* sidebar = ctxt.context->sidebar(); - if (!sidebar->container() || !sidebar->container()->isActive(type)) + if (!sidebar->isActive(type)) return (T*)nullptr; QWidget* widget = sidebar->widget(type); if (!widget) @@ -447,7 +314,7 @@ class BINARYNINJAUIAPI Sidebar : public QWidget if (!type || !ctxt.context) return false; Sidebar* sidebar = ctxt.context->sidebar(); - if (!sidebar->container() || !sidebar->container()->isActive(type)) + if (!sidebar->isActive(type)) return false; QWidget* widget = sidebar->widget(type); if (!widget) diff --git a/ui/sidebarcontainer.h b/ui/sidebarcontainer.h new file mode 100644 index 00000000..fa33c3ee --- /dev/null +++ b/ui/sidebarcontainer.h @@ -0,0 +1,162 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QStackedWidget> +#include <QtWidgets/QWidget> +#include "splitter.h" + +class Sidebar; +class SidebarWidgetType; +class SidebarWidgetAndHeader; +class SplitPaneWidget; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI FloatingSidebarStackedWidget: public QWidget +{ + Q_OBJECT + + SidebarWidgetType* m_type; + bool m_isWindowed; + QSize m_savedSize; + std::optional<QPoint> m_savedPosition; + bool m_visible = false; + +public: + FloatingSidebarStackedWidget( + SidebarWidgetType* type, QStackedWidget* stackedWidget, const QString& title, bool windowed); + bool isWindowed() const; + void setWindowed(bool windowed); + void setVisible(bool visible) override; + + QRect savedGeometry() const; + void setSavedGeometry(const QRect& rect); + +protected: + void closeEvent(QCloseEvent* event) override; + +Q_SIGNALS: + void floatingWidgetClosed(SidebarWidgetType* type); +}; + +/*! + \ingroup sidebar +*/ +struct BINARYNINJAUIAPI SidebarStackedWidget +{ + bool floating; + QStackedWidget* stackedWidget; + FloatingSidebarStackedWidget* floatingWidget; +}; + +/*! + \ingroup sidebar +*/ +enum SidebarContainerLocation +{ + LeftSideContainer, + LeftBottomContainer, + RightSideContainer, + RightBottomContainer +}; + +/*! + \ingroup sidebar +*/ +struct BINARYNINJAUIAPI SidebarFloatingWidgetState +{ + bool floating, windowed; + QRect rect; +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarWidgetContainer : public QWidget +{ + Q_OBJECT + + Sidebar* m_sidebar; + SidebarContainerLocation m_location; + + Splitter* m_contentSplitter; + std::map<SplitPaneWidget*, std::map<QString, QVariantMap>> m_priorContentSplitterState; + + std::set<SidebarWidgetType*> m_active, m_docked; + std::map<SidebarWidgetType*, SidebarStackedWidget> m_stackedWidgets; + std::map<SplitPaneWidget*, + std::map<ViewFrame*, std::map<QString, std::map<SidebarWidgetType*, SidebarWidgetAndHeader*>>>> + m_widgets; + std::map<SplitPaneWidget*, std::map<QString, std::set<SidebarWidgetType*>>> m_priorWidgets; + + std::map<SidebarWidgetType*, SidebarFloatingWidgetState> m_savedFloatingWidgetState; + + SidebarStackedWidget& stackedWidgetForType(SidebarWidgetType* type); + std::vector<SidebarWidgetAndHeader*> widgetsForContext() const; + void insertWidgetIntoContainer(SidebarWidgetType* type, QStackedWidget* widget); + void updateContentsVisibility(); + +private Q_SLOTS: + void floatingWidgetClosed(SidebarWidgetType* type); + +public: + SidebarWidgetContainer(Sidebar* sidebar, SidebarContainerLocation location); + + Sidebar* sidebar() const { return m_sidebar; } + Splitter* contentSplitter() const { return m_contentSplitter; } + SidebarContainerLocation location() const { return m_location; } + + void savePriorContext(); + void setActiveContext(SplitPaneWidget* panes, const QString& dataType); + void destroyContext(ViewFrame* frame); + void destroyContext(SplitPaneWidget* panes); + + bool isContentActive() const { return !m_docked.empty(); } + bool isActive(SidebarWidgetType* type) const { return m_active.count(type) != 0; } + const std::set<SidebarWidgetType*>& activeTypes() const { return m_active; } + const std::set<SidebarWidgetType*>& dockedTypes() const { return m_docked; } + + void activate(SidebarWidgetType* type); + void deactivate(SidebarWidgetType* type); + + void moveSidebarWidgetType(SidebarWidgetType* type); + void transferSidebarWidgetType(SidebarWidgetType* type, SidebarWidgetContainer* target); + + SidebarWidget* widget(SidebarWidgetType* type) const; + SidebarWidget* widget(const QString& name) const; + SidebarWidgetAndHeader* widgetAndHeader(SidebarWidgetType* type) const; + + void addWidget(SidebarWidgetType* type, SidebarWidget* widget, bool canClose = false); + void removeWidget(SidebarWidgetType* type, SidebarWidget* widget); + SidebarWidget* widgetWithTitle(SidebarWidgetType* type, const QString& title) const; + bool hasWidgetWithTitle(SidebarWidgetType* type, const QString& title) const; + bool activateWidgetWithTitle(SidebarWidgetType* type, const QString& title) const; + bool hasContent(SidebarWidgetType* type) const; + + virtual QSize sizeHint() const override; + + void updateTheme(); + void updateFonts(); + + void saveSizes(QSettings& settings, const QString& windowStateName); + void restoreSizes(const QSettings& settings, const QString& windowStateName); + std::optional<SidebarFloatingWidgetState> floatingWidgetState(SidebarWidgetType* type) const; + void restoreFloatingWidgetState(SidebarWidgetType* type, const SidebarFloatingWidgetState& state); + + void updateViewLocation(View* view, const ViewLocation& viewLocation); + void viewChanged(); + + void moveContextToContainer(SplitPaneWidget* panes, SidebarWidgetContainer* target); + + void dockWidget(SidebarWidgetType* type); + void floatWidget(SidebarWidgetType* type); + void windowedWidget(SidebarWidgetType* type); + bool isDocked(SidebarWidgetType* type); + bool isFloating(SidebarWidgetType* type); + bool isWindowed(SidebarWidgetType* type); + +Q_SIGNALS: + void showContents(); + void hideContents(); +}; diff --git a/ui/sidebaricons.h b/ui/sidebaricons.h new file mode 100644 index 00000000..b68ace9e --- /dev/null +++ b/ui/sidebaricons.h @@ -0,0 +1,107 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QRubberBand> + +class Sidebar; +class SidebarWidgetType; +class SidebarWidgetContainer; + +/*! + \ingroup sidebar +*/ +enum SidebarLocation +{ + LeftSide, + RightSide, +}; + +/*! + \ingroup sidebar +*/ +struct BINARYNINJAUIAPI SidebarIconInfo +{ + SidebarWidgetType* type; + SidebarWidgetLocation location; + size_t index; + QRect rect; +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarIconDragIndicator : public QWidget +{ + Q_OBJECT + + QImage m_image; + QSize m_size; + QPoint m_offset; + +public: + SidebarIconDragIndicator(QImage image, QSize size, QPoint pt, QPoint offset); + void moveToMouse(QPoint pt); + + QSize size() const { return m_size; } + QPoint offset() const { return m_offset; } + +protected: + virtual QSize sizeHint() const override; + virtual QSize minimumSizeHint() const override; + virtual void paintEvent(QPaintEvent* event) override; +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarIconsWidget : public QWidget +{ + Q_OBJECT + + Sidebar* m_sidebar; + SidebarLocation m_location; + SidebarWidgetType* m_hoverItem = nullptr; + SidebarWidgetContainer* m_sideContainer = nullptr; + SidebarWidgetContainer* m_bottomContainer = nullptr; + + std::optional<QPoint> m_dragStart; + std::optional<SidebarIconInfo> m_dragItem; + bool m_dragItemAsPlaceholder = false; + SidebarIconsWidget* m_dragTargetSidebar = nullptr; + Pane* m_dragTargetPane = nullptr; + Qt::Edge m_dragTargetPaneEdge = Qt::LeftEdge; + SidebarIconDragIndicator* m_dragIndicator = nullptr; + QRubberBand* m_dropIndicator = nullptr; + + std::vector<SidebarWidgetType*> filterTypesForPlaceholder(const std::vector<SidebarWidgetType*>& types) const; + std::optional<SidebarIconInfo> itemForY(int y) const; + std::pair<SidebarWidgetLocation, size_t> findDropLocation(int y) const; + QRect placeholderRect() const; + bool shouldBeVisible() const; + +private Q_SLOTS: + void containerUpdated(); + +protected: + virtual void paintEvent(QPaintEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseReleaseEvent(QMouseEvent* event) override; + virtual void leaveEvent(QEvent* event) override; + +public: + SidebarIconsWidget(Sidebar* sidebar, SidebarLocation location); + + SidebarWidgetContainer* sideContainer() const { return m_sideContainer; } + SidebarWidgetContainer* bottomContainer() const { return m_bottomContainer; } + SidebarWidgetContainer* containerForLocation(SidebarWidgetLocation location) const; + SidebarIconsWidget* other() const; + void setContainers(SidebarWidgetContainer* sideContainer, SidebarWidgetContainer* bottomContainer); + + void updateTheme(); + void updateVisibility(); + void refreshMetrics(); + +Q_SIGNALS: + void containerVisibilityChanged(); +}; diff --git a/ui/sidebarwidget.h b/ui/sidebarwidget.h new file mode 100644 index 00000000..50681098 --- /dev/null +++ b/ui/sidebarwidget.h @@ -0,0 +1,225 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QLabel> +#include <QtWidgets/QStackedWidget> +#include <QtWidgets/QVBoxLayout> +#include <QtGui/QPicture> +#include "theme.h" + +class ContextMenuManager; +class SplitTabWidget; +class SidebarWidgetType; +class SidebarHeader; +class DockableTabCollection; +class Pane; +class SplitPaneWidget; +class DockableTabStyle; + +/*! + \defgroup sidebar Sidebar + \ingroup uiapi +*/ + +/*! + \ingroup sidebar +*/ +struct BINARYNINJAUIAPI SidebarIcon +{ + QImage original; + QImage active; + QImage inactive; + + static SidebarIcon generate(const QImage& src); +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarWidget : public QWidget +{ + Q_OBJECT + +protected: + QString m_title; + UIActionHandler m_actionHandler; + ContextMenuManager* m_contextMenuManager = nullptr; + Menu* m_menu = nullptr; + + QTimer* m_updateTimer = nullptr; + +public: + SidebarWidget(const QString& title); + ~SidebarWidget() { closing(); } + const QString& title() const { return m_title; } + + void enableRefreshTimer(int interval); + void setRefreshQuiesce(bool enable); + virtual void notifyRefresh() {}; + + virtual void notifyFontChanged() {} + virtual void notifyOffsetChanged(uint64_t /*offset*/) {} + virtual void notifyThemeChanged(); + virtual void notifyViewChanged(ViewFrame* /*frame*/) {} + virtual void notifyViewLocationChanged(View* /*view*/, const ViewLocation& /*viewLocation*/) {} + virtual void focus(); + virtual void closing() {} + virtual void setPrimaryOrientation(Qt::Orientation /*orientation*/) {} + + virtual QWidget* headerWidget() { return nullptr; } +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarWidgetAndHeader : public QWidget +{ + Q_OBJECT + bool m_tabsActive = false; + bool m_combinedTabsAndHeader = false; + bool m_alwaysShowTabs; + bool m_fixedHeaderWidget; + SidebarWidgetType* m_type; + SidebarWidget* m_widget = nullptr; + SidebarHeader* m_header = nullptr; + + QVBoxLayout* m_layout; + SplitTabWidget* m_tabs = nullptr; + DockableTabCollection* m_tabCollection = nullptr; + QStackedWidget* m_headerStack; + std::map<QWidget*, SidebarHeader*> m_headerWidgets; + std::set<SidebarWidget*> m_activeWidgets; + QLabel* m_noWidgetLabel = nullptr; + +private Q_SLOTS: + void tabChanged(QWidget* widget); + void tabClosed(QWidget* widget); + +public: + SidebarWidgetAndHeader(SidebarWidgetType* type, SplitPaneWidget* panes, ViewFrame* frame, BinaryViewRef data); + ~SidebarWidgetAndHeader() override; + + SidebarWidget* widget() const { return m_widget; } + QWidget* header() const; + + void addWidget(SidebarWidget* widget, bool canClose = false); + void removeWidget(SidebarWidget* widget); + SidebarWidget* widgetWithTitle(const QString& title) const; + bool hasWidgetWithTitle(const QString& title) const; + bool activateWidgetWithTitle(const QString& title); + bool hasContent() const; + + void updateTheme(); + void updateFonts(); + void closing(); + void notifyViewChanged(ViewFrame* frame); + void notifyViewLocationChanged(View* view, const ViewLocation& viewLocation); + void notifyOffsetChanged(uint64_t offset); + + void forAllWidgets(const std::function<void(SidebarWidget*)>& func) const; +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarHeaderTitle : public QLabel +{ + Q_OBJECT + +public: + SidebarHeaderTitle(const QString& name); +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarHeader : public QWidget +{ + Q_OBJECT + bool m_hasRightSide = false; + +public: + SidebarHeader(const QString& name, QWidget* rightSide = nullptr); + bool hasRightSide() const { return m_hasRightSide; } +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarInvalidContextWidget : public SidebarWidget +{ + Q_OBJECT + +public: + SidebarInvalidContextWidget(const QString& title); + +private Q_SLOTS: + void openFile(); +}; + +/*! + \ingroup sidebar +*/ +enum SidebarWidgetLocation +{ + LeftContent, + LeftReference, + LeftBottom, + RightContent, + RightReference, + RightBottom +}; + +enum SidebarContextSensitivity +{ + GlobalSidebarContext, + SelfManagedSidebarContext, + PerTabSidebarContext, + PerViewTypeSidebarContext, + PerPaneSidebarContext +}; + +/*! + \ingroup sidebar +*/ +class BINARYNINJAUIAPI SidebarWidgetType +{ + SidebarIcon m_icon; + QString m_name; + +public: + SidebarWidgetType(const QImage& icon, const QString& name); + virtual ~SidebarWidgetType() {} + + const SidebarIcon& icon() const { return m_icon; } + const QString& name() const { return m_name; } + + /*! + \deprecated Use `defaultLocation()` + */ + virtual bool isInReferenceArea() const { return false; } + + /*! + \deprecated Use `contextSensitivity()` + */ + virtual bool viewSensitive() const { return true; } + + virtual SidebarWidgetLocation defaultLocation() const; + virtual SidebarContextSensitivity contextSensitivity() const; + virtual bool alwaysShowTabs() const { return false; } + virtual bool hideIfNoContent() const { return false; } + + virtual SidebarWidget* createWidget(ViewFrame* /*frame*/, BinaryViewRef /*data*/) { return nullptr; } + virtual SidebarWidget* createInvalidContextWidget(); + virtual QWidget* headerWidget(SplitPaneWidget* /*panes*/, ViewFrame* /*frame*/, BinaryViewRef /*data*/) + { + return nullptr; + } + virtual QString noWidgetMessage() const { return "No content active"; } + virtual DockableTabStyle* tabStyle() const; + + virtual bool canUseAsPane(SplitPaneWidget* /*panes*/, BinaryViewRef /*data*/) const { return false; } + virtual Pane* createPane(SplitPaneWidget* /*panes*/, BinaryViewRef /*data*/) { return nullptr; } + + void updateTheme(); +}; diff --git a/ui/splitter.h b/ui/splitter.h new file mode 100644 index 00000000..089de444 --- /dev/null +++ b/ui/splitter.h @@ -0,0 +1,123 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtCore/QSettings> +#include <vector> +#include <set> +#include <map> +#include "uicontext.h" + +/*! + \defgroup splitter Splitter + \ingroup uiapi +*/ + +/*! + \ingroup splitter +*/ +enum SplitterWidgetSizingStyle +{ + RelativeWidgetSize, + WidgetSizeInPoints +}; + +/*! + \ingroup splitter +*/ +struct BINARYNINJAUIAPI SplitterWidgetSizing +{ + SplitterWidgetSizingStyle style; + float referenceSize; + bool isDefault; + float requestedSize; + QString group; + + static SplitterWidgetSizing relativeSize(float relativeSize = 1, const QString& group = QString()); + static SplitterWidgetSizing pointSize(int size); + + QVariantMap serialize() const; + static std::optional<SplitterWidgetSizing> deserialize(const QVariantMap& value); +}; + +/*! + \ingroup splitter +*/ +struct BINARYNINJAUIAPI SplitterWidget +{ + QString key; + QWidget* widget; + bool visible; + SplitterWidgetSizing sizing; + int actualSize, minimumSize; +}; + +/*! + \ingroup splitter +*/ +class BINARYNINJAUIAPI Splitter: public QWidget +{ + Q_OBJECT + + struct SplitterDragInfo + { + size_t left, right; + int offset; + }; + + struct GroupInfo + { + QString group; + std::set<SplitterWidget*> widgets; + SplitterWidgetSizing sizing; + int actualSize, minimumSize; + }; + + Qt::Orientation m_orientation; + int m_handleSize; + + std::vector<SplitterWidget> m_widgets; + std::map<QString, SplitterWidgetSizing> m_sizing; + std::map<QString, SplitterWidgetSizing> m_groupSizing; + + std::optional<size_t> m_handleHover; + std::optional<SplitterDragInfo> m_handleDrag; + + bool m_updatingLayout = false; + +public: + Splitter(Qt::Orientation orientation); + + void addWidget(const QString& key, QWidget* widget, const SplitterWidgetSizing& defaultSize); + void insertWidget(const QString& key, size_t index, QWidget* widget, const SplitterWidgetSizing& defaultSize); + void addRelativeSizeGroup(const QString& group, float relativeSize); + + QVariantMap saveState(); + void saveState(QSettings& settings, const QString& stateName); + void restoreState(const QVariantMap& state); + void restoreState(const QSettings& settings, const QString& stateName); + void resetToDefault(); + +protected: + virtual void paintEvent(QPaintEvent* event) override; + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mouseReleaseEvent(QMouseEvent* event) override; + virtual void leaveEvent(QEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; + virtual void childEvent(QChildEvent* event) override; + virtual bool event(QEvent* event) override; + +private: + void forAllSplitterHandles(const std::function<void(size_t leftIdx, size_t rightIdx, int pos)>& func); + void processLayout(const std::function<int(int availablePointSize)>& processPointSizeWidgets, + const std::function<void(int availableWidgetSize)>& processRelativeSizeWidgets); + void getWidgetsForSizingStyle(SplitterWidgetSizingStyle style, + std::set<SplitterWidget*>& widgets, std::vector<GroupInfo>& groups); + void regenerateLayoutForRelativeSizedWidgets( + std::set<SplitterWidget*> widgets, std::vector<GroupInfo> groups, int availableSize); + void regenerateLayout(); + void calculateRequestedSizesForRelativeSizedWidgets( + const std::set<SplitterWidget*>& widgets, const std::vector<GroupInfo>& groups, int availableSize); + void calculateRequestedSizesForActualLayout(); + void updateWidgetPositions(); +}; diff --git a/ui/stackview.h b/ui/stackview.h index 2f5c043c..934410f9 100644 --- a/ui/stackview.h +++ b/ui/stackview.h @@ -297,4 +297,5 @@ class BINARYNINJAUIAPI StackViewSidebarWidgetType : public SidebarWidgetType public: StackViewSidebarWidgetType(); SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; + virtual SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::RightContent; } }; diff --git a/ui/stringsview.h b/ui/stringsview.h index be52aebd..e2db0ef5 100644 --- a/ui/stringsview.h +++ b/ui/stringsview.h @@ -259,7 +259,10 @@ class BINARYNINJAUIAPI StringsViewSidebarWidget : public SidebarWidget */ class BINARYNINJAUIAPI StringsViewSidebarWidgetType : public SidebarWidgetType { - public: +public: StringsViewSidebarWidgetType(); + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::RightBottom; } virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; + virtual bool canUseAsPane(SplitPaneWidget*, BinaryViewRef) const override { return true; } + virtual Pane* createPane(SplitPaneWidget* panes, BinaryViewRef data) override; }; diff --git a/ui/tabwidget.h b/ui/tabwidget.h index e55abf60..81783b88 100644 --- a/ui/tabwidget.h +++ b/ui/tabwidget.h @@ -25,11 +25,12 @@ class DockableTabWidget; \ingroup tabwidget */ -class BINARYNINJAUIAPI DockableTabCollection +class BINARYNINJAUIAPI DockableTabCollection : public QObject { + Q_OBJECT std::set<DockableTabWidget*> m_containers; - public: +public: void registerContainer(DockableTabWidget* widget); void unregisterContainer(DockableTabWidget* widget); @@ -378,11 +379,12 @@ class BINARYNINJAUIAPI SplitTabWidget : public QWidget SplitTabWidget(DockableTabCollection* collection); void addTab(QWidget* widget, const QString& title); + bool removeTab(QWidget* widget); void setCanCloseTab(QWidget* widget, bool canClose); void enumerateTabs(const std::function<void(QWidget*)>& func); void selectWidget(QWidget* widget); bool isWidgetVisible(QWidget* widget); - void closeTab(QWidget* widget); + bool closeTab(QWidget* widget); void setTabStyle(DockableTabStyle* style); diff --git a/ui/typebrowser.h b/ui/typebrowser.h index b6f442a2..783de834 100644 --- a/ui/typebrowser.h +++ b/ui/typebrowser.h @@ -380,6 +380,8 @@ public: bool navigateToType(const std::string& typeName, uint64_t offset); void scrollToIndexWithContext(const QModelIndex& index, int context = 1); + void setPrimaryOrientation(Qt::Orientation orientation); + // Selection helpers // All nodes @@ -507,6 +509,7 @@ public: TypeBrowserContainer* container() { return m_container; } virtual QWidget* headerWidget() override { return m_header; } virtual void focus() override; + virtual void setPrimaryOrientation(Qt::Orientation orientation) override; protected: virtual void contextMenuEvent(QContextMenuEvent* event) override; @@ -521,4 +524,8 @@ class BINARYNINJAUIAPI TypeBrowserSidebarWidgetType : public SidebarWidgetType public: TypeBrowserSidebarWidgetType(); virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; + + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftContent; } + virtual bool canUseAsPane(SplitPaneWidget*, BinaryViewRef) const override { return true; } + virtual Pane* createPane(SplitPaneWidget* panes, BinaryViewRef data) override; }; diff --git a/ui/typeview.h b/ui/typeview.h index a7d447fd..24e898bf 100644 --- a/ui/typeview.h +++ b/ui/typeview.h @@ -452,4 +452,8 @@ class BINARYNINJAUIAPI TypeViewSidebarWidgetType : public SidebarWidgetType public: TypeViewSidebarWidgetType(); virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; + + SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::LeftContent; } + virtual bool canUseAsPane(SplitPaneWidget*, BinaryViewRef) const override { return true; } + virtual Pane* createPane(SplitPaneWidget* panes, BinaryViewRef data) override; }; diff --git a/ui/uicontext.h b/ui/uicontext.h index df4ff0a2..9d8e3377 100644 --- a/ui/uicontext.h +++ b/ui/uicontext.h @@ -465,6 +465,8 @@ public: void updateCrossReferences(ViewFrame* frame, View* view, const SelectionInfoForXref& selection); + virtual void findAll(const BinaryNinja::FindParameters& params); + /*! Register an object to receive notifications of UIContext events \param notification Object which will receive notifications @@ -491,6 +493,9 @@ public: virtual QWidget* fileContentsLockStatusWidget() = 0; + void associateAdditionalWindowWithContext(QWidget* window); + static void deassociateAdditionalWindowWithContext(QWidget* window); + static void setHandler(UIContextHandler* handler); static QSize getScaledWindowSize(int x, int y); diff --git a/ui/variablelist.h b/ui/variablelist.h index 2f05f853..2b7ed8e7 100644 --- a/ui/variablelist.h +++ b/ui/variablelist.h @@ -257,4 +257,5 @@ class BINARYNINJAUIAPI VariableListSidebarWidgetType : public SidebarWidgetType public: VariableListSidebarWidgetType(); virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; + virtual SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::RightContent; } }; diff --git a/ui/xreflist.h b/ui/xreflist.h index 02175cf5..50730705 100644 --- a/ui/xreflist.h +++ b/ui/xreflist.h @@ -596,6 +596,7 @@ class BINARYNINJAUIAPI CrossReferenceWidget : public SidebarWidget, public UICon CrossReferenceTree* m_tree; CrossReferenceContainer* m_container; bool m_useTableView; + Qt::Orientation m_primaryOrientation; std::optional<BNFunctionGraphType> m_graphType; QTimer* m_hoverTimer; @@ -638,7 +639,7 @@ class BINARYNINJAUIAPI CrossReferenceWidget : public SidebarWidget, public UICon virtual void startHoverTimer(QMouseEvent* e); virtual void keyPressEvent(QKeyEvent* e) override; virtual bool keyPressHandler(QKeyEvent* e); - void useTableView(bool tableView, bool init); + void useTableView(bool tableView, bool init, bool updateSetting); bool tableView() const { return m_useTableView; } bool uiMaxItemsExceeded() const { return m_uiMaxItemsExceeded; } void setUIMaxItemsExceeded(bool value) { m_uiMaxItemsExceeded = value; } @@ -650,8 +651,9 @@ class BINARYNINJAUIAPI CrossReferenceWidget : public SidebarWidget, public UICon UIContext* context, ViewFrame* frame, View* view, const SelectionInfoForXref& selection) override; virtual QWidget* headerWidget() override { return m_header; } + virtual void setPrimaryOrientation(Qt::Orientation orientation) override; - private Q_SLOTS: +private Q_SLOTS: void hoverTimerEvent(); void newPinnedPane(); |
