vdistributecmd.cpp
1/* This file is doc of the KDE project
2 Copyright (C) 2005 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 "vdistributecmd.h"
24#include "vtransformcmd.h"
25#include "vdocument.h"
26#include "vselection.h"
27
28VDistributeCmd::VDistributeCmd( VDocument *doc, Distribute distribute )
29 : VCommand( doc, i18n( "Distribute Objects" ) ), m_distribute( distribute )
30{
31 m_trafoCmds.setAutoDelete( true );
32}
33
34VDistributeCmd::~VDistributeCmd()
35{
36}
37
38void
40{
41 if( document()->selection()->objects().count() <= 2 )
42 return;
43
44 KoRect bbox;
45 double extent = 0.0;
46 double dx, dy;
47
48 VObjectList objs = document()->selection()->objects();
49 VObjectListIterator itr( objs );
50
51 TQMap<double,VObject*> sortedPos;
52
53 // sort by position and calculate sum of objects widht/height
54 for( ; itr.current(); ++itr )
55 {
56 bbox = itr.current()->boundingBox();
57 switch( m_distribute )
58 {
59 case DISTRIBUTE_HORIZONTAL_CENTER:
60 sortedPos[bbox.center().x()] = itr.current();
61 break;
62 case DISTRIBUTE_HORIZONTAL_GAP:
63 case DISTRIBUTE_HORIZONTAL_LEFT:
64 sortedPos[bbox.left()] = itr.current();
65 extent += bbox.width();
66 break;
67 case DISTRIBUTE_HORIZONTAL_RIGHT:
68 sortedPos[bbox.right()] = itr.current();
69 break;
70 case DISTRIBUTE_VERTICAL_CENTER:
71 sortedPos[bbox.center().y()] = itr.current();
72 break;
73 case DISTRIBUTE_VERTICAL_GAP:
74 case DISTRIBUTE_VERTICAL_BOTTOM:
75 sortedPos[bbox.bottom()] = itr.current();
76 extent += bbox.height();
77 break;
78 case DISTRIBUTE_VERTICAL_TOP:
79 sortedPos[bbox.top()] = itr.current();
80 break;
81 }
82 }
83
84 VObject* first = sortedPos.begin().data();
85 VObject* last = (--sortedPos.end()).data();
86
87 // determine the available space to distribute
88 double space = getAvailableSpace( first, last, extent );
89 double pos = 0.0, step = space / double(objs.count() - 1);
90
91 VTranslateCmd *trafoCmd = 0L;
92 TQMapIterator<double,VObject*> it = sortedPos.begin(), et = sortedPos.end();
93
94 for( ; it != et; ++it )
95 {
96 if( it.data() == first || it.data() == last )
97 continue;
98
99 pos += step;
100
101 document()->selection()->clear();
102
103 bbox = it.data()->boundingBox();
104
105 switch( m_distribute )
106 {
107 case DISTRIBUTE_HORIZONTAL_CENTER:
108 dx = first->boundingBox().center().x() + pos - bbox.center().x();
109 dy = 0.0;
110 break;
111 case DISTRIBUTE_HORIZONTAL_GAP:
112 dx = first->boundingBox().right() + pos + 0.5 * bbox.width() - bbox.center().x();
113 dy = 0.0;
114 pos += bbox.width();
115 break;
116 case DISTRIBUTE_HORIZONTAL_LEFT:
117 dx = first->boundingBox().left() + pos - bbox.left();
118 dy = 0.0;
119 break;
120 case DISTRIBUTE_HORIZONTAL_RIGHT:
121 dx = first->boundingBox().right() + pos - bbox.right();
122 dy = 0.0;
123 break;
124 case DISTRIBUTE_VERTICAL_CENTER:
125 dx = 0.0;
126 dy = first->boundingBox().center().y() + pos - bbox.center().y();
127 break;
128 case DISTRIBUTE_VERTICAL_GAP:
129 dx = 0.0;
130 dy = first->boundingBox().bottom() + pos + 0.5 * bbox.height() - bbox.center().y();
131 pos += bbox.height();
132 break;
133 case DISTRIBUTE_VERTICAL_BOTTOM:
134 dx = 0.0;
135 dy = first->boundingBox().bottom() + pos - bbox.bottom();
136 break;
137 case DISTRIBUTE_VERTICAL_TOP:
138 dx = 0.0;
139 dy = first->boundingBox().top() + pos - bbox.top();
140 break;
141 };
142 document()->selection()->append( it.data() );
143 trafoCmd = new VTranslateCmd( document(), dx, dy );
144 m_trafoCmds.append( trafoCmd );
145 trafoCmd->execute();
146 }
147
148 // re-add object to selection
149 itr.toFirst();
150 for( ; itr.current() ; ++itr )
151 document()->selection()->append( itr.current() );
152 setSuccess( true );
153}
154
155void
157{
158 TQPtrListIterator<VTranslateCmd> itr( m_trafoCmds );
159 for( ; itr.current() ; ++itr )
160 itr.current()->unexecute();
161 setSuccess( false );
162}
163
164double
165VDistributeCmd::getAvailableSpace( VObject *first, VObject *last, double extent )
166{
167 switch( m_distribute )
168 {
169 case DISTRIBUTE_HORIZONTAL_CENTER:
170 return last->boundingBox().center().x() - first->boundingBox().center().x();
171 break;
172 case DISTRIBUTE_HORIZONTAL_GAP:
173 extent -= first->boundingBox().width() + last->boundingBox().width();
174 return last->boundingBox().left() - first->boundingBox().right() - extent;
175 break;
176 case DISTRIBUTE_HORIZONTAL_LEFT:
177 return last->boundingBox().left() - first->boundingBox().left();
178 break;
179 case DISTRIBUTE_HORIZONTAL_RIGHT:
180 return last->boundingBox().right() - first->boundingBox().right();
181 break;
182 case DISTRIBUTE_VERTICAL_CENTER:
183 return last->boundingBox().center().y() - first->boundingBox().center().y();
184 break;
185 case DISTRIBUTE_VERTICAL_GAP:
186 extent -= first->boundingBox().height() + last->boundingBox().height();
187 return last->boundingBox().top() - first->boundingBox().bottom() - extent;
188 break;
189 case DISTRIBUTE_VERTICAL_BOTTOM:
190 return last->boundingBox().bottom() - first->boundingBox().bottom();
191 break;
192 case DISTRIBUTE_VERTICAL_TOP:
193 return last->boundingBox().top() - first->boundingBox().top();
194 break;
195 }
196
197 return 0.0;
198}
The base class for all karbon commands.
Definition vcommand.h:42
VDocument * document() const
Returns the document the command works on.
Definition vcommand.h:121
virtual void unexecute()
Unexecutes the command.
virtual void execute()
Executes the command.
All non-visual, static doc info is in here.
Definition vdocument.h:53
VSelection * selection() const
Returns a pointer to the selection.
Definition vdocument.h:238
The base class for all karbon objects.
Definition vobject.h:50
virtual const KoRect & boundingBox() const
Calculates the tightest bounding box around the object.
Definition vobject.h:111
const VObjectList & objects() const
Read only access to the selected objects.
Definition vselection.h:136
void append()
Adds all objects to the selection.
void clear()
Removes the references to all objects, not the objects themselves.
void setSuccess(bool success=true)
Set the success property.
Definition vvisitor.h:142