1 /**************************************************************************
2 * Copyright (C) 2005 by David Cuadrado *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
23 #include <QGraphicsView>
24 #include <QGraphicsSceneMouseEvent>
26 #include <QHBoxLayout>
27 #include <QRadioButton>
29 #include <QButtonGroup>
30 #include <QXmlStreamWriter>
32 #include <dcore/global.h>
33 #include <dcore/debug.h>
35 #include <dgui/iconloader.h>
36 #include <dgui/action.h>
38 #include <dgraphics/pathhelper.h>
39 #include <dgraphics/algorithm.h>
41 #include "yamf/model/object.h"
42 #include "yamf/model/frame.h"
43 #include "yamf/model/scene.h"
45 #include "yamf/drawing/paintarea.h"
46 #include "yamf/drawing/brushmanager.h"
47 #include "yamf/drawing/photogram.h"
48 #include "yamf/item/path.h"
49 #include "yamf/item/proxy.h"
50 #include "yamf/item/line.h"
51 #include "yamf/item/converter.h"
52 #include "yamf/item/tweener.h"
53 #include "yamf/item/serializer.h"
55 #include "yamf/model/command/addtweening.h"
56 #include "yamf/tools/selection/private/contoureditor.h"
58 #include <dgraphics/itemtransformer.h>
68 struct ITween::Private
{
69 Private() : target(0), nodeEditor(0), transformer(0), paintArea(0) {}
77 DGui::Action
* action
;
78 QWidget
*configWidget
;
81 Model::Object
*target
;
87 Drawing::Tool::Private::ContourEditor
*nodeEditor
;
88 DGraphics::ItemTransformer
* transformer
;
90 QGraphicsPathItem
*pathItem
;
95 Drawing::PaintArea
*paintArea
;
97 Item::Tweener
*createObjectTweener(int frames
= 1);
102 Item::Tweener
*ITween::Private::createObjectTweener(int frames
)
104 Item::Tweener
*tweener
= target
->tweener();
108 tweener
= new Item::Tweener(1, target
);
110 tweener
->setPosAt(0, target
->item()->scenePos());
111 tweener
->setRotationAt(0, 0);
112 tweener
->setScaleAt(0, 1.0, 1.0);
114 if( QAbstractGraphicsShapeItem
*shape
= qgraphicsitem_cast
<QAbstractGraphicsShapeItem
*>(target
->item()) )
116 tweener
->setBrushAt(0, shape
->brush());
117 tweener
->setPenAt(0, shape
->pen());
120 if( QGraphicsPathItem
*path
= qgraphicsitem_cast
<QGraphicsPathItem
*>(target
->item()) )
122 tweener
->setPathAt(0, path
->path());
125 target
->setTweener(tweener
);
128 frames
= qMax(frames
, tweener
->frames());
129 tweener
->setFrames(frames
);
134 void ITween::Private::saveChanges()
138 int objectPos
= target
->frame()->visualIndex();
139 int framePos
= paintArea
->currentFrame()->visualIndex();
140 int step
= qAbs(framePos
- objectPos
);
143 if( target
->tweener() )
145 frames
= qMax(step
, target
->tweener()->frames());
148 Item::Tweener
*tweener
= createObjectTweener(frames
);
150 switch(group
.checkedId())
152 case Private::Transform
:
154 if( currentPos
!= target
->item()->pos() ) // The object was changed
156 tweener
->setPosAt(step
, target
->item()->pos());
159 if( transformer
->isModified() )
161 switch(transformer
->operation() )
163 case DGraphics::ItemTransformer::Scale
:
165 tweener
->setScaleAt(step
, transformer
->currentVerticalScale(), transformer
->currentHorizontalScale() );
167 tweener
->setPosAt(step
, transformer
->currentPosition() );
170 case DGraphics::ItemTransformer::Rotate
:
172 QPointF pos
= transformer
->currentPosition();
173 tweener
->setRotationAt(step
, transformer
->currentRotation());
174 tweener
->setPosAt(step
, pos
);
179 // transformer->setItem(target->item()); // To reset
183 case Private::PathMotion
:
185 QRectF br
= target
->item()->sceneBoundingRect();
186 QPointF origin
= absItemPos
;
188 QTransform transform
;
189 transform
.translate(-origin
.x(), -origin
.y());
191 double factor
= 1.0/step
;
193 QPainterPath npath
= transform
.map(path
);
196 for(double percent
= 0; percent
< 1; percent
+= factor
)
198 QPointF pos
= npath
.pointAtPercent(percent
);
199 tweener
->setPosAt(n
, pos
);
205 paintArea
->currentFrame()->addItem(pathItem
);
209 case Private::NodeMotion
:
211 if( QGraphicsPathItem
*item
= qgraphicsitem_cast
<QGraphicsPathItem
*>(target
->item()) )
213 tweener
->setPathAt(step
, item
->path());
219 if( QAbstractGraphicsShapeItem
*item
= qgraphicsitem_cast
<QAbstractGraphicsShapeItem
*>(target
->item()) )
221 tweener
->setBrushAt(step
, item
->brush());
222 tweener
->setPenAt(step
, item
->pen());
232 paintArea
->addCommand(new YAMF::Command::AddTweening(target
, tweener
));
233 tweener
->setStep(step
);
237 void ITween::Private::releaseObject()
243 transformer
->setVisible(false);
246 target
->scene()->setAlwaysVisible(target
, false);
247 if( target
->tweener() )
249 target
->tweener()->setFrames(target
->tweener()->frames());
253 // delete this->nodeEditor;
254 // this->nodeEditor = 0;
255 // delete this->pathItem;
256 // this->pathItem = 0;
260 ITween::ITween(QObject
*parent
) : AbstractTool(parent
), d(new Private
)
262 d
->action
= new DGui::Action( DGui::IconLoader::self()->load("itween.svg"), tr("iTween"), this);
263 // d->action->setShortcut( QKeySequence(tr("Ctrl+W")) );
265 d
->configWidget
= new QWidget
;
266 QHBoxLayout
*layout
= new QHBoxLayout(d
->configWidget
);
267 layout
->setMargin(0);
268 layout
->setSpacing(2);
271 QRadioButton
*transform
= new QRadioButton(tr("Transform"));
272 transform
->setChecked(true);
273 layout
->addWidget(transform
);
275 QRadioButton
*pathMotion
= new QRadioButton(tr("Path motion"));
276 layout
->addWidget(pathMotion
);
278 QRadioButton
*fill
= new QRadioButton(tr("Fill"));
279 layout
->addWidget(fill
);
281 QRadioButton
*nodeMotion
= new QRadioButton(tr("Node motion"));
282 layout
->addWidget(nodeMotion
);
284 d
->group
.addButton(pathMotion
, Private::PathMotion
);
285 d
->group
.addButton(fill
, Private::Fill
);
286 d
->group
.addButton(transform
, Private::Transform
);
287 d
->group
.addButton(nodeMotion
, Private::NodeMotion
);
289 connect(&d
->group
, SIGNAL(
290 buttonClicked(int)), this, SLOT(onChangeTool(int)));
295 delete d
->transformer
;
296 delete d
->nodeEditor
;
300 void ITween::init(Photogram
*photogram
)
302 foreach(QGraphicsItem
*item
, photogram
->items() )
304 item
->setFlag(QGraphicsItem::ItemIsSelectable
, true);
305 item
->setFlag(QGraphicsItem::ItemIsFocusable
, true);
306 item
->setFlag(QGraphicsItem::ItemIsMovable
, true);
310 QString
ITween::id() const
315 void ITween::press(const QGraphicsSceneMouseEvent
*input
)
317 PaintArea
*paintArea
= this->paintArea(); // FIXME
319 d
->firstPos
= input
->scenePos();
320 d
->lastPos
= input
->scenePos();
322 d
->paintArea
= paintArea
;
323 Photogram
*photogram
= paintArea
->photogram();
327 if( !d
->target
->item()->isSelected() )
334 QList
<QGraphicsItem
*> selected
= photogram
->selectedItems();
335 if( selected
.isEmpty() ) return;
337 Model::Object
*object
= paintArea
->currentFrame()->graphic(selected
.first());
341 // If the object has a tweener, it may be not in the current frame.
343 foreach(Model::Object
*obj
, paintArea
->currentScene()->tweeningObjects())
345 if( obj
->item() == selected
.first() )
357 if( d
->target
!= object
)
361 d
->target
->scene()->setAlwaysVisible(d
->target
, false);
365 d
->target
->scene()->setAlwaysVisible(d
->target
, true);
367 d
->createObjectTweener();
369 d
->currentPos
= d
->target
->item()->pos();
370 d
->absItemPos
= d
->target
->item()->sceneBoundingRect().topLeft();
372 int objectPos
= d
->target
->frame()->visualIndex();
373 int framePos
= paintArea
->currentFrame()->visualIndex();
374 int step
= qAbs(framePos
- objectPos
);
377 if( d
->target
->tweener() )
379 frames
= qMax(step
, d
->target
->tweener()->frames());
382 if(input
->buttons() == Qt::LeftButton
)
384 switch(d
->group
.checkedId())
386 case Private::Transform
:
388 if( d
->transformer
== 0)
390 d
->transformer
= new DGraphics::ItemTransformer(d
->target
->item(), d
->target
->item()->scene());
392 else if( d
->transformer
->item() != d
->target
->item() )
394 d
->transformer
->setItem(d
->target
->item());
397 else if( input
->modifiers() != Qt::ControlModifier
)
399 if(photogram
->mouseGrabberItem() == d
->transformer
->item())
401 switch(d
->transformer
->operation())
403 case DGraphics::ItemTransformer::Scale
:
405 d
->transformer
->setOperation(DGraphics::ItemTransformer::Rotate
);
408 case DGraphics::ItemTransformer::Rotate
:
410 d
->transformer
->setOperation(DGraphics::ItemTransformer::Scale
);
419 case Private::PathMotion
:
421 d
->path
= QPainterPath();
422 d
->path
.moveTo(d
->firstPos
);
424 d
->pathItem
= new QGraphicsPathItem
;
425 d
->pathItem
->setZValue(1000);
428 QColor c
= Qt::lightGray
;
432 pen
.setStyle(Qt::DashDotDotLine
);
433 d
->pathItem
->setPen(pen
);
435 photogram
->addItem( d
->pathItem
);
440 // qFatal("Not implemented!");
447 void ITween::move(const QGraphicsSceneMouseEvent
*input
)
449 if( d
->target
== 0 ) return;
451 PaintArea
*paintArea
= this->paintArea();
452 if(input
->buttons() == Qt::LeftButton
)
454 if( d
->group
.checkedId() == Private::PathMotion
)
456 d
->lastPos
= input
->scenePos();
457 d
->path
.lineTo( d
->lastPos
);
459 d
->pathItem
->setPath(d
->path
);
460 paintArea
->brushManager()->map(d
->pathItem
);
465 void ITween::release(const QGraphicsSceneMouseEvent
*input
)
467 if( d
->target
== 0 ) return;
469 PaintArea
*paintArea
= this->paintArea();
470 switch(d
->group
.checkedId())
472 case Private::Transform
:
475 d
->transformer
->show();
478 case Private::PathMotion
:
481 double smoothness
= 1.0;
483 QPolygonF polygon
= d
->path
.toFillPolygon();
484 if(!polygon
.isEmpty() && polygon
.isClosed())
487 d
->path
= DGraphics::Algorithm::smooth(polygon
, smoothness
);
488 d
->pathItem
->setPath(d
->path
);
492 if( d
->nodeEditor
) delete d
->nodeEditor
;
493 d
->nodeEditor
= new Drawing::Tool::Private::ContourEditor(d
->pathItem
, paintArea
->photogram());
495 d
->nodeEditor
->show();
498 case Private::NodeMotion
:
500 if( QGraphicsPathItem
*item
= qgraphicsitem_cast
<QGraphicsPathItem
*>(d
->target
->item()) )
502 if( d
->nodeEditor
) delete d
->nodeEditor
;
503 d
->nodeEditor
= new Drawing::Tool::Private::ContourEditor(item
, paintArea
->photogram());
505 d
->nodeEditor
->show();
516 if( QAbstractGraphicsShapeItem
*item
= qgraphicsitem_cast
<QAbstractGraphicsShapeItem
*>(d
->target
->item()) )
518 paintArea
->brushManager()->apply(item
);
531 DGui::Action
* ITween::action() const
536 int ITween::type() const
538 return AbstractTool::Brush
;
541 void ITween::aboutToChangeTool()
547 void ITween::setupConfigBar(QToolBar
*configBar
)
549 configBar
->addWidget(d
->configWidget
)->setVisible(true);
552 void ITween::onChangeTool(int id
)
557 // case Private::Transform:
561 // case Private::NodeMotion: