File indexing completed on 2024-05-19 13:32:58

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2005 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #ifndef CANVAsmANIPULATOR_H
0012 #define CANVAsmANIPULATOR_H
0013 
0014 #include "eventinfo.h"
0015 
0016 //#include <canvas.h> // 2018.10.16 - not needed
0017 #include "canvasitems.h"
0018 #include <QPointer>
0019 
0020 class CanvasManipulator;
0021 class Connector;
0022 class CMManager;
0023 class CNItem;
0024 class CNItemGroup;
0025 class EventInfo;
0026 class FlowContainer;
0027 class ICNDocument;
0028 class Item;
0029 class ItemDocument;
0030 class ItemGroup;
0031 class ItemView;
0032 class ManipulatorInfo;
0033 class ManualConnectorDraw;
0034 class MechanicsItem;
0035 class MechanicsGroup;
0036 class MechanicsDocument;
0037 class Node;
0038 class NodeGroup;
0039 class ResizeHandle;
0040 
0041 class KtlQCanvas;
0042 class KtlQCanvasItem;
0043 class KtlQCanvasLine;
0044 class KtlQCanvasRectangle;
0045 class QMouseEvent;
0046 class QTimer;
0047 class QWheelEvent;
0048 
0049 typedef CanvasManipulator *(*CreateManipulatorPtr)(ItemDocument *, CMManager *);
0050 typedef bool (*AcceptManipulationPtr)(uint eventState, uint cmState, uint itemType, uint cnItemType);
0051 typedef QList<NodeGroup *> NodeGroupList;
0052 typedef QList<QPointer<Connector>> ConnectorList;
0053 typedef QList<QPoint> QPointList;
0054 
0055 class ManipulatorInfo
0056 {
0057 public:
0058     ManipulatorInfo();
0059     AcceptManipulationPtr m_acceptManipulationPtr;
0060     CreateManipulatorPtr m_createManipulatorPtr;
0061 };
0062 typedef QList<ManipulatorInfo *> ManipulatorInfoList;
0063 
0064 /**
0065 Handles canvas manipulation, such as moving an item or resizing the canvas
0066 @author David Saxton
0067 */
0068 class CMManager : public QObject
0069 {
0070     Q_OBJECT
0071 public:
0072     enum EventState { es_right_click = 1 << 0, es_ctrl_pressed = 1 << 1 };
0073     enum CMState { cms_repeated_add = 1 << 0, cms_manual_route = 1 << 1, cms_draw = 1 << 2 };
0074     enum ItemType { it_none = 1 << 0, it_node = 1 << 1, it_connector = 1 << 2, it_pin = 1 << 3, it_canvas_item = 1 << 4, it_mechanics_item = 1 << 5, it_resize_handle = 1 << 6, it_drawpart = 1 << 7 };
0075 
0076     enum ItemStateInfo { isi_isMovable = 0x2 };
0077     CMManager(ItemDocument *itemDocument);
0078     ~CMManager() override;
0079     /**
0080      * Called when the user single-clicks the mouse
0081      */
0082     void mousePressEvent(EventInfo eventInfo);
0083     /**
0084      * Called when the user releases the mouse
0085      */
0086     void mouseReleaseEvent(const EventInfo &eventInfo);
0087     /**
0088      * Called when the user double clicks the mouse
0089      */
0090     void mouseDoubleClickEvent(const EventInfo &eventInfo);
0091     /**
0092      * Called when the user moves the mouse
0093      */
0094     void mouseMoveEvent(const EventInfo &eventInfo);
0095     /**
0096      * Called when the user scrolls the mouse
0097      */
0098     void wheelEvent(const EventInfo &eventInfo);
0099     /**
0100      * Set a current CMState to true or false
0101      */
0102     void setCMState(CMState type, bool state);
0103     /**
0104      * Cancels the current manipulation (if there is one)
0105      */
0106     void cancelCurrentManipulation();
0107     CanvasManipulator *currentManipulator() const
0108     {
0109         return m_canvasManipulator;
0110     }
0111     void setRepeatedAddId(const QString &repeatedId = QString());
0112     uint cmState() const
0113     {
0114         return m_cmState;
0115     }
0116     void addManipulatorInfo(ManipulatorInfo *info);
0117     QString repeatedItemId() const
0118     {
0119         return m_repeatedItemId;
0120     }
0121     void setDrawAction(int drawAction);
0122     int drawAction() const
0123     {
0124         return m_drawAction;
0125     }
0126 
0127 public slots:
0128     void slotSetManualRoute(bool manualRoute);
0129 
0130 signals:
0131     void manualRoutingChanged(bool manualRouting);
0132 
0133 protected:
0134     /**
0135      * Called when the mouse is moved or released, with the ResizeHandle that
0136      * the mouse is currently over (which can be null). Updates which handle is
0137      * selected, etc.
0138      */
0139     void updateCurrentResizeHandle(ResizeHandle *mouseOver);
0140     CanvasManipulator *m_canvasManipulator;
0141     uint m_cmState;
0142     QString m_repeatedItemId;
0143     ItemDocument *p_itemDocument;
0144     ManipulatorInfoList m_manipulatorInfoList;
0145     QPointer<Item> p_lastMouseOverItem; // Pointer to the item where the mouse was last over - this is used to determine when mouse
0146     QPointer<ResizeHandle> p_lastMouseOverResizeHandle;
0147     QPointer<Item> p_lastItemClicked;
0148     QTimer *m_allowItemScrollTmr; // When a user scrolls on the canvas, we don't want to stop scrolling when the user gets to (e.g.) a scrollable widget. So this timer prevents scrolling a widget for a few hundred milliseconds after a
0149                                   // scroll event if it was initiated over the canvas
0150     bool b_allowItemScroll;       // See above.
0151     int m_drawAction;
0152 
0153 private slots:
0154     void slotAllowItemScroll()
0155     {
0156         b_allowItemScroll = true;
0157     }
0158 };
0159 
0160 /**
0161 Abstract class for a "editing operation" on the ICNDocument, such as moving an item or resizing the canvas
0162 @author David Saxton
0163 */
0164 class CanvasManipulator : public QObject
0165 {
0166     Q_OBJECT
0167 
0168 public:
0169     CanvasManipulator(ItemDocument *itemDocument, CMManager *cmManager);
0170     ~CanvasManipulator() override;
0171     enum Type { RepeatedItemAdd, RightClick, AutoConnector, ManualConnector, ItemMove, ItemResize, MechItemMove, Select, CanvasResize, ItemDrag, Draw };
0172     virtual Type type() const = 0;
0173     /**
0174      * Called when the user single-clicks the mouse
0175      * @returns true if the manipulation operation has finished
0176      */
0177     virtual bool mousePressedInitial(const EventInfo & /*info*/)
0178     {
0179         return false;
0180     }
0181     /**
0182      * Called when the user single-clicks the mouse after the first time (only
0183      * applicable for those operations who are not oneClick
0184      * @returns true if the manipulation operation has finished
0185      */
0186     virtual bool mousePressedRepeat(const EventInfo & /*info*/)
0187     {
0188         return false;
0189     };
0190     /**
0191      * Called when the user moves the mouse
0192      * @returns true if the manipulation operation has finished
0193      */
0194     virtual bool mouseMoved(const EventInfo & /*info*/)
0195     {
0196         return false;
0197     };
0198     /**
0199      * Called when the user releases the mouse
0200      * @returns true if the manipulation operation has finished
0201      */
0202     virtual bool mouseReleased(const EventInfo & /*info*/)
0203     {
0204         return true;
0205     }
0206     /**
0207      * Snaps the point to the 8-sized canvas grid.
0208      */
0209     static QPoint snapPoint(QPoint point);
0210 
0211 protected slots:
0212     /**
0213      * Called when the working canvas emits a resized signal.
0214      */
0215     virtual void canvasResized(const QRect &oldSize, const QRect &newSize)
0216     {
0217         (void)oldSize;
0218         (void)newSize;
0219     }
0220 
0221 protected:
0222     Type m_type;
0223     EventInfo m_eventInfo;
0224     QPoint m_prevPos;
0225     ItemDocument *p_itemDocument;
0226     ICNDocument *p_icnDocument;
0227     MechanicsDocument *p_mechanicsDocument;
0228     KtlQCanvas *p_canvas;
0229     ItemGroup *p_selectList;
0230     CNItemGroup *p_cnItemSelectList;
0231     MechanicsGroup *p_mechItemSelectList;
0232     CNItem *p_cnItemClickedOn;
0233     MechanicsItem *p_mechanicsItemClickedOn;
0234     CMManager *p_cmManager;
0235 };
0236 
0237 /**
0238 @author David Saxton
0239 */
0240 class CMRepeatedItemAdd : public CanvasManipulator
0241 {
0242 public:
0243     CMRepeatedItemAdd(ItemDocument *itemDocument, CMManager *cmManager);
0244     ~CMRepeatedItemAdd() override;
0245     Type type() const override
0246     {
0247         return RepeatedItemAdd;
0248     }
0249 
0250     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0251     static ManipulatorInfo *manipulatorInfo();
0252     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0253 
0254     bool mousePressedInitial(const EventInfo &info) override;
0255     bool mousePressedRepeat(const EventInfo &info) override;
0256     bool mouseMoved(const EventInfo &info) override;
0257     bool mouseReleased(const EventInfo &info) override;
0258 
0259 protected:
0260 };
0261 
0262 /**
0263 @author David Saxton
0264 */
0265 class CMRightClick : public CanvasManipulator
0266 {
0267 public:
0268     CMRightClick(ItemDocument *itemDocument, CMManager *cmManager);
0269     ~CMRightClick() override;
0270     Type type() const override
0271     {
0272         return RightClick;
0273     }
0274 
0275     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0276     static ManipulatorInfo *manipulatorInfo();
0277     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0278 
0279     bool mousePressedInitial(const EventInfo &info) override;
0280     bool mouseMoved(const EventInfo &info) override;
0281     bool mouseReleased(const EventInfo &info) override;
0282 
0283 protected:
0284 };
0285 
0286 /**
0287 @author David Saxton
0288 */
0289 class ConnectorDraw : public CanvasManipulator
0290 {
0291 public:
0292     ConnectorDraw(ItemDocument *itemDocument, CMManager *cmManager);
0293     ~ConnectorDraw() override;
0294 
0295     /**
0296      * Returns the colour used to indicate that the current connection
0297      * being drawn is valid. Invalid colour is black.
0298      */
0299     static QColor validConnectionColor();
0300 
0301 protected:
0302     /**
0303      * If the node has more than 2 connections, return one of the
0304      * connectors
0305      */
0306     Connector *toConnector(Node *node);
0307     /**
0308      * Converts the given qcanvasitem to an appropriate node or connector.
0309      * @param posIsExact if true, then only gets an appropriate node or
0310      * connector when the to-be end-point of the new connector will coincide
0311      * with pos (i.e. auto-connector will call this with posIsExact = false,
0312      * and manual-connector will call this with posIsExact = true).
0313      */
0314     void grabEndStuff(KtlQCanvasItem *endItem, const QPoint &pos, bool posIsExact);
0315     /**
0316      * Returns the closest point to the clickPos that is on the given
0317      * connector.
0318      */
0319     QPoint toValidPos(const QPoint &clickPos, Connector *clickedConnector) const;
0320 
0321     QPointer<Node> p_startNode;
0322     QPointer<Connector> p_startConnector;
0323     Node *p_endNode;
0324     Connector *p_endConnector;
0325     QPoint startConnectorPoint;
0326 };
0327 
0328 /**
0329 @author David Saxton
0330 */
0331 class CMAutoConnector : public ConnectorDraw
0332 {
0333 public:
0334     CMAutoConnector(ItemDocument *itemDocument, CMManager *cmManager);
0335     ~CMAutoConnector() override;
0336     Type type() const override
0337     {
0338         return AutoConnector;
0339     }
0340 
0341     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0342     static ManipulatorInfo *manipulatorInfo();
0343     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0344 
0345     bool mousePressedInitial(const EventInfo &info) override;
0346     bool mouseMoved(const EventInfo &info) override;
0347     bool mouseReleased(const EventInfo &info) override;
0348 
0349 protected:
0350     KtlQCanvasLine *m_connectorLine;
0351 };
0352 
0353 /**
0354 @author David Saxton
0355 */
0356 class CMManualConnector : public ConnectorDraw
0357 {
0358 public:
0359     CMManualConnector(ItemDocument *itemDocument, CMManager *cmManager);
0360     ~CMManualConnector() override;
0361     Type type() const override
0362     {
0363         return ManualConnector;
0364     }
0365 
0366     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0367     static ManipulatorInfo *manipulatorInfo();
0368     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0369 
0370     bool mousePressedInitial(const EventInfo &info) override;
0371     bool mousePressedRepeat(const EventInfo &info) override;
0372     bool mouseMoved(const EventInfo &info) override;
0373     bool mouseReleased(const EventInfo &info) override;
0374 
0375 protected:
0376     ConnectorList m_fixedRouteConnectors;
0377     ManualConnectorDraw *m_manualConnectorDraw;
0378 };
0379 
0380 /**
0381 @author David Saxton
0382 */
0383 class CMItemMove : public CanvasManipulator
0384 {
0385 public:
0386     CMItemMove(ItemDocument *itemDocument, CMManager *cmManager);
0387     ~CMItemMove() override;
0388     Type type() const override
0389     {
0390         return ItemMove;
0391     }
0392 
0393     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0394     static ManipulatorInfo *manipulatorInfo();
0395     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0396 
0397     bool mousePressedInitial(const EventInfo &info) override;
0398     bool mouseMoved(const EventInfo &info) override;
0399     bool mouseReleased(const EventInfo &info) override;
0400     bool mousePressedRepeat(const EventInfo &info) override;
0401 
0402 protected:
0403     void canvasResized(const QRect &oldSize, const QRect &newSize) override;
0404     void scrollCanvasToSelection();
0405 
0406     QPoint m_prevSnapPoint;
0407     bool m_bItemsSnapToGrid; ///< true iff selection contains CNItems
0408     int m_dx;
0409     int m_dy;
0410     ConnectorList m_translatableConnectors;
0411     NodeGroupList m_translatableNodeGroups;
0412     FlowContainer *p_flowContainerCandidate;
0413 };
0414 
0415 /**
0416 @author David Saxton
0417 */
0418 class CMItemResize : public CanvasManipulator
0419 {
0420 public:
0421     CMItemResize(ItemDocument *itemDocument, CMManager *cmManager);
0422     ~CMItemResize() override;
0423     Type type() const override
0424     {
0425         return ItemResize;
0426     }
0427 
0428     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0429     static ManipulatorInfo *manipulatorInfo();
0430     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0431 
0432     bool mousePressedInitial(const EventInfo &info) override;
0433     bool mouseMoved(const EventInfo &info) override;
0434     bool mouseReleased(const EventInfo &info) override;
0435 
0436 protected:
0437     ResizeHandle *p_resizeHandle;
0438     double m_rh_dx;
0439     double m_rh_dy;
0440 };
0441 
0442 /**
0443 @author David Saxton
0444 */
0445 class CMMechItemMove : public CanvasManipulator
0446 {
0447 public:
0448     CMMechItemMove(ItemDocument *itemDocument, CMManager *cmManager);
0449     ~CMMechItemMove() override;
0450     Type type() const override
0451     {
0452         return MechItemMove;
0453     }
0454 
0455     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0456     static ManipulatorInfo *manipulatorInfo();
0457     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0458 
0459     bool mousePressedInitial(const EventInfo &info) override;
0460     bool mouseMoved(const EventInfo &info) override;
0461     bool mouseReleased(const EventInfo &info) override;
0462 
0463 protected:
0464     uint m_prevClickedOnSM; // Previous select mode of the item that was clicked on
0465 };
0466 
0467 /**
0468 @author David Saxton
0469 */
0470 class SelectRectangle
0471 {
0472 public:
0473     SelectRectangle(int x, int y, int w, int h, KtlQCanvas *qcanvas);
0474     ~SelectRectangle();
0475 
0476     void setSize(int w, int h);
0477     KtlQCanvasItemList collisions();
0478 
0479 protected:
0480     KtlQCanvasLine *m_topLine;
0481     KtlQCanvasLine *m_rightLine;
0482     KtlQCanvasLine *m_bottomLine;
0483     KtlQCanvasLine *m_leftLine;
0484     const int m_x;
0485     const int m_y;
0486     int m_w;
0487     int m_h;
0488     int m_prevCollisions_w;
0489     int m_prevCollisions_h;
0490     KtlQCanvasItemList m_prevCollisions;
0491 };
0492 
0493 /**
0494 @author David Saxton
0495 */
0496 class CMSelect : public CanvasManipulator
0497 {
0498 public:
0499     CMSelect(ItemDocument *itemDocument, CMManager *cmManager);
0500     ~CMSelect() override;
0501     Type type() const override
0502     {
0503         return Select;
0504     }
0505 
0506     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0507     static ManipulatorInfo *manipulatorInfo();
0508     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0509 
0510     bool mousePressedInitial(const EventInfo &info) override;
0511     bool mouseMoved(const EventInfo &info) override;
0512     bool mouseReleased(const EventInfo &info) override;
0513 
0514 protected:
0515     SelectRectangle *m_selectRectangle;
0516 };
0517 
0518 /**
0519 @author David Saxton
0520 */
0521 class CMItemDrag : public CanvasManipulator
0522 {
0523 public:
0524     CMItemDrag(ItemDocument *itemDocument, CMManager *cmManager);
0525     ~CMItemDrag() override;
0526     Type type() const override
0527     {
0528         return ItemDrag;
0529     }
0530 
0531     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0532     static ManipulatorInfo *manipulatorInfo();
0533     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0534 
0535     bool mousePressedInitial(const EventInfo &info) override;
0536     bool mouseMoved(const EventInfo &info) override;
0537     bool mouseReleased(const EventInfo &info) override;
0538 
0539 protected:
0540     bool b_dragged;
0541 };
0542 
0543 /**
0544 @author David Saxton
0545 A KtlQCanvasEllipse that uses a pen (not a brush) to paint
0546 */
0547 class CanvasEllipseDraw : public KtlQCanvasEllipse
0548 {
0549 public:
0550     CanvasEllipseDraw(int x, int y, KtlQCanvas *canvas);
0551 
0552 protected:
0553     void drawShape(QPainter &p) override;
0554 };
0555 
0556 /**
0557 @author David Saxton
0558 */
0559 class CMDraw : public CanvasManipulator
0560 {
0561 public:
0562     CMDraw(ItemDocument *itemDocument, CMManager *cmManager);
0563     ~CMDraw() override;
0564     Type type() const override
0565     {
0566         return Draw;
0567     }
0568 
0569     static CanvasManipulator *construct(ItemDocument *itemDocument, CMManager *cmManager);
0570     static ManipulatorInfo *manipulatorInfo();
0571     static bool acceptManipulation(uint eventState, uint cmState, uint itemType, uint cnItemType);
0572 
0573     bool mousePressedInitial(const EventInfo &info) override;
0574     bool mouseMoved(const EventInfo &info) override;
0575     bool mouseReleased(const EventInfo &info) override;
0576 
0577 protected:
0578     KtlQCanvasRectangle *m_pDrawRectangle;
0579     CanvasEllipseDraw *m_pDrawEllipse;
0580     KtlQCanvasLine *m_pDrawLine;
0581 };
0582 
0583 /**
0584 @author David Saxton
0585 */
0586 class ManualConnectorDraw
0587 {
0588 public:
0589     ManualConnectorDraw(ICNDocument *_icnDocument, const QPoint &initialPos);
0590     virtual ~ManualConnectorDraw();
0591 
0592     /**
0593      * Called when the mouse is moved.
0594      * Normally will do something like updating the connector route
0595      */
0596     void mouseMoved(const QPoint &pos);
0597     /**
0598      * Called when the user clicks the mouse. If the connector finishes on a
0599      * valid KtlQCanvasItem (Node or Connetor), then this is returned. Otherwise,
0600      * null is returned.
0601      */
0602     KtlQCanvasItem *mouseClicked(const QPoint &pos);
0603     /**
0604      * Returns the list of points that define the manual connection route
0605      */
0606     QPointList pointList();
0607     /**
0608      * Sets the colour used to draw the connection lines.
0609      */
0610     void setColor(const QColor &color);
0611 
0612 protected:
0613     void updateConnectorEnds();
0614 
0615     QList<KtlQCanvasLine *> m_connectorLines;
0616     ICNDocument *icnDocument;
0617 
0618     bool b_currentVertical;
0619     bool b_orientationDefined;
0620 
0621     QPoint m_initialPos;
0622     QPoint m_previousPos;
0623     QPoint m_currentPos;
0624 
0625     KtlQCanvasLine *m_currentCon;
0626     KtlQCanvasLine *m_previousCon;
0627 
0628     // The first item that we clicked on
0629     KtlQCanvasItem *p_initialItem;
0630 
0631     QColor m_color;
0632 };
0633 
0634 #endif