summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjacore.h10
-rw-r--r--examples/triage/byte.cpp2
-rw-r--r--examples/triage/view.cpp3
-rw-r--r--python/examples/hellodockwidget.py6
-rw-r--r--python/examples/hellosidebar.py107
-rw-r--r--ui/clickablelabel.h46
-rw-r--r--ui/filter.h7
-rw-r--r--ui/render.h1
-rw-r--r--ui/sidebar.h408
-rw-r--r--ui/stringsview.h23
-rw-r--r--ui/symbolsview.h17
-rw-r--r--ui/taglist.h17
-rw-r--r--ui/typeview.h59
-rw-r--r--ui/uicontext.h21
-rw-r--r--ui/viewframe.h23
-rw-r--r--ui/xreflist.h22
16 files changed, 738 insertions, 34 deletions
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 3f48736d..1037114d 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -1654,7 +1654,15 @@ extern "C"
FeatureMapFunctionColor,
FeatureMapImportColor,
FeatureMapExternColor,
- FeatureMapLibraryColor
+ FeatureMapLibraryColor,
+
+ // Sidebar colors
+ SidebarBackgroundColor,
+ SidebarInactiveIconColor,
+ SidebarActiveIconColor,
+ SidebarHeaderBackgroundColor,
+ SidebarHeaderTextColor,
+ SidebarWidgetBackgroundColor
};
// The following edge styles map to QT's Qt::PenStyle enumeration
diff --git a/examples/triage/byte.cpp b/examples/triage/byte.cpp
index c3a91372..be25368a 100644
--- a/examples/triage/byte.cpp
+++ b/examples/triage/byte.cpp
@@ -548,6 +548,7 @@ void ByteView::repositionCaret()
m_cursorTimer->start();
updateCaret();
UIContext::updateStatus();
+ updateCrossReferenceSelection();
}
@@ -817,6 +818,7 @@ void ByteView::selectAll()
m_cursorAddr = getEnd();
viewport()->update();
UIContext::updateStatus();
+ updateCrossReferenceSelection();
}
diff --git a/examples/triage/view.cpp b/examples/triage/view.cpp
index 417006b2..e69fa0d9 100644
--- a/examples/triage/view.cpp
+++ b/examples/triage/view.cpp
@@ -135,7 +135,8 @@ void TriageView::setSelectionOffsets(BNAddressRange range)
void TriageView::setCurrentOffset(uint64_t offset)
{
m_currentOffset = offset;
- UIContext::updateStatus(true);
+ UIContext::updateStatus();
+ updateCrossReferenceSelection();
}
diff --git a/python/examples/hellodockwidget.py b/python/examples/hellodockwidget.py
index 6f5f52ea..879b424f 100644
--- a/python/examples/hellodockwidget.py
+++ b/python/examples/hellodockwidget.py
@@ -31,9 +31,9 @@
# For Dynamic dock widgets, the UI widget operates on a single binary view instance
from binaryninjaui import DockHandler, DockContextHandler, UIActionHandler
-from PySide2 import QtCore
-from PySide2.QtCore import Qt
-from PySide2.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QLabel, QWidget
+from PySide6 import QtCore
+from PySide6.QtCore import Qt
+from PySide6.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QLabel, QWidget
instance_id = 0
class HelloDockWidget(QWidget, DockContextHandler):
diff --git a/python/examples/hellosidebar.py b/python/examples/hellosidebar.py
new file mode 100644
index 00000000..7c490dbb
--- /dev/null
+++ b/python/examples/hellosidebar.py
@@ -0,0 +1,107 @@
+# Copyright (c) 2015-2021 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+# This is an example UI plugin which demonstrates how to add sidebar widgets to Binary Ninja.
+# See .../api/ui/sidebar.h for interface details.
+
+from binaryninjaui import SidebarWidget, SidebarWidgetType, Sidebar, UIActionHandler
+from PySide6 import QtCore
+from PySide6.QtCore import Qt, QRectF
+from PySide6.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QLabel, QWidget
+from PySide6.QtGui import QImage, QPixmap, QPainter, QFont, QColor
+
+instance_id = 0
+
+# Sidebar widgets must derive from SidebarWidget, not QWidget. SidebarWidget is a QWidget but
+# provides callbacks for sidebar events, and must be created with a title.
+class HelloSidebarWidget(SidebarWidget):
+ def __init__(self, name, frame, data):
+ global instance_id
+ SidebarWidget.__init__(self, name)
+ self.actionHandler = UIActionHandler()
+ self.actionHandler.setupActionHandler(self)
+ offset_layout = QHBoxLayout()
+ offset_layout.addWidget(QLabel("Offset: "))
+ self.offset = QLabel(hex(0))
+ offset_layout.addWidget(self.offset)
+ offset_layout.setAlignment(QtCore.Qt.AlignCenter)
+ datatype_layout = QHBoxLayout()
+ datatype_layout.addWidget(QLabel("Data Type: "))
+ self.datatype = QLabel("")
+ datatype_layout.addWidget(self.datatype)
+ datatype_layout.setAlignment(QtCore.Qt.AlignCenter)
+ layout = QVBoxLayout()
+ title = QLabel(name, self)
+ title.setAlignment(QtCore.Qt.AlignCenter)
+ instance = QLabel("Instance: " + str(instance_id), self)
+ instance.setAlignment(QtCore.Qt.AlignCenter)
+ layout.addStretch()
+ layout.addWidget(title)
+ layout.addWidget(instance)
+ layout.addLayout(datatype_layout)
+ layout.addLayout(offset_layout)
+ layout.addStretch()
+ self.setLayout(layout)
+ instance_id += 1
+ self.data = data
+
+ def notifyOffsetChanged(self, offset):
+ self.offset.setText(hex(offset))
+
+ def notifyViewChanged(self, view_frame):
+ if view_frame is None:
+ self.datatype.setText("None")
+ self.data = None
+ else:
+ self.datatype.setText(view_frame.getCurrentView())
+ view = view_frame.getCurrentViewInterface()
+ self.data = view.getData()
+
+ def contextMenuEvent(self, event):
+ self.m_contextMenuManager.show(self.m_menu, self.actionHandler)
+
+class HelloSidebarWidgetType(SidebarWidgetType):
+ def __init__(self):
+ # Sidebar icons are 28x28 points. Should be at least 56x56 pixels for
+ # HiDPI display compatibility. They will be automatically made theme
+ # aware, so you need only provide a grayscale image, where white is
+ # the color of the shape.
+ icon = QImage(56, 56, QImage.Format_RGB32)
+ icon.fill(0)
+
+ # Render an "H" as the example icon
+ p = QPainter()
+ p.begin(icon)
+ p.setFont(QFont("Open Sans", 56))
+ p.setPen(QColor(255, 255, 255, 255))
+ p.drawText(QRectF(0, 0, 56, 56), Qt.AlignCenter, "H")
+ p.end()
+
+ SidebarWidgetType.__init__(self, icon, "Hello")
+
+ def createWidget(self, frame, data):
+ # This callback is called when a widget needs to be created for a given context. Different
+ # widgets are created for each unique BinaryView. They are created on demand when the sidebar
+ # widget is visible and the BinaryView becomes active.
+ return HelloSidebarWidget("Hello", frame, data)
+
+# Register the sidebar widget type with Binary Ninja. This will make it appear as an icon in the
+# sidebar and the `createWidget` method will be called when a widget is required.
+Sidebar.addSidebarWidgetType(HelloSidebarWidgetType())
diff --git a/ui/clickablelabel.h b/ui/clickablelabel.h
index 4025d7c3..606ec369 100644
--- a/ui/clickablelabel.h
+++ b/ui/clickablelabel.h
@@ -1,8 +1,21 @@
#pragma once
+#include <QtCore/QTimer>
#include <QtGui/QColor>
#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
#include <QtWidgets/QLabel>
+#include "uicontext.h"
+
+
+struct BINARYNINJAUIAPI IconImage
+{
+ QImage original;
+ QImage active, activeHover;
+ QImage inactive, inactiveHover;
+
+ static IconImage generate(const QImage& src);
+};
class BINARYNINJAUIAPI ClickableLabel: public QLabel
@@ -20,6 +33,39 @@ protected:
};
+class BINARYNINJAUIAPI ClickableIcon: public QWidget
+{
+ Q_OBJECT
+
+ IconImage m_image;
+ bool m_canToggle = false;
+ bool m_active = true;
+ bool m_hover = false;
+ QTimer* m_timer;
+
+public:
+ ClickableIcon(const QImage& icon, const QSize& desiredPointSize);
+
+ void setAllowToggle(bool canToggle);
+ void setActive(bool state);
+ bool active() const { return m_active; }
+
+Q_SIGNALS:
+ void clicked();
+ void toggle(bool newState);
+
+private Q_SLOTS:
+ void underMouseTimerEvent();
+ void handleToggle();
+
+protected:
+ void enterEvent(QEnterEvent* event) override;
+ void leaveEvent(QEvent* event) override;
+ void paintEvent(QPaintEvent* event) override;
+ void mouseReleaseEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton) Q_EMIT clicked(); }
+};
+
+
class BINARYNINJAUIAPI ClickableStateLabel: public ClickableLabel
{
Q_OBJECT
diff --git a/ui/filter.h b/ui/filter.h
index 5a43100f..72e2e930 100644
--- a/ui/filter.h
+++ b/ui/filter.h
@@ -24,7 +24,7 @@ class BINARYNINJAUIAPI FilterEdit: public QLineEdit
FilterTarget* m_target;
public:
- FilterEdit(QWidget* parent, FilterTarget* target);
+ FilterEdit(FilterTarget* target);
protected:
virtual void keyPressEvent(QKeyEvent* event) override;
@@ -37,9 +37,12 @@ class BINARYNINJAUIAPI FilteredView: public QWidget
FilterTarget* m_target;
QWidget* m_widget;
FilterEdit* m_filter;
+ bool m_autoHide;
public:
- FilteredView(QWidget* parent, QWidget* filtered, FilterTarget* target);
+ FilteredView(QWidget* parent, QWidget* filtered, FilterTarget* target,
+ FilterEdit* edit = nullptr);
+ void setFilterPlaceholderText(const QString& text);
void updateFonts();
void clearFilter();
void showFilter(const QString& initialText);
diff --git a/ui/render.h b/ui/render.h
index 5277f81f..5464f684 100644
--- a/ui/render.h
+++ b/ui/render.h
@@ -83,6 +83,7 @@ public:
HighlightTokenState getHighlightTokenForTextToken(const BinaryNinja::InstructionTextToken& token);
void drawText(QPainter& p, int x, int y, QColor color, const QString& text);
+ void drawUnderlinedText(QPainter& p, int x, int y, QColor color, const QString& text);
void drawSeparatorLine(QPainter& p, QColor top, QColor bottom, QColor line, const QRect& rect);
void drawInstructionHighlight(QPainter& p, const QRect& rect);
diff --git a/ui/sidebar.h b/ui/sidebar.h
new file mode 100644
index 00000000..0c3bc2c7
--- /dev/null
+++ b/ui/sidebar.h
@@ -0,0 +1,408 @@
+#pragma once
+
+#include <QtWidgets/QWidget>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QStackedWidget>
+#include <QtWidgets/QSplitter>
+#include <QtGui/QPicture>
+#include <QtCore/QSettings>
+#include "theme.h"
+
+class SidebarEntry;
+class MainWindow;
+class ContextMenuManager;
+
+struct SidebarIcon
+{
+ QImage original;
+ QImage active;
+ QImage inactive;
+
+ static SidebarIcon generate(const QImage& src);
+};
+
+class BINARYNINJAUIAPI SidebarWidget: public QWidget
+{
+ Q_OBJECT
+
+protected:
+ QString m_title;
+ UIActionHandler m_actionHandler;
+ ContextMenuManager* m_contextMenuManager = nullptr;
+ Menu* m_menu = nullptr;
+
+public:
+ SidebarWidget(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();
+
+ virtual QWidget* headerWidget() { return nullptr; }
+};
+
+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();
+};
+
+class BINARYNINJAUIAPI SidebarHeaderTitle: public QLabel
+{
+ Q_OBJECT
+public:
+ SidebarHeaderTitle(const QString& name);
+};
+
+class BINARYNINJAUIAPI SidebarHeader: public QWidget
+{
+ Q_OBJECT
+public:
+ SidebarHeader(const QString& name, QWidget* rightSide = nullptr);
+};
+
+class BINARYNINJAUIAPI SidebarInvalidContextWidget: public SidebarWidget
+{
+ Q_OBJECT
+public:
+ SidebarInvalidContextWidget(const QString& title);
+
+private Q_SLOTS:
+ void openFile();
+};
+
+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; }
+
+ virtual bool isInReferenceArea() const { return false; }
+ virtual bool viewSensitive() const { return true; }
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) = 0;
+ virtual SidebarWidget* createInvalidContextWidget();
+
+ void updateTheme();
+};
+
+class ViewFrame;
+
+struct SidebarWidgetContainerState
+{
+ SidebarWidgetType* contentWidgetType;
+ SidebarWidgetType* referenceWidgetType;
+ QList<int> contentSplitterSizes;
+ QList<int> parentSplitterSizes;
+};
+
+class BINARYNINJAUIAPI SidebarWidgetContainer: public QWidget
+{
+ Q_OBJECT
+
+ QSplitter* m_parentSplitter = nullptr;
+ QSplitter* m_contentSplitter;
+ QStackedWidget* m_contentStackedWidget;
+ QStackedWidget* m_referenceStackedWidget;
+ 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<ViewFrame*, std::map<QString, std::pair<SidebarWidgetType*, SidebarWidgetType*>>> m_priorWidgets;
+ std::map<ViewFrame*, std::map<QString, QList<int>>> m_priorContentSplitterSizes;
+ std::map<ViewFrame*, 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;
+
+ void activateWidgetForType(SidebarWidgetType* type);
+ void deactivateWidgetForType(SidebarWidgetType* type);
+
+ static QVariant sizesToVariant(const QList<int>& sizes);
+ static std::optional<QList<int>> variantToSizes(const QVariant& variant);
+
+public:
+ SidebarWidgetContainer();
+
+ void setSplitter(QSplitter* splitter);
+ void setActiveContext(ViewFrame* frame, const QString& dataType, BinaryViewRef data);
+ void destroyContext(ViewFrame* frame);
+
+ 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);
+
+ SidebarWidget* widget(SidebarWidgetType* type);
+ SidebarWidget* widget(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();
+
+Q_SIGNALS:
+ void showContents();
+ void hideContents();
+};
+
+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(ViewFrame* frame, const QString& dataType, BinaryViewRef data);
+
+ SidebarWidget* widget(SidebarWidgetType* type);
+ SidebarWidget* widget(const QString& name);
+
+ void activate(SidebarWidgetType* type);
+ void activate(const QString& name);
+
+ void updateTheme();
+ void updateFonts();
+
+ static void addSidebarWidgetType(SidebarWidgetType* type);
+ 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 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 Sidebar* current()
+ {
+ UIContext* context = UIContext::activeContext();
+ if (!context)
+ return nullptr;
+ return context->sidebar();
+ }
+
+ template<class T>
+ static T* widget(SidebarWidgetType* type)
+ {
+ Sidebar* sidebar = current();
+ if (!type || !sidebar || !sidebar->container() || !sidebar->container()->isActive(type))
+ return (T*)nullptr;
+ QWidget* widget = sidebar->widget(type);
+ if (!widget)
+ return (T*)nullptr;
+ return qobject_cast<T*>(widget);
+ }
+
+ template<class T>
+ static T* widget(const QString& name)
+ {
+ return widget<T>(Sidebar::typeFromName(name));
+ }
+
+ template<class T>
+ static T* activateWidget(SidebarWidgetType* type)
+ {
+ Sidebar* sidebar = current();
+ if (!type || !sidebar || !sidebar->container())
+ return (T*)nullptr;
+ sidebar->activate(type);
+ QWidget* widget = sidebar->widget(type);
+ if (!widget)
+ return (T*)nullptr;
+ T* result = qobject_cast<T*>(widget);
+ if (!result)
+ return (T*)nullptr;
+ return result;
+ }
+
+ template<class T>
+ static T* activateWidget(const QString& name)
+ {
+ return activateWidget<T>(Sidebar::typeFromName(name));
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(const QString& name,
+ const std::function<void(T* obj)>& activate)
+ {
+ return globalSidebarAction<T>(name,
+ [=](T* obj, const UIActionContext&) { activate(obj); },
+ [=](T*, const UIActionContext&) { return true; });
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(const QString& name,
+ const std::function<void(T* obj, const UIActionContext& ctxt)>& activate)
+ {
+ return globalSidebarAction<T>(name, activate,
+ [](T*, const UIActionContext&) { return true; });
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(const QString& name,
+ const std::function<void(T* obj)>& activate, const std::function<bool(T* obj)>& isValid)
+ {
+ return globalSidebarAction<T>(name,
+ [=](T* obj, const UIActionContext&) { activate(obj); },
+ [=](T* obj, const UIActionContext&) { return isValid(obj); });
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(const QString& name,
+ const std::function<void(T* obj, const UIActionContext& ctxt)>& activate,
+ const std::function<bool(T* obj, const UIActionContext& ctxt)>& isValid)
+ {
+ return globalSidebarAction<T>(Sidebar::typeFromName(name), activate, isValid);
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(SidebarWidgetType* type,
+ const std::function<void(T* obj)>& activate)
+ {
+ return globalSidebarAction<T>(type,
+ [=](T* obj, const UIActionContext&) { activate(obj); },
+ [=](T*, const UIActionContext&) { return true; });
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(SidebarWidgetType* type,
+ const std::function<void(T* obj, const UIActionContext& ctxt)>& activate)
+ {
+ return globalSidebarAction<T>(type, activate,
+ [](T*, const UIActionContext&) { return true; });
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(SidebarWidgetType* type,
+ const std::function<void(T* obj)>& activate, const std::function<bool(T* obj)>& isValid)
+ {
+ return globalSidebarAction<T>(type,
+ [=](T* obj, const UIActionContext&) { activate(obj); },
+ [=](T* obj, const UIActionContext&) { return isValid(obj); });
+ }
+
+ template<class T>
+ static UIAction globalSidebarAction(SidebarWidgetType* type,
+ const std::function<void(T* obj, const UIActionContext& ctxt)>& activate,
+ const std::function<bool(T* obj, const UIActionContext& ctxt)>& isValid)
+ {
+ std::function<T*(const UIActionContext& ctxt)> lookup = [=](const UIActionContext& ctxt) {
+ if (!type || !ctxt.context)
+ return (T*)nullptr;
+ Sidebar* sidebar = ctxt.context->sidebar();
+ if (!sidebar->container() || !sidebar->container()->isActive(type))
+ return (T*)nullptr;
+ QWidget* widget = sidebar->widget(type);
+ if (!widget)
+ return (T*)nullptr;
+ return qobject_cast<T*>(widget);
+ };
+ return UIAction(
+ [=](const UIActionContext& ctxt) {
+ T* obj = lookup(ctxt);
+ if (obj)
+ activate(obj, ctxt);
+ },
+ [=](const UIActionContext& ctxt) {
+ T* obj = lookup(ctxt);
+ if (obj)
+ return isValid(obj, ctxt);
+ return false;
+ });
+ }
+
+ template<class T>
+ static std::function<bool(const UIActionContext&)> globalSidebarActionChecked(const QString& name,
+ const std::function<bool(T* obj)>& isChecked)
+ {
+ return globalSidebarActionChecked<T>(name,
+ [=](T* obj, const UIActionContext&) { return isChecked(obj); });
+ }
+
+ template<class T>
+ static std::function<bool(const UIActionContext&)> globalSidebarActionChecked(const QString& name,
+ const std::function<bool(T* obj, const UIActionContext& ctxt)>& isChecked)
+ {
+ return globalSidebarActionChecked<T>(Sidebar::typeFromName(name), isChecked);
+ }
+
+ template<class T>
+ static std::function<bool(const UIActionContext&)> globalSidebarActionChecked(SidebarWidgetType* type,
+ const std::function<bool(T* obj)>& isChecked)
+ {
+ return globalSidebarActionChecked<T>(type,
+ [=](T* obj, const UIActionContext&) { return isChecked(obj); });
+ }
+
+ template<class T>
+ static std::function<bool(const UIActionContext&)> globalSidebarActionChecked(SidebarWidgetType* type,
+ const std::function<bool(T* obj, const UIActionContext& ctxt)>& isChecked)
+ {
+ return [=](const UIActionContext& ctxt) {
+ if (!type || !ctxt.context)
+ return false;
+ Sidebar* sidebar = ctxt.context->sidebar();
+ if (!sidebar->container() || !sidebar->container()->isActive(type))
+ return false;
+ QWidget* widget = sidebar->widget(type);
+ if (!widget)
+ return false;
+ T* obj = qobject_cast<T*>(widget);
+ if (obj)
+ return isChecked(obj, ctxt);
+ return false;
+ };
+ }
+};
diff --git a/ui/stringsview.h b/ui/stringsview.h
index 5b5dbff5..9dc71fed 100644
--- a/ui/stringsview.h
+++ b/ui/stringsview.h
@@ -126,13 +126,15 @@ class BINARYNINJAUIAPI StringsContainer: public QWidget, public ViewContainer
ViewFrame* m_view;
StringsView* m_strings;
FilteredView* m_filter;
+ FilterEdit* m_separateEdit = nullptr;
public:
- StringsContainer(BinaryViewRef data, ViewFrame* view);
+ StringsContainer(BinaryViewRef data, ViewFrame* view, bool separateEdit = false);
virtual View* getView() override { return m_strings; }
StringsView* getStringsView() { return m_strings; }
FilteredView* getFilter() { return m_filter; }
+ FilterEdit* getSeparateFilterEdit() { return m_separateEdit; }
protected:
virtual void focusInEvent(QFocusEvent* event) override;
@@ -148,3 +150,22 @@ public:
virtual QWidget* create(BinaryViewRef data, ViewFrame* viewFrame);
static void init();
};
+
+
+class BINARYNINJAUIAPI StringsViewSidebarWidget: public SidebarWidget
+{
+ Q_OBJECT
+
+ QWidget* m_header;
+public:
+ StringsViewSidebarWidget(BinaryViewRef data, ViewFrame* frame);
+ virtual QWidget* headerWidget() { return m_header; }
+};
+
+
+class BINARYNINJAUIAPI StringsViewSidebarWidgetType: public SidebarWidgetType
+{
+public:
+ StringsViewSidebarWidgetType();
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override;
+};
diff --git a/ui/symbolsview.h b/ui/symbolsview.h
index da857521..26a0a7d0 100644
--- a/ui/symbolsview.h
+++ b/ui/symbolsview.h
@@ -2,17 +2,16 @@
#include <QtCore/QTimer>
#include "binaryninjaapi.h"
-#include "dockhandler.h"
+#include "sidebar.h"
#include "filter.h"
#include "symbollist.h"
class ViewFrame;
class SymbolList;
-class BINARYNINJAUIAPI SymbolsView: public QWidget, public DockContextHandler, public BinaryNinja::BinaryDataNotification
+class BINARYNINJAUIAPI SymbolsView: public SidebarWidget, public BinaryNinja::BinaryDataNotification
{
Q_OBJECT
- Q_INTERFACES(DockContextHandler)
friend class SymbolList;
@@ -20,6 +19,7 @@ class BINARYNINJAUIAPI SymbolsView: public QWidget, public DockContextHandler, p
SymbolList* m_funcList;
FilteredView* m_funcFilter;
+ QWidget* m_header;
bool m_updatesPending;
QTimer* m_updateTimer;
@@ -48,11 +48,20 @@ public:
void toggleLocalFunctions() { m_funcList->toggleLocalFunctions(); }
void toggleLocalDataVars() { m_funcList->toggleLocalDataVars(); }
+ virtual QWidget* headerWidget() override { return m_header; }
+
protected:
virtual void contextMenuEvent(QContextMenuEvent* event) override;
virtual void notifyFontChanged() override;
- virtual bool shouldBeVisible(ViewFrame* frame) override;
private Q_SLOTS:
void updateTimerEvent();
+ void showContextMenu();
+};
+
+class BINARYNINJAUIAPI SymbolsViewSidebarWidgetType: public SidebarWidgetType
+{
+public:
+ SymbolsViewSidebarWidgetType();
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override;
};
diff --git a/ui/taglist.h b/ui/taglist.h
index 924bc04d..fb7ecce8 100644
--- a/ui/taglist.h
+++ b/ui/taglist.h
@@ -7,7 +7,7 @@
#include <QtWidgets/QStyledItemDelegate>
#include <QtWidgets/QDialog>
#include "binaryninjaapi.h"
-#include "dockhandler.h"
+#include "sidebar.h"
#include "viewframe.h"
#include "filter.h"
#include "tagtypelist.h"
@@ -176,10 +176,9 @@ public:
};
-class BINARYNINJAUIAPI TagListWidget: public QWidget, public DockContextHandler
+class BINARYNINJAUIAPI TagListWidget: public SidebarWidget
{
Q_OBJECT
- Q_INTERFACES(DockContextHandler)
ViewFrame* m_view;
QTabWidget* m_tabs;
@@ -205,8 +204,10 @@ public:
TagList* GetList();
void editTag(TagRef tag);
- TagListWidget(QWidget* parent, ViewFrame* view, BinaryViewRef data);
+ TagListWidget(ViewFrame* view, BinaryViewRef data);
virtual ~TagListWidget();
+
+ virtual void focus() override;
};
@@ -236,3 +237,11 @@ private Q_SLOTS:
void createTagAccept(TagTypeRef tt);
void removeTag();
};
+
+
+class BINARYNINJAUIAPI TagListSidebarWidgetType: public SidebarWidgetType
+{
+public:
+ TagListSidebarWidgetType();
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override;
+};
diff --git a/ui/typeview.h b/ui/typeview.h
index f31f2aae..5d0a59fc 100644
--- a/ui/typeview.h
+++ b/ui/typeview.h
@@ -17,6 +17,7 @@
#include "render.h"
#include "menus.h"
#include "xreflist.h"
+#include "clickablelabel.h"
#define TYPE_VIEW_UPDATE_CHECK_INTERVAL 200
@@ -102,7 +103,11 @@ class BINARYNINJAUIAPI TypeView: public QAbstractScrollArea, public View, public
QWidget* m_lineNumberArea;
int m_lineNumberAreaWidth = 0;
int m_lineCount = 0;
- int m_cols, m_rows, m_paddingCols;
+ size_t m_systemTypesHidden = 0;
+ std::optional<size_t> m_showSystemTypesLine;
+ size_t m_typesFiltered = 0;
+ std::optional<size_t> m_clearFilterLine;
+ int m_cols, m_rows, m_paddingCols, m_offsetPaddingWidth;
uint64_t m_maxOffset;
size_t m_offsetWidth;
HighlightTokenState m_highlight;
@@ -130,6 +135,8 @@ class BINARYNINJAUIAPI TypeView: public QAbstractScrollArea, public View, public
QAction* m_actionCopy;
QAction* m_actionSelectAll;
+ bool m_compact;
+
void adjustSize(int width, int height);
void refreshAllTypes();
@@ -163,7 +170,7 @@ class BINARYNINJAUIAPI TypeView: public QAbstractScrollArea, public View, public
static TypeDefinitionLine getTypeDefinitionHeaderLine(PlatformRef platform, const std::string& name, TypeRef type);
public:
- explicit TypeView(BinaryViewRef data, ViewFrame* view, TypesContainer* container);
+ explicit TypeView(BinaryViewRef data, ViewFrame* view, TypesContainer* container, bool compact = false);
virtual ~TypeView();
virtual bool findNextData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, uint64_t& addr, BNFindFlag flags,
@@ -230,6 +237,8 @@ public:
const std::string& varName, size_t index, TypeRef type, TypeRef parent, BinaryViewRef data,
int paddingCols, bool collapsed = false);
+ void showContextMenu(Menu* source = nullptr);
+
protected:
virtual void resizeEvent(QResizeEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
@@ -295,8 +304,7 @@ class BINARYNINJAUIAPI TypeFilter: public QWidget
Q_OBJECT
TypesContainer* m_container;
- ExpandableGroup* m_group;
- QComboBox* m_showTypes;
+ ClickableIcon* m_showSystemTypes;
QLineEdit* m_textFilter;
bool MatchesAutoFilter(BinaryViewRef data, const BinaryNinja::QualifiedName& name);
@@ -306,12 +314,15 @@ Q_SIGNALS:
void filterChanged();
public:
- TypeFilter(TypesContainer* container);
+ TypeFilter(TypesContainer* container = nullptr);
+ void setContainer(TypesContainer* container) { m_container = container; }
- std::map<BinaryNinja::QualifiedName, std::vector<TypeDefinitionLine>> GetFilteredTypeLines(BinaryViewRef data, int padding);
+ std::map<BinaryNinja::QualifiedName, std::vector<TypeDefinitionLine>> GetFilteredTypeLines(
+ BinaryViewRef data, int padding, size_t& systemTypesHidden, size_t& typesFiltered);
void showAndFocus();
- uint64_t getCurrentTypeFilter();
- void setTypeFilter(uint64_t typesToShow);
+ bool areAutoTypesVisible();
+ void setShowAutoTypes(bool showAutoTypes);
+ void clearTextFilter();
};
@@ -324,7 +335,8 @@ class BINARYNINJAUIAPI TypesContainer: public QWidget, public ViewContainer
UIActionHandler m_actionHandler;
public:
- TypesContainer(BinaryViewRef data, ViewFrame* view);
+ TypesContainer(BinaryViewRef data, ViewFrame* view,
+ TypeFilter* filter = nullptr, bool compact = false);
virtual View* getView() override { return m_typeView; }
TypeView* getTypesView() { return m_typeView; }
@@ -335,3 +347,32 @@ public:
protected:
virtual void focusInEvent(QFocusEvent* event) override;
};
+
+
+class BINARYNINJAUIAPI TypeViewSidebarWidget: public SidebarWidget
+{
+ Q_OBJECT
+
+ TypesContainer* m_container;
+ QWidget* m_header;
+ Menu m_addMenu;
+
+public:
+ TypeViewSidebarWidget(BinaryViewRef data, ViewFrame* frame);
+
+ TypesContainer* container() const { return m_container; }
+ virtual void focus() override;
+
+ virtual QWidget* headerWidget() override { return m_header; }
+
+private Q_SLOTS:
+ void showAddMenu();
+};
+
+
+class BINARYNINJAUIAPI TypeViewSidebarWidgetType: public SidebarWidgetType
+{
+public:
+ TypeViewSidebarWidgetType();
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override;
+};
diff --git a/ui/uicontext.h b/ui/uicontext.h
index c1cc2993..b0e2adde 100644
--- a/ui/uicontext.h
+++ b/ui/uicontext.h
@@ -18,6 +18,9 @@ class ViewFrame;
class UIActionHandler;
class FileContext;
class ViewLocation;
+class Sidebar;
+class SidebarWidgetContainer;
+struct SelectionInfoForXref;
/*!
Interface used to receive notifications related to files and contexts. Many notifications include the ability
@@ -131,13 +134,22 @@ public:
\return True if the value in name should be used
*/
virtual bool GetNameForPath(UIContext* context, const QString& path, QString& name) { (void)context; (void)path; (void)name; return false; }
+
+ /*!
+ Callback when the ui changes selection and should update cross references
+ \param context Context changing selection
+ \param frame ViewFrame which changed selection
+ \param view View that changed selection
+ \param selection New selection
+ */
+ virtual void OnNewSelectionForXref(UIContext* context, ViewFrame* frame, View* view, const SelectionInfoForXref& selection) { (void)context; (void)frame; (void)view; (void)selection; }
};
class BINARYNINJAUIAPI UIContextHandler
{
public:
virtual ~UIContextHandler();
- virtual void updateStatus(bool updateInfo) = 0;
+ virtual void updateStatus() = 0;
virtual void notifyThemeChanged() = 0;
virtual void registerFileOpenMode(const QString& buttonName, const QString& description, const QString& action);
};
@@ -168,6 +180,7 @@ protected:
void NotifyOnViewChange(ViewFrame* frame, const QString& type);
void NotifyOnAddressChange(ViewFrame* frame, View* view, const ViewLocation& location);
+ void NotifyOnNewSelectionForXref(ViewFrame* frame, View* view, const SelectionInfoForXref& selection);
public:
UIContext();
@@ -257,6 +270,10 @@ public:
UIActionHandler* globalActions() { return &m_globalActions; }
virtual UIActionHandler* contentActionHandler() = 0;
+ virtual Sidebar* sidebar() = 0;
+
+ void updateCrossReferences(ViewFrame* frame, View* view, const SelectionInfoForXref& selection);
+
/*!
Register an object to receive notifications of UIContext events
\param notification Object which will receive notifications
@@ -284,7 +301,7 @@ public:
static void setHandler(UIContextHandler* handler);
static QSize getScaledWindowSize(int x, int y);
- static void updateStatus(bool updateInfo = true);
+ static void updateStatus();
static void notifyThemeChanged();
static void showPreview(QWidget* parent, PreviewWidget* preview, QPoint localPos, bool anchorAtPoint = false);
static void closePreview();
diff --git a/ui/viewframe.h b/ui/viewframe.h
index 1a87e7af..016ccc20 100644
--- a/ui/viewframe.h
+++ b/ui/viewframe.h
@@ -19,6 +19,7 @@
#include "filecontext.h"
#include "viewtype.h"
#include "action.h"
+#include "sidebar.h"
// this struct is used to pass selection information for cross references
struct SelectionInfoForXref
@@ -221,6 +222,8 @@ public:
QString viewType();
+ void updateCrossReferenceSelection(ViewFrame* frame = nullptr);
+
static void registerActions();
};
@@ -307,7 +310,7 @@ private:
ClickableStateLabel* m_fileContentsLockStatus;
BinaryViewRef m_data;
DockHandler* m_docks;
- QWidget* m_view;
+ QWidget* m_view = nullptr;
QWidget* m_viewContainer;
QVBoxLayout* m_viewLayout;
std::map<QString, std::map<QString, QPointer<QWidget>>> m_extViewCache;
@@ -349,6 +352,7 @@ public:
std::vector<QString> getAvailableTypes() const;
QString getCurrentView() const;
+ BinaryViewRef getCurrentBinaryView() const;
QString getCurrentDataType() const;
uint64_t getCurrentOffset() const;
BNAddressRange getSelectionOffsets() const;
@@ -369,6 +373,20 @@ public:
QWidget* getExtendedView(const QString& name, bool create = false);
+ Sidebar* getSidebar();
+
+ template<class T>
+ T* getSidebarWidget(const QString& name)
+ {
+ Sidebar* sidebar = getSidebar();
+ if (!sidebar)
+ return (T*)nullptr;
+ QWidget* widget = sidebar->widget(name);
+ if (!widget)
+ return (T*)nullptr;
+ return qobject_cast<T*>(widget);
+ }
+
bool navigate(const QString& type, uint64_t offset, bool updateInfo = true, bool addHistoryEntry = true);
bool navigate(const QString& type, const std::function<bool(View*)>& handler, bool updateInfo = true, bool addHistoryEntry = true);
bool navigate(BinaryViewRef data, uint64_t offset, bool updateInfo = true, bool addHistoryEntry = true);
@@ -412,12 +430,11 @@ public:
void setCurrentFunction(FunctionRef func);
void updateCrossReferences();
- void showCrossReferences();
+ void updateCrossReferenceSelection();
void showPinnedCrossReferences();
void nextCrossReference();
void prevCrossReference();
- void showTags();
void editTag(TagRef tag);
void nextTag();
void prevTag();
diff --git a/ui/xreflist.h b/ui/xreflist.h
index d603c599..403178f2 100644
--- a/ui/xreflist.h
+++ b/ui/xreflist.h
@@ -20,7 +20,7 @@
#include <memory>
#include "binaryninjaapi.h"
-#include "dockhandler.h"
+#include "sidebar.h"
#include "viewframe.h"
#include "fontsettings.h"
#include "expandablegroup.h"
@@ -452,10 +452,9 @@ Q_SIGNALS:
class ExpandableGroup;
class QCheckboxCombo;
-class BINARYNINJAUIAPI CrossReferenceWidget: public QWidget, public DockContextHandler
+class BINARYNINJAUIAPI CrossReferenceWidget: public SidebarWidget, public UIContextNotification
{
Q_OBJECT
- Q_INTERFACES(DockContextHandler)
ViewFrame* m_view;
BinaryViewRef m_data;
@@ -488,11 +487,12 @@ class BINARYNINJAUIAPI CrossReferenceWidget: public QWidget, public DockContextH
public:
CrossReferenceWidget(ViewFrame* view, BinaryViewRef data, bool pinned);
+ virtual ~CrossReferenceWidget();
virtual void notifyFontChanged() override;
- virtual bool shouldBeVisible(ViewFrame* frame) override;
virtual QString getHeaderText(SelectionInfoForXref selectionInfo);
virtual void setCurrentSelection(SelectionInfoForXref selectionInfo);
+ virtual void updateCrossReferences();
virtual void setCurrentPinnedSelection(SelectionInfoForXref selectionInfo);
void updatePinnedSelection();
virtual void navigateToNext();
@@ -510,6 +510,11 @@ public:
bool uiMaxItemsExceeded() const { return m_uiMaxItemsExceeded; }
void setUIMaxItemsExceeded(bool value) { m_uiMaxItemsExceeded = value; }
+ virtual void focus() override;
+
+ virtual void OnNewSelectionForXref(UIContext* context, ViewFrame* frame, View* view,
+ const SelectionInfoForXref& selection) override;
+
private Q_SLOTS:
void hoverTimerEvent();
@@ -522,6 +527,15 @@ public Q_SLOTS:
};
+class BINARYNINJAUIAPI CrossReferenceSidebarWidgetType: public SidebarWidgetType
+{
+public:
+ CrossReferenceSidebarWidgetType();
+ virtual bool isInReferenceArea() const override { return true; }
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override;
+};
+
+
// https://github.com/CuriousCrow/QCheckboxCombo
/*
* QCheckboxCombo is a combobox widget that contains items with checkboxes