/* This file is part of the KDE project Copyright (C) 2002, The Karbon Developers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vselectnodestool.h" #include #include #include #include VSelectNodesTool::VSelectNodesTool( KarbonView* view ) : VTool( view, "tool_select_nodes" ), m_state( normal ), m_select( true ) { registerTool( this ); } VSelectNodesTool::~VSelectNodesTool() { } void VSelectNodesTool::activate() { if( view() ) { view()->setCursor( VCursor::needleArrow() ); view()->part()->document().selection()->showHandle( false ); view()->part()->document().selection()->setSelectObjects( false ); // deselect all nodes view()->part()->document().selection()->selectNodes( false ); view()->repaintAll( view()->part()->document().selection()->boundingBox() ); } VTool::activate(); } QString VSelectNodesTool::statusText() { if( m_state == normal ) return i18n( "Editing Nodes" ); else return QString( "" ); } void VSelectNodesTool::draw() { VPainter *painter = view()->painterFactory()->editpainter(); painter->setZoomFactor( view()->zoom() ); painter->setRasterOp( Qt::NotROP ); if( m_state == dragging ) { painter->setPen( Qt::DotLine ); painter->newPath(); painter->moveTo( KoPoint( m_first.x(), m_first.y() ) ); painter->lineTo( KoPoint( m_current.x(), m_first.y() ) ); painter->lineTo( KoPoint( m_current.x(), m_current.y() ) ); painter->lineTo( KoPoint( m_first.x(), m_current.y() ) ); painter->lineTo( KoPoint( m_first.x(), m_first.y() ) ); painter->strokePath(); } else { VDrawSelection op( m_objects, painter, true, VSelection::handleSize() ); VObjectListIterator itr = m_objects; for( ; itr.current(); ++itr ) op.visit( *( itr.current() ) ); } } void VSelectNodesTool::setCursor() const { if( m_state >= moving ) { view()->setCursor( VCursor::needleMoveArrow() ); return; } KoRect selrect = calcSelRect( last() ); QPtrList segments = view()->part()->document().selection()->getSegments( selrect ); if( segments.count() > 0 ) { VSegment* seg = segments.at( 0 ); for( int i = 0; i < seg->degree(); ++i ) if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) ) { view()->setCursor( VCursor::needleMoveArrow() ); break; } } else view()->setCursor( VCursor::needleArrow() ); } void VSelectNodesTool::mouseButtonPress() { m_first = m_current = first(); m_state = normal; m_select = true; recalc(); view()->part()->document().selection()->setState( VObject::edit ); view()->repaintAll( view()->part()->document().selection()->boundingBox() ); view()->part()->document().selection()->setState( VObject::selected ); VSelection* selection = view()->part()->document().selection(); KoRect selrect = calcSelRect( m_current ); // get segments with control points inside selection rect QPtrList segments = selection->getSegments( selrect ); if( segments.count() > 0 ) { VSegment *seg = segments.at( 0 ); VSegment* prev = seg->prev(); VSegment* next = seg->next(); // allow moving bezier points only if one of the bezier points is within the selection rect // and no neighboring knot is selected if( segments.count() == 1 && ! selrect.contains( seg->knot() ) && ! seg->knotIsSelected() && ( prev && ! prev->knotIsSelected() ) ) { if( selrect.contains( seg->point( 1 ) ) ) { m_state = movingbezier1; if( next ) next->selectPoint( 0, false ); } else if( selrect.contains( seg->point( 0 ) ) ) { m_state = movingbezier2; if( prev ) prev->selectPoint( 1, false ); } } else { for( VSegment *seg = segments.first(); seg; seg = segments.next() ) { for( int i = 0; i < seg->degree(); ++i ) { if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) ) { m_state = moving; break; } } if( m_state == moving ) break; } } double minDist = -1.0; // use the nearest control point of all the segments as starting point for( VSegment *seg = segments.first(); seg; seg = segments.next() ) { for( int i = 0; i < seg->degree(); ++i ) { if( selrect.contains( seg->point( i ) ) ) { KoPoint vDist = seg->point( i ) - m_current; double dist = vDist.x()*vDist.x() + vDist.y()*vDist.y(); if( minDist < 0.0 || dist < minDist ) { m_first = seg->point( i ); minDist = dist; } } } } recalc(); } else m_state = dragging; draw(); } void VSelectNodesTool::rightMouseButtonPress() { m_first = m_current = first(); m_state = normal; m_select = false; recalc(); view()->part()->document().selection()->setState( VObject::edit ); view()->repaintAll( view()->part()->document().selection()->boundingBox() ); view()->part()->document().selection()->setState( VObject::selected ); draw(); } bool VSelectNodesTool::keyReleased( Qt::Key key ) { VSelection* selection = view()->part()->document().selection(); switch( key ) { // increase/decrease the handle size case Qt::Key_I: { uint handleSize = selection->handleSize(); if( shiftPressed() ) selection->setHandleSize( ++handleSize ); else if( handleSize > 1 ) selection->setHandleSize( --handleSize ); } break; case Qt::Key_Delete: if( selection->objects().count() > 0 ) view()->part()->addCommand( new VDeleteNodeCmd( &view()->part()->document() ), true ); break; default: return false; } if( view() ) view()->repaintAll( selection->boundingBox() ); return true; } void VSelectNodesTool::mouseButtonRelease() { // erase old object: draw(); VSelection* selection = view()->part()->document().selection(); KoRect selrect = calcSelRect( last() ); if( ctrlPressed() ) selection->append( selrect.normalize(), false, false ); else selection->append( selrect.normalize(), false, true ); view()->selectionChanged(); view()->part()->repaintAllViews(); m_state = normal; } void VSelectNodesTool::rightMouseButtonRelease() { // erase old object: draw(); VSelection* selection = view()->part()->document().selection(); KoRect selrect = calcSelRect( last() ); selection->take( selrect.normalize(), false, false ); view()->selectionChanged(); view()->part()->repaintAllViews(); m_state = normal; } void VSelectNodesTool::mouseDrag() { draw(); recalc(); draw(); } void VSelectNodesTool::mouseDragRelease() { if( m_state >= moving ) { view()->part()->document().selection()->setState( VObject::selected ); VCommand *cmd; QPtrList segments; KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); if( m_state == movingbezier1 || m_state == movingbezier2 ) { KoRect selrect = calcSelRect( m_first ); segments = view()->part()->document().selection()->getSegments( selrect ); cmd = new VTranslateBezierCmd( &view()->part()->document(), segments.at( 0 ), qRound( ( _last.x() - m_first.x() ) ), qRound( ( _last.y() - m_first.y() ) ), m_state == movingbezier2 ); } else { cmd = new VTranslatePointCmd( &view()->part()->document(), qRound( ( _last.x() - m_first.x() ) ), qRound( ( _last.y() - m_first.y() ) ) ); } view()->part()->addCommand( cmd, true ); m_state = normal; } else { KoPoint fp = m_first; KoPoint lp = last(); if ( (fabs(lp.x() - fp.x()) + fabs(lp.y()-fp.y())) < 3.0 ) { // AK - should take the middle point here fp = last() - KoPoint(8.0, 8.0); lp = last() + KoPoint(8.0, 8.0); } // erase old object: draw(); if( m_select ) { view()->part()->document().selection()->append(); // select all view()->part()->document().selection()->append( KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(), false, true ); } else { view()->part()->document().selection()->take( KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(), false, false ); } view()->selectionChanged(); view()->part()->repaintAllViews(); m_state = normal; } } void VSelectNodesTool::cancel() { // Erase old object: if ( isDragging() ) { draw(); m_state = normal; view()->repaintAll( view()->part()->document().selection()->boundingBox() ); } } void VSelectNodesTool::recalc() { if( m_state == dragging ) { m_current = last(); } else if( m_state == moving || m_state == movingbezier1 || m_state == movingbezier2 ) { KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); double distx = _last.x() - m_first.x(); double disty = _last.y() - m_first.y(); // move operation QWMatrix mat; mat.translate( distx, disty ); // Copy selected objects and transform: m_objects.clear(); VObject* copy; VTransformNodes op( mat ); VObjectListIterator itr = view()->part()->document().selection()->objects(); for ( ; itr.current() ; ++itr ) { if( itr.current()->state() != VObject::deleted ) { copy = itr.current()->clone(); copy->setState( VObject::edit ); op.visit( *copy ); m_objects.append( copy ); } } } } void VSelectNodesTool::setup( KActionCollection *collection ) { m_action = static_cast(collection -> action( name() ) ); if( m_action == 0 ) { m_action = new KRadioAction( i18n( "Select Nodes Tool" ), "14_selectnodes", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); m_action->setToolTip( i18n( "Select Nodes" ) ); m_action->setExclusiveGroup( "select" ); //m_ownAction = true; } } KoRect VSelectNodesTool::calcSelRect( const KoPoint &pos ) const { double tolerance = view()->part()->document().selection()->handleSize() / view()->zoom(); return KoRect( pos.x() - tolerance, pos.y() - tolerance, 2 * tolerance + 1.0, 2 * tolerance + 1.0 ); }