summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-01-12 10:11:19 -0700
committerRusty Wagner <rusty.wagner@gmail.com>2024-02-05 13:42:52 -0500
commit97ac519092fc87e27c49ab21aafb41b77f40dc03 (patch)
tree33d1a72b835a73c25868cb170106f865d9d54430
parentefa49ca6d23530b5e1ececccea4a2dc0bbe3406b (diff)
Sidebar improvements
-rw-r--r--binaryninjacore.h2
-rw-r--r--ui/globalarea.h67
-rw-r--r--ui/logview.h27
-rw-r--r--ui/memorymap.h5
-rw-r--r--ui/minigraph.h6
-rw-r--r--ui/pane.h2
-rw-r--r--ui/scriptingconsole.h16
-rw-r--r--ui/searchresult.h49
-rw-r--r--ui/sidebar.h347
-rw-r--r--ui/sidebarcontainer.h162
-rw-r--r--ui/sidebaricons.h107
-rw-r--r--ui/sidebarwidget.h225
-rw-r--r--ui/splitter.h123
-rw-r--r--ui/stackview.h1
-rw-r--r--ui/stringsview.h5
-rw-r--r--ui/tabwidget.h8
-rw-r--r--ui/typebrowser.h7
-rw-r--r--ui/typeview.h4
-rw-r--r--ui/uicontext.h5
-rw-r--r--ui/variablelist.h1
-rw-r--r--ui/xreflist.h6
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;
};
diff --git a/ui/pane.h b/ui/pane.h
index 3301efd0..f06158a9 100644
--- a/ui/pane.h
+++ b/ui/pane.h
@@ -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();