File indexing completed on 2024-12-01 11:20:44
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