karbon

vtransformcmd.cc

00001 /* This file is doc of the KDE project
00002    Copyright (C) 2001, 2002, 2003 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 
00021 #include <klocale.h>
00022 
00023 #include "vcomposite.h"
00024 #include "vpath.h"
00025 #include "vsegment.h"
00026 #include "vselection.h"
00027 #include "vtext.h"
00028 #include "vimage.h"
00029 #include "vtransformcmd.h"
00030 #include "vstroke.h"
00031 #include "vfill.h"
00032 #include "vdocument.h"
00033 
00034 #include <kdebug.h>
00035 
00036 VTransformCmd::VTransformCmd( VDocument *doc, const QWMatrix& mat, bool duplicate )
00037     : VCommand( doc, i18n( "Transform Objects" ) ), m_mat( mat ), m_duplicate( duplicate )
00038 {
00039     m_selection = ( document() && document()->selection() )
00040         ? document()->selection()->clone()
00041         : new VSelection();
00042 
00043     if( m_duplicate )
00044     {
00045         if( !m_selection || m_selection->objects().count() == 1 )
00046             setName( i18n( "Duplicate Object" ) );
00047         else
00048             setName( i18n( "Duplicate Objects" ) );
00049     }
00050     else if( !m_selection || m_selection->objects().count() == 1 )
00051         setName( i18n( "Transform Object" ) );
00052 }
00053 
00054 VTransformCmd::VTransformCmd( VDocument *doc, const QString& name, const QString& icon, bool duplicate )
00055         : VCommand( doc, name, icon ), m_duplicate( duplicate )
00056 {
00057     m_selection = ( document() && document()->selection() )
00058         ? document()->selection()->clone()
00059         : new VSelection();
00060 
00061     if( m_duplicate )
00062     {
00063         if( !m_selection || m_selection->objects().count() == 1 )
00064             setName( i18n( "Duplicate Object" ) );
00065         else
00066             setName( i18n( "Duplicate Objects" ) );
00067     }
00068 }
00069 
00070 VTransformCmd::~VTransformCmd()
00071 {
00072     delete( m_selection );
00073     m_selection = 0L;
00074 }
00075 
00076 void
00077 VTransformCmd::execute()
00078 {
00079     VObjectListIterator itr( m_selection->objects() );
00080 
00081     if( m_duplicate )
00082     {
00083         // clone original objects, add duplicates to document, transform and select them
00084         VObject *copy = 0L;
00085         for( ; itr.current() ; ++itr )
00086         {
00087             copy = itr.current()->clone();
00088             visit( *copy );
00089             document()->append( copy );
00090             document()->selection()->take( *itr.current() );
00091             document()->selection()->append( copy );
00092             m_duplicates.append( copy );
00093         }
00094     }
00095     else
00096     {
00097         // clear selection ...
00098         document()->selection()->clear();
00099         // transform objects
00100         for( ; itr.current() ; ++itr )
00101         {
00102             visit( *itr.current() );
00103         }
00104         // ... and re-add all objects incase we are re-executing the command
00105         document()->selection()->append( m_selection->objects() );
00106     }
00107 
00108     setSuccess( true );
00109 }
00110 
00111 void
00112 VTransformCmd::unexecute()
00113 {
00114     // inverting the matrix should undo the affine transformation
00115     m_mat = m_mat.invert();
00116 
00117     if( m_duplicate )
00118     {
00119         // remove duplicated objects
00120         VObjectListIterator itr( m_duplicates );
00121         for( ; itr.current() ; ++itr )
00122         {
00123             document()->selection()->take( *itr.current() );
00124             itr.current()->setState( VObject::deleted );
00125         }
00126         VObjectListIterator jtr( m_selection->objects() );
00127 
00128         // add original selection objects to new selection
00129         for( ; jtr.current() ; ++jtr )
00130         {
00131             document()->selection()->append( jtr.current() );
00132         }
00133     }
00134     else
00135     {
00136         document()->selection()->clear();
00137         // move objects back to original position
00138         visit( *m_selection );
00139         document()->selection()->append( m_selection->objects() );
00140     }
00141     // reset
00142     m_mat = m_mat.invert();
00143     setSuccess( false );
00144 }
00145 
00146 void
00147 VTransformCmd::visitVObject( VObject& object )
00148 {
00149     // Apply transformation to gradients.
00150     VStroke* stroke = object.stroke();
00151     if( stroke && stroke->type() == VStroke::grad )
00152         stroke->gradient().transform( m_mat );
00153     else if( stroke && stroke->type() == VStroke::patt )
00154         stroke->pattern().transform( m_mat );
00155 
00156     VFill* fill = object.fill();
00157     if( fill && fill->type() == VFill::grad )
00158         fill->gradient().transform( m_mat );
00159     else if( fill && fill->type() == VFill::patt )
00160         fill->pattern().transform( m_mat );
00161 }
00162 
00163 void
00164 VTransformCmd::visitVPath( VPath& composite )
00165 {
00166     if( composite.state() == VObject::hidden ||
00167         composite.state() == VObject::normal_locked ||
00168         composite.state() == VObject::hidden_locked )
00169         return;
00170 
00171     visitVObject( composite );
00172 
00173     composite.transform( m_mat );
00174 
00175     VVisitor::visitVPath( composite );
00176 }
00177 
00178 void
00179 VTransformCmd::visitVSubpath( VSubpath& path )
00180 {
00181     if( path.state() == VObject::hidden ||
00182         path.state() == VObject::normal_locked ||
00183         path.state() == VObject::hidden_locked )
00184         return;
00185 
00186     VSegment* segment = path.first();
00187 
00188     while( segment )
00189     {
00190         for( unsigned short i = 0; i < segment->degree(); ++i )
00191         {
00192             segment->setPoint( i, segment->point( i ).transform( m_mat ) );
00193         }
00194 
00195         segment = segment->next();
00196     }
00197 
00198     path.invalidateBoundingBox();
00199 }
00200 
00201 void
00202 VTransformCmd::visitVText( VText& text )
00203 {
00204     if( text.state() == VObject::hidden ||
00205         text.state() == VObject::normal_locked ||
00206         text.state() == VObject::hidden_locked )
00207         return;
00208 
00209     visitVObject( text );
00210 
00211     visit( text.basePath() );
00212 
00213     VPathListIterator itr( text.glyphs() );
00214 
00215     for( ; itr.current() ; ++itr )
00216     {
00217         visit( *itr.current() );
00218     }
00219 
00220     text.invalidateBoundingBox();
00221 }
00222 
00223 void
00224 VTransformCmd::visitVImage( VImage &img )
00225 {
00226     if( img.state() == VObject::hidden ||
00227         img.state() == VObject::normal_locked ||
00228         img.state() == VObject::hidden_locked )
00229         return;
00230 
00231     img.transform( m_mat );
00232 }
00233 
00234 VTranslateCmd::VTranslateCmd( VDocument *doc, double d1, double d2, bool duplicate )
00235         : VTransformCmd( doc, i18n( "Translate Objects" ), "translate", duplicate )
00236 {
00237     if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
00238         setName( i18n( "Translate Object" ) );
00239 
00240     m_mat.translate( d1, d2 );
00241 }
00242 
00243 
00244 VScaleCmd::VScaleCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate )
00245         : VTransformCmd( doc, i18n( "Scale Objects" ), "14_select", duplicate )
00246 {
00247     if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
00248         setName( i18n( "Scale Object" ) );
00249 
00250     m_mat.translate( p.x(), p.y() );
00251     m_mat.scale( s1, s2 );
00252     m_mat.translate( -p.x(), -p.y() );
00253 }
00254 
00255 
00256 VShearCmd::VShearCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate )
00257         : VTransformCmd( doc, i18n( "Shear Objects" ), "14_shear", duplicate )
00258 {
00259     if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
00260         setName( i18n( "Shear Object" ) );
00261 
00262     m_mat.translate( p.x(), p.y() );
00263     m_mat.shear( s1, s2 );
00264     m_mat.translate( -p.x(), -p.y() );
00265 }
00266 
00267 VRotateCmd::VRotateCmd( VDocument *doc, const KoPoint& p, double angle, bool duplicate )
00268         : VTransformCmd( doc, i18n( "Rotate Objects" ), "14_rotate", duplicate )
00269 {
00270     if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
00271         setName( i18n( "Rotate Object" ) );
00272 
00273     m_mat.translate( p.x(), p.y() );
00274     m_mat.rotate( angle );
00275     m_mat.translate( -p.x(), -p.y() );
00276 }
00277 
00278 VTranslateBezierCmd::VTranslateBezierCmd( VDocument *doc, VSegment *segment, double d1, double d2, bool firstControl )
00279     : VCommand( doc, i18n( "Translate Bezier" ) ), m_segment( segment ), m_firstControl( firstControl )
00280     , m_subpath(0L)
00281 {
00282     m_mat.translate( d1, d2 );
00283     m_segmenttwo = 0L;
00284 
00285     if( document() && document()->selection() )
00286     {
00287         VObjectListIterator itr( document()->selection()->objects() );
00288 
00289         // find subpath containing the segment
00290         for( ; itr.current() ; ++itr )
00291             visit( *itr.current() );
00292     }
00293 }
00294 
00295 VTranslateBezierCmd::~VTranslateBezierCmd()
00296 {
00297 }
00298 
00299 void
00300 VTranslateBezierCmd::execute()
00301 {
00302     if( m_segment->degree() == 3 )
00303     {
00304         QWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() );
00305         if( m_firstControl )
00306         {
00307             if( m_segment->prev() &&
00308                 m_segment->prev()->degree() == 3 &&
00309                 m_segment->prev()->isSmooth() )
00310             {
00311                 m_segmenttwo = m_segment->prev();
00312                 for( uint i = 0;i < m_segmenttwo->degree();i++ )
00313                 {
00314                     m_segmenttwo->selectPoint( i, i == 1 );
00315 
00316                     if( i == 1 )
00317                         m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) );
00318                 }
00319             }
00320         }
00321         else
00322         {
00323             m_segmenttwo = ( m_segment->isSmooth() && m_segment->next()->degree() == 3 ) ? m_segment->next() : 0L;
00324             if( m_segmenttwo )
00325             {
00326                 for( uint i = 0;i < m_segmenttwo->degree();i++ )
00327                 {
00328                     m_segmenttwo->selectPoint( i, i == 0 );
00329 
00330                     if( i == 0 )
00331                         m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) );
00332                 }
00333             }
00334         }
00335 
00336         for( uint i = 0;i < m_segment->degree();i++ )
00337         {
00338             m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) );
00339 
00340             if( i == uint( m_firstControl ? 0 : 1 ) )
00341                 m_segment->setPoint( i, m_segment->point( i ).transform( m_mat ) );
00342         }
00343     }
00344 
00345     if( m_subpath )
00346         m_subpath->invalidateBoundingBox();
00347 
00348     setSuccess( true );
00349 }
00350 
00351 void
00352 VTranslateBezierCmd::unexecute()
00353 {
00354     QWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() );
00355     if( m_segment )
00356     {
00357         for( uint i = 0;i < m_segment->degree();i++ )
00358         {
00359             m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) );
00360     
00361             if( i == uint( m_firstControl ? 0 : 1 ) )
00362                 m_segment->setPoint( i, m_segment->point( i ).transform( m_mat.invert() ) );
00363         }
00364 
00365         if( m_segmenttwo )
00366         {
00367             uint index = m_firstControl ? 1 : 0;
00368             for( uint i = 0;i < m_segmenttwo->degree();i++ )
00369             {
00370                 m_segmenttwo->selectPoint( i, i == index );
00371 
00372             if( i == index )
00373                 m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2.invert() ) );
00374             }
00375         }
00376     }
00377     setSuccess( false );
00378 }
00379 
00380 void
00381 VTranslateBezierCmd::visitVSubpath( VSubpath& path )
00382 {
00383     if( m_subpath ) 
00384         return;
00385 
00386     VSegment* segment = path.first();
00387 
00388     // check all segments of the path
00389     while( segment )
00390     {
00391         if( segment == m_segment )
00392         {
00393             m_subpath = &path;
00394             break;
00395         }
00396         segment = segment->next();
00397     }
00398 }
00399 
00400 VTranslatePointCmd::VTranslatePointCmd( VDocument *doc, double d1, double d2 )
00401         : VCommand( doc, i18n( "Translate Points" ), "translate" )
00402 {
00403     m_mat.translate( d1, d2 );
00404 
00405     if( document() && document()->selection() )
00406     {
00407         VObjectListIterator itr( document()->selection()->objects() );
00408 
00409         // collect all points to translate
00410         for( ; itr.current() ; ++itr )
00411             visit( *itr.current() );
00412     
00413         if( m_segPnts.size() > 1 || ( m_segPnts.size() == 0 && m_segPnts.begin().data().size() > 1 ) )
00414             setName( i18n( "Translate Point" ) );
00415     }
00416 }
00417 
00418 VTranslatePointCmd::~VTranslatePointCmd()
00419 {
00420 }
00421 
00422 void
00423 VTranslatePointCmd::execute()
00424 {
00425     translatePoints();
00426     setSuccess( true );
00427 }
00428 
00429 void
00430 VTranslatePointCmd::unexecute()
00431 {
00432     m_mat = m_mat.invert();
00433     translatePoints();
00434     m_mat = m_mat.invert();
00435     setSuccess( false );
00436 }
00437 
00438 void
00439 VTranslatePointCmd::visitVSubpath( VSubpath& path )
00440 {
00441     if( path.state() == VObject::hidden ||
00442         path.state() == VObject::normal_locked ||
00443         path.state() == VObject::hidden_locked )
00444         return;
00445 
00446     VSegment* segment = path.first();
00447 
00448     uint segCnt = m_segPnts.size();
00449 
00450     // save indices of selected points for all segments
00451     while( segment )
00452     {
00453         QValueVector<int> pnts;
00454 
00455         for( unsigned short i = 0; i < segment->degree(); ++i )
00456         {
00457             if( segment->pointIsSelected( i ) )
00458                 pnts.push_back( i );
00459         }
00460         if( pnts.size() )
00461             m_segPnts[segment] = pnts;
00462 
00463         segment = segment->next();
00464     }
00465 
00466     // save subpaths which have selected points
00467     if( segCnt != m_segPnts.size() )
00468         m_subpaths.append( &path );
00469 }
00470 
00471 void
00472 VTranslatePointCmd::translatePoints()
00473 {
00474     QMap<VSegment*, QValueVector<int> >::iterator it, et = m_segPnts.end();
00475 
00476     // iterate over the segments and transform all selected points
00477     for( it = m_segPnts.begin(); it != et; ++it )
00478     {
00479         VSegment *segment = it.key();
00480         QValueVector<int> &pnts = it.data();
00481 
00482         int pntCnt = pnts.size();
00483         for( int i = 0; i < pntCnt; ++i )
00484             segment->setPoint( pnts[i], segment->point( pnts[i] ).transform( m_mat ) );
00485     }
00486 
00487     // invalidate all changed subpaths
00488     VObjectListIterator itr( m_subpaths );
00489     for( ; itr.current(); ++itr )
00490         itr.current()->invalidateBoundingBox();
00491 }
KDE Home | KDE Accessibility Home | Description of Access Keys