vtransformcmd.cpp
1/* This file is doc of the KDE project
2 Copyright (C) 2001, 2002, 2003 The Karbon Developers
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20
21#include <tdelocale.h>
22
23#include "vcomposite.h"
24#include "vpath.h"
25#include "vsegment.h"
26#include "vselection.h"
27#include "vtext.h"
28#include "vimage.h"
29#include "vtransformcmd.h"
30#include "vstroke.h"
31#include "vfill.h"
32#include "vdocument.h"
33
34#include <kdebug.h>
35
36VTransformCmd::VTransformCmd( VDocument *doc, const TQWMatrix& mat, bool duplicate )
37 : VCommand( doc, i18n( "Transform Objects" ) ), m_mat( mat ), m_duplicate( duplicate )
38{
39 m_selection = ( document() && document()->selection() )
40 ? document()->selection()->clone()
41 : new VSelection();
42
43 if( m_duplicate )
44 {
45 if( !m_selection || m_selection->objects().count() == 1 )
46 setName( i18n( "Duplicate Object" ) );
47 else
48 setName( i18n( "Duplicate Objects" ) );
49 }
50 else if( !m_selection || m_selection->objects().count() == 1 )
51 setName( i18n( "Transform Object" ) );
52}
53
54VTransformCmd::VTransformCmd( VDocument *doc, const TQString& name, const TQString& icon, bool duplicate )
55 : VCommand( doc, name, icon ), m_duplicate( duplicate )
56{
57 m_selection = ( document() && document()->selection() )
58 ? document()->selection()->clone()
59 : new VSelection();
60
61 if( m_duplicate )
62 {
63 if( !m_selection || m_selection->objects().count() == 1 )
64 setName( i18n( "Duplicate Object" ) );
65 else
66 setName( i18n( "Duplicate Objects" ) );
67 }
68}
69
70VTransformCmd::~VTransformCmd()
71{
72 delete( m_selection );
73 m_selection = 0L;
74}
75
76void
77VTransformCmd::execute()
78{
79 VObjectListIterator itr( m_selection->objects() );
80
81 if( m_duplicate )
82 {
83 // clone original objects, add duplicates to document, transform and select them
84 VObject *copy = 0L;
85 for( ; itr.current() ; ++itr )
86 {
87 copy = itr.current()->clone();
88 visit( *copy );
89 document()->append( copy );
90 document()->selection()->take( *itr.current() );
91 document()->selection()->append( copy );
92 m_duplicates.append( copy );
93 }
94 }
95 else
96 {
97 // clear selection ...
98 document()->selection()->clear();
99 // transform objects
100 for( ; itr.current() ; ++itr )
101 {
102 visit( *itr.current() );
103 }
104 // ... and re-add all objects incase we are re-executing the command
105 document()->selection()->append( m_selection->objects() );
106 }
107
108 setSuccess( true );
109}
110
111void
112VTransformCmd::unexecute()
113{
114 // inverting the matrix should undo the affine transformation
115 m_mat = m_mat.invert();
116
117 if( m_duplicate )
118 {
119 // remove duplicated objects
120 VObjectListIterator itr( m_duplicates );
121 for( ; itr.current() ; ++itr )
122 {
123 document()->selection()->take( *itr.current() );
124 itr.current()->setState( VObject::deleted );
125 }
126 VObjectListIterator jtr( m_selection->objects() );
127
128 // add original selection objects to new selection
129 for( ; jtr.current() ; ++jtr )
130 {
131 document()->selection()->append( jtr.current() );
132 }
133 }
134 else
135 {
136 document()->selection()->clear();
137 // move objects back to original position
138 visit( *m_selection );
139 document()->selection()->append( m_selection->objects() );
140 }
141 // reset
142 m_mat = m_mat.invert();
143 setSuccess( false );
144}
145
146void
147VTransformCmd::visitVObject( VObject& object )
148{
149 // Apply transformation to gradients.
150 VStroke* stroke = object.stroke();
151 if( stroke && stroke->type() == VStroke::grad )
152 stroke->gradient().transform( m_mat );
153 else if( stroke && stroke->type() == VStroke::patt )
154 stroke->pattern().transform( m_mat );
155
156 VFill* fill = object.fill();
157 if( fill && fill->type() == VFill::grad )
158 fill->gradient().transform( m_mat );
159 else if( fill && fill->type() == VFill::patt )
160 fill->pattern().transform( m_mat );
161}
162
163void
164VTransformCmd::visitVPath( VPath& composite )
165{
166 if( composite.state() == VObject::hidden ||
167 composite.state() == VObject::normal_locked ||
168 composite.state() == VObject::hidden_locked )
169 return;
170
171 visitVObject( composite );
172
173 composite.transform( m_mat );
174
175 VVisitor::visitVPath( composite );
176}
177
178void
179VTransformCmd::visitVSubpath( VSubpath& path )
180{
181 if( path.state() == VObject::hidden ||
182 path.state() == VObject::normal_locked ||
183 path.state() == VObject::hidden_locked )
184 return;
185
186 VSegment* segment = path.first();
187
188 while( segment )
189 {
190 for( unsigned short i = 0; i < segment->degree(); ++i )
191 {
192 segment->setPoint( i, segment->point( i ).transform( m_mat ) );
193 }
194
195 segment = segment->next();
196 }
197
199}
200
201void
202VTransformCmd::visitVText( VText& text )
203{
204 if( text.state() == VObject::hidden ||
205 text.state() == VObject::normal_locked ||
206 text.state() == VObject::hidden_locked )
207 return;
208
209 visitVObject( text );
210
211 visit( text.basePath() );
212
213 VPathListIterator itr( text.glyphs() );
214
215 for( ; itr.current() ; ++itr )
216 {
217 visit( *itr.current() );
218 }
219
220 text.invalidateBoundingBox();
221}
222
223void
224VTransformCmd::visitVImage( VImage &img )
225{
226 if( img.state() == VObject::hidden ||
227 img.state() == VObject::normal_locked ||
228 img.state() == VObject::hidden_locked )
229 return;
230
231 img.transform( m_mat );
232}
233
234VTranslateCmd::VTranslateCmd( VDocument *doc, double d1, double d2, bool duplicate )
235 : VTransformCmd( doc, i18n( "Translate Objects" ), "translate", duplicate )
236{
237 if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
238 setName( i18n( "Translate Object" ) );
239
240 m_mat.translate( d1, d2 );
241}
242
243
244VScaleCmd::VScaleCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate )
245 : VTransformCmd( doc, i18n( "Scale Objects" ), "14_select", duplicate )
246{
247 if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
248 setName( i18n( "Scale Object" ) );
249
250 m_mat.translate( p.x(), p.y() );
251 m_mat.scale( s1, s2 );
252 m_mat.translate( -p.x(), -p.y() );
253}
254
255
256VShearCmd::VShearCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate )
257 : VTransformCmd( doc, i18n( "Shear Objects" ), "14_shear", duplicate )
258{
259 if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
260 setName( i18n( "Shear Object" ) );
261
262 m_mat.translate( p.x(), p.y() );
263 m_mat.shear( s1, s2 );
264 m_mat.translate( -p.x(), -p.y() );
265}
266
267VRotateCmd::VRotateCmd( VDocument *doc, const KoPoint& p, double angle, bool duplicate )
268 : VTransformCmd( doc, i18n( "Rotate Objects" ), "14_rotate", duplicate )
269{
270 if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) )
271 setName( i18n( "Rotate Object" ) );
272
273 m_mat.translate( p.x(), p.y() );
274 m_mat.rotate( angle );
275 m_mat.translate( -p.x(), -p.y() );
276}
277
278VTranslateBezierCmd::VTranslateBezierCmd( VDocument *doc, VSegment *segment, double d1, double d2, bool firstControl )
279 : VCommand( doc, i18n( "Translate Bezier" ) ), m_segment( segment ), m_firstControl( firstControl )
280 , m_subpath(0L)
281{
282 m_mat.translate( d1, d2 );
283 m_segmenttwo = 0L;
284
285 if( document() && document()->selection() )
286 {
287 VObjectListIterator itr( document()->selection()->objects() );
288
289 // find subpath containing the segment
290 for( ; itr.current() ; ++itr )
291 visit( *itr.current() );
292 }
293}
294
295VTranslateBezierCmd::~VTranslateBezierCmd()
296{
297}
298
299void
300VTranslateBezierCmd::execute()
301{
302 if( m_segment->degree() == 3 )
303 {
304 TQWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() );
305 if( m_firstControl )
306 {
307 if( m_segment->prev() &&
308 m_segment->prev()->degree() == 3 &&
309 m_segment->prev()->isSmooth() )
310 {
311 m_segmenttwo = m_segment->prev();
312 for( uint i = 0;i < m_segmenttwo->degree();i++ )
313 {
314 m_segmenttwo->selectPoint( i, i == 1 );
315
316 if( i == 1 )
317 m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) );
318 }
319 }
320 }
321 else
322 {
323 m_segmenttwo = ( m_segment->isSmooth() && m_segment->next()->degree() == 3 ) ? m_segment->next() : 0L;
324 if( m_segmenttwo )
325 {
326 for( uint i = 0;i < m_segmenttwo->degree();i++ )
327 {
328 m_segmenttwo->selectPoint( i, i == 0 );
329
330 if( i == 0 )
331 m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) );
332 }
333 }
334 }
335
336 for( uint i = 0;i < m_segment->degree();i++ )
337 {
338 m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) );
339
340 if( i == uint( m_firstControl ? 0 : 1 ) )
341 m_segment->setPoint( i, m_segment->point( i ).transform( m_mat ) );
342 }
343 }
344
345 if( m_subpath )
346 m_subpath->invalidateBoundingBox();
347
348 setSuccess( true );
349}
350
351void
352VTranslateBezierCmd::unexecute()
353{
354 TQWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() );
355 if( m_segment )
356 {
357 for( uint i = 0;i < m_segment->degree();i++ )
358 {
359 m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) );
360
361 if( i == uint( m_firstControl ? 0 : 1 ) )
362 m_segment->setPoint( i, m_segment->point( i ).transform( m_mat.invert() ) );
363 }
364
365 if( m_segmenttwo )
366 {
367 uint index = m_firstControl ? 1 : 0;
368 for( uint i = 0;i < m_segmenttwo->degree();i++ )
369 {
370 m_segmenttwo->selectPoint( i, i == index );
371
372 if( i == index )
373 m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2.invert() ) );
374 }
375 }
376 }
377 setSuccess( false );
378}
379
380void
381VTranslateBezierCmd::visitVSubpath( VSubpath& path )
382{
383 if( m_subpath )
384 return;
385
386 VSegment* segment = path.first();
387
388 // check all segments of the path
389 while( segment )
390 {
391 if( segment == m_segment )
392 {
393 m_subpath = &path;
394 break;
395 }
396 segment = segment->next();
397 }
398}
399
400VTranslatePointCmd::VTranslatePointCmd( VDocument *doc, double d1, double d2 )
401 : VCommand( doc, i18n( "Translate Points" ), "translate" )
402{
403 m_mat.translate( d1, d2 );
404
405 if( document() && document()->selection() )
406 {
407 VObjectListIterator itr( document()->selection()->objects() );
408
409 // collect all points to translate
410 for( ; itr.current() ; ++itr )
411 visit( *itr.current() );
412
413 if( m_segPnts.size() > 1 || ( m_segPnts.size() == 0 && m_segPnts.begin().data().size() > 1 ) )
414 setName( i18n( "Translate Point" ) );
415 }
416}
417
418VTranslatePointCmd::~VTranslatePointCmd()
419{
420}
421
422void
423VTranslatePointCmd::execute()
424{
425 translatePoints();
426 setSuccess( true );
427}
428
429void
430VTranslatePointCmd::unexecute()
431{
432 m_mat = m_mat.invert();
433 translatePoints();
434 m_mat = m_mat.invert();
435 setSuccess( false );
436}
437
438void
439VTranslatePointCmd::visitVSubpath( VSubpath& path )
440{
441 if( path.state() == VObject::hidden ||
442 path.state() == VObject::normal_locked ||
443 path.state() == VObject::hidden_locked )
444 return;
445
446 VSegment* segment = path.first();
447
448 uint segCnt = m_segPnts.size();
449
450 // save indices of selected points for all segments
451 while( segment )
452 {
453 TQValueVector<int> pnts;
454
455 for( unsigned short i = 0; i < segment->degree(); ++i )
456 {
457 if( segment->pointIsSelected( i ) )
458 pnts.push_back( i );
459 }
460 if( pnts.size() )
461 m_segPnts[segment] = pnts;
462
463 segment = segment->next();
464 }
465
466 // save subpaths which have selected points
467 if( segCnt != m_segPnts.size() )
468 m_subpaths.append( &path );
469}
470
471void
472VTranslatePointCmd::translatePoints()
473{
474 TQMap<VSegment*, TQValueVector<int> >::iterator it, et = m_segPnts.end();
475
476 // iterate over the segments and transform all selected points
477 for( it = m_segPnts.begin(); it != et; ++it )
478 {
479 VSegment *segment = it.key();
480 TQValueVector<int> &pnts = it.data();
481
482 int pntCnt = pnts.size();
483 for( int i = 0; i < pntCnt; ++i )
484 segment->setPoint( pnts[i], segment->point( pnts[i] ).transform( m_mat ) );
485 }
486
487 // invalidate all changed subpaths
488 VObjectListIterator itr( m_subpaths );
489 for( ; itr.current(); ++itr )
490 itr.current()->invalidateBoundingBox();
491}
The base class for all karbon commands.
Definition vcommand.h:42
All non-visual, static doc info is in here.
Definition vdocument.h:53
Manages the fill of shapes.
Definition vfill.h:45
@ grad
solid fill
Definition vfill.h:51
@ patt
gradient fill
Definition vfill.h:52
The base class for all karbon objects.
Definition vobject.h:50
virtual VObject * clone() const =0
Create an exact copy of this object.
@ normal_locked
visible, but locked (r/o)
Definition vobject.h:55
@ hidden_locked
hidden and locked (r/o)
Definition vobject.h:57
@ deleted
deleted, nearly dead
Definition vobject.h:58
@ hidden
hidden
Definition vobject.h:56
void invalidateBoundingBox()
Invalidates the bounding box, so it has to be recalculated.
Definition vobject.h:127
VState state() const
Get the state the object is in.
Definition vobject.h:154
A composite path consists of one or many subpaths.
Definition vcomposite.h:48
A class representing lines and beziers.
Definition vsegment.h:43
bool pointIsSelected(int i) const
Returns true if the point with index 0 <= i < degree() is selected.
Definition vsegment.h:173
VSegment * next() const
Returns a pointer to the next not deleted segment, if stored in a VSubpath.
void setPoint(int i, const KoPoint &p)
Sets the segment's point with index 0 <= i < degree() to "p".
Definition vsegment.h:143
unsigned short degree() const
Returns the segment's degree, which is identical to the number of nodes.
Definition vsegment.h:77
const KoPoint & point(int i) const
Returns the segment's point with index 0 <= i < degree().
Definition vsegment.h:115
VSelection manages a set of selected vobjects.
Definition vselection.h:62
Manages stroke properties.
Definition vstroke.h:49
@ patt
gradient as stroke
Definition vstroke.h:56
@ grad
solid stroke
Definition vstroke.h:55
VSubpath provides a sophisticated list of VSegment.
Definition vpath.h:43
virtual void visitVPath(VPath &composite)
Visit method for a VPath.
Definition vvisitor.cpp:74