00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <math.h>
00021 #include <stdlib.h>
00022
00023 #include <qcursor.h>
00024 #include <qlabel.h>
00025 #include <qradiobutton.h>
00026 #include <qbuttongroup.h>
00027
00028 #include <KoPoint.h>
00029 #include <KoRect.h>
00030 #include <kdebug.h>
00031
00032 #include <karbon_part.h>
00033 #include <karbon_view.h>
00034 #include <render/vpainter.h>
00035 #include <render/vpainterfactory.h>
00036 #include <core/vselection.h>
00037 #include "vselecttool.h"
00038 #include <commands/vtransformcmd.h>
00039 #include <visitors/vselectiondesc.h>
00040 #include <visitors/vselectobjects.h>
00041 #include <widgets/vcanvas.h>
00042
00043 VSelectOptionsWidget::VSelectOptionsWidget( KarbonPart *part )
00044 : KDialogBase( 0L, "", true, i18n( "Selection" ), Ok | Cancel ), m_part( part )
00045 {
00046 QButtonGroup *group = new QButtonGroup( 1, Qt::Horizontal, i18n( "Selection Mode" ), this );
00047
00048 new QRadioButton( i18n( "Select in current layer" ), group );
00049 new QRadioButton( i18n( "Select in visible layers" ), group );
00050 new QRadioButton( i18n( "Select in selected layers" ), group );
00051
00052 group->setRadioButtonExclusive( true );
00053 group->setButton( part->document().selectionMode() );
00054
00055 connect( group, SIGNAL( clicked( int ) ), this, SLOT( modeChange( int ) ) );
00056
00057 group->setInsideMargin( 4 );
00058 group->setInsideSpacing( 2 );
00059
00060 setMainWidget( group );
00061 setFixedSize( baseSize() );
00062 }
00063
00064 void VSelectOptionsWidget::modeChange( int mode )
00065 {
00066 m_part->document().setSelectionMode( (VDocument::VSelectionMode)mode );
00067 }
00068
00069 VSelectTool::VSelectTool( KarbonView *view )
00070 : VTool( view, "tool_select" ), m_state( normal )
00071 {
00072 m_lock = false;
00073 m_add = true;
00074 m_objects.setAutoDelete( true );
00075 m_optionsWidget = new VSelectOptionsWidget( view->part() );
00076 registerTool( this );
00077 connect( view, SIGNAL( selectionChange() ), this, SLOT( updateStatusBar() ) );
00078 }
00079
00080 VSelectTool::~VSelectTool()
00081 {
00082 delete m_optionsWidget;
00083 }
00084
00085 void
00086 VSelectTool::activate()
00087 {
00088 VTool::activate();
00089 view()->setCursor( QCursor( Qt::arrowCursor ) );
00090 view()->part()->document().selection()->showHandle();
00091 view()->part()->document().selection()->setSelectObjects();
00092 view()->part()->document().selection()->setState( VObject::selected );
00093 view()->part()->document().selection()->selectNodes();
00094 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00095 updateStatusBar();
00096 }
00097
00098 QString
00099 VSelectTool::statusText()
00100 {
00101 return i18n( "Select" );
00102 }
00103
00104 QString VSelectTool::contextHelp()
00105 {
00106 QString s = i18n( "<qt><b>Selection tool:</b><br>" );
00107 s += i18n( "<i>Select in current layer:</i><br>The selection is made in the layer selected in the layers docker.<br><br>" );
00108 s += i18n( "<i>Select in visible layers:</i><br>The selection is made in the visible layers (eye in the layers docker).<br><br>" );
00109 s += i18n( "<i>Select in selected layers:</i><br>The selection is made in the checked layers in the layers docker.<br><br>" );
00110 s += i18n( "<i>Position using arrow keys</i><br>The selection can be positioned up, down, left and right using the corresponding arrow keys." );
00111 return s;
00112 }
00113
00114 void
00115 VSelectTool::draw()
00116 {
00117 VPainter *painter = view()->painterFactory()->editpainter();
00118
00119 painter->setRasterOp( Qt::NotROP );
00120
00121 KoRect rect = view()->part()->document().selection()->boundingBox();
00122
00123 if( m_state != normal )
00124 {
00125 VObjectListIterator itr = m_objects;
00126 for( ; itr.current(); ++itr )
00127 {
00128 itr.current()->draw( painter, &itr.current()->boundingBox() );
00129 }
00130 }
00131 else if( m_state == normal )
00132 {
00133 painter->setPen( Qt::DotLine );
00134 painter->newPath();
00135 painter->moveTo( KoPoint( first().x(), first().y() ) );
00136 painter->lineTo( KoPoint( m_current.x(), first().y() ) );
00137 painter->lineTo( KoPoint( m_current.x(), m_current.y() ) );
00138 painter->lineTo( KoPoint( first().x(), m_current.y() ) );
00139 painter->lineTo( KoPoint( first().x(), first().y() ) );
00140 painter->strokePath();
00141
00142 m_state = normal;
00143 }
00144 }
00145
00146 void
00147 VSelectTool::setCursor() const
00148 {
00149 if( m_state != normal || !view() ) return;
00150 switch( view()->part()->document().selection()->handleNode( last() ) )
00151 {
00152 case node_lt:
00153 case node_rb:
00154 view()->setCursor( QCursor( Qt::SizeFDiagCursor ) );
00155 break;
00156 case node_rt:
00157 case node_lb:
00158 view()->setCursor( QCursor( Qt::SizeBDiagCursor ) );
00159 break;
00160 case node_lm:
00161 case node_rm:
00162 view()->setCursor( QCursor( Qt::SizeHorCursor ) );
00163 break;
00164 case node_mt:
00165 case node_mb:
00166 view()->setCursor( QCursor( Qt::SizeVerCursor ) );
00167 break;
00168 default:
00169 view()->setCursor( QCursor( Qt::arrowCursor ) );
00170 }
00171 }
00172
00173 void
00174 VSelectTool::mouseButtonPress()
00175 {
00176
00177 m_add = true;
00178
00179 m_current = first();
00180
00181 m_activeNode = view()->part()->document().selection()->handleNode( first() );
00182 KoRect rect = view()->part()->document().selection()->boundingBox();
00183
00184 if( m_activeNode != node_none )
00185 m_state = scaling;
00186 else if( rect.contains( m_current ) && m_state == normal )
00187 m_state = moving;
00188
00189 recalc();
00190
00191
00192 view()->part()->document().selection()->setState( VObject::edit );
00193 view()->repaintAll( rect );
00194 view()->part()->document().selection()->setState( VObject::selected );
00195
00196 draw();
00197 }
00198
00199 void
00200 VSelectTool::rightMouseButtonPress()
00201 {
00202
00203 m_add = false;
00204
00205 m_current = first();
00206
00207 recalc();
00208
00209
00210 view()->part()->document().selection()->setState( VObject::edit );
00211 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00212 view()->part()->document().selection()->setState( VObject::selected );
00213
00214 draw();
00215 }
00216
00217 void
00218 VSelectTool::mouseDrag()
00219 {
00220 draw();
00221
00222 recalc();
00223
00224 draw();
00225 }
00226
00227 void
00228 VSelectTool::rightMouseButtonRelease()
00229 {
00230 m_state = normal;
00231 m_add = true;
00232
00233 if( ctrlPressed() )
00234 {
00235
00236 VObjectList newSelection;
00237 VSelectObjects selector( newSelection, first() );
00238 if( selector.visit( view()->part()->document() ) )
00239 view()->part()->document().selection()->take( *newSelection.last() );
00240
00241 view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() );
00242 view()->selectionChanged();
00243
00244 updateStatusBar();
00245 }
00246 else if( view()->part()->document().selection()->objects().count() > 0 )
00247 {
00248 view()->showSelectionPopupMenu( QCursor::pos() );
00249 }
00250 }
00251
00252 void
00253 VSelectTool::mouseButtonRelease()
00254 {
00255 m_state = normal;
00256 m_add = true;
00257
00258
00259 if( shiftPressed() )
00260 {
00261 VObjectList newSelection;
00262 VObjectList oldSelection = view()->part()->document().selection()->objects();
00263
00264
00265 if( ! ctrlPressed() )
00266 view()->part()->document().selection()->clear();
00267
00268
00269 VSelectObjects selector( newSelection, first(), true, true );
00270 if( selector.visit( view()->part()->document() ) )
00271 {
00272
00273 VObject *lastMatched = 0L;
00274 VObjectListIterator it( newSelection );
00275 for( ; it.current(); ++it )
00276 {
00277 if( oldSelection.contains( it.current() ) )
00278 lastMatched = it.current();
00279 }
00280
00281
00282
00283
00284 if( lastMatched && lastMatched != newSelection.first() )
00285 view()->part()->document().selection()->append( newSelection.at( newSelection.find( lastMatched )-1 ) );
00286 else
00287 view()->part()->document().selection()->append( newSelection.last() );
00288 }
00289 }
00290 else
00291 {
00292
00293 if( ! ctrlPressed() )
00294 view()->part()->document().selection()->clear();
00295
00296
00297 VObjectList newSelection;
00298 VSelectObjects selector( newSelection, first() );
00299 if( selector.visit( view()->part()->document() ) )
00300 view()->part()->document().selection()->append( newSelection.last() );
00301 }
00302
00303 view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() );
00304 view()->selectionChanged();
00305
00306 updateStatusBar();
00307 }
00308
00309 void
00310 VSelectTool::mouseDragRelease()
00311 {
00312 if( m_state == normal )
00313 {
00314
00315 KoPoint fp = first();
00316 KoPoint lp = last();
00317 if( ! ctrlPressed() )
00318 view()->part()->document().selection()->clear();
00319
00320 KoRect selRect = KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize();
00321 if( m_add )
00322 view()->part()->document().selection()->append( selRect );
00323 else
00324 view()->part()->document().selection()->take( selRect );
00325 view()->part()->repaintAllViews( selRect );
00326 }
00327 else if( m_state == moving )
00328 {
00329 m_state = normal;
00330 recalc();
00331 if( m_lock )
00332 view()->part()->addCommand(
00333 new VTranslateCmd(
00334 &view()->part()->document(),
00335 abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? qRound( m_distx ) : 0,
00336 abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? qRound( m_disty ) : 0, altPressed() ),
00337 true );
00338 else
00339 view()->part()->addCommand(
00340 new VTranslateCmd( &view()->part()->document(), qRound( m_distx ), qRound( m_disty ), altPressed() ),
00341 true );
00342 }
00343 else if( m_state == scaling )
00344 {
00345 m_state = normal;
00346 view()->part()->addCommand(
00347 new VScaleCmd( &view()->part()->document(), m_sp, m_s1, m_s2, altPressed() ),
00348 true );
00349 m_s1 = m_s2 = 1;
00350 }
00351
00352 view()->selectionChanged();
00353 m_lock = false;
00354 updateStatusBar();
00355 }
00356
00357 void
00358 VSelectTool::arrowKeyReleased( Qt::Key key )
00359 {
00360 int dx = 0;
00361 int dy = 0;
00362 switch( key )
00363 {
00364 case Qt::Key_Up: dy = 10; break;
00365 case Qt::Key_Down: dy = -10; break;
00366 case Qt::Key_Right: dx = 10; break;
00367 case Qt::Key_Left: dx = -10; break;
00368 default: return;
00369 }
00370 m_state = normal;
00371 view()->part()->addCommand(
00372 new VTranslateCmd(
00373 &view()->part()->document(),
00374 dx, dy ),
00375 true );
00376 view()->selectionChanged();
00377 updateStatusBar();
00378 }
00379
00380 bool
00381 VSelectTool::keyReleased( Qt::Key key )
00382 {
00383
00384 VSelection* selection = view()->part()->document().selection();
00385
00386 switch( key )
00387 {
00388
00389 case Qt::Key_I:
00390 {
00391 uint handleSize = selection->handleSize();
00392 if( shiftPressed() )
00393 selection->setHandleSize( ++handleSize );
00394 else if( handleSize > 1 )
00395 selection->setHandleSize( --handleSize );
00396 }
00397 break;
00398 default: return false;
00399 }
00400
00401 if( view() )
00402 view()->repaintAll( selection->boundingBox() );
00403
00404 return true;
00405 }
00406
00407 void
00408 VSelectTool::updateStatusBar() const
00409 {
00410 if( ! view() )
00411 return;
00412
00413 if( ! view()->part() )
00414 return;
00415
00416 int objcount = view()->part()->document().selection()->objects().count();
00417 if( objcount > 0 )
00418 {
00419 KoRect rect = view()->part()->document().selection()->boundingBox();
00420
00421 double x = KoUnit::toUserValue( rect.x(), view()->part()->unit() );
00422 double y = KoUnit::toUserValue( rect.y(), view()->part()->unit() );
00423 double r = KoUnit::toUserValue( rect.right(), view()->part()->unit() );
00424 double b = KoUnit::toUserValue( rect.bottom(), view()->part()->unit() );
00425
00426
00427 QString selectMessage = i18n( "[(left,bottom), (right,top)] (actual unit)", "Selection [(%1, %2), (%3, %4)] (%5)").arg( x, 0, 'f', 1 ).arg( y, 0, 'f', 1 ).arg( r, 0, 'f', 1 ).arg( b, 0, 'f', 1 ).arg( view()->part()->unitName() );
00428
00429 VSelectionDescription selectionDesc;
00430 selectionDesc.visit( *view()->part()->document().selection() );
00431 selectMessage += QString( "(%1)" ).arg( selectionDesc.description() );
00432
00433 view()->statusMessage()->setText( selectMessage );
00434 }
00435 else
00436 view()->statusMessage()->setText( i18n( "No selection" ) );
00437 }
00438
00439 void
00440 VSelectTool::mouseDragCtrlPressed()
00441 {
00442 m_lock = true;
00443 }
00444
00445 void
00446 VSelectTool::mouseDragCtrlReleased()
00447 {
00448 m_lock = false;
00449 }
00450
00451 void
00452 VSelectTool::mouseDragShiftPressed()
00453 {
00454 draw();
00455
00456 recalc();
00457
00458 draw();
00459 }
00460
00461 void
00462 VSelectTool::mouseDragShiftReleased()
00463 {
00464 draw();
00465
00466 recalc();
00467
00468 draw();
00469 }
00470
00471 void
00472 VSelectTool::cancel()
00473 {
00474
00475 if ( isDragging() )
00476 {
00477 draw();
00478 m_state = normal;
00479 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00480 }
00481 }
00482
00483 void
00484 VSelectTool::recalc()
00485 {
00486 if( m_state == normal )
00487 {
00488 m_current = last();
00489 }
00490 else
00491 {
00492 VTransformCmd* cmd;
00493 KoPoint _first = view()->canvasWidget()->snapToGrid( first() );
00494 KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
00495 KoRect rect = view()->part()->document().selection()->boundingBox();
00496
00497 if( m_state == moving )
00498 {
00499 KoPoint p( rect.x() + last().x() - first().x(), rect.bottom() + last().y() - first().y() );
00500 p = view()->canvasWidget()->snapToGrid( p );
00501 m_distx = p.x() - rect.x();
00502 m_disty = p.y() - rect.bottom();
00503 if( m_lock )
00504 cmd = new VTranslateCmd( 0L, abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? m_distx : 0,
00505 abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? m_disty : 0 );
00506 else
00507 cmd = new VTranslateCmd( 0L, m_distx, m_disty );
00508 }
00509 else
00510 {
00511 if( m_activeNode == node_lb )
00512 {
00513 m_sp = KoPoint( rect.right(), rect.bottom() );
00514 m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
00515 m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
00516 }
00517 else if( m_activeNode == node_mb )
00518 {
00519 m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.bottom() );
00520 m_s1 = 1;
00521 m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
00522 }
00523 else if( m_activeNode == node_rb )
00524 {
00525 m_sp = KoPoint( rect.x(), rect.bottom() );
00526 m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
00527 m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
00528 }
00529 else if( m_activeNode == node_rm)
00530 {
00531 m_sp = KoPoint( rect.x(), ( rect.bottom() + rect.top() ) / 2 );
00532 m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
00533 m_s2 = 1;
00534 }
00535 else if( m_activeNode == node_rt )
00536 {
00537 m_sp = KoPoint( rect.x(), rect.y() );
00538 m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
00539 m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
00540 }
00541 else if( m_activeNode == node_mt )
00542 {
00543 m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.y() );
00544 m_s1 = 1;
00545 m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
00546 }
00547 else if( m_activeNode == node_lt )
00548 {
00549 m_sp = KoPoint( rect.right(), rect.y() );
00550 m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
00551 m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
00552 }
00553 else if( m_activeNode == node_lm )
00554 {
00555 m_sp = KoPoint( rect.right(), ( rect.bottom() + rect.top() ) / 2 );
00556 m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
00557 m_s2 = 1;
00558 }
00559
00560 if( shiftPressed() )
00561 m_s1 = m_s2 = kMax( m_s1, m_s2 );
00562 cmd = new VScaleCmd( 0L, m_sp, m_s1, m_s2 );
00563 }
00564
00565
00566 m_objects.clear();
00567 VObject* copy;
00568
00569 VObjectListIterator itr = view()->part()->document().selection()->objects();
00570 for( ; itr.current() ; ++itr )
00571 {
00572 if( itr.current()->state() != VObject::deleted )
00573 {
00574 copy = itr.current()->clone();
00575 copy->setState( VObject::edit );
00576
00577 cmd->visit( *copy );
00578
00579 m_objects.append( copy );
00580 }
00581 }
00582
00583 delete( cmd );
00584 }
00585 }
00586
00587 bool
00588 VSelectTool::showDialog() const
00589 {
00590 return m_optionsWidget->exec() == QDialog::Accepted;
00591 }
00592
00593 void
00594 VSelectTool::refreshUnit()
00595 {
00596 updateStatusBar();
00597 }
00598
00599 void
00600 VSelectTool::setup( KActionCollection *collection )
00601 {
00602 m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
00603
00604 if( m_action == 0 )
00605 {
00606 m_action = new KRadioAction( i18n( "Select Tool" ), "14_select", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() );
00607 m_action->setToolTip( i18n( "Select" ) );
00608 m_action->setExclusiveGroup( "select" );
00609
00610 }
00611 }
00612
00613 #include "vselecttool.moc"