karbon

vselectnodestool.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002, The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <math.h>
00021 
00022 #include <qcursor.h>
00023 #include <qlabel.h>
00024 
00025 #include <klocale.h>
00026 #include <KoPoint.h>
00027 #include <KoRect.h>
00028 
00029 #include <karbon_part.h>
00030 #include <karbon_view.h>
00031 
00032 #include <render/vpainter.h>
00033 #include <render/vpainterfactory.h>
00034 #include <visitors/vselectnodes.h>
00035 #include <commands/vtransformcmd.h>
00036 #include <visitors/vdrawselection.h>
00037 #include <core/vselection.h>
00038 #include <core/vcursor.h>
00039 #include "vselectnodestool.h"
00040 #include <vtransformnodes.h>
00041 #include <commands/vdeletenodescmd.h>
00042 #include <widgets/vcanvas.h>
00043 
00044 #include <kdebug.h>
00045 
00046 VSelectNodesTool::VSelectNodesTool( KarbonView* view )
00047     : VTool( view, "tool_select_nodes" ), m_state( normal ), m_select( true )
00048 {
00049     registerTool( this );
00050 }
00051 
00052 VSelectNodesTool::~VSelectNodesTool()
00053 {
00054 }
00055 
00056 void
00057 VSelectNodesTool::activate()
00058 {
00059     if( view() )
00060     {
00061         view()->setCursor( VCursor::needleArrow() );
00062         view()->part()->document().selection()->showHandle( false );
00063         view()->part()->document().selection()->setSelectObjects( false );
00064         // deselect all nodes
00065         view()->part()->document().selection()->selectNodes( false );
00066         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00067     }
00068     VTool::activate();
00069 }
00070 
00071 QString
00072 VSelectNodesTool::statusText()
00073 {
00074     if( m_state == normal )
00075         return i18n( "Editing Nodes" );
00076     else
00077         return QString( "" );
00078 }
00079 
00080 void
00081 VSelectNodesTool::draw()
00082 {
00083     VPainter *painter = view()->painterFactory()->editpainter();
00084     painter->setZoomFactor( view()->zoom() );
00085     painter->setRasterOp( Qt::NotROP );
00086 
00087     if( m_state == dragging )
00088     {
00089         painter->setPen( Qt::DotLine );
00090         painter->newPath();
00091         painter->moveTo( KoPoint( m_first.x(), m_first.y() ) );
00092         painter->lineTo( KoPoint( m_current.x(), m_first.y() ) );
00093         painter->lineTo( KoPoint( m_current.x(), m_current.y() ) );
00094         painter->lineTo( KoPoint( m_first.x(), m_current.y() ) );
00095         painter->lineTo( KoPoint( m_first.x(), m_first.y() ) );
00096         painter->strokePath();
00097     }
00098     else
00099     {
00100         VDrawSelection op( m_objects, painter, true, VSelection::handleSize() );
00101         VObjectListIterator itr = m_objects;
00102         for( ; itr.current(); ++itr )
00103             op.visit( *( itr.current() ) );
00104     }
00105 }
00106 
00107 void
00108 VSelectNodesTool::setCursor() const
00109 {
00110     if( m_state >= moving ) 
00111     {
00112         view()->setCursor( VCursor::needleMoveArrow() );
00113         return;
00114     }
00115 
00116     KoRect selrect = calcSelRect( last() );
00117 
00118     QPtrList<VSegment> segments = view()->part()->document().selection()->getSegments( selrect );
00119     if( segments.count() > 0  )
00120     {
00121         VSegment* seg = segments.at( 0 );
00122         for( int i = 0; i < seg->degree(); ++i )
00123             if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) )
00124             {
00125                 view()->setCursor( VCursor::needleMoveArrow() );
00126                 break;
00127             }
00128     }
00129     else
00130         view()->setCursor( VCursor::needleArrow() );
00131 }
00132 
00133 void
00134 VSelectNodesTool::mouseButtonPress()
00135 {
00136     m_first = m_current = first();
00137 
00138     m_state = normal;
00139     m_select = true;
00140 
00141     recalc();
00142 
00143     view()->part()->document().selection()->setState( VObject::edit );
00144     view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00145     view()->part()->document().selection()->setState( VObject::selected );
00146 
00147     VSelection* selection = view()->part()->document().selection();
00148 
00149     KoRect selrect = calcSelRect( m_current );
00150 
00151     // get segments with control points inside selection rect
00152     QPtrList<VSegment> segments = selection->getSegments( selrect );
00153     if( segments.count() > 0 )
00154     {
00155         VSegment *seg = segments.at( 0 );
00156         VSegment* prev = seg->prev();
00157         VSegment* next = seg->next();
00158 
00159         // allow moving bezier points only if one of the bezier points is within the selection rect
00160         // and no neighboring knot is selected
00161         if( segments.count() == 1 && ! selrect.contains( seg->knot() ) && ! seg->knotIsSelected() 
00162         && ( prev && ! prev->knotIsSelected() ) )
00163         {
00164             if( selrect.contains( seg->point( 1 ) ) )
00165             {
00166                 m_state = movingbezier1;
00167                 if( next )
00168                     next->selectPoint( 0, false );
00169             }
00170             else if( selrect.contains( seg->point( 0 ) ) )
00171             {
00172                 m_state = movingbezier2;
00173                 if( prev ) 
00174                     prev->selectPoint( 1, false );
00175             }
00176         }
00177         else
00178         {
00179             for( VSegment *seg = segments.first(); seg; seg = segments.next() )
00180             {
00181                 for( int i = 0; i < seg->degree(); ++i )
00182                 {
00183                     if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) )
00184                     {
00185                         m_state = moving;
00186                         break;
00187                     }
00188                 }
00189                 if( m_state == moving )
00190                     break;
00191             }
00192         }
00193 
00194         double minDist = -1.0;
00195         // use the nearest control point of all the segments as starting point
00196         for( VSegment *seg = segments.first(); seg; seg = segments.next() )
00197         {
00198             for( int i = 0; i < seg->degree(); ++i )
00199             {
00200                 if( selrect.contains( seg->point( i ) ) )
00201                 {
00202                     KoPoint vDist = seg->point( i ) - m_current;
00203                     double dist = vDist.x()*vDist.x() + vDist.y()*vDist.y();
00204                     if( minDist < 0.0 || dist < minDist )
00205                     {
00206                         m_first = seg->point( i );
00207                         minDist = dist;
00208                     }
00209                 }
00210             }
00211         }
00212         recalc();
00213     }
00214     else
00215         m_state = dragging;
00216 
00217     draw();
00218 }
00219 
00220 void 
00221 VSelectNodesTool::rightMouseButtonPress()
00222 {
00223     m_first = m_current = first();
00224 
00225     m_state = normal;
00226     m_select = false;
00227 
00228     recalc();
00229 
00230     view()->part()->document().selection()->setState( VObject::edit );
00231     view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00232     view()->part()->document().selection()->setState( VObject::selected );
00233 
00234     draw();
00235 }
00236 
00237 bool
00238 VSelectNodesTool::keyReleased( Qt::Key key )
00239 {
00240     VSelection* selection = view()->part()->document().selection();
00241 
00242     switch( key )
00243     {
00244         // increase/decrease the handle size
00245         case Qt::Key_I:
00246         {
00247             uint handleSize = selection->handleSize();
00248             if( shiftPressed() ) 
00249                 selection->setHandleSize( ++handleSize );
00250             else if( handleSize > 1 )
00251                 selection->setHandleSize( --handleSize );
00252         }
00253         break;
00254         case Qt::Key_Delete:
00255             if( selection->objects().count() > 0 )
00256                 view()->part()->addCommand( new VDeleteNodeCmd( &view()->part()->document() ), true );
00257         break;
00258         default: return false;
00259     }
00260 
00261     if( view() )
00262         view()->repaintAll( selection->boundingBox() );
00263 
00264     return true;
00265 }
00266 
00267 void
00268 VSelectNodesTool::mouseButtonRelease()
00269 {
00270     // erase old object:
00271     draw();
00272 
00273     VSelection* selection = view()->part()->document().selection();
00274 
00275     KoRect selrect = calcSelRect( last() );
00276 
00277     if( ctrlPressed() )
00278         selection->append( selrect.normalize(), false, false );
00279     else
00280         selection->append( selrect.normalize(), false, true );
00281 
00282     view()->selectionChanged();
00283     view()->part()->repaintAllViews();
00284     m_state = normal;
00285 }
00286 
00287 void 
00288 VSelectNodesTool::rightMouseButtonRelease()
00289 {
00290     // erase old object:
00291     draw();
00292 
00293     VSelection* selection = view()->part()->document().selection();
00294 
00295     KoRect selrect = calcSelRect( last() );
00296 
00297     selection->take( selrect.normalize(), false, false );
00298 
00299     view()->selectionChanged();
00300     view()->part()->repaintAllViews();
00301     m_state = normal;
00302 }
00303 
00304 void
00305 VSelectNodesTool::mouseDrag()
00306 {
00307     draw();
00308 
00309     recalc();
00310 
00311     draw();
00312 }
00313 
00314 void
00315 VSelectNodesTool::mouseDragRelease()
00316 {
00317     if( m_state >= moving )
00318     {
00319         view()->part()->document().selection()->setState( VObject::selected );
00320         VCommand *cmd;
00321         QPtrList<VSegment> segments;
00322         KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
00323         if( m_state == movingbezier1 || m_state == movingbezier2 )
00324         {
00325             KoRect selrect = calcSelRect( m_first );
00326             segments = view()->part()->document().selection()->getSegments( selrect );
00327             cmd = new VTranslateBezierCmd( &view()->part()->document(), segments.at( 0 ),
00328                     qRound( ( _last.x() - m_first.x() ) ),
00329                     qRound( ( _last.y() - m_first.y() ) ),
00330                     m_state == movingbezier2 );
00331         }
00332         else
00333         {
00334             cmd = new VTranslatePointCmd(
00335                     &view()->part()->document(),
00336                     qRound( ( _last.x() - m_first.x() ) ),
00337                     qRound( ( _last.y() - m_first.y() ) ) );
00338         }
00339         view()->part()->addCommand( cmd, true );
00340         m_state = normal;
00341     }
00342     else
00343     {
00344         KoPoint fp = m_first;
00345         KoPoint lp = last();
00346 
00347         if ( (fabs(lp.x() - fp.x()) + fabs(lp.y()-fp.y())) < 3.0 )
00348         {
00349             // AK - should take the middle point here
00350             fp = last() - KoPoint(8.0, 8.0);
00351             lp = last() + KoPoint(8.0, 8.0);
00352         }
00353 
00354         // erase old object:
00355         draw();
00356 
00357         if( m_select )
00358         {
00359             view()->part()->document().selection()->append();   // select all
00360             view()->part()->document().selection()->append(
00361                 KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(),
00362                 false, true );
00363         }
00364         else
00365         {
00366             view()->part()->document().selection()->take(
00367                 KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(),
00368                 false, false );
00369         }
00370         view()->selectionChanged();
00371         view()->part()->repaintAllViews();
00372         m_state = normal;
00373     }
00374 }
00375 
00376 void
00377 VSelectNodesTool::cancel()
00378 {
00379     // Erase old object:
00380     if ( isDragging() )
00381     {
00382         draw();
00383         m_state = normal;
00384         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00385     }
00386 }
00387 
00388 void
00389 VSelectNodesTool::recalc()
00390 {
00391     if( m_state == dragging )
00392     {
00393         m_current = last();
00394     }
00395     else if( m_state == moving || m_state == movingbezier1 || m_state == movingbezier2 )
00396     {
00397         KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
00398         double distx = _last.x() - m_first.x();
00399         double disty = _last.y() - m_first.y();
00400         // move operation
00401         QWMatrix mat;
00402         mat.translate( distx, disty );
00403 
00404         // Copy selected objects and transform:
00405         m_objects.clear();
00406         VObject* copy;
00407 
00408         VTransformNodes op( mat );
00409 
00410         VObjectListIterator itr = view()->part()->document().selection()->objects();
00411         for ( ; itr.current() ; ++itr )
00412         {
00413             if( itr.current()->state() != VObject::deleted )
00414             {
00415                 copy = itr.current()->clone();
00416                 copy->setState( VObject::edit );
00417                 op.visit( *copy );
00418                 m_objects.append( copy );
00419             }
00420         }
00421     }
00422 }
00423 
00424 void
00425 VSelectNodesTool::setup( KActionCollection *collection )
00426 {
00427     m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
00428 
00429     if( m_action == 0 )
00430     {
00431         m_action = new KRadioAction( i18n( "Select Nodes Tool" ), "14_selectnodes", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() );
00432         m_action->setToolTip( i18n( "Select Nodes" ) );
00433         m_action->setExclusiveGroup( "select" );
00434         //m_ownAction = true;
00435     }
00436 }
00437 
00438 KoRect 
00439 VSelectNodesTool::calcSelRect( const KoPoint &pos ) const
00440 {
00441     double tolerance = view()->part()->document().selection()->handleSize() / view()->zoom();
00442     return KoRect( pos.x() - tolerance, pos.y() - tolerance, 2 * tolerance + 1.0, 2 * tolerance + 1.0 );
00443 }
KDE Home | KDE Accessibility Home | Description of Access Keys