diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2021-11-18 13:52:25 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2022-01-10 15:25:18 -0700 |
| commit | 7f6e54fdc8ff4a06fdcd3c510a37add337f04bac (patch) | |
| tree | 60cce5955fcc05fc84f35f9662d49c7e0790dde1 /ui/pane.h | |
| parent | d9661f34eec6855d495a10eaafc2a8e2679756a7 (diff) | |
Refactor main area to use pane system
Diffstat (limited to 'ui/pane.h')
| -rw-r--r-- | ui/pane.h | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/ui/pane.h b/ui/pane.h new file mode 100644 index 00000000..dfda17a4 --- /dev/null +++ b/ui/pane.h @@ -0,0 +1,356 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QSplitter> +#include <QtWidgets/QStackedWidget> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QRubberBand> +#include "uicontext.h" +#include "clickablelabel.h" + +class ViewFrame; +class FeatureMap; +class PaneHeader; +class CloseButton; +class TabDragIndicator; + +class BINARYNINJAUIAPI Pane: public QWidget +{ + Q_OBJECT + + QWidget* m_widget; + QWidget* m_headerContainer = nullptr; + PaneHeader* m_header = nullptr; + CloseButton* m_closeButton = nullptr; + bool m_active = false; + +public: + Pane(QWidget* widget); + + QWidget* widget() const { return m_widget; } + virtual bool canSplitPane() const { return false; } + virtual Pane* createSplitPane() { return nullptr; } + virtual void updateStatus(); + virtual void focus(); + virtual QString title() = 0; + void closePane(); + void splitPane(Qt::Orientation orientation); + + virtual void setIsSinglePane(bool isSinglePane); + virtual void setIsActivePane(bool active); + virtual Qt::Orientation defaultSplitDirection() const { return Qt::Horizontal; } + virtual void setDefaultSplitDirection(Qt::Orientation orientation); + +protected: + void init(PaneHeader* header); + +Q_SIGNALS: + void paneCloseRequested(); + void paneSplitRequested(Pane* newPane, Qt::Edge edge); + void movePane(Pane* target, Qt::Edge edge); + void newWindowForPane(QScreen* screen, QPoint pos); + void notifyViewChanged(ViewFrame* frame); + +public Q_SLOTS: + void splitButtonClicked(Qt::Orientation orientation); + void closeButtonClicked(); + void headerClicked(); + void movePaneRequested(Pane* target, Qt::Edge edge); + void newWindowForPaneRequested(QScreen* screen, QPoint pos); +}; + +class BINARYNINJAUIAPI SplitButton: public ClickableIcon +{ + Q_OBJECT + + Qt::Orientation m_defaultOrientation; + bool m_mouseInside = false; + bool m_inverted = false; + + void setIconForOrientation(Qt::Orientation orientation); + +public: + SplitButton(); + + void setDefaultOrientation(Qt::Orientation orientation); + Qt::Orientation orientation() const; + Qt::Orientation defaultOrientation() const { return m_defaultOrientation; } + +protected: + virtual void enterEvent(QEnterEvent* event) override; + virtual void leaveEvent(QEvent* event) override; + virtual bool eventFilter(QObject* obj, QEvent* event) override; +}; + +class BINARYNINJAUIAPI PaneHeader: public QWidget +{ + Q_OBJECT + + Pane* m_owner = nullptr; + std::optional<QPoint> m_dragStart; + TabDragIndicator* m_dragIndicator = nullptr; + bool m_dragNewWindow = false; + Pane* m_dropTarget = nullptr; + Qt::Edge m_dropEdge = Qt::RightEdge; + QRubberBand* m_dropIndicator = nullptr; + +public: + PaneHeader(); + + void setOwner(Pane* pane) { m_owner = pane; } + +protected: + virtual void mousePressEvent(QMouseEvent* event) override; + virtual void mouseMoveEvent(QMouseEvent* event) override; + virtual void mouseReleaseEvent(QMouseEvent* event) override; + +Q_SIGNALS: + void paneCloseRequested(); + void paneSplitRequested(Qt::Orientation orientation); + void movePane(Pane* target, Qt::Edge edge); + void newWindowForPane(QScreen* screen, QPoint pos); + void headerClicked(); +}; + +class ViewFrame; +class ViewPaneHeader; + +class BINARYNINJAUIAPI ViewPane: public Pane +{ + Q_OBJECT + + ViewFrame* m_frame; + UIActionHandler m_actionHandler; + ViewPaneHeader* m_header; + +public: + ViewPane(ViewFrame* frame); + + ViewFrame* viewFrame() const { return m_frame; } + virtual bool canSplitPane() const override { return true; } + virtual Pane* createSplitPane() override; + virtual void updateStatus() override; + virtual Qt::Orientation defaultSplitDirection() const override; + virtual void setDefaultSplitDirection(Qt::Orientation orientation) override; + virtual void focus() override; + virtual QString title() override; + +private Q_SLOTS: + void viewChanged(ViewFrame* frame); + void viewChangeRequested(QString type); +}; + +class DataTypeList; +class ViewList; +class SyncGroupWidget; + +class BINARYNINJAUIAPI ViewPaneHeaderSubtypeWidget: public QWidget +{ + Q_OBJECT + +public: + ViewPaneHeaderSubtypeWidget() {} + virtual void updateStatus() = 0; +}; + +class BINARYNINJAUIAPI ViewPaneHeader: public PaneHeader +{ + Q_OBJECT + + ViewPane* m_owner; + DataTypeList* m_dataTypeList; + ViewList* m_viewList; + SyncGroupWidget* m_syncGroup; + + View* m_subtypeView = nullptr; + ViewPaneHeaderSubtypeWidget* m_subtypeWidget = nullptr; + QWidget* m_optionsWidget = nullptr; + QStackedWidget* m_subtypeWidgetContainer; + QStackedWidget* m_optionsWidgetContainer; + + SplitButton* m_splitButton; + +public: + ViewPaneHeader(ViewPane* owner, UIActionHandler* handler); + + void updateStatus(); + Qt::Orientation defaultSplitDirection() const; + void setDefaultSplitDirection(Qt::Orientation orientation); + +Q_SIGNALS: + void viewChanged(QString type); + +private Q_SLOTS: + void splitButtonClicked(); + void viewChangeRequested(QString type); + void updateViewType(ViewFrame* frame); +}; + +class BINARYNINJAUIAPI WidgetPane: public Pane +{ + Q_OBJECT + + QString m_title; + +public: + WidgetPane(QWidget* widget, QString title); + virtual QString title() override { return m_title; } + virtual void updateStatus() override; + +Q_SIGNALS: + void updateWidgetStatus(); +}; + +class BINARYNINJAUIAPI WidgetPaneHeader: public PaneHeader +{ + Q_OBJECT + + QString m_title; + +public: + WidgetPaneHeader(const QString& title); + +protected: + virtual void paintEvent(QPaintEvent* event) override; +}; + +class SplitPaneWidget; + +class BINARYNINJAUIAPI SplitPaneContainer: public QWidget +{ + Q_OBJECT + + Pane* m_pane = nullptr; + QSplitter* m_splitter = nullptr; + SplitPaneContainer* m_parent = nullptr; + std::vector<SplitPaneContainer*> m_children; + Pane* m_currentChild = nullptr; + ViewPane* m_currentViewPane = nullptr; + QVBoxLayout* m_layout; + FileContext* m_fileContext = nullptr; + + SplitPaneContainer(const std::vector<SplitPaneContainer*>& children, Qt::Orientation orientation); + + void removeChild(SplitPaneContainer* child); + void promoteChild(SplitPaneContainer* child); + void updateDefaultSplitDirectionForColumnCount(uint64_t count); + void removePaneForRelocation(); + void emitNewWindowForPane(SplitPaneWidget* paneWidget, QRect rect); + void openForColumnCount(Pane* pane, Qt::Orientation primaryDirection, uint64_t count); + void deactivateIfCurrent(Pane* pane); + void notifyCurrentChanged(Pane* pane); + +public: + SplitPaneContainer(Pane* initial); + Pane* currentPane() const { return m_currentChild; } + ViewPane* currentViewPane() const { return m_currentViewPane; } + void notifyFocused(); + void updateStatus(); + + void enumeratePanes(const std::function<void(Pane*)>& func); + void enumerateViewPanes(const std::function<void(ViewPane*)>& func); + + bool isSinglePane(); + bool canSplitCurrentPane(); + void closeCurrentPane(); + void splitCurrentPane(Qt::Orientation orientation); + Qt::Orientation defaultSplitDirection() const; + void nextPane(); + void prevPane(); + void focusPaneForEdge(Qt::Edge edge); + + SplitPaneContainer* root(); + static SplitPaneContainer* containerForWidget(QWidget* widget); + + FileContext* fileContext() const { return m_fileContext; } + void setFileContext(FileContext* fileContext) { m_fileContext = fileContext; } + + void open(Pane* pane, Qt::Orientation primaryDirection = Qt::Vertical); + +Q_SIGNALS: + void paneClosed(Pane* pane); + void currentChanged(Pane* pane); + void layoutChanged(); + void notifyViewChanged(ViewFrame* frame); + void lastPaneClosed(); + void newWindowForPane(SplitPaneWidget* paneWidget, QRect rect); + +private Q_SLOTS: + void paneCloseRequested(); + void paneSplitRequested(Pane* newPane, Qt::Edge edge); + void movePane(Pane* target, Qt::Edge edge); + void newWindowForPaneRequested(QScreen* screen, QPoint pos); + void paneViewChanged(ViewFrame* frame); + void childPaneClosed(Pane* pane); + void childLayoutChanged(); + void childViewChanged(ViewFrame* frame); +}; + +class BINARYNINJAUIAPI SplitPaneWidget: public QWidget +{ + Q_OBJECT + + SplitPaneContainer* m_container; + + QStackedWidget* m_featureMapContainer; + std::map<BinaryViewRef, FeatureMap*> m_featureMaps; + QSplitter* m_featureMapSplitter; + bool m_rightSideFeatureMap = true; + + UIActionHandler m_actionHandler; + + void bindActions(); + +public: + SplitPaneWidget(Pane* initial, FileContext* fileContext); + Pane* currentPane() const; + ViewPane* currentViewPane() const; + ViewFrame* currentViewFrame() const; + SplitPaneContainer* container() const { return m_container; } + FileContext* fileContext() const { return m_container->fileContext(); } + + void enumeratePanes(const std::function<void(Pane*)>& func); + void enumerateViewPanes(const std::function<void(ViewPane*)>& func); + + void createFeatureMap(); + void recreateFeatureMaps(); + void refreshFeatureMap(); + void updateFeatureMapLocation(const ViewLocation& location); + BinaryViewRef getCurrentBinaryView(); + + void updateStatus(); + + bool isSinglePane(); + bool canSplitCurrentPane(); + void closeCurrentPane(); + void splitCurrentPane(Qt::Orientation orientation); + Qt::Orientation defaultSplitDirection() const; + void nextPane(); + void prevPane(); + void focusPaneForEdge(Qt::Edge edge); + + QString getTabName(); + + void open(Pane* pane, Qt::Orientation primaryDirection = Qt::Vertical); + + bool closeRequest(); + void closing(); + + static void registerActions(); + +Q_SIGNALS: + void paneClosed(Pane* pane); + void currentChanged(Pane* pane); + void layoutChanged(); + void notifyViewChanged(ViewFrame* frame); + void newWindowForPane(SplitPaneWidget* paneWidget, QRect rect); + +private Q_SLOTS: + void containerPaneClosed(Pane* pane); + void containerCurrentChanged(Pane* pane); + void containerLayoutChanged(); + void containerNotifyViewChanged(ViewFrame* frame); + void containerLastPaneClosed(); + void containerNewWindowForPane(SplitPaneWidget* paneWidget, QRect rect); + void featureMapSplitterMoved(int pos, int idx); +}; |
