summaryrefslogtreecommitdiffstats
path: root/karbon/commands/vtransformcmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'karbon/commands/vtransformcmd.cpp')
-rw-r--r--karbon/commands/vtransformcmd.cpp491
1 files changed, 491 insertions, 0 deletions
diff --git a/karbon/commands/vtransformcmd.cpp b/karbon/commands/vtransformcmd.cpp
new file mode 100644
index 000000000..ebcb443ed
--- /dev/null
+++ b/karbon/commands/vtransformcmd.cpp
@@ -0,0 +1,491 @@
+/* This file is doc 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 <tdelocale.h>
+
+#include "vcomposite.h"
+#include "vpath.h"
+#include "vsegment.h"
+#include "vselection.h"
+#include "vtext.h"
+#include "vimage.h"
+#include "vtransformcmd.h"
+#include "vstroke.h"
+#include "vfill.h"
+#include "vdocument.h"
+
+#include <kdebug.h>
+
+VTransformCmd::VTransformCmd( VDocument *doc, const TQWMatrix& mat, bool duplicate )
+ : VCommand( doc, i18n( "Transform Objects" ) ), m_mat( mat ), m_duplicate( duplicate )
+{
+ m_selection = ( document() && document()->selection() )
+ ? document()->selection()->clone()
+ : new VSelection();
+
+ if( m_duplicate )
+ {
+ if( !m_selection || m_selection->objects().count() == 1 )
+ setName( i18n( "Duplicate Object" ) );
+ else
+ setName( i18n( "Duplicate Objects" ) );
+ }
+ else if( !m_selection || m_selection->objects().count() == 1 )
+ setName( i18n( "Transform Object" ) );
+}
+
+VTransformCmd::VTransformCmd( VDocument *doc, const TQString& name, const TQString& icon, bool duplicate )
+ : VCommand( doc, name, icon ), m_duplicate( duplicate )
+{
+ m_selection = ( document() && document()->selection() )
+ ? document()->selection()->clone()
+ : new VSelection();
+
+ if( m_duplicate )
+ {
+ if( !m_selection || m_selection->objects().count() == 1 )
+ setName( i18n( "Duplicate Object" ) );
+ else
+ setName( i18n( "Duplicate Objects" ) );
+ }
+}
+
+VTransformCmd::~VTransformCmd()
+{
+ delete( m_selection );
+ m_selection = 0L;
+}
+
+void
+VTransformCmd::execute()
+{
+ VObjectListIterator itr( m_selection->objects() );
+
+ if( m_duplicate )
+ {
+ // clone original objects, add duplicates to document, transform and select them
+ VObject *copy = 0L;
+ for( ; itr.current() ; ++itr )
+ {
+ copy = itr.current()->clone();
+ visit( *copy );
+ document()->append( copy );
+ document()->selection()->take( *itr.current() );
+ document()->selection()->append( copy );
+ m_duplicates.append( copy );
+ }
+ }
+ else
+ {
+ // clear selection ...
+ document()->selection()->clear();
+ // transform objects
+ for( ; itr.current() ; ++itr )
+ {
+ visit( *itr.current() );
+ }
+ // ... and re-add all objects incase we are re-executing the command
+ document()->selection()->append( m_selection->objects() );
+ }
+
+ setSuccess( true );
+}
+
+void
+VTransformCmd::unexecute()
+{
+ // inverting the matrix should undo the affine transformation
+ m_mat = m_mat.invert();
+
+ if( m_duplicate )
+ {
+ // remove duplicated objects
+ VObjectListIterator itr( m_duplicates );
+ for( ; itr.current() ; ++itr )
+ {
+ document()->selection()->take( *itr.current() );
+ itr.current()->setState( VObject::deleted );
+ }
+ VObjectListIterator jtr( m_selection->objects() );
+
+ // add original selection objects to new selection
+ for( ; jtr.current() ; ++jtr )
+ {
+ document()->selection()->append( jtr.current() );
+ }
+ }
+ else
+ {
+ document()->selection()->clear();
+ // move objects back to original position
+ visit( *m_selection );
+ document()->selection()->append( m_selection->objects() );
+ }
+ // reset
+ m_mat = m_mat.invert();
+ setSuccess( false );
+}
+
+void
+VTransformCmd::visitVObject( VObject& object )
+{
+ // Apply transformation to gradients.
+ VStroke* stroke = object.stroke();
+ if( stroke && stroke->type() == VStroke::grad )
+ stroke->gradient().transform( m_mat );
+ else if( stroke && stroke->type() == VStroke::patt )
+ stroke->pattern().transform( m_mat );
+
+ VFill* fill = object.fill();
+ if( fill && fill->type() == VFill::grad )
+ fill->gradient().transform( m_mat );
+ else if( fill && fill->type() == VFill::patt )
+ fill->pattern().transform( m_mat );
+}
+
+void
+VTransformCmd::visitVPath( VPath& composite )
+{
+ if( composite.state() == VObject::hidden ||
+ composite.state() == VObject::normal_locked ||
+ composite.state() == VObject::hidden_locked )
+ return;
+
+ visitVObject( composite );
+
+ composite.transform( m_mat );
+
+ VVisitor::visitVPath( composite );
+}
+
+void
+VTransformCmd::visitVSubpath( VSubpath& path )
+{
+ if( path.state() == VObject::hidden ||
+ path.state() == VObject::normal_locked ||
+ path.state() == VObject::hidden_locked )
+ return;
+
+ VSegment* segment = path.first();
+
+ while( segment )
+ {
+ for( unsigned short i = 0; i < segment->degree(); ++i )
+ {
+ segment->setPoint( i, segment->point( i ).transform( m_mat ) );
+ }
+
+ segment = segment->next();
+ }
+
+ path.invalidateBoundingBox();
+}
+
+void
+VTransformCmd::visitVText( VText& text )
+{
+ if( text.state() == VObject::hidden ||
+ text.state() == VObject::normal_locked ||
+ text.state() == VObject::hidden_locked )
+ return;
+
+ visitVObject( text );
+
+ visit( text.basePath() );
+
+ VPathListIterator itr( text.glyphs() );
+
+ for( ; itr.current() ; ++itr )
+ {
+ visit( *itr.current() );
+ }
+
+ text.invalidateBoundingBox();
+}
+
+void
+VTransformCmd::visitVImage( VImage &img )
+{
+ if( img.state() == VObject::hidden ||
+ img.state() == VObject::normal_locked ||
+ img.state() == VObject::hidden_locked )
+ return;
+
+ img.transform( m_mat );
+}
+
+VTranslateCmd::VTranslateCmd( VDocument *doc, double d1, double d2, bool duplicate )
+ : VTransformCmd( doc, i18n( "Translate Objects" ), "translate", duplicate )
+{
+ if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
+ setName( i18n( "Translate Object" ) );
+
+ m_mat.translate( d1, d2 );
+}
+
+
+VScaleCmd::VScaleCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate )
+ : VTransformCmd( doc, i18n( "Scale Objects" ), "14_select", duplicate )
+{
+ if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
+ setName( i18n( "Scale Object" ) );
+
+ m_mat.translate( p.x(), p.y() );
+ m_mat.scale( s1, s2 );
+ m_mat.translate( -p.x(), -p.y() );
+}
+
+
+VShearCmd::VShearCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate )
+ : VTransformCmd( doc, i18n( "Shear Objects" ), "14_shear", duplicate )
+{
+ if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
+ setName( i18n( "Shear Object" ) );
+
+ m_mat.translate( p.x(), p.y() );
+ m_mat.shear( s1, s2 );
+ m_mat.translate( -p.x(), -p.y() );
+}
+
+VRotateCmd::VRotateCmd( VDocument *doc, const KoPoint& p, double angle, bool duplicate )
+ : VTransformCmd( doc, i18n( "Rotate Objects" ), "14_rotate", duplicate )
+{
+ if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
+ setName( i18n( "Rotate Object" ) );
+
+ m_mat.translate( p.x(), p.y() );
+ m_mat.rotate( angle );
+ m_mat.translate( -p.x(), -p.y() );
+}
+
+VTranslateBezierCmd::VTranslateBezierCmd( VDocument *doc, VSegment *segment, double d1, double d2, bool firstControl )
+ : VCommand( doc, i18n( "Translate Bezier" ) ), m_segment( segment ), m_firstControl( firstControl )
+ , m_subpath(0L)
+{
+ m_mat.translate( d1, d2 );
+ m_segmenttwo = 0L;
+
+ if( document() && document()->selection() )
+ {
+ VObjectListIterator itr( document()->selection()->objects() );
+
+ // find subpath containing the segment
+ for( ; itr.current() ; ++itr )
+ visit( *itr.current() );
+ }
+}
+
+VTranslateBezierCmd::~VTranslateBezierCmd()
+{
+}
+
+void
+VTranslateBezierCmd::execute()
+{
+ if( m_segment->degree() == 3 )
+ {
+ TQWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() );
+ if( m_firstControl )
+ {
+ if( m_segment->prev() &&
+ m_segment->prev()->degree() == 3 &&
+ m_segment->prev()->isSmooth() )
+ {
+ m_segmenttwo = m_segment->prev();
+ for( uint i = 0;i < m_segmenttwo->degree();i++ )
+ {
+ m_segmenttwo->selectPoint( i, i == 1 );
+
+ if( i == 1 )
+ m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) );
+ }
+ }
+ }
+ else
+ {
+ m_segmenttwo = ( m_segment->isSmooth() && m_segment->next()->degree() == 3 ) ? m_segment->next() : 0L;
+ if( m_segmenttwo )
+ {
+ for( uint i = 0;i < m_segmenttwo->degree();i++ )
+ {
+ m_segmenttwo->selectPoint( i, i == 0 );
+
+ if( i == 0 )
+ m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) );
+ }
+ }
+ }
+
+ for( uint i = 0;i < m_segment->degree();i++ )
+ {
+ m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) );
+
+ if( i == uint( m_firstControl ? 0 : 1 ) )
+ m_segment->setPoint( i, m_segment->point( i ).transform( m_mat ) );
+ }
+ }
+
+ if( m_subpath )
+ m_subpath->invalidateBoundingBox();
+
+ setSuccess( true );
+}
+
+void
+VTranslateBezierCmd::unexecute()
+{
+ TQWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() );
+ if( m_segment )
+ {
+ for( uint i = 0;i < m_segment->degree();i++ )
+ {
+ m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) );
+
+ if( i == uint( m_firstControl ? 0 : 1 ) )
+ m_segment->setPoint( i, m_segment->point( i ).transform( m_mat.invert() ) );
+ }
+
+ if( m_segmenttwo )
+ {
+ uint index = m_firstControl ? 1 : 0;
+ for( uint i = 0;i < m_segmenttwo->degree();i++ )
+ {
+ m_segmenttwo->selectPoint( i, i == index );
+
+ if( i == index )
+ m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2.invert() ) );
+ }
+ }
+ }
+ setSuccess( false );
+}
+
+void
+VTranslateBezierCmd::visitVSubpath( VSubpath& path )
+{
+ if( m_subpath )
+ return;
+
+ VSegment* segment = path.first();
+
+ // check all segments of the path
+ while( segment )
+ {
+ if( segment == m_segment )
+ {
+ m_subpath = &path;
+ break;
+ }
+ segment = segment->next();
+ }
+}
+
+VTranslatePointCmd::VTranslatePointCmd( VDocument *doc, double d1, double d2 )
+ : VCommand( doc, i18n( "Translate Points" ), "translate" )
+{
+ m_mat.translate( d1, d2 );
+
+ if( document() && document()->selection() )
+ {
+ VObjectListIterator itr( document()->selection()->objects() );
+
+ // collect all points to translate
+ for( ; itr.current() ; ++itr )
+ visit( *itr.current() );
+
+ if( m_segPnts.size() > 1 || ( m_segPnts.size() == 0 && m_segPnts.begin().data().size() > 1 ) )
+ setName( i18n( "Translate Point" ) );
+ }
+}
+
+VTranslatePointCmd::~VTranslatePointCmd()
+{
+}
+
+void
+VTranslatePointCmd::execute()
+{
+ translatePoints();
+ setSuccess( true );
+}
+
+void
+VTranslatePointCmd::unexecute()
+{
+ m_mat = m_mat.invert();
+ translatePoints();
+ m_mat = m_mat.invert();
+ setSuccess( false );
+}
+
+void
+VTranslatePointCmd::visitVSubpath( VSubpath& path )
+{
+ if( path.state() == VObject::hidden ||
+ path.state() == VObject::normal_locked ||
+ path.state() == VObject::hidden_locked )
+ return;
+
+ VSegment* segment = path.first();
+
+ uint segCnt = m_segPnts.size();
+
+ // save indices of selected points for all segments
+ while( segment )
+ {
+ TQValueVector<int> pnts;
+
+ for( unsigned short i = 0; i < segment->degree(); ++i )
+ {
+ if( segment->pointIsSelected( i ) )
+ pnts.push_back( i );
+ }
+ if( pnts.size() )
+ m_segPnts[segment] = pnts;
+
+ segment = segment->next();
+ }
+
+ // save subpaths which have selected points
+ if( segCnt != m_segPnts.size() )
+ m_subpaths.append( &path );
+}
+
+void
+VTranslatePointCmd::translatePoints()
+{
+ TQMap<VSegment*, TQValueVector<int> >::iterator it, et = m_segPnts.end();
+
+ // iterate over the segments and transform all selected points
+ for( it = m_segPnts.begin(); it != et; ++it )
+ {
+ VSegment *segment = it.key();
+ TQValueVector<int> &pnts = it.data();
+
+ int pntCnt = pnts.size();
+ for( int i = 0; i < pntCnt; ++i )
+ segment->setPoint( pnts[i], segment->point( pnts[i] ).transform( m_mat ) );
+ }
+
+ // invalidate all changed subpaths
+ VObjectListIterator itr( m_subpaths );
+ for( ; itr.current(); ++itr )
+ itr.current()->invalidateBoundingBox();
+}