You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/canvasmanipulator.h

607 lines
17 KiB

/***************************************************************************
* 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 <tqcanvas.h>
#include <tqguardedptr.h>
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<NodeGroup*> NodeGroupList;
typedef TQValueList<TQGuardedPtr<Connector> > ConnectorList;
typedef TQValueList<TQPoint> TQPointList;
class ManipulatorInfo
{
public:
ManipulatorInfo();
AcceptManipulationPtr m_acceptManipulationPtr;
CreateManipulatorPtr m_createManipulatorPtr;
};
typedef TQValueList<ManipulatorInfo*> ManipulatorInfoList;
/**
Handles canvas manipulation, such as moving an item or resizing the canvas
@author David Saxton
*/
class CMManager : public TQObject
{
TQ_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<Item> p_lastMouseOverItem; // Pointer to the item where the mouse was last over - this is used to determine when mouse
TQGuardedPtr<ResizeHandle> p_lastMouseOverResizeHandle;
TQGuardedPtr<Item> 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<Node> p_startNode;
TQGuardedPtr<Connector> 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<TQCanvasLine*> 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