diff options
Diffstat (limited to 'kig/modes/moving.cc')
-rw-r--r-- | kig/modes/moving.cc | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/kig/modes/moving.cc b/kig/modes/moving.cc new file mode 100644 index 00000000..e628a7ce --- /dev/null +++ b/kig/modes/moving.cc @@ -0,0 +1,245 @@ +// Copyright (C) 2002 Dominique Devriese <devriese@kde.org> + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#include "moving.h" + +#include "normal.h" + +#include "../objects/object_imp.h" +#include "../objects/object_factory.h" +#include "../kig/kig_document.h" +#include "../kig/kig_part.h" +#include "../kig/kig_view.h" +#include "../kig/kig_commands.h" +#include "../misc/kigpainter.h" +#include "../misc/calcpaths.h" +#include "../misc/coordinate_system.h" + +#include <qevent.h> + +#include <functional> +#include <algorithm> +#include <map> + +void MovingModeBase::initScreen( const std::vector<ObjectCalcer*>& in ) +{ + mcalcable = in; + std::set<ObjectCalcer*> calcableset( mcalcable.begin(), mcalcable.end() ); + + // don't try to move objects that have been deleted from the + // document or internal objects that the user is not aware of.. + std::vector<ObjectHolder*> docobjs = mdoc.document().objects(); + for ( std::vector<ObjectHolder*>::iterator i = docobjs.begin(); + i != docobjs.end(); ++i ) + if ( calcableset.find( ( *i )->calcer() ) != calcableset.end() ) + mdrawable.push_back( *i ); + + std::set<ObjectHolder*> docobjsset( docobjs.begin(), docobjs.end() ); + std::set<ObjectHolder*> drawableset( mdrawable.begin(), mdrawable.end() ); + std::set<ObjectHolder*> notmovingobjs; + std::set_difference( docobjsset.begin(), docobjsset.end(), drawableset.begin(), drawableset.end(), + std::inserter( notmovingobjs, notmovingobjs.begin() ) ); + + mview.clearStillPix(); + KigPainter p( mview.screenInfo(), &mview.stillPix, mdoc.document() ); + p.drawGrid( mdoc.document().coordinateSystem(), mdoc.document().grid(), + mdoc.document().axes() ); + p.drawObjects( notmovingobjs.begin(), notmovingobjs.end(), false ); + mview.updateCurPix(); + + KigPainter p2( mview.screenInfo(), &mview.curPix, mdoc.document() ); + p2.drawObjects( drawableset.begin(), drawableset.end(), true ); +} + +void MovingModeBase::leftReleased( QMouseEvent*, KigWidget* v ) +{ + // clean up after ourselves: + for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin(); + i != mcalcable.end(); ++i ) + ( *i )->calc( mdoc.document() ); + stopMove(); + mdoc.setModified( true ); + + // refresh the screen: + v->redrawScreen( std::vector<ObjectHolder*>() ); + v->updateScrollBars(); + + mdoc.doneMode( this ); +} + +void MovingModeBase::mouseMoved( QMouseEvent* e, KigWidget* v ) +{ + v->updateCurPix(); + Coordinate c = v->fromScreen( e->pos() ); + + bool snaptogrid = e->state() & Qt::ShiftButton; + moveTo( c, snaptogrid ); + for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin(); + i != mcalcable.end(); ++i ) + ( *i )->calc( mdoc.document() ); + KigPainter p( v->screenInfo(), &v->curPix, mdoc.document() ); + // TODO: only draw the explicitly moving objects as selected, the + // other ones as deselected.. Needs some support from the + // subclasses.. + p.drawObjects( mdrawable, true ); + v->updateWidget( p.overlay() ); + v->updateScrollBars(); +} + +class MovingMode::Private +{ +public: + // explicitly moving objects: these are the objects that the user + // requested to move... + std::vector<ObjectCalcer*> emo; + // point where we started moving.. + Coordinate pwwsm; + MonitorDataObjects* mon; + // we keep a map from the emo objects to their reference location. + // This is the location that they claim to be at before moving + // starts, and we use it as a reference point to determine where + // they should move next.. + std::map<const ObjectCalcer*, Coordinate> refmap; +}; + +MovingMode::MovingMode( const std::vector<ObjectHolder*>& os, const Coordinate& c, + KigWidget& v, KigPart& doc ) + : MovingModeBase( doc, v ), d( new Private ) +{ + d->pwwsm = c; + std::vector<ObjectCalcer*> emo; + std::set<ObjectCalcer*> objs; + for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i ) + if ( (*i)->canMove() ) + { + emo.push_back( ( *i )->calcer() ); + d->refmap[( *i )->calcer()] = (*i)->moveReferencePoint(); + objs.insert( ( *i )->calcer() ); + std::vector<ObjectCalcer*> parents = ( *i )->calcer()->movableParents(); + objs.insert( parents.begin(), parents.end() ); + }; + + emo = calcPath( emo ); + for ( std::vector<ObjectCalcer*>::const_iterator i = emo.begin(); i != emo.end(); ++i ) + if ( !isChild( *i, d->emo ) ) + d->emo.push_back( *i ); + + d->mon = new MonitorDataObjects( std::vector<ObjectCalcer*>( objs.begin(),objs.end() ) ); + + std::set<ObjectCalcer*> tmp = objs; + for ( std::set<ObjectCalcer*>::const_iterator i = tmp.begin(); i != tmp.end(); ++i ) + { + std::set<ObjectCalcer*> children = getAllChildren(*i); + objs.insert( children.begin(), children.end() ); + } + + initScreen( calcPath( std::vector<ObjectCalcer*>( objs.begin(), objs.end() ) ) ); +} + +void MovingMode::stopMove() +{ + QString text = d->emo.size() == 1 ? + d->emo[0]->imp()->type()->moveAStatement() : + i18n( "Move %1 Objects" ).arg( d->emo.size() ); + KigCommand* mc = new KigCommand( mdoc, text ); + d->mon->finish( mc ); + mdoc.history()->addCommand( mc ); +} + +void MovingMode::moveTo( const Coordinate& o, bool snaptogrid ) +{ + for( std::vector<ObjectCalcer*>::iterator i = d->emo.begin(); i != d->emo.end(); ++i ) + { + assert( d->refmap.find( *i ) != d->refmap.end() ); + Coordinate nc = d->refmap[*i] + ( o - d->pwwsm ); + if ( snaptogrid ) nc = mdoc.document().coordinateSystem().snapToGrid( nc, mview ); + (*i)->move( nc, mdoc.document() ); + }; +} + +PointRedefineMode::PointRedefineMode( ObjectHolder* p, KigPart& d, KigWidget& v ) + : MovingModeBase( d, v ), mp( p ), mmon( 0 ) +{ + assert( dynamic_cast<ObjectTypeCalcer*>( p->calcer() ) ); + moldtype = static_cast<ObjectTypeCalcer*>( p->calcer() )->type(); + std::vector<ObjectCalcer*> oldparents = p->calcer()->parents(); + std::copy( oldparents.begin(), oldparents.end(), std::back_inserter( moldparents ) ); + + std::vector<ObjectCalcer*> parents = getAllParents( mp->calcer() ); + mmon = new MonitorDataObjects( parents ); + std::vector<ObjectCalcer*> moving = parents; + std::set<ObjectCalcer*> children = getAllChildren( mp->calcer() ); + std::copy( children.begin(), children.end(), std::back_inserter( moving ) ); + initScreen( moving ); +} + +void PointRedefineMode::moveTo( const Coordinate& o, bool snaptogrid ) +{ + Coordinate realo = + snaptogrid ? mdoc.document().coordinateSystem().snapToGrid( o, mview ) : o; + ObjectFactory::instance()->redefinePoint( + static_cast<ObjectTypeCalcer*>( mp->calcer() ), realo, mdoc.document(), mview ); +} + +PointRedefineMode::~PointRedefineMode() +{ +} + +MovingModeBase::MovingModeBase( KigPart& doc, KigWidget& v ) + : KigMode( doc ), mview( v ) +{ +} + +MovingModeBase::~MovingModeBase() +{ +} + +void MovingModeBase::leftMouseMoved( QMouseEvent* e, KigWidget* v ) +{ + mouseMoved( e, v ); +} + +MovingMode::~MovingMode() +{ + delete d->mon; + delete d; +} + +void PointRedefineMode::stopMove() +{ + assert( dynamic_cast<ObjectTypeCalcer*>( mp->calcer() ) ); + ObjectTypeCalcer* mpcalc = static_cast<ObjectTypeCalcer*>( mp->calcer() ); + + std::vector<ObjectCalcer*> newparents = mpcalc->parents(); + std::vector<ObjectCalcer::shared_ptr> newparentsref( + newparents.begin(), newparents.end() ); + const ObjectType* newtype = mpcalc->type(); + + std::vector<ObjectCalcer*> oldparents; + for( std::vector<ObjectCalcer::shared_ptr>::iterator i = moldparents.begin(); + i != moldparents.end(); ++i ) + oldparents.push_back( i->get() ); + mpcalc->setType( moldtype ); + mpcalc->setParents( oldparents ); + mp->calc( mdoc.document() ); + + KigCommand* command = new KigCommand( mdoc, i18n( "Redefine Point" ) ); + command->addTask( + new ChangeParentsAndTypeTask( mpcalc, newparents, newtype ) ); + mmon->finish( command ); + mdoc.history()->addCommand( command ); +} |