/*************************************************************************** * Copyright (C) 2004-2005 by David Saxton * * david@bluehaze.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef CANVAsmANIPULATOR_H #define CANVAsmANIPULATOR_H #include "eventinfo.h" #include #include class CanvasManipulator; class Connector; class CMManager; class CNItem; class CNItemGroup; class EventInfo; class FlowContainer; class ICNDocument; class Item; class ItemDocument; class ItemGroup; class ItemView; class ManipulatorInfo; class ManualConnectorDraw; class MechanicsItem; class MechanicsGroup; class MechanicsDocument; class Node; class NodeGroup; class ResizeHandle; class TQCanvas; class TQCanvasItem; class TQCanvasLine; class TQCanvasRectangle; class TQMouseEvent; class TQTimer; class TQWheelEvent; typedef CanvasManipulator*(*CreateManipulatorPtr)( ItemDocument *, CMManager * ); typedef bool(*AcceptManipulationPtr)( uint eventState, uint cmState, uint itemType, uint cnItemType ); typedef TQValueList NodeGroupList; typedef TQValueList > ConnectorList; typedef TQValueList TQPointList; class ManipulatorInfo { public: ManipulatorInfo(); AcceptManipulationPtr m_acceptManipulationPtr; CreateManipulatorPtr m_createManipulatorPtr; }; typedef TQValueList ManipulatorInfoList; /** Handles canvas manipulation, such as moving an item or resizing the canvas @author David Saxton */ class CMManager : public TQObject { Q_OBJECT public: enum EventState { es_right_click = 1 << 0, es_ctrl_pressed = 1 << 1 }; enum CMState { cms_repeated_add = 1 << 0, cms_manual_route = 1 << 1, cms_draw = 1 << 2 }; 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 }; enum ItemStateInfo { isi_isMovable = 0x2, }; CMManager( ItemDocument *itemDocument ); ~CMManager(); /** * Called when the user single-clicks the mouse */ void mousePressEvent( EventInfo eventInfo ); /** * Called when the user releases the mouse */ void mouseReleaseEvent( const EventInfo &eventInfo ); /** * Called when the user double clicks the mouse */ void mouseDoubleClickEvent( const EventInfo &eventInfo ); /** * Called when the user moves the mouse */ void mouseMoveEvent( const EventInfo &eventInfo ); /** * Called when the user scrolls the mouse */ void wheelEvent( const EventInfo &eventInfo ); /** * Set a current CMState to true or false */ void setCMState( CMState type, bool state ); /** * Cancels the current manipulation (if there is one) */ void cancelCurrentManipulation(); CanvasManipulator * currentManipulator() const { return m_canvasManipulator; } void setRepeatedAddId( const TQString & repeatedId = TQString() ); uint cmState() const { return m_cmState; } void addManipulatorInfo( ManipulatorInfo *info ); TQString repeatedItemId() const { return m_repeatedItemId; } void setDrawAction( int drawAction ); int drawAction() const { return m_drawAction; } public slots: void slotSetManualRoute( bool manualRoute ); signals: void manualRoutingChanged( bool manualRouting ); protected: /** * Called when the mouse is moved or released, with the ResizeHandle that * the mouse is currently over (which can be null). Updates which handle is * selected, etc. */ void updateCurrentResizeHandle( ResizeHandle * mouseOver ); CanvasManipulator *m_canvasManipulator; uint m_cmState; TQString m_repeatedItemId; ItemDocument *p_itemDocument; ManipulatorInfoList m_manipulatorInfoList; TQGuardedPtr p_lastMouseOverItem; // Pointer to the item where the mouse was last over - this is used to determine when mouse TQGuardedPtr p_lastMouseOverResizeHandle; TQGuardedPtr p_lastItemClicked; TQTimer *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 scroll event if it was initiated over the canvas bool b_allowItemScroll; // See above. int m_drawAction; private slots: void slotAllowItemScroll() { b_allowItemScroll = true; } }; /** Abstract class for a "editing operation" on the ICNDocument, such as moving an item or resizing the canvas @author David Saxton */ class CanvasManipulator { public: CanvasManipulator( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CanvasManipulator(); enum Type { RepeatedItemAdd, RightClick, AutoConnector, ManualConnector, ItemMove, ItemResize, MechItemMove, Select, CanvasResize, ItemDrag, Draw }; virtual Type type() const = 0; /** * Called when the user single-clicks the mouse * @returns true if the manipulation operation has finished */ virtual bool mousePressedInitial( const EventInfo &/*info*/ ) { return false; } /** * Called when the user single-clicks the mouse after the first time (only * applicable for those operations who are not oneClick * @returns true if the manipulation operation has finished */ virtual bool mousePressedRepeat( const EventInfo &/*info*/ ) { return false; }; /** * Called when the user moves the mouse * @returns true if the manipulation operation has finished */ virtual bool mouseMoved( const EventInfo &/*info*/ ) { return false; }; /** * Called when the user releases the mouse * @returns true if the manipulation operation has finished */ virtual bool mouseReleased( const EventInfo &/*info*/ ) { return true; } protected: Type m_type; EventInfo m_eventInfo; TQPoint m_prevPos; ItemDocument *p_itemDocument; ICNDocument *p_icnDocument; MechanicsDocument *p_mechanicsDocument; TQCanvas *p_canvas; ItemGroup *p_selectList; CNItemGroup *p_cnItemSelectList; MechanicsGroup *p_mechItemSelectList; CNItem *p_cnItemClickedOn; MechanicsItem *p_mechanicsItemClickedOn; CMManager *p_cmManager; }; /** @author David Saxton */ class CMRepeatedItemAdd : public CanvasManipulator { public: CMRepeatedItemAdd( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMRepeatedItemAdd(); virtual Type type() const { return RepeatedItemAdd; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mousePressedRepeat( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: }; /** @author David Saxton */ class CMRightClick : public CanvasManipulator { public: CMRightClick( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMRightClick(); virtual Type type() const { return RightClick; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: }; /** @author David Saxton */ class ConnectorDraw : public CanvasManipulator { public: ConnectorDraw( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~ConnectorDraw(); /** * Returns the colour used to indicate that the current connection * being drawn is valid. Invalid colour is black. */ static TQColor validConnectionColor(); protected: /** * If the node has more than 2 connections, return one of the * connectors */ Connector * toConnector( Node * node ); /** * Converts the given qcanvasitem to an appropriate node or connector. * @param posIsExact if true, then only gets an appropriate node or * connector when the to-be end-point of the new connector will coincide * with pos (i.e. auto-connector will call this with posIsExact = false, * and manual-connector will call this with posIsExact = true). */ void grabEndStuff( TQCanvasItem * endItem, const TQPoint & pos, bool posIsExact ); /** * Returns the closest point to the clickPos that is on the given * connector. */ TQPoint toValidPos( const TQPoint & clickPos, Connector * clickedConnector ) const; TQGuardedPtr p_startNode; TQGuardedPtr p_startConnector; Node * p_endNode; Connector * p_endConnector; TQPoint startConnectorPoint; }; /** @author David Saxton */ class CMAutoConnector : public ConnectorDraw { public: CMAutoConnector( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMAutoConnector(); virtual Type type() const { return AutoConnector; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: TQCanvasLine *m_connectorLine; }; /** @author David Saxton */ class CMManualConnector : public ConnectorDraw { public: CMManualConnector( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMManualConnector(); virtual Type type() const { return ManualConnector; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mousePressedRepeat( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: ConnectorList m_fixedRouteConnectors; ManualConnectorDraw *m_manualConnectorDraw; }; /** @author David Saxton */ class CMItemMove : public CanvasManipulator { public: CMItemMove( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMItemMove(); virtual Type type() const { return ItemMove; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: ConnectorList m_translatableConnectors; NodeGroupList m_translatableNodeGroups; FlowContainer *p_flowContainerCandidate; }; /** @author David Saxton */ class CMItemResize : public CanvasManipulator { public: CMItemResize( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMItemResize(); virtual Type type() const { return ItemResize; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: ResizeHandle *p_resizeHandle; double m_rh_dx; double m_rh_dy; }; /** @author David Saxton */ class CMMechItemMove : public CanvasManipulator { public: CMMechItemMove( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMMechItemMove(); virtual Type type() const { return MechItemMove; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: uint m_prevClickedOnSM; // Previous select mode of the item that was clicked on }; /** @author David Saxton */ class SelectRectangle { public: SelectRectangle( int x, int y, int w, int h, TQCanvas *qcanvas ); ~SelectRectangle(); void setSize( int w, int h ); TQCanvasItemList collisions(); protected: TQCanvasLine *m_topLine; TQCanvasLine *m_rightLine; TQCanvasLine *m_bottomLine; TQCanvasLine *m_leftLine; const int m_x; const int m_y; int m_w; int m_h; int m_prevCollisions_w; int m_prevCollisions_h; TQCanvasItemList m_prevCollisions; }; /** @author David Saxton */ class CMSelect : public CanvasManipulator { public: CMSelect( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMSelect(); virtual Type type() const { return Select; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: SelectRectangle *m_selectRectangle; }; /** @author David Saxton */ class CMItemDrag : public CanvasManipulator { public: CMItemDrag( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMItemDrag(); virtual Type type() const { return ItemDrag; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: bool b_dragged; }; /** @author David Saxton A TQCanvasEllipse that uses a pen (not a brush) to paint */ class CanvasEllipseDraw : public TQCanvasEllipse { public: CanvasEllipseDraw( int x, int y, TQCanvas * canvas ); protected: virtual void drawShape( TQPainter & p ); }; /** @author David Saxton */ class CMDraw : public CanvasManipulator { public: CMDraw( ItemDocument *itemDocument, CMManager *cmManager ); virtual ~CMDraw(); virtual Type type() const { return Draw; } static CanvasManipulator* construct( ItemDocument *itemDocument, CMManager *cmManager ); static ManipulatorInfo *manipulatorInfo(); static bool acceptManipulation( uint eventState, uint cmState, uint itemType, uint cnItemType ); virtual bool mousePressedInitial( const EventInfo &info ); virtual bool mouseMoved( const EventInfo &info ); virtual bool mouseReleased( const EventInfo &info ); protected: TQCanvasRectangle * m_pDrawRectangle; CanvasEllipseDraw * m_pDrawEllipse; TQCanvasLine * m_pDrawLine; }; /** @author David Saxton */ class ManualConnectorDraw { public: ManualConnectorDraw( ICNDocument *_icnDocument, const TQPoint &initialPos ); virtual ~ManualConnectorDraw(); /** * Called when the mouse is moved. * Normally will do something like updating the connector route */ void mouseMoved( const TQPoint &pos ); /** * Called when the user clicks the mouse. If the connector finishes on a * valid TQCanvasItem (Node or Connetor), then this is returned. Otherwise, * null is returned. */ TQCanvasItem * mouseClicked( const TQPoint &pos ); /** * Returns the list of points that define the manual connection route */ TQPointList pointList(); /** * Sets the colour used to draw the connection lines. */ void setColor( const TQColor & color ); protected: void updateConnectorEnds(); TQValueList m_connectorLines; ICNDocument *icnDocument; bool b_currentVertical; bool b_orientationDefined; TQPoint m_initialPos; TQPoint m_previousPos; TQPoint m_currentPos; TQCanvasLine *m_currentCon; TQCanvasLine *m_previousCon; // The first item that we clicked on TQCanvasItem *p_initialItem; TQColor m_color; }; #endif