summaryrefslogtreecommitdiffstats
path: root/karbon/tools/vselecttool.cc
diff options
context:
space:
mode:
Diffstat (limited to 'karbon/tools/vselecttool.cc')
-rw-r--r--karbon/tools/vselecttool.cc613
1 files changed, 613 insertions, 0 deletions
diff --git a/karbon/tools/vselecttool.cc b/karbon/tools/vselecttool.cc
new file mode 100644
index 00000000..19338038
--- /dev/null
+++ b/karbon/tools/vselecttool.cc
@@ -0,0 +1,613 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001, 2002, 2003 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 <math.h>
+#include <stdlib.h>
+
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+
+#include <KoPoint.h>
+#include <KoRect.h>
+#include <kdebug.h>
+
+#include <karbon_part.h>
+#include <karbon_view.h>
+#include <render/vpainter.h>
+#include <render/vpainterfactory.h>
+#include <core/vselection.h>
+#include "vselecttool.h"
+#include <commands/vtransformcmd.h>
+#include <visitors/vselectiondesc.h>
+#include <visitors/vselectobjects.h>
+#include <widgets/vcanvas.h>
+
+VSelectOptionsWidget::VSelectOptionsWidget( KarbonPart *part )
+ : KDialogBase( 0L, "", true, i18n( "Selection" ), Ok | Cancel ), m_part( part )
+{
+ QButtonGroup *group = new QButtonGroup( 1, Qt::Horizontal, i18n( "Selection Mode" ), this );
+
+ new QRadioButton( i18n( "Select in current layer" ), group );
+ new QRadioButton( i18n( "Select in visible layers" ), group );
+ new QRadioButton( i18n( "Select in selected layers" ), group );
+
+ group->setRadioButtonExclusive( true );
+ group->setButton( part->document().selectionMode() );
+
+ connect( group, SIGNAL( clicked( int ) ), this, SLOT( modeChange( int ) ) );
+
+ group->setInsideMargin( 4 );
+ group->setInsideSpacing( 2 );
+
+ setMainWidget( group );
+ setFixedSize( baseSize() );
+} // VSelectOptionsWidget::VSelectOptionsWidget
+
+void VSelectOptionsWidget::modeChange( int mode )
+{
+ m_part->document().setSelectionMode( (VDocument::VSelectionMode)mode );
+} // VSelectOptionsWidget::modeChanged
+
+VSelectTool::VSelectTool( KarbonView *view )
+ : VTool( view, "tool_select" ), m_state( normal )
+{
+ m_lock = false;
+ m_add = true;
+ m_objects.setAutoDelete( true );
+ m_optionsWidget = new VSelectOptionsWidget( view->part() );
+ registerTool( this );
+ connect( view, SIGNAL( selectionChange() ), this, SLOT( updateStatusBar() ) );
+}
+
+VSelectTool::~VSelectTool()
+{
+ delete m_optionsWidget;
+}
+
+void
+VSelectTool::activate()
+{
+ VTool::activate();
+ view()->setCursor( QCursor( Qt::arrowCursor ) );
+ view()->part()->document().selection()->showHandle();
+ view()->part()->document().selection()->setSelectObjects();
+ view()->part()->document().selection()->setState( VObject::selected );
+ view()->part()->document().selection()->selectNodes();
+ view()->repaintAll( view()->part()->document().selection()->boundingBox() );
+ updateStatusBar();
+}
+
+QString
+VSelectTool::statusText()
+{
+ return i18n( "Select" );
+}
+
+QString VSelectTool::contextHelp()
+{
+ QString s = i18n( "<qt><b>Selection tool:</b><br>" );
+ s += i18n( "<i>Select in current layer:</i><br>The selection is made in the layer selected in the layers docker.<br><br>" );
+ s += i18n( "<i>Select in visible layers:</i><br>The selection is made in the visible layers (eye in the layers docker).<br><br>" );
+ s += i18n( "<i>Select in selected layers:</i><br>The selection is made in the checked layers in the layers docker.<br><br>" );
+ s += i18n( "<i>Position using arrow keys</i><br>The selection can be positioned up, down, left and right using the corresponding arrow keys." );
+ return s;
+} // VSelectTool::contextHelp
+
+void
+VSelectTool::draw()
+{
+ VPainter *painter = view()->painterFactory()->editpainter();
+ //painter->setZoomFactor( view()->zoom() );
+ painter->setRasterOp( Qt::NotROP );
+
+ KoRect rect = view()->part()->document().selection()->boundingBox();
+
+ if( m_state != normal )
+ {
+ VObjectListIterator itr = m_objects;
+ for( ; itr.current(); ++itr )
+ {
+ itr.current()->draw( painter, &itr.current()->boundingBox() );
+ }
+ }
+ else if( m_state == normal )
+ {
+ painter->setPen( Qt::DotLine );
+ painter->newPath();
+ painter->moveTo( KoPoint( first().x(), first().y() ) );
+ painter->lineTo( KoPoint( m_current.x(), first().y() ) );
+ painter->lineTo( KoPoint( m_current.x(), m_current.y() ) );
+ painter->lineTo( KoPoint( first().x(), m_current.y() ) );
+ painter->lineTo( KoPoint( first().x(), first().y() ) );
+ painter->strokePath();
+
+ m_state = normal;
+ }
+}
+
+void
+VSelectTool::setCursor() const
+{
+ if( m_state != normal || !view() ) return;
+ switch( view()->part()->document().selection()->handleNode( last() ) )
+ {
+ case node_lt:
+ case node_rb:
+ view()->setCursor( QCursor( Qt::SizeFDiagCursor ) );
+ break;
+ case node_rt:
+ case node_lb:
+ view()->setCursor( QCursor( Qt::SizeBDiagCursor ) );
+ break;
+ case node_lm:
+ case node_rm:
+ view()->setCursor( QCursor( Qt::SizeHorCursor ) );
+ break;
+ case node_mt:
+ case node_mb:
+ view()->setCursor( QCursor( Qt::SizeVerCursor ) );
+ break;
+ default:
+ view()->setCursor( QCursor( Qt::arrowCursor ) );
+ }
+}
+
+void
+VSelectTool::mouseButtonPress()
+{
+ // we are adding to the selection
+ m_add = true;
+
+ m_current = first();
+
+ m_activeNode = view()->part()->document().selection()->handleNode( first() );
+ KoRect rect = view()->part()->document().selection()->boundingBox();
+
+ if( m_activeNode != node_none )
+ m_state = scaling;
+ else if( rect.contains( m_current ) && m_state == normal )
+ m_state = moving;
+
+ recalc();
+
+ // undraw selection bounding box
+ view()->part()->document().selection()->setState( VObject::edit );
+ view()->repaintAll( rect );
+ view()->part()->document().selection()->setState( VObject::selected );
+
+ draw();
+}
+
+void
+VSelectTool::rightMouseButtonPress()
+{
+ // we are removing from the selection
+ m_add = false;
+
+ m_current = first();
+
+ recalc();
+
+ // undraw selection bounding box
+ view()->part()->document().selection()->setState( VObject::edit );
+ view()->repaintAll( view()->part()->document().selection()->boundingBox() );
+ view()->part()->document().selection()->setState( VObject::selected );
+
+ draw();
+}
+
+void
+VSelectTool::mouseDrag()
+{
+ draw();
+
+ recalc();
+
+ draw();
+}
+
+void
+VSelectTool::rightMouseButtonRelease()
+{
+ m_state = normal;
+ m_add = true;
+
+ if( ctrlPressed() )
+ {
+ // unselect the topmost object under the mouse cursor
+ VObjectList newSelection;
+ VSelectObjects selector( newSelection, first() );
+ if( selector.visit( view()->part()->document() ) )
+ view()->part()->document().selection()->take( *newSelection.last() );
+
+ view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() );
+ view()->selectionChanged();
+
+ updateStatusBar();
+ }
+ else if( view()->part()->document().selection()->objects().count() > 0 )
+ {
+ view()->showSelectionPopupMenu( QCursor::pos() );
+ }
+}
+
+void
+VSelectTool::mouseButtonRelease()
+{
+ m_state = normal;
+ m_add = true;
+
+ // selection of next underlying object
+ if( shiftPressed() )
+ {
+ VObjectList newSelection;
+ VObjectList oldSelection = view()->part()->document().selection()->objects();
+
+ // clear selection if not in multi-slection-mode
+ if( ! ctrlPressed() )
+ view()->part()->document().selection()->clear();
+
+ // get a list of all object under the mouse cursor
+ VSelectObjects selector( newSelection, first(), true, true );
+ if( selector.visit( view()->part()->document() ) )
+ {
+ // determine the last selected object of the object stack
+ VObject *lastMatched = 0L;
+ VObjectListIterator it( newSelection );
+ for( ; it.current(); ++it )
+ {
+ if( oldSelection.contains( it.current() ) )
+ lastMatched = it.current();
+ }
+
+ // select the next underlying object or the first if:
+ // - none is selected
+ // - the stack's bottom object was the last selected object
+ if( lastMatched && lastMatched != newSelection.first() )
+ view()->part()->document().selection()->append( newSelection.at( newSelection.find( lastMatched )-1 ) );
+ else
+ view()->part()->document().selection()->append( newSelection.last() );
+ }
+ }
+ else
+ {
+ // clear selection if not in multi-slection-mode
+ if( ! ctrlPressed() )
+ view()->part()->document().selection()->clear();
+
+ // append the topmost object under the mouse cursor to the selection
+ VObjectList newSelection;
+ VSelectObjects selector( newSelection, first() );
+ if( selector.visit( view()->part()->document() ) )
+ view()->part()->document().selection()->append( newSelection.last() );
+ }
+
+ view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() );
+ view()->selectionChanged();
+
+ updateStatusBar();
+}
+
+void
+VSelectTool::mouseDragRelease()
+{
+ if( m_state == normal )
+ {
+ // Y mirroring
+ KoPoint fp = first();
+ KoPoint lp = last();
+ if( ! ctrlPressed() )
+ view()->part()->document().selection()->clear();
+
+ KoRect selRect = KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize();
+ if( m_add )
+ view()->part()->document().selection()->append( selRect );
+ else
+ view()->part()->document().selection()->take( selRect );
+ view()->part()->repaintAllViews( selRect );
+ }
+ else if( m_state == moving )
+ {
+ m_state = normal;
+ recalc();
+ if( m_lock )
+ view()->part()->addCommand(
+ new VTranslateCmd(
+ &view()->part()->document(),
+ abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? qRound( m_distx ) : 0,
+ abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? qRound( m_disty ) : 0, altPressed() ),
+ true );
+ else
+ view()->part()->addCommand(
+ new VTranslateCmd( &view()->part()->document(), qRound( m_distx ), qRound( m_disty ), altPressed() ),
+ true );
+ }
+ else if( m_state == scaling )
+ {
+ m_state = normal;
+ view()->part()->addCommand(
+ new VScaleCmd( &view()->part()->document(), m_sp, m_s1, m_s2, altPressed() ),
+ true );
+ m_s1 = m_s2 = 1;
+ }
+
+ view()->selectionChanged();
+ m_lock = false;
+ updateStatusBar();
+}
+
+void
+VSelectTool::arrowKeyReleased( Qt::Key key )
+{
+ int dx = 0;
+ int dy = 0;
+ switch( key )
+ {
+ case Qt::Key_Up: dy = 10; break;
+ case Qt::Key_Down: dy = -10; break;
+ case Qt::Key_Right: dx = 10; break;
+ case Qt::Key_Left: dx = -10; break;
+ default: return;
+ }
+ m_state = normal;
+ view()->part()->addCommand(
+ new VTranslateCmd(
+ &view()->part()->document(),
+ dx, dy ),
+ true );
+ view()->selectionChanged();
+ updateStatusBar();
+}
+
+bool
+VSelectTool::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;
+ default: return false;
+ }
+
+ if( view() )
+ view()->repaintAll( selection->boundingBox() );
+
+ return true;
+}
+
+void
+VSelectTool::updateStatusBar() const
+{
+ if( ! view() )
+ return;
+
+ if( ! view()->part() )
+ return;
+
+ int objcount = view()->part()->document().selection()->objects().count();
+ if( objcount > 0 )
+ {
+ KoRect rect = view()->part()->document().selection()->boundingBox();
+
+ double x = KoUnit::toUserValue( rect.x(), view()->part()->unit() );
+ double y = KoUnit::toUserValue( rect.y(), view()->part()->unit() );
+ double r = KoUnit::toUserValue( rect.right(), view()->part()->unit() );
+ double b = KoUnit::toUserValue( rect.bottom(), view()->part()->unit() );
+
+ // print bottom-left (%1,%2), top-right (%3,%4) corner of selection bounding box and document unit (%5)
+ 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() );
+
+ VSelectionDescription selectionDesc;
+ selectionDesc.visit( *view()->part()->document().selection() );
+ selectMessage += QString( "(%1)" ).arg( selectionDesc.description() );
+
+ view()->statusMessage()->setText( selectMessage );
+ }
+ else
+ view()->statusMessage()->setText( i18n( "No selection" ) );
+}
+
+void
+VSelectTool::mouseDragCtrlPressed()
+{
+ m_lock = true;
+}
+
+void
+VSelectTool::mouseDragCtrlReleased()
+{
+ m_lock = false;
+}
+
+void
+VSelectTool::mouseDragShiftPressed()
+{
+ draw();
+
+ recalc();
+
+ draw();
+}
+
+void
+VSelectTool::mouseDragShiftReleased()
+{
+ draw();
+
+ recalc();
+
+ draw();
+}
+
+void
+VSelectTool::cancel()
+{
+ // Erase old object:
+ if ( isDragging() )
+ {
+ draw();
+ m_state = normal;
+ view()->repaintAll( view()->part()->document().selection()->boundingBox() );
+ }
+}
+
+void
+VSelectTool::recalc()
+{
+ if( m_state == normal )
+ {
+ m_current = last();
+ }
+ else
+ {
+ VTransformCmd* cmd;
+ KoPoint _first = view()->canvasWidget()->snapToGrid( first() );
+ KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
+ KoRect rect = view()->part()->document().selection()->boundingBox();
+
+ if( m_state == moving )
+ {
+ KoPoint p( rect.x() + last().x() - first().x(), rect.bottom() + last().y() - first().y() );
+ p = view()->canvasWidget()->snapToGrid( p );
+ m_distx = p.x() - rect.x();
+ m_disty = p.y() - rect.bottom();
+ if( m_lock )
+ cmd = new VTranslateCmd( 0L, abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? m_distx : 0,
+ abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? m_disty : 0 );
+ else
+ cmd = new VTranslateCmd( 0L, m_distx, m_disty );
+ }
+ else
+ {
+ if( m_activeNode == node_lb )
+ {
+ m_sp = KoPoint( rect.right(), rect.bottom() );
+ m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
+ m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
+ }
+ else if( m_activeNode == node_mb )
+ {
+ m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.bottom() );
+ m_s1 = 1;
+ m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
+ }
+ else if( m_activeNode == node_rb )
+ {
+ m_sp = KoPoint( rect.x(), rect.bottom() );
+ m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
+ m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
+ }
+ else if( m_activeNode == node_rm)
+ {
+ m_sp = KoPoint( rect.x(), ( rect.bottom() + rect.top() ) / 2 );
+ m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
+ m_s2 = 1;
+ }
+ else if( m_activeNode == node_rt )
+ {
+ m_sp = KoPoint( rect.x(), rect.y() );
+ m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
+ m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
+ }
+ else if( m_activeNode == node_mt )
+ {
+ m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.y() );
+ m_s1 = 1;
+ m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
+ }
+ else if( m_activeNode == node_lt )
+ {
+ m_sp = KoPoint( rect.right(), rect.y() );
+ m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
+ m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
+ }
+ else if( m_activeNode == node_lm )
+ {
+ m_sp = KoPoint( rect.right(), ( rect.bottom() + rect.top() ) / 2 );
+ m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
+ m_s2 = 1;
+ }
+
+ if( shiftPressed() )
+ m_s1 = m_s2 = kMax( m_s1, m_s2 );
+ cmd = new VScaleCmd( 0L, m_sp, m_s1, m_s2 );
+ }
+
+ // Copy selected objects and transform:
+ m_objects.clear();
+ VObject* copy;
+
+ 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 );
+
+ cmd->visit( *copy );
+
+ m_objects.append( copy );
+ }
+ }
+
+ delete( cmd );
+ }
+}
+
+bool
+VSelectTool::showDialog() const
+{
+ return m_optionsWidget->exec() == QDialog::Accepted;
+}
+
+void
+VSelectTool::refreshUnit()
+{
+ updateStatusBar();
+}
+
+void
+VSelectTool::setup( KActionCollection *collection )
+{
+ m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
+
+ if( m_action == 0 )
+ {
+ m_action = new KRadioAction( i18n( "Select Tool" ), "14_select", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() );
+ m_action->setToolTip( i18n( "Select" ) );
+ m_action->setExclusiveGroup( "select" );
+ //m_ownAction = true;
+ }
+}
+
+#include "vselecttool.moc"