0.3.1
[qanava.git] / src / qanController.cpp
blobf871f9fe096c53ca2f5b1a41757501e1db91a61e
1 /*
2 Qanava - Graph drawing library for QT
3 Copyright (C) 2006 Benoit AUTHEMAN
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //-----------------------------------------------------------------------------
21 // This file is a part of the Qanava software.
23 // \file canController.cpp
24 // \author Benoit Autheman (benoit@libqanava.org)
25 // \date 2003 August 13
26 //-----------------------------------------------------------------------------
29 // Qanava headers
30 #include "./qanController.h"
31 #include "./qanGraphView.h"
34 // QT headers
35 #include <QMatrix>
36 #include <QTimer>
37 #include <QPixmap>
38 #include <QKeyEvent>
39 #include <QResizeEvent>
40 #include <QMouseEvent>
41 #include <QScrollBar>
44 namespace qan { // ::qan
47 bool Controller::Manager::keyPressEvent( QKeyEvent* e )
49 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
51 if ( ( *controllerIter )->keyPressEvent( e ) )
52 return true;
54 return false;
57 bool Controller::Manager::mousePressEvent( QMouseEvent* e )
59 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
61 if ( ( *controllerIter )->mousePressEvent( e ) )
62 return true;
64 return false;
67 bool Controller::Manager::mouseReleaseEvent( QMouseEvent* e )
69 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
71 if ( ( *controllerIter )->mouseReleaseEvent( e ) )
72 return true;
74 return false;
77 bool Controller::Manager::mouseMoveEvent( QMouseEvent* e )
79 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
81 if ( ( *controllerIter )->mouseMoveEvent( e ) )
82 return true;
84 return false;
87 bool Controller::Manager::mouseDoubleClickEvent( QMouseEvent* e )
89 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
91 if ( ( *controllerIter )->mouseDoubleClickEvent( e ) )
92 return true;
94 return false;
97 bool Controller::Manager::wheelEvent( QWheelEvent* e )
99 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
101 if ( ( *controllerIter )->wheelEvent( e ) )
102 return true;
104 return false;
107 Controller* Controller::Manager::getController( QString name )
109 for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ )
111 if ( ( *controllerIter )->getName( ) == name )
112 return ( *controllerIter );
114 return 0;
117 void Controller::Manager::registerController( Controller* controller )
119 if ( controller == 0 )
120 return;
122 push_back( controller );
123 QAction* controllerAction = controller->getAction( );
124 if ( controllerAction->isCheckable( ) )
125 _actionGroup->addAction( controllerAction ); // Only one checkable action active at a time
128 Controller::Controller( QString name, GraphView& GraphView ) :
129 _GraphView( GraphView ),
130 _action( 0 ),
131 _name( name )
137 /* PanController Constructor/Destructor *///-----------------------------------
138 PanController::PanController( GraphView& GraphView ) :
139 Controller( "pan_controller", GraphView ),
140 _keyboardNavigation( true ),
141 _keyboardNavigationIntensity( 10.0 ),
142 _start( 0., 0. )
144 QAction* action = new QAction( this );
145 action->setCheckable( true );
146 action->setText( "Pan" );
147 action->setVisible( true );
148 action->setIcon( QIcon( "images/qanava_pan.png" ) );
149 connect( action, SIGNAL( toggled( bool ) ), this, SLOT( toggled( bool ) ) );
150 setAction( action );
152 setKeyboardNavigation( true );
155 void PanController::toggled( bool state )
157 setMode( state ? PAN : NONE );
159 //-----------------------------------------------------------------------------
163 /* PanController Keyboard Management *///--------------------------------------
164 bool PanController::keyPressEvent( QKeyEvent* e )
166 getGraphView( ).setFocusPolicy( Qt::ClickFocus );
167 if ( getKeyboardNavigation( ) )
169 switch ( e->key( ) )
171 case Qt::Key_Left:
172 getGraphView( ).translate( ( int )-_keyboardNavigationIntensity, 0 );
173 break;
175 case Qt::Key_Up:
176 getGraphView( ).translate( 0, ( int )-_keyboardNavigationIntensity );
177 break;
179 case Qt::Key_Right:
180 getGraphView( ).translate( ( int )_keyboardNavigationIntensity, 0 );
181 break;
183 case Qt::Key_Down:
184 getGraphView( ).translate( 0, ( int )_keyboardNavigationIntensity );
185 break;
187 default:
188 e->ignore( );
189 break;
192 return false;
195 /*! To use keyboard navigation, ensure that this widget parent widget has at least a 'Click'
196 focus policy (in Designer or with the QWidget::setFocusPolicy() method).
198 void PanController::setKeyboardNavigation( bool state )
200 _keyboardNavigation = state;
201 if ( state )
203 getGraphView( ).viewport( )->setFocusPolicy( Qt::StrongFocus );
204 getGraphView( ).setFocusPolicy( Qt::StrongFocus );
207 //-----------------------------------------------------------------------------
211 /* PanController Mouse Management *///-----------------------------------------
212 bool PanController::mousePressEvent( QMouseEvent* e )
214 // Navigation must not occurs if a node is under the mouse
215 QPointF p = getGraphView( ).mapToScene( e->pos( ) );
216 QList< QGraphicsItem* > items = getGraphView( ).scene( )->items( p );
217 if ( items.size( ) == 0 )
218 { // TODO: prendre les elements de grille en compte (et tous ceux qui ne sont pas manipulables)
219 if ( getMode( ) == PAN )
221 _start = e->pos( );
222 getGraphView( ).viewport( )->setCursor( QCursor( Qt::SizeAllCursor ) );
223 setState( PANNING );
224 return true;
228 return false;
231 bool PanController::mouseReleaseEvent( QMouseEvent* e )
233 getGraphView( ).viewport( )->setCursor( QCursor( Qt::ArrowCursor ) );
235 if ( getMode( ) == PAN && getState( ) == PANNING )
236 setState( NONE ); // Stop panning until next click
238 return false;
241 bool PanController::mouseMoveEvent( QMouseEvent* e )
243 if ( getMode( ) == PAN && getState( ) == PANNING )
245 QPointF p = e->pos( ); // No mapping, we move scrollbars in their coordinate system
246 //QPointF p = getGraphView( ).mapToScene( e->pos( ) );
248 double accel = 1.0;
249 double dx = ( _start.x( ) - p.x( ) ) * accel;
250 double dy = ( _start.y( ) - p.y( ) ) * accel;
252 int valueY = ( int )( getGraphView( ).verticalScrollBar( )->value( ) + dy );
253 getGraphView( ).verticalScrollBar( )->setValue( valueY );
254 int valueX = ( int )( getGraphView( ).horizontalScrollBar( )->value( ) + dx );
255 getGraphView( ).horizontalScrollBar( )->setValue( valueX );
257 _start = p;
258 return true;
260 return false;
262 //-----------------------------------------------------------------------------
266 /* ZoomWindowController Constructor/Destructor *///-------------------------------
267 ZoomWindowController::ZoomWindowController( GraphView& GraphView ) :
268 Controller( "zoom_window_controller", GraphView ),
269 _start( 0., 0. ),
270 _zoomRectItem( 0 )
272 QAction* action = new QAction( this );
273 action->setCheckable( true );
274 action->setText( "Zoom Window" );
275 action->setVisible( true );
276 action->setIcon( QIcon( "images/qanava_zoomwindow.png" ) );
277 connect( action, SIGNAL( toggled( bool ) ), this, SLOT( toggled( bool ) ) );
278 setAction( action );
280 _zoomRectItem = new QGraphicsRectItem( QRectF( 0., 0., 50., 50. ), 0, getGraphView( ).scene( ) );
281 _zoomRectItem->setZValue( 100. );
282 QPen p;
283 p.setStyle( Qt::DotLine );
284 p.setWidth( 1 );
285 p.setColor( QColor( 55, 55, 55 ) );
286 _zoomRectItem->setPen( p );
287 _zoomRectItem->hide( );
290 void ZoomWindowController::toggled( bool state )
292 setMode( state ? ZOOM : NONE );
294 //-----------------------------------------------------------------------------
298 /* ZoomWindowController Zooming Management *///--------------------------------
299 bool ZoomWindowController::mousePressEvent( QMouseEvent* e )
301 // Navigation must not occurs if a node is under the mouse
302 QPointF p = getGraphView( ).mapToScene( e->pos( ) );
303 QList< QGraphicsItem* > items = getGraphView( ).scene( )->items( p );
304 if ( items.size( ) == 0 )
305 { // TODO: prendre les elements de grille en compte (et tous ceux qui ne sont pas manipulables)
306 if ( getMode( ) == ZOOM )
308 _start = getGraphView( ).mapToScene( e->pos( ) );
309 setState( ZOOMING );
310 return true;
314 return false;
317 bool ZoomWindowController::mouseReleaseEvent( QMouseEvent* e )
319 if ( getMode( ) == ZOOM && getState( ) == ZOOMING )
321 getGraphView( ).fitInView( _zoomRectItem->rect( ), Qt::KeepAspectRatioByExpanding );
322 _zoomRectItem->hide( );
323 setState( NONE ); // Stop zooming until next click
324 return true;
327 return false;
330 bool ZoomWindowController::mouseMoveEvent( QMouseEvent* e )
332 if ( getMode( ) == ZOOM && getState( ) == ZOOMING && _zoomRectItem != 0 )
334 QPointF p = getGraphView( ).mapToScene( e->pos( ) );
336 QRectF r( _start.x( ), _start.y( ),
337 p.x( ) - _start.x( ), p.y( ) - _start.y( ) );
338 _zoomRectItem->setRect( r );
339 _zoomRectItem->show( );
340 return true;
342 return false;
344 //-----------------------------------------------------------------------------
348 /* ZoomController Constructor/Destructor *///----------------------------------
349 ZoomController::ZoomController( GraphView& GraphView ) :
350 Controller( "zoom_controller", GraphView ),
351 _actionZoomIn( new QAction( this ) ),
352 _actionZoomOut( new QAction( this ) )
354 QAction* action = new QAction( this );
355 action->setCheckable( true );
356 action->setText( "Zoom" );
357 action->setVisible( true );
358 action->setIcon( QIcon( "images/qanava_zoom.png" ) );
359 setAction( action );
361 _actionZoomIn->setText( "Zoom In" );
362 _actionZoomIn->setVisible( true );
363 _actionZoomIn->setIcon( QIcon( "images/qanava_zoomin.png" ) );
364 connect( _actionZoomIn, SIGNAL( triggered( bool ) ), this, SLOT( zoomIn( bool ) ) );
366 _actionZoomOut->setText( "Zoom Out" );
367 _actionZoomOut->setVisible( true );
368 _actionZoomOut->setIcon( QIcon( "images/qanava_zoomout.png" ) );
369 connect( _actionZoomOut, SIGNAL( triggered( bool ) ), this, SLOT( zoomOut( bool ) ) );
371 //-----------------------------------------------------------------------------
375 /* ZoomController Zooming Management *///--------------------------------------
376 void ZoomController::zoomIn( bool state )
378 getGraphView( ).setZoom( getGraphView( ).getZoom( ) + 0.2 );
381 void ZoomController::zoomOut( bool state )
383 getGraphView( ).setZoom( getGraphView( ).getZoom( ) - 0.2 );
386 bool ZoomController::wheelEvent( QWheelEvent* e )
388 return false;
391 QAction* ZoomController::getAction( QString name )
393 if ( name == "zoom_in" )
394 return _actionZoomIn;
395 else if ( name == "zoom_out" )
396 return _actionZoomOut;
398 return 0;
400 //-----------------------------------------------------------------------------
404 /* Selection Controller Management *///------------------------------------------
405 /*SelectionController::SelectionController( GraphView& GraphView ) :
406 Controller( GraphView )
410 bool SelectionController::mouseDoubleClickEvent( QMouseEvent* e )
412 // FIXME
413 /* QPointF p = getGraphView( ).mapToScene( e->pos( ) );
414 Item::List collisions;
415 getGraphView( ).getCanvas( )->getCollisions( p, collisions );
416 for ( Item::List::iterator itemIter = collisions.begin( ); itemIter != collisions.end( ); itemIter++ )
418 Item* item = *itemIter;
419 if ( getGraphView( ).getCanvas( )->isFreed( item ) )
420 break;
422 Node* node = getGraphView( ).getGraphicItemNode( item );
423 if ( node != 0 )
424 emit nodeSelected( node, p );
427 /* return false;
429 //-----------------------------------------------------------------------------
433 /* Tooltip Controller Management *///--------------------------------------------
434 /*TooltipController::TooltipController( GraphView& GraphView ) :
435 Controller( GraphView ),
436 //_tipItem( 0 ),
437 _tipPos( 0, 0 ),
438 _timer( 0 )
440 _timer = new QTimer( this );
441 connect( _timer, SIGNAL( timeout( ) ), SLOT( tipTimeout( ) ) );
444 /*void TooltipController::tipTimeout( )
446 // FIXME
447 // Don't show tooltips in case of error or if another controller is already active
448 /* if ( _tipItem == 0 || getGraphView( ).getControllerManager( ).isControllerActive( ) )
450 _timer->stop( );
451 return;
454 // Test if the mouse is still on the item that has started the tooltip demand (tooltip delay) milliseconds ago
455 Item::List collisions;
456 getGraphView( ).getCanvas( )->getCollisions( _tipPos, collisions );
457 for ( Item::List::iterator itemIter = collisions.begin( ); itemIter != collisions.end( ); itemIter++ )
459 Item* item = *itemIter;
461 if ( item == _tipItem )
463 Node* node = getGraphView( ).getGraphicItemNode( _tipItem );
464 if ( node != 0 )
466 // Compute the real screen viewport coordinates
467 QPoint viewportTipPosContent = getGraphView( ).mapFromCanvas( _tipPos );
468 emit nodeTipped( node, getGraphView( ).viewport( )->mapToGlobal( viewportTipPosContent ) );
472 _timer->stop( );
473 _tipItem = 0;*/
476 //bool TooltipController::mouseMoveEvent( QMouseEvent* e )
478 // FIXME
479 /* QPointF p = getGraphView( ).mapToScene( e->pos( ) );
480 _tipPos = p;
482 // If no button is pressed, there is no manipulation or navigation operation going on, so tooltip can be displayed
483 if ( e->button() != Qt::LeftButton )
485 Item::List collisions;
486 getGraphView( ).getCanvas( )->getCollisions( _tipPos, collisions );
487 for ( Item::List::iterator itemIter = collisions.begin( ); itemIter != collisions.end( ); itemIter++ )
489 Item* item = *itemIter;
490 if ( item == _tipItem && _timer->isActive( ) ) // Avoid the timer to be restarted when moving in the same item
491 break;
493 _tipPos = p;
494 if ( getGraphView( ).getCanvas( )->isFreed( item ) )
495 break;
497 Node* node = getGraphView( ).getGraphicItemNode( item );
498 if ( node != 0 )
500 _timer->start( 800 );
501 _tipItem = item;
502 return true;
504 break; // Take just the first intersecting item to avoid deep z selection
507 else
509 // There is a complex navigation or manipulation operation going on, don't display tooltips
510 _timer->stop( );
511 _tipItem = 0;
514 // return false;
517 //bool TooltipController::mouseDoubleClickEvent( QMouseEvent* e )
519 // Avoid interference with other controllers (such as simultaneous tip and double click node selection)
520 // FIXME
521 /*_timer->stop( );
522 _tipItem = 0;*/
523 // return false;
525 //-----------------------------------------------------------------------------
528 } // ::qan