karbon

vdistributecmd.cc

00001 /* This file is doc of the KDE project
00002    Copyright (C) 2005 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 "vdistributecmd.h"
00024 #include "vtransformcmd.h"
00025 #include "vdocument.h"
00026 #include "vselection.h"
00027 
00028 VDistributeCmd::VDistributeCmd( VDocument *doc, Distribute distribute )
00029     : VCommand( doc, i18n( "Distribute Objects" ) ), m_distribute( distribute )
00030 {
00031     m_trafoCmds.setAutoDelete( true );
00032 }
00033 
00034 VDistributeCmd::~VDistributeCmd()
00035 {
00036 }
00037 
00038 void
00039 VDistributeCmd::execute()
00040 {
00041     if( document()->selection()->objects().count() <= 2 )
00042         return;
00043     
00044     KoRect bbox;
00045     double extent = 0.0;
00046     double dx, dy;
00047 
00048     VObjectList objs = document()->selection()->objects();
00049     VObjectListIterator itr( objs );
00050 
00051     QMap<double,VObject*> sortedPos;
00052 
00053     // sort by position and calculate sum of objects widht/height
00054     for( ; itr.current(); ++itr )
00055     {
00056         bbox = itr.current()->boundingBox();
00057         switch( m_distribute )
00058         {
00059             case DISTRIBUTE_HORIZONTAL_CENTER:
00060                 sortedPos[bbox.center().x()] = itr.current();
00061             break;
00062             case DISTRIBUTE_HORIZONTAL_GAP:
00063             case DISTRIBUTE_HORIZONTAL_LEFT:
00064                 sortedPos[bbox.left()] = itr.current();
00065                 extent += bbox.width();
00066             break;
00067             case DISTRIBUTE_HORIZONTAL_RIGHT:
00068                 sortedPos[bbox.right()] = itr.current();
00069             break;
00070             case DISTRIBUTE_VERTICAL_CENTER:
00071                 sortedPos[bbox.center().y()] = itr.current();
00072             break;
00073             case DISTRIBUTE_VERTICAL_GAP:
00074             case DISTRIBUTE_VERTICAL_BOTTOM:
00075                 sortedPos[bbox.bottom()] = itr.current();
00076                 extent += bbox.height();
00077             break;
00078             case DISTRIBUTE_VERTICAL_TOP:
00079                 sortedPos[bbox.top()] = itr.current();
00080             break;
00081         }
00082     }
00083     
00084     VObject* first = sortedPos.begin().data();
00085     VObject* last = (--sortedPos.end()).data();
00086 
00087     // determine the available space to distribute
00088     double space = getAvailableSpace( first, last, extent );
00089     double pos = 0.0, step = space / double(objs.count() - 1);
00090 
00091     VTranslateCmd *trafoCmd = 0L;
00092     QMapIterator<double,VObject*> it = sortedPos.begin(), et = sortedPos.end();
00093 
00094     for( ; it != et; ++it ) 
00095     {
00096         if( it.data() == first || it.data() == last )
00097             continue;
00098 
00099         pos += step;
00100 
00101         document()->selection()->clear();
00102         
00103         bbox = it.data()->boundingBox();
00104 
00105         switch( m_distribute )
00106         {
00107             case DISTRIBUTE_HORIZONTAL_CENTER:
00108                 dx = first->boundingBox().center().x() + pos - bbox.center().x();
00109                 dy = 0.0;
00110             break;
00111             case DISTRIBUTE_HORIZONTAL_GAP:
00112                 dx = first->boundingBox().right() + pos + 0.5 * bbox.width() - bbox.center().x();
00113                 dy = 0.0;
00114                 pos += bbox.width();
00115             break;
00116             case DISTRIBUTE_HORIZONTAL_LEFT:
00117                 dx = first->boundingBox().left() + pos - bbox.left();
00118                 dy = 0.0;
00119             break;
00120             case DISTRIBUTE_HORIZONTAL_RIGHT:
00121                 dx = first->boundingBox().right() + pos - bbox.right();
00122                 dy = 0.0;
00123             break;
00124             case DISTRIBUTE_VERTICAL_CENTER:
00125                 dx = 0.0;
00126                 dy = first->boundingBox().center().y() + pos - bbox.center().y();
00127             break;
00128             case DISTRIBUTE_VERTICAL_GAP:
00129                 dx = 0.0;
00130                 dy = first->boundingBox().bottom() + pos + 0.5 * bbox.height() - bbox.center().y();
00131                 pos += bbox.height();
00132             break;
00133             case DISTRIBUTE_VERTICAL_BOTTOM:
00134                 dx = 0.0;
00135                 dy = first->boundingBox().bottom() + pos - bbox.bottom();
00136             break;
00137             case DISTRIBUTE_VERTICAL_TOP:
00138                 dx = 0.0;
00139                 dy = first->boundingBox().top() + pos - bbox.top();
00140             break;
00141         };
00142         document()->selection()->append( it.data() );
00143         trafoCmd = new VTranslateCmd( document(), dx, dy );
00144         m_trafoCmds.append( trafoCmd );
00145         trafoCmd->execute();
00146     }
00147     
00148     // re-add object to selection
00149     itr.toFirst();
00150     for( ; itr.current() ; ++itr )
00151         document()->selection()->append( itr.current() );
00152     setSuccess( true );
00153 }
00154 
00155 void
00156 VDistributeCmd::unexecute()
00157 {
00158     QPtrListIterator<VTranslateCmd> itr( m_trafoCmds );
00159     for( ; itr.current() ; ++itr )
00160         itr.current()->unexecute();
00161     setSuccess( false );
00162 }
00163 
00164 double
00165 VDistributeCmd::getAvailableSpace( VObject *first, VObject *last, double extent )
00166 {
00167     switch( m_distribute )
00168     {
00169         case DISTRIBUTE_HORIZONTAL_CENTER:
00170             return last->boundingBox().center().x() - first->boundingBox().center().x();
00171         break;
00172         case DISTRIBUTE_HORIZONTAL_GAP:
00173             extent -= first->boundingBox().width() + last->boundingBox().width();
00174             return last->boundingBox().left() - first->boundingBox().right() - extent;
00175         break;
00176         case DISTRIBUTE_HORIZONTAL_LEFT:
00177             return last->boundingBox().left() - first->boundingBox().left();
00178         break;
00179         case DISTRIBUTE_HORIZONTAL_RIGHT:
00180             return last->boundingBox().right() - first->boundingBox().right();
00181         break;
00182         case DISTRIBUTE_VERTICAL_CENTER:
00183             return last->boundingBox().center().y() - first->boundingBox().center().y();
00184         break;
00185         case DISTRIBUTE_VERTICAL_GAP:
00186             extent -= first->boundingBox().height() + last->boundingBox().height();
00187             return last->boundingBox().top() - first->boundingBox().bottom() - extent;
00188         break;
00189         case DISTRIBUTE_VERTICAL_BOTTOM:
00190             return last->boundingBox().bottom() - first->boundingBox().bottom();
00191         break;
00192         case DISTRIBUTE_VERTICAL_TOP:
00193             return last->boundingBox().top() - first->boundingBox().top();
00194         break;
00195     }
00196 
00197     return 0.0;
00198 }
KDE Home | KDE Accessibility Home | Description of Access Keys