Warning, file /graphics/glaxnimate/src/gui/tools/base.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include <map>
0010 #include <memory>
0011 
0012 #include <QMouseEvent>
0013 #include <QKeyEvent>
0014 #include <QAction>
0015 
0016 #include "glaxnimate_app.hpp"
0017 #include "graphics/document_scene.hpp"
0018 #include "graphics/document_node_graphics_item.hpp"
0019 #include "graphics/handle.hpp"
0020 #include "widgets/canvas.hpp"
0021 #include "widgets/scalable_button.hpp"
0022 #include "widgets/dialogs/selection_manager.hpp"
0023 
0024 namespace glaxnimate::gui::tools {
0025 
0026 struct Event
0027 {
0028     Canvas* view;
0029     graphics::DocumentScene* scene;
0030     glaxnimate::gui::SelectionManager* window;
0031 
0032     void repaint() const
0033     {
0034         view->viewport()->update();
0035     }
0036 };
0037 
0038 struct MouseEvent : Event
0039 {
0040     /// Originating Qt event
0041     QMouseEvent* event;
0042     /// Mouse position in scene coordinates
0043     QPointF scene_pos;
0044 
0045     /// Mouse press that started the event (also available in move events)
0046     Qt::MouseButton press_button;
0047     /// Position of when the button has been pressed (scene coordinates)
0048     QPointF press_scene_pos;
0049     /// Position of when the button has been pressed (screen coordinates)
0050     QPoint press_screen_pos;
0051     /// Position of the last known mouse position (scene coordinates)
0052     QPointF last_scene_pos;
0053     /// Position of the last known mouse position (screen coordinates)
0054     QPoint last_screen_pos;
0055 
0056     /// Modifiers being held during the event
0057     Qt::KeyboardModifiers modifiers() const { return event->modifiers(); }
0058     /// Button that triggered press/release
0059     Qt::MouseButton button() const { return event->button(); }
0060     /// Buttons being held during the event
0061     Qt::MouseButtons buttons() const { return event->buttons(); }
0062     /// Position of the event in view coordinates
0063 #if QT_VERSION_MAJOR < 6
0064     const QPointF& pos() const { return event->localPos(); }
0065 #else
0066     QPointF pos() const { return event->position(); }
0067 #endif
0068     /// Tell the Qt event that it should not propagate
0069     void accept() const { event->accept(); }
0070 
0071     /// Use the default behaviour for this event (useful to select items etc)
0072     void forward_to_scene() const;
0073 };
0074 
0075 struct PaintEvent : Event
0076 {
0077     QPainter* painter;
0078     QPalette palette;
0079 };
0080 
0081 struct KeyEvent : public Event
0082 {
0083     QKeyEvent* event;
0084 
0085     Qt::KeyboardModifiers modifiers() const { return event->modifiers(); }
0086     int key() const { return event->key(); }
0087     QString text() const { return event->text(); }
0088     void accept() const { event->accept(); }
0089 };
0090 
0091 using Priority = int;
0092 
0093 class Tool : public QObject
0094 {
0095     Q_OBJECT
0096 
0097 public:
0098     using SelectionMode = graphics::DocumentNodeGraphicsItem::SelectionMode;
0099 
0100     virtual ~Tool() = default;
0101 
0102     virtual QString id() const = 0;
0103     virtual QIcon icon() const = 0;
0104     virtual QString name() const = 0;
0105     virtual QString tooltip() const { return name(); }
0106     virtual QKeySequence key_sequence() const = 0;
0107 
0108     QAction* get_action();
0109 
0110     /**
0111      * \pre get_action() called before calling this
0112      */
0113     ScalableButton* get_button();
0114 
0115     QWidget* get_settings_widget();
0116 
0117     /**
0118      * \pre get_action and get_button already called
0119      */
0120     void retranslate();
0121 
0122     virtual void mouse_press(const MouseEvent& event) = 0;
0123     virtual void mouse_move(const MouseEvent& event) = 0;
0124     virtual void mouse_release(const MouseEvent& event) = 0;
0125     virtual void mouse_double_click(const MouseEvent& event) = 0;
0126     virtual void paint(const PaintEvent& event) = 0;
0127     virtual void key_press(const KeyEvent& event) = 0;
0128     virtual void key_release(const KeyEvent& event) { Q_UNUSED(event); }
0129     virtual QCursor cursor() = 0;
0130     virtual void enable_event(const Event& event) = 0;
0131     virtual void disable_event(const Event& event) = 0;
0132     virtual void close_document_event(const Event& event) { Q_UNUSED(event); }
0133     virtual void shape_style_change_event(const Event& event) { Q_UNUSED(event); }
0134 
0135     virtual void on_selected(graphics::DocumentScene* scene, model::VisualNode* node) { Q_UNUSED(scene); Q_UNUSED(node); }
0136     virtual void on_deselected(graphics::DocumentScene* scene, model::VisualNode* node);
0137     // Brief called once the GUI has been fully initialized
0138     virtual void initialize(const Event& event) { Q_UNUSED(event); }
0139 
0140     virtual int group() const noexcept = 0;
0141 
0142 protected:
0143     struct UnderMouse
0144     {
0145         graphics::MoveHandle* handle = nullptr;
0146         std::vector<graphics::DocumentNodeGraphicsItem*> nodes;
0147     };
0148 
0149     UnderMouse under_mouse(const MouseEvent& event, bool only_selectable, SelectionMode mode) const;
0150     graphics::MoveHandle* handle_under_mouse(const MouseEvent& event) const;
0151 
0152     virtual QWidget* on_create_widget() = 0;
0153     virtual void on_translate() {}
0154 
0155     QVariantMap settings_values;
0156 
0157     static constexpr Priority max_priority = std::numeric_limits<Priority>::min();
0158 
0159     void edit_clicked(const MouseEvent& event);
0160 
0161 Q_SIGNALS:
0162     void cursor_changed(const QCursor&);
0163 
0164 private:
0165     QAction* action = nullptr;
0166     ScalableButton* button = nullptr;
0167     QWidget* settings_widget = nullptr;
0168 
0169 //     friend Canvas;
0170 };
0171 
0172 
0173 class Registry
0174 {
0175 public:
0176     enum Group
0177     {
0178         Core,
0179         Draw,
0180         Shape,
0181         Style,
0182         User
0183     };
0184 
0185     using container = std::map<int, std::multimap<Priority, std::unique_ptr<Tool>>>;
0186     using iterator = container::const_iterator;
0187     using mapped_type = container::mapped_type;
0188 
0189     static Registry& instance()
0190     {
0191         static Registry instance;
0192         return instance;
0193     }
0194 
0195     iterator begin() const { return tools.begin(); }
0196     iterator end() const { return tools.end(); }
0197 
0198     void register_tool(int group, qreal priority, std::unique_ptr<Tool> tool)
0199     {
0200         by_id[tool->id()] = tool.get();
0201         tools[group].emplace(priority, std::move(tool));
0202     }
0203 
0204     Tool* tool(const QString& id) const
0205     {
0206         auto it = by_id.find(id);
0207         if ( it == by_id.end() )
0208             return nullptr;
0209         return it->second;
0210     }
0211 
0212     const mapped_type& operator[](Group g) const
0213     {
0214         return tools.at(g);
0215     }
0216 
0217 private:
0218     Registry() = default;
0219     Registry(const Registry&) = delete;
0220     ~Registry() = default;
0221 
0222     container tools;
0223     std::map<QString, Tool*> by_id;
0224 };
0225 
0226 
0227 
0228 template<class T>
0229 class Autoreg
0230 {
0231 public:
0232     Autoreg(Priority priority)
0233     {
0234         Registry::instance().register_tool(T::static_group(), priority, std::make_unique<T>());
0235     }
0236 };
0237 
0238 
0239 } // namespace glaxnimate::gui::tools