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 "private/contoureditor.h"
58 #include <dgraphics/itemtransformer.h>
60 #include "commonalgorithms.h"
70 struct ITween::Private
{
71 Private() : target(0), nodeEditor(0), transformer(0), pathItem(0), paintArea(0) {}
79 DGui::Action
* action
;
80 QWidget
*configWidget
;
83 Model::Object
*target
;
89 Drawing::Tool::Private::ContourEditor
*nodeEditor
;
90 DGraphics::ItemTransformer
* transformer
;
92 QGraphicsPathItem
*pathItem
;
97 Drawing::PaintArea
*paintArea
;
99 Item::Tweener
*createObjectTweener(int frames
= 1);
101 void releaseObject();
104 Item::Tweener
*ITween::Private::createObjectTweener(int frames
)
106 Item::Tweener
*tweener
= target
->tweener();
110 tweener
= new Item::Tweener(1, target
);
112 tweener
->setPosAt(0, target
->item()->scenePos());
113 // tweener->setRotationAt(0, 0);
114 // tweener->setScaleAt(0, 1.0, 1.0);
116 // if( item()->type() != QAbstractGraphicsShapeItem::Type ) return;
117 if( QAbstractGraphicsShapeItem
*shape
= dynamic_cast<QAbstractGraphicsShapeItem
*>(target
->item()) )
119 tweener
->setBrushAt(0, shape
->brush());
120 tweener
->setPenAt(0, shape
->pen());
123 if( QGraphicsPathItem
*path
= dynamic_cast<QGraphicsPathItem
*>(target
->item()) )
125 tweener
->setPathAt(0, path
->path());
128 target
->setTweener(tweener
);
131 frames
= qMax(frames
, tweener
->frames());
132 tweener
->setFrames(frames
);
137 void ITween::Private::saveChanges()
141 int objectPos
= target
->frame()->visualIndex();
142 int framePos
= paintArea
->currentFrame()->visualIndex();
143 int step
= qAbs(framePos
- objectPos
);
146 if( target
->tweener() )
148 frames
= qMax(step
, target
->tweener()->frames());
151 Item::Tweener
*tweener
= createObjectTweener(frames
);
153 switch(group
.checkedId())
155 case Private::Transform
:
157 if( currentPos
!= target
->item()->pos() ) // The object was changed
159 tweener
->setPosAt(step
, target
->item()->pos());
164 if( transformer
->isModified() )
166 switch(transformer
->operation() )
168 case DGraphics::ItemTransformer::Scale
:
170 tweener
->setScaleAt(step
, transformer
->currentVerticalScale(), transformer
->currentHorizontalScale() );
172 tweener
->setPosAt(step
, transformer
->currentPosition() );
175 case DGraphics::ItemTransformer::Rotate
:
177 QPointF pos
= transformer
->currentPosition();
178 tweener
->setRotationAt(step
, transformer
->currentRotation());
179 tweener
->setPosAt(step
, pos
);
184 // transformer->setItem(target->item()); // To reset
189 case Private::PathMotion
:
191 if( path
.elementCount() < 3 ) break;
193 QRectF br
= target
->item()->sceneBoundingRect();
194 QPointF origin
= absItemPos
;
196 QTransform transform
;
197 transform
.translate(-origin
.x(), -origin
.y());
199 double factor
= 1.0/step
;
201 QPainterPath npath
= transform
.map(path
);
204 for(double percent
= 0; percent
< 1; percent
+= factor
)
206 QPointF pos
= npath
.pointAtPercent(percent
);
207 tweener
->setPosAt(n
, pos
);
213 paintArea
->currentFrame()->addItem(pathItem
);
217 case Private::NodeMotion
:
219 if( QGraphicsPathItem
*item
= dynamic_cast<QGraphicsPathItem
*>(target
->item()) )
221 tweener
->setPathAt(step
, item
->path());
227 if( QAbstractGraphicsShapeItem
*item
= dynamic_cast<QAbstractGraphicsShapeItem
*>(target
->item()) )
229 tweener
->setBrushAt(step
, item
->brush());
230 tweener
->setPenAt(step
, item
->pen());
240 paintArea
->addCommand(new YAMF::Command::AddTweening(target
, tweener
));
241 tweener
->setStep(step
);
245 void ITween::Private::releaseObject()
251 transformer
->setVisible(false);
252 foreach(QGraphicsItem
*node
, transformer
->nodes())
254 paintArea
->setAlwaysVisible(node
, false);
259 paintArea
->setAlwaysVisible(pathItem
, false);
267 foreach(QGraphicsItem
*node
, nodeEditor
->nodes())
269 paintArea
->setAlwaysVisible(node
, false);
277 target
->scene()->setAlwaysVisible(target
, false);
278 if( target
->tweener() )
280 target
->tweener()->setFrames(target
->tweener()->frames());
286 ITween::ITween(QObject
*parent
) : AbstractTool(parent
), d(new Private
)
288 d
->action
= new DGui::Action( DGui::IconLoader::self()->load("itween.svg"), tr("iTween"), this);
290 // d->action->setShortcut( QKeySequence(tr("Ctrl+W")) );
292 d
->configWidget
= new QWidget
;
293 QHBoxLayout
*layout
= new QHBoxLayout(d
->configWidget
);
294 layout
->setMargin(0);
295 layout
->setSpacing(2);
298 QRadioButton
*transform
= new QRadioButton(tr("Transform"));
299 transform
->setChecked(true);
300 layout
->addWidget(transform
);
302 QRadioButton
*pathMotion
= new QRadioButton(tr("Path motion"));
303 layout
->addWidget(pathMotion
);
305 QRadioButton
*fill
= new QRadioButton(tr("Fill"));
306 layout
->addWidget(fill
);
308 QRadioButton
*nodeMotion
= new QRadioButton(tr("Node motion"));
309 layout
->addWidget(nodeMotion
);
311 d
->group
.addButton(pathMotion
, Private::PathMotion
);
312 d
->group
.addButton(fill
, Private::Fill
);
313 d
->group
.addButton(transform
, Private::Transform
);
314 d
->group
.addButton(nodeMotion
, Private::NodeMotion
);
316 connect(&d
->group
, SIGNAL(buttonClicked(int)), this, SLOT(onChangeTool(int)));
323 foreach(QGraphicsItem
*node
, d
->nodeEditor
->nodes())
325 paintArea()->setAlwaysVisible(node
, false);
327 delete d
->nodeEditor
;
332 foreach(QGraphicsItem
*node
, d
->transformer
->nodes())
334 paintArea()->setAlwaysVisible(node
, false);
336 delete d
->transformer
;
341 paintArea()->setAlwaysVisible(d
->pathItem
, false);
349 void ITween::init(Photogram
*photogram
)
351 foreach(QGraphicsItem
*item
, photogram
->items() )
353 item
->setFlag(QGraphicsItem::ItemIsSelectable
, true);
354 item
->setFlag(QGraphicsItem::ItemIsFocusable
, true);
355 item
->setFlag(QGraphicsItem::ItemIsMovable
, true);
359 QString
ITween::id() const
364 void ITween::press(const QGraphicsSceneMouseEvent
*input
)
366 PaintArea
*paintArea
= this->paintArea(); // FIXME
368 d
->firstPos
= input
->scenePos();
369 d
->lastPos
= input
->scenePos();
371 d
->paintArea
= paintArea
;
372 Photogram
*photogram
= paintArea
->photogram();
376 if( !d
->target
->item()->isSelected() )
383 QList
<QGraphicsItem
*> selected
= photogram
->selectedItems();
384 if( selected
.isEmpty() ) return;
386 Model::Object
*object
= paintArea
->currentFrame()->graphic(selected
.first());
390 // If the object has a tweener, it may be not in the current frame.
391 object
= paintArea
->currentScene()->tweeningObject(selected
.first());
397 if( d
->target
!= object
)
401 d
->target
->scene()->setAlwaysVisible(d
->target
, false);
405 d
->target
->scene()->setAlwaysVisible(d
->target
, true);
407 d
->createObjectTweener();
409 d
->currentPos
= d
->target
->item()->pos();
410 d
->absItemPos
= d
->target
->item()->boundingRect().topLeft();
412 int objectPos
= d
->target
->frame()->visualIndex();
413 int framePos
= paintArea
->currentFrame()->visualIndex();
414 int step
= qAbs(framePos
- objectPos
);
417 if( d
->target
->tweener() )
419 frames
= qMax(step
, d
->target
->tweener()->frames());
422 if(input
->buttons() == Qt::LeftButton
)
424 switch(d
->group
.checkedId())
426 case Private::Transform
:
428 QList
<DGraphics::ItemTransformer
*> transformers
;
432 transformers
<< d
->transformer
;
435 CommonAlgorithms::createTransfromers(transformers
, QList
<QGraphicsItem
*>() << d
->target
->item(), paintArea
);
437 if(!transformers
.isEmpty())
439 d
->transformer
= transformers
.first();
442 else if( input
->modifiers() != Qt::ControlModifier
)
444 if(photogram
->mouseGrabberItem() == d
->transformer
->item())
446 switch(d
->transformer
->operation())
448 case DGraphics::ItemTransformer::Scale
:
450 d
->transformer
->setOperation(DGraphics::ItemTransformer::Rotate
);
453 case DGraphics::ItemTransformer::Rotate
:
455 d
->transformer
->setOperation(DGraphics::ItemTransformer::Scale
);
464 case Private::PathMotion
:
466 d
->path
= QPainterPath();
467 d
->path
.moveTo(d
->firstPos
);
471 paintArea
->setAlwaysVisible(d
->pathItem
, false);
478 foreach(QGraphicsItem
*node
, d
->nodeEditor
->nodes())
480 paintArea
->setAlwaysVisible(node
, false);
483 delete d
->nodeEditor
;
487 d
->pathItem
= new QGraphicsPathItem
;
488 d
->pathItem
->setZValue(1000);
491 QColor c
= Qt::lightGray
;
495 pen
.setStyle(Qt::DashDotDotLine
);
496 d
->pathItem
->setPen(pen
);
498 photogram
->addItem( d
->pathItem
);
503 // qFatal("Not implemented!");
510 void ITween::move(const QGraphicsSceneMouseEvent
*input
)
512 if( d
->target
== 0 ) return;
514 PaintArea
*paintArea
= this->paintArea();
515 if(input
->buttons() == Qt::LeftButton
)
517 if( d
->group
.checkedId() == Private::PathMotion
)
519 d
->lastPos
= paintArea
->mapToScene(paintArea
->viewport()->mapFromGlobal(QCursor::pos()));;
520 d
->path
.lineTo( d
->lastPos
);
522 d
->pathItem
->setPath(d
->path
);
523 paintArea
->brushManager()->map(d
->pathItem
);
528 void ITween::release(const QGraphicsSceneMouseEvent
*input
)
530 if( d
->target
== 0 ) return;
532 PaintArea
*paintArea
= this->paintArea();
533 switch(d
->group
.checkedId())
535 case Private::Transform
:
540 d
->transformer
->show();
544 QList
<DGraphics::ItemTransformer
*> transformers
;
545 CommonAlgorithms::createTransfromers(transformers
, QList
<QGraphicsItem
*>() << d
->target
->item(), paintArea
);
547 if(!transformers
.isEmpty())
549 d
->transformer
= transformers
.first();
555 case Private::PathMotion
:
557 if(!d
->path
.isEmpty())
560 double smoothness
= 1.0;
562 QPolygonF polygon
= d
->path
.toFillPolygon();
563 if(!polygon
.isEmpty() && polygon
.isClosed())
566 d
->path
= DGraphics::Algorithm::smooth(polygon
, smoothness
);
567 d
->pathItem
->setPath(d
->path
);
569 paintArea
->setAlwaysVisible(d
->pathItem
, true);
576 foreach(QGraphicsItem
*node
, d
->nodeEditor
->nodes())
578 paintArea
->setAlwaysVisible(node
, false);
580 delete d
->nodeEditor
;
582 d
->nodeEditor
= new Drawing::Tool::Private::ContourEditor(d
->pathItem
, paintArea
->photogram());
584 d
->nodeEditor
->show();
585 foreach(QGraphicsItem
*node
, d
->nodeEditor
->nodes())
587 paintArea
->setAlwaysVisible(node
, true);
592 case Private::NodeMotion
:
594 QList
<Drawing::Tool::Private::ContourEditor
*> editors
;
597 editors
<< d
->nodeEditor
;
600 CommonAlgorithms::createEditors(editors
, QList
<QGraphicsItem
*>() << d
->target
->item(), paintArea
);
602 if(!editors
.isEmpty())
604 d
->nodeEditor
= editors
.first();
605 d
->nodeEditor
->show();
613 if( QAbstractGraphicsShapeItem
*item
= dynamic_cast<QAbstractGraphicsShapeItem
*>(d
->target
->item()) )
615 paintArea
->brushManager()->apply(item
);
628 DGui::Action
* ITween::action() const
633 int ITween::type() const
635 return AbstractTool::Brush
;
638 void ITween::aboutToChangeTool()
640 PaintArea
*paintArea
= this->paintArea();
646 paintArea
->setAlwaysVisible(d
->pathItem
, false);
653 foreach(QGraphicsItem
*node
, d
->nodeEditor
->nodes())
655 paintArea
->setAlwaysVisible(node
, false);
657 delete d
->nodeEditor
;
663 foreach(QGraphicsItem
*node
, d
->transformer
->nodes())
665 paintArea
->setAlwaysVisible(node
, false);
667 delete d
->transformer
;
672 void ITween::setupConfigBar(QToolBar
*configBar
)
674 configBar
->addWidget(d
->configWidget
)->setVisible(true);
677 void ITween::onChangeTool(int id
)
679 PaintArea
*paintArea
= this->paintArea();
682 // case Private::Transform:
686 case Private::NodeMotion
:
690 paintArea
->setAlwaysVisible(d
->pathItem
, false);
697 foreach(QGraphicsItem
*node
, d
->nodeEditor
->nodes())
699 paintArea
->setAlwaysVisible(node
, false);
702 delete d
->nodeEditor
;