summaryrefslogtreecommitdiff
path: root/ui/sidebar.h
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2021-06-02 11:27:24 -0400
committerRusty Wagner <rusty.wagner@gmail.com>2021-07-28 19:31:25 -0400
commitc08ddcab02433cb5078b6cfea11bf972e47b3169 (patch)
tree02f05276ac497521a76e1591f3776e4f1cfe31d9 /ui/sidebar.h
parent8c0fa1737552e548909a435ddcc2b661a71b5da9 (diff)
Add sidebar and move some dock widgets to it
Diffstat (limited to 'ui/sidebar.h')
-rw-r--r--ui/sidebar.h408
1 files changed, 408 insertions, 0 deletions
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;
+ };
+ }
+};