You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/kig/modes/moving.cpp

246 lines
8.3 KiB

// 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 <tqevent.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(), TQT_TQPAINTDEVICE(&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(), TQT_TQPAINTDEVICE(&mview.curPix), mdoc.document() );
p2.drawObjects( drawableset.begin(), drawableset.end(), true );
}
void MovingModeBase::leftReleased( TQMouseEvent*, 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( TQMouseEvent* e, KigWidget* v )
{
v->updateCurPix();
Coordinate c = v->fromScreen( e->pos() );
bool snaptogrid = e->state() & TQt::ShiftButton;
moveTo( c, snaptogrid );
for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin();
i != mcalcable.end(); ++i )
( *i )->calc( mdoc.document() );
KigPainter p( v->screenInfo(), TQT_TQPAINTDEVICE(&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()
{
TQString 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( TQMouseEvent* 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 );
}