#pragma once #include #include #include #include #include #include #include "theme.h" class SidebarEntry; class MainWindow; class ContextMenuManager; class SplitPaneWidget; 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 contentSplitterSizes; QList parentSplitterSizes; }; class BINARYNINJAUIAPI SidebarWidgetContainer : public QWidget { Q_OBJECT 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>> m_widgets; std::map>> m_priorWidgets; std::map>> m_priorContentSplitterSizes; std::map>> m_priorParentSplitterSizes; std::optional> m_pendingContentSplitterSizes; std::optional> m_pendingParentSplitterSizes; std::map>> m_currentViewLocation; void activateWidgetForType(SidebarWidgetType* type); void deactivateWidgetForType(SidebarWidgetType* type); static QVariant sizesToVariant(const QList& sizes); static std::optional> variantToSizes(const QVariant& variant); public: SidebarWidgetContainer(); void setSplitter(QSplitter* splitter); void setActiveContext(SplitPaneWidget* panes, ViewFrame* frame, const QString& dataType, BinaryViewRef data); void destroyContext(ViewFrame* frame); void destroyContext(SplitPaneWidget* panes); 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(); void toggleSidebar(); void moveContextToContainer( SplitPaneWidget* panes, const std::vector& frames, SidebarWidgetContainer* target); Q_SIGNALS: void showContents(); void hideContents(); }; class BINARYNINJAUIAPI Sidebar : public QWidget { Q_OBJECT SidebarWidgetType* m_hoverItem = nullptr; SidebarWidgetContainer* m_currentContainer = nullptr; static std::vector m_contentTypes; static std::vector 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 activate(SidebarWidgetType* type); void activate(const QString& name); void deactivate(SidebarWidgetType* type); void deactivate(const QString& name); void updateTheme(); void updateFonts(); void toggleSidebar(); static void addSidebarWidgetType(SidebarWidgetType* type); static SidebarWidgetType* typeFromName(const QString& name); static const std::vector& contentTypes() { return m_contentTypes; } static const std::vector& 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 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(widget); } template static T* widget(const QString& name) { return widget(Sidebar::typeFromName(name)); } template 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(widget); if (!result) return (T*)nullptr; return result; } template static T* activateWidget(const QString& name) { return activateWidget(Sidebar::typeFromName(name)); } template static UIAction globalSidebarAction(const QString& name, const std::function& activate) { return globalSidebarAction( name, [=](T* obj, const UIActionContext&) { activate(obj); }, [=](T*, const UIActionContext&) { return true; }); } template static UIAction globalSidebarAction( const QString& name, const std::function& activate) { return globalSidebarAction(name, activate, [](T*, const UIActionContext&) { return true; }); } template static UIAction globalSidebarAction( const QString& name, const std::function& activate, const std::function& isValid) { return globalSidebarAction( name, [=](T* obj, const UIActionContext&) { activate(obj); }, [=](T* obj, const UIActionContext&) { return isValid(obj); }); } template static UIAction globalSidebarAction(const QString& name, const std::function& activate, const std::function& isValid) { return globalSidebarAction(Sidebar::typeFromName(name), activate, isValid); } template static UIAction globalSidebarAction(SidebarWidgetType* type, const std::function& activate) { return globalSidebarAction( type, [=](T* obj, const UIActionContext&) { activate(obj); }, [=](T*, const UIActionContext&) { return true; }); } template static UIAction globalSidebarAction( SidebarWidgetType* type, const std::function& activate) { return globalSidebarAction(type, activate, [](T*, const UIActionContext&) { return true; }); } template static UIAction globalSidebarAction(SidebarWidgetType* type, const std::function& activate, const std::function& isValid) { return globalSidebarAction( type, [=](T* obj, const UIActionContext&) { activate(obj); }, [=](T* obj, const UIActionContext&) { return isValid(obj); }); } template static UIAction globalSidebarAction(SidebarWidgetType* type, const std::function& activate, const std::function& isValid) { std::function 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(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 static std::function globalSidebarActionChecked( const QString& name, const std::function& isChecked) { return globalSidebarActionChecked(name, [=](T* obj, const UIActionContext&) { return isChecked(obj); }); } template static std::function globalSidebarActionChecked( const QString& name, const std::function& isChecked) { return globalSidebarActionChecked(Sidebar::typeFromName(name), isChecked); } template static std::function globalSidebarActionChecked( SidebarWidgetType* type, const std::function& isChecked) { return globalSidebarActionChecked(type, [=](T* obj, const UIActionContext&) { return isChecked(obj); }); } template static std::function globalSidebarActionChecked( SidebarWidgetType* type, const std::function& 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(widget); if (obj) return isChecked(obj, ctxt); return false; }; } };