#pragma once #include "Document/ProjectWorkspace.h" #include "UI/ProjectTabLayout.h" #include #include // Swift's TabDragPhase: a reorder drag goes on, or ends. enum class TabDragPhase { changed, ended }; // One tab: its title, the unsaved dot, its close button. class ProjectTabButton : public QWidget { Q_OBJECT public: ProjectTabButton(ProjectWorkspace &workspace, std::shared_ptr tab, std::function onReorder, QWidget *parent = nullptr); const std::shared_ptr tab; // What the session and the workspace hold, shown. void synchronize(); bool isActive() const; protected: bool eventFilter(QObject *watched, QEvent *event) override; void paintEvent(QPaintEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override; void dragLeaveEvent(QDragLeaveEvent *event) override; void dropEvent(QDropEvent *event) override; private: bool acceptsDrop(const QMimeData &data) const; void setTargeted(bool targeted); ProjectWorkspace &m_workspace; const std::function m_onReorder; QToolButton *const m_select; QToolButton *const m_close; bool m_targeted = false; // Swift's DragGesture: the press, in the window's space. std::optional m_press; bool m_dragging = false; }; // Swift's NewProjectDropTarget: the New canvas button takes drops. class NewCanvasButton : public QToolButton { Q_OBJECT public: explicit NewCanvasButton(ProjectWorkspace &workspace, QWidget *parent = nullptr); protected: void paintEvent(QPaintEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override; void dragLeaveEvent(QDragLeaveEvent *event) override; void dropEvent(QDropEvent *event) override; private: bool acceptsDrop(const QMimeData &data) const; void setTargeted(bool targeted); ProjectWorkspace &m_workspace; bool m_targeted = false; }; // Swift's OverflowTabsPill: the tabs that do not fit, a menu. class OverflowTabsPill : public QToolButton { Q_OBJECT public: explicit OverflowTabsPill(ProjectWorkspace &workspace, QWidget *parent = nullptr); // Swift's projectTabOverflowPillWidth. static double pillWidth(int hiddenCount); void setHiddenIDs(std::vector hiddenIDs); protected: void paintEvent(QPaintEvent *event) override; private: void showMenu(); ProjectWorkspace &m_workspace; std::vector m_hiddenIDs; }; // The row of tabs; the rest gather in a menu. class ProjectTabStrip : public QWidget { Q_OBJECT public: explicit ProjectTabStrip(ProjectWorkspace &workspace, QWidget *parent = nullptr); QList buttons() const; OverflowTabsPill *pill() const { return m_pill; } QSize sizeHint() const override; protected: void resizeEvent(QResizeEvent *event) override; private: // Swift's TabReorderState, taken once as the drag starts. struct Reorder { QUuid id; std::vector others; std::map widths; std::map compactedX; double startX; double originX; double translation = 0; int targetIndex = 0; int nearestSlot() const; }; void synchronize(); std::map widths() const; ProjectTabOverflow overflow() const; // Places the pill and the tabs; others slide when `animated`. void layOut(bool animated = false); double renderX(const ProjectTabSlot &slot, double contentWidth) const; void handleReorder(QUuid id, TabDragPhase phase, double translation); Reorder makeReorder(QUuid id) const; void commitReorder(const Reorder &state); ProjectWorkspace &m_workspace; OverflowTabsPill *const m_pill; std::vector m_buttons; std::optional m_reorder; };