modify abstracttool iface
[yamf.git] / yamf / tools / itween / itween.cpp
blob9d58f91f252ede56a57f83031b32edff1493aa1b
1 /**************************************************************************
2 * Copyright (C) 2005 by David Cuadrado *
3 * krawek@toonka.com *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
21 #include "itween.h"
23 #include <QGraphicsView>
24 #include <QGraphicsSceneMouseEvent>
25 #include <QSet>
26 #include <QHBoxLayout>
27 #include <QRadioButton>
28 #include <QToolBar>
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>
60 #define DEBUG 0
62 namespace YAMF {
63 namespace Drawing {
64 class BrushManager;
66 namespace Tool {
68 struct ITween::Private {
69 Private() : target(0), nodeEditor(0), transformer(0), paintArea(0) {}
70 enum Type {
71 PathMotion = 0x01,
72 Fill,
73 Transform,
74 NodeMotion
77 DGui::Action * action;
78 QWidget *configWidget;
79 QButtonGroup group;
81 Model::Object *target;
83 QPointF currentPos;
84 QPointF absItemPos;
87 Drawing::Tool::Private::ContourEditor *nodeEditor;
88 DGraphics::ItemTransformer* transformer;
90 QGraphicsPathItem *pathItem;
91 QPainterPath path;
92 QPointF firstPos;
93 QPointF lastPos;
95 Drawing::PaintArea *paintArea;
97 Item::Tweener *createObjectTweener(int frames = 1);
98 void saveChanges();
99 void releaseObject();
102 Item::Tweener *ITween::Private::createObjectTweener(int frames)
104 Item::Tweener *tweener = target->tweener();
106 if( tweener == 0 )
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);
131 return tweener;
134 void ITween::Private::saveChanges()
136 if( target )
138 int objectPos = target->frame()->visualIndex();
139 int framePos = paintArea->currentFrame()->visualIndex();
140 int step = qAbs(framePos - objectPos);
142 int frames = step;
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() );
169 break;
170 case DGraphics::ItemTransformer::Rotate:
172 QPointF pos = transformer->currentPosition();
173 tweener->setRotationAt(step, transformer->currentRotation());
174 tweener->setPosAt(step, pos );
176 break;
179 // transformer->setItem(target->item()); // To reset
182 break;
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);
195 int n = 0;
196 for(double percent = 0; percent < 1; percent += factor )
198 QPointF pos = npath.pointAtPercent(percent);
199 tweener->setPosAt(n, pos);
201 n++;
204 #if DEBUG
205 paintArea->currentFrame()->addItem(pathItem);
206 #endif
208 break;
209 case Private::NodeMotion:
211 if( QGraphicsPathItem *item = qgraphicsitem_cast<QGraphicsPathItem *>(target->item()) )
213 tweener->setPathAt(step, item->path());
216 break;
217 case Private::Fill:
219 if( QAbstractGraphicsShapeItem *item = qgraphicsitem_cast<QAbstractGraphicsShapeItem *>(target->item()) )
221 tweener->setBrushAt(step, item->brush());
222 tweener->setPenAt(step, item->pen());
225 break;
226 default:
229 break;
232 paintArea->addCommand(new YAMF::Command::AddTweening(target, tweener));
233 tweener->setStep(step);
237 void ITween::Private::releaseObject()
239 if( target )
241 if( transformer )
243 transformer->setVisible(false);
246 target->scene()->setAlwaysVisible(target, false);
247 if( target->tweener() )
249 target->tweener()->setFrames(target->tweener()->frames());
251 target = 0;
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)));
293 ITween::~ITween()
295 delete d->transformer;
296 delete d->nodeEditor;
297 delete d;
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
312 return "itween";
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();
325 if( d->target )
327 if( !d->target->item()->isSelected() )
329 d->saveChanges();
330 d->releaseObject();
334 QList<QGraphicsItem *> selected = photogram->selectedItems();
335 if( selected.isEmpty() ) return;
337 Model::Object *object = paintArea->currentFrame()->graphic(selected.first());
339 if( object == 0 )
341 // If the object has a tweener, it may be not in the current frame.
342 bool found = false;
343 foreach(Model::Object *obj, paintArea->currentScene()->tweeningObjects())
345 if( obj->item() == selected.first() )
347 object = obj;
348 found = true;
349 break;
353 if( !found )
354 return;
357 if( d->target != object )
359 if( d->target )
361 d->target->scene()->setAlwaysVisible(d->target, false);
364 d->target = object;
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);
376 int frames = step;
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());
396 #if 0
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);
407 break;
408 case DGraphics::ItemTransformer::Rotate:
410 d->transformer->setOperation(DGraphics::ItemTransformer::Scale);
412 break;
416 #endif
418 break;
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;
429 c.setAlpha(120);
431 QPen pen(c, 1);
432 pen.setStyle(Qt::DashDotDotLine);
433 d->pathItem->setPen(pen);
435 photogram->addItem( d->pathItem );
437 break;
438 default:
440 // qFatal("Not implemented!");
442 break;
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:
474 d->saveChanges();
475 d->transformer->show();
477 break;
478 case Private::PathMotion:
481 double smoothness = 1.0;
483 QPolygonF polygon = d->path.toFillPolygon();
484 if(!polygon.isEmpty() && polygon.isClosed())
485 polygon.pop_back();
487 d->path = DGraphics::Algorithm::smooth(polygon, smoothness);
488 d->pathItem->setPath(d->path);
491 d->saveChanges();
492 if( d->nodeEditor ) delete d->nodeEditor;
493 d->nodeEditor = new Drawing::Tool::Private::ContourEditor(d->pathItem, paintArea->photogram());
495 d->nodeEditor->show();
497 break;
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());
504 d->saveChanges();
505 d->nodeEditor->show();
507 else
509 d->releaseObject();
510 return;
513 break;
514 case Private::Fill:
516 if( QAbstractGraphicsShapeItem *item = qgraphicsitem_cast<QAbstractGraphicsShapeItem *>(d->target->item()) )
518 paintArea->brushManager()->apply(item);
519 d->saveChanges();
521 else
523 d->releaseObject();
524 return;
527 break;
531 DGui::Action * ITween::action() const
533 return d->action;
536 int ITween::type() const
538 return AbstractTool::Brush;
541 void ITween::aboutToChangeTool()
543 d->saveChanges();
544 d->releaseObject();
547 void ITween::setupConfigBar(QToolBar *configBar)
549 configBar->addWidget(d->configWidget)->setVisible(true);
552 void ITween::onChangeTool(int id)
554 d->saveChanges();
555 // switch(id)
556 // {
557 // case Private::Transform:
558 // {
559 // }
560 // break;
561 // case Private::NodeMotion:
562 // {
564 // }
565 // break;
566 // default:
567 // {
568 // }
569 // break;
570 // }