#pragma once #include "Menus.hpp" #include "TaskBoard.hpp" #include "TaskStore.hpp" #include #include #include namespace tp::taskboard { // Copies tasks with their whole subtrees and pastes them back as new tasks. Sessions, workspaces and // dependencies are not copied: a pasted task is a fresh, never-run task. class TaskClipboard { public: void copy(const TaskBoard& board, const std::vector& ids); std::vector paste(TaskBoard& board, std::optional parent) const; [[nodiscard]] bool isEmpty() const { return mEntries.empty(); } [[nodiscard]] size_t taskCount() const { return mEntries.size(); } private: struct Entry { Task task; std::optional parent; }; void copySubtree(const TaskBoard& board, ui::NodeId id, std::optional parent); std::vector mEntries; }; // Where the user asked for the menu: the tasks it acts on (empty over empty space) and, in the kanban, the // status of the column, which new and pasted tasks take. struct TaskMenuTarget { std::vector tasks; std::optional column; [[nodiscard]] bool isEmptySpace() const { return tasks.empty(); } }; // The quick-action menu shown on a secondary click in the tree and the kanban. Both views build it from the // same target description, so they always offer the same actions. class TaskContextMenu { public: struct Actions { std::function open; std::function parent, std::optional status)> create; std::function&)> copy; std::function parent, std::optional status)> paste; std::function&)> remove; std::function&, TaskStatus)> setStatus; std::function openSession; }; TaskContextMenu(const TaskBoard& board, const TaskClipboard& clipboard, Actions actions); void setStore(TaskStore* store) { mStore = store; } void setReadOnly(bool readOnly) { mReadOnly = readOnly; } void build(const TaskMenuTarget& target); void open(ui::Ui& ui, const TaskMenuTarget& target, Vec2F windowPoint); [[nodiscard]] ui::Menu& menu() { return mMenu; } [[nodiscard]] ui::Menu& statusMenu() { return mStatusMenu; } [[nodiscard]] ui::Menu& sessionMenu() { return mSessionMenu; } [[nodiscard]] const TaskMenuTarget& target() const { return mTarget; } private: void addTaskItems(); void addEmptySpaceItems(); void addClipboardItems(std::optional pasteParent); void fillStatusMenu(); void fillSessionMenu(ui::NodeId id); [[nodiscard]] std::string pasteText(std::optional parent) const; const TaskBoard& mBoard; const TaskClipboard& mClipboard; Actions mActions; TaskStore* mStore = nullptr; bool mReadOnly = false; TaskMenuTarget mTarget; ui::Menu mMenu; ui::Menu mStatusMenu; ui::Menu mSessionMenu; }; }