diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2021-06-02 11:27:24 -0400 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2021-07-28 19:31:25 -0400 |
| commit | c08ddcab02433cb5078b6cfea11bf972e47b3169 (patch) | |
| tree | 02f05276ac497521a76e1591f3776e4f1cfe31d9 /ui | |
| parent | 8c0fa1737552e548909a435ddcc2b661a71b5da9 (diff) | |
Add sidebar and move some dock widgets to it
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/clickablelabel.h | 46 | ||||
| -rw-r--r-- | ui/filter.h | 7 | ||||
| -rw-r--r-- | ui/render.h | 1 | ||||
| -rw-r--r-- | ui/sidebar.h | 408 | ||||
| -rw-r--r-- | ui/stringsview.h | 23 | ||||
| -rw-r--r-- | ui/symbolsview.h | 17 | ||||
| -rw-r--r-- | ui/taglist.h | 17 | ||||
| -rw-r--r-- | ui/typeview.h | 59 | ||||
| -rw-r--r-- | ui/uicontext.h | 21 | ||||
| -rw-r--r-- | ui/viewframe.h | 23 | ||||
| -rw-r--r-- | ui/xreflist.h | 22 |
11 files changed, 615 insertions, 29 deletions
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 |
