- Used visual index for all model operation
[yamf.git] / yamf / drawing / paintarea.cpp
blob45fb061a5a29a4a5efd3b4f83f1cc0da48b90733
1 /***************************************************************************
2 * Copyright (C) 2005 by Jorge Cuadrado *
3 * kuadrosxx@gmail.com *
4 * Copyright (C) 2006 by David Cuadrado *
5 * krawek@gmail.com *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
23 #include "paintarea.h"
25 #include "private/paintarearotator.h"
27 #include <QGraphicsScene>
28 #include <QMouseEvent>
29 #include <QGraphicsSceneMouseEvent>
30 #include <QGraphicsRectItem>
31 #include <QPolygon>
32 #include <QApplication>
33 #include <QTimer>
34 #include <QStyleOptionGraphicsItem>
35 #include <QClipboard>
36 #include <QUndoStack>
37 #include <QMenu>
38 #include <QToolBar>
40 #include "photogram.h"
41 #include <dgraphics/algorithm.h>
43 #include <dcore/config.h>
44 #include <dcore/debug.h>
45 #include <dgui/application.h>
46 #include <dgui/osd.h>
47 #include <dgui/commandhistory.h>
48 #include <dgui/action.h>
49 #include <dgui/actionmanager.h>
50 #include <dgui/iconloader.h>
52 #include <cmath>
54 #include <model/scene.h>
55 #include <model/layer.h>
56 #include <model/frame.h>
57 #include <model/object.h>
58 #include <model/library.h>
60 #include <item/group.h>
61 #include <item/serializer.h>
62 #include "yamf/item/tweenerstep.h"
63 #include "yamf/item/tweener.h"
65 #include "model/command/base.h"
66 #include "model/command/groupitem.h"
67 #include "model/command/ungroupitem.h"
68 #include "model/command/modifyitem.h"
69 #include "model/command/modifysymbol.h"
70 #include "model/command/sendtobackitem.h"
71 #include "model/command/bringtofrontitem.h"
72 #include "model/command/sendbackwardsitem.h"
73 #include "model/command/bringforwardsitem.h"
74 #include "model/command/manager.h"
75 #include "yamf/model/command/additemfilter.h"
77 #include "yamf/model/libraryitem.h"
78 #include "yamf/model/audiolayer.h"
80 #include "yamf/effect/factory.h"
81 #include "yamf/effect/filter.h"
83 #include <drawing/abstracttool.h>
84 #include <private/addsymboldialog.h>
86 namespace YAMF {
87 namespace Drawing {
89 #ifdef QT_OPENGL_LIB
91 #include <QGLWidget>
92 #include <QGLFramebufferObject>
94 class GLDevice : public QGLWidget
96 public:
97 GLDevice() : QGLWidget()
99 makeCurrent();
101 ~GLDevice() {};
103 protected:
104 void initializeGL()
106 glDisable(GL_DEPTH_TEST);
109 #endif
111 struct YAMF::Drawing::PaintArea::Private
113 Private(YAMF::Drawing::PaintArea *paintArea, Model::Project *const project) : paintArea(paintArea), project(project), lastScaleFactor(1.0)
117 DGui::CommandHistory *history;
119 YAMF::Drawing::PaintArea *paintArea;
121 QRectF drawingRect;
123 bool drawGrid;
124 double angle;
126 YAMF::Drawing::Private::PaintAreaRotator *rotator;
127 Photogram *photogram;
129 struct FramePosition {
130 int layer;
131 int frame;
132 } framePosition;
135 struct ItemProperties {
136 QGraphicsItem *item;
137 QString properties;
140 QList<ItemProperties> properties;
142 QPointF origin;
144 DGui::ActionManager actionManager;
146 Model::Project *const project;
148 double lastScaleFactor;
150 QToolBar *toolsConfigBar;
151 QToolBar *effectsConfigBar;
153 struct RecordStep
155 Item::TweenerStep *step;
157 QList<RecordStep> steps;
159 void recordIt();
162 void PaintArea::Private::recordIt()
164 Model::Object *recorded = photogram->recorded();
166 int currentPos = paintArea->currentFrame()->visualIndex();
167 int objectPos = recorded->frame()->visualIndex();
169 RecordStep record;
170 record.step = new Item::TweenerStep(currentPos-objectPos);
172 record.step->setPosition(recorded->item()->pos());
174 steps << record;
180 * @~spanish
181 * Construye un area de trabajo relacionada con el proyecto @p project.
183 PaintArea::PaintArea(Model::Project *const project, QWidget * parent) : QGraphicsView(parent), d(new Private(this, project) )
185 d->history = new DGui::CommandHistory( project->commandManager()->stack(), this);
187 d->photogram = new Photogram(this);
189 d->drawGrid = false;
190 d->angle = 0;
192 d->rotator = new YAMF::Drawing::Private::PaintAreaRotator(this, this);
194 d->drawingRect = QRectF(QPointF(0,0), QSizeF( 500, 400 ) ); // FIXME: configurable
196 d->photogram->setSceneRect(d->drawingRect);
197 setScene(d->photogram);
199 centerDrawingArea();
201 setUseOpenGL( false );
202 setInteractive ( true );
204 restoreState();
206 setCurrentFrame(-1, -1, -1);
208 d->origin = mapToScene(QPoint(0, 0));
210 createActions();
211 checkActions();
213 d->toolsConfigBar = new QToolBar(tr("Configure tool"), this);
215 d->effectsConfigBar = new QToolBar(tr("Configure effects"), this);
219 * @~spanish
220 * Guarda en la configuracion el estado de las propiedades del area de dibujo.
222 void PaintArea::saveState()
224 DCore::Config *config = dApp->config( "PaintArea" );
226 config->setValue("render_hints", int(renderHints()));
227 config->setValue("show_grid", d->drawGrid);
229 config->endGroup();
233 * @~spanish
234 * Recupera de la configuracion el estado de las propiedades del area de dibujo.
236 void PaintArea::restoreState()
238 DCore::Config *config = dApp->config( "PaintArea" );
240 int renderHints = config->value("render_hints", int(this->renderHints())).toInt();
241 setRenderHints(QPainter::RenderHints(renderHints));
243 bool showGrid = config->value("show_grid", false).toBool();
244 setDrawGrid(showGrid);
246 config->endGroup();
250 * Destructor
252 PaintArea::~PaintArea()
254 d->toolsConfigBar->clear();
255 saveState();
256 delete d;
261 * @~spanish
262 * Crea las acciones relacionadas con el area de dibujo.
264 void PaintArea::createActions()
266 addAction( d->history->undoAction() );
267 addAction( d->history->redoAction() );
269 connect(d->project->commandManager(), SIGNAL(historyChanged()), this, SLOT(onHistoryChanged()));
271 QAction *remove = new QAction(DGui::IconLoader::self()->load("edit-delete.svg"), tr("Delete"), this);
272 remove->setShortcut(QKeySequence::Delete);
273 connect(remove, SIGNAL(triggered()), this, SLOT(removeSelectedObjects()));
274 addAction(remove);
276 QAction *selectAll = new QAction(DGui::IconLoader::self()->load("select-all.svg"), tr("Select all"), this);
277 selectAll->setShortcut(QKeySequence::SelectAll);
278 connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAllObjects()));
279 addAction(selectAll);
281 QAction *copy = new QAction( DGui::IconLoader::self()->load("edit-copy.svg"), tr("Copy"), this);
282 copy->setShortcut(QKeySequence::Copy);
283 connect(copy, SIGNAL(triggered()), this, SLOT(copySelectedObjects()));
284 addAction(copy);
286 QAction *paste = new QAction(DGui::IconLoader::self()->load("edit-paste.svg"), tr("Paste"), this);
287 paste->setShortcut(QKeySequence::Paste);
288 connect(paste, SIGNAL(triggered()), this, SLOT(pasteObjects()));
289 addAction(paste);
291 QAction *cut = new QAction(DGui::IconLoader::self()->load("edit-cut.svg"), tr("Cut"), this);
292 cut->setShortcut(QKeySequence::Cut);
293 connect(cut, SIGNAL(triggered()), this, SLOT(cutSelectedObjects()));
294 addAction(cut);
297 d->actionManager.add(selectAll, "selectall", "edit");
298 d->actionManager.addSeparator("edit");
299 d->actionManager.add(cut, "cut", "edit");
300 d->actionManager.add(copy, "copy", "edit");
301 d->actionManager.add(paste, "paste", "edit");
302 d->actionManager.addSeparator("edit");
303 d->actionManager.add(remove, "remove", "edit");
305 /////////
307 QAction *group = new QAction(DGui::IconLoader::self()->load("object-group.svg"), tr("Group"), this);
308 group->setShortcut(Qt::CTRL + Qt::Key_G);
309 connect(group, SIGNAL(triggered()), this, SLOT(groupSelectedObjects()));
310 d->actionManager.add(group, "group", "object");
311 addAction(group);
313 QAction *ungroup = new QAction(DGui::IconLoader::self()->load("object-ungroup.svg"), tr("Ungroup"), this);
314 ungroup->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_G);
315 connect(ungroup, SIGNAL(triggered()), this, SLOT(ungroupSelectedObject()));
316 d->actionManager.add(ungroup, "ungroup", "object");
317 addAction(ungroup);
319 QAction *sendToBack = new QAction(DGui::IconLoader::self()->load("object-send-to-back.svg"), tr("Send to back"), this);
320 sendToBack->setShortcut(Qt::Key_Home);
321 connect(sendToBack, SIGNAL(triggered()), this, SLOT(sendToBackSelectedObjects()));
322 d->actionManager.add(sendToBack, "sendtoback", "object-order");
323 addAction(sendToBack);
325 QAction *bringToFront = new QAction(DGui::IconLoader::self()->load("object-bring-to-front.svg"), tr("Bring to front"), this);
326 bringToFront->setShortcut(Qt::Key_End);
327 connect(bringToFront, SIGNAL(triggered()), this, SLOT(bringToFrontSelectedObjects()));
328 d->actionManager.add(bringToFront, "bringtofront", "object-order");
329 addAction(bringToFront);
331 QAction *sendBackwards = new QAction(DGui::IconLoader::self()->load("object-send-backwards.svg"), tr("Send backwards"), this);
332 sendBackwards->setShortcut(Qt::Key_PageDown);
333 connect(sendBackwards, SIGNAL(triggered()), this, SLOT(sendBackwardsSelectedObjects()));
334 d->actionManager.add(sendBackwards, "sendbackwards", "object-order");
335 addAction(sendBackwards);
337 QAction *bringForwards = new QAction(DGui::IconLoader::self()->load("object-bring-forwards.svg"), tr("Bring forwards"), this);
338 bringForwards->setShortcut(Qt::Key_PageUp);
339 connect(bringForwards, SIGNAL(triggered()), this, SLOT(bringForwardsSelectedObjects()));
340 d->actionManager.add(bringForwards, "bringforwards", "object-order");
341 addAction(bringForwards);
343 // Library
345 QAction *addToLibrary = new QAction(DGui::IconLoader::self()->load("object-bring-forwards.svg"), tr("Add to library..."), this);
346 connect(addToLibrary, SIGNAL(triggered()), this, SLOT(addToLibrary()));
347 d->actionManager.add(addToLibrary, "addtolibrary", "library");
348 addAction(addToLibrary);
350 QAction *applySymbol = new QAction(DGui::IconLoader::self()->load(""), tr("Apply to symbol..."), this);
351 connect(applySymbol, SIGNAL(triggered()), this, SLOT(applyCurrentSymbol()));
352 d->actionManager.add(applySymbol, "applysymbol", "library");
354 // Item
356 QAction *recordItem = new QAction(DGui::IconLoader::self()->load("media-record.svg"), tr("Record item"), this);
357 connect(recordItem, SIGNAL(triggered()), this, SLOT(recordItem()));
358 d->actionManager.add(recordItem, "recorditem", "item");
360 QAction *stopRecordItem = new QAction(DGui::IconLoader::self()->load("media-playback-stop.svg"), tr("Stop to record item"), this);
361 connect(stopRecordItem, SIGNAL(triggered()), this, SLOT(stopRecordItem()));
362 d->actionManager.add(stopRecordItem, "stoprecorditem", "item");
366 * @~spanish
367 * Si @p use es verdadero permite que la animación se vea con antialiasing y si es false desactiva el antialiasing.
369 void PaintArea::setAntialiasing(bool use)
371 #ifdef QT_OPENGL_LIB
372 if ( QGLWidget *gl = dynamic_cast<QGLWidget *>(viewport() ) )
374 gl->setUpdatesEnabled(false); // works better
375 gl->setFormat(QGLFormat(QGL::SampleBuffers | QGL::HasOverlay /*| QGL::DirectRendering | QGL::AccumBuffer | QGL::Rgba */));
376 gl->setUpdatesEnabled(true);
378 #endif
380 setRenderHint(QPainter::Antialiasing, use);
381 setRenderHint(QPainter::TextAntialiasing, use);
385 * @~spanish
386 * Si @p opengl es verdadero activa el uso de openGl para dibujar el fotograma.
388 void PaintArea::setUseOpenGL(bool opengl)
390 D_FUNCINFO << opengl;
392 QCursor cursor(Qt::ArrowCursor);
393 if ( viewport() )
395 cursor = viewport()->cursor();
398 #ifdef QT_OPENGL_LIB
399 if ( opengl )
401 setViewport(new GLDevice());
403 else
405 // setViewport( new KTImageDevice() );
407 #else
408 Q_UNUSED(opengl);
409 dWarning() << tr("OpenGL isn't supported");
410 #endif
412 // to restore the cursor.
413 if ( viewport() )
415 viewport()->setCursor(cursor);
416 viewport()->setAcceptDrops(true);
421 * @~spanish
422 * Si @p draw es verdadero activa el dibujo de una grilla guia en el area, y si es falso la desactiva.
423 * Por defecto no se dibuja la grilla.
425 void PaintArea::setDrawGrid(bool draw)
427 d->drawGrid = draw;
428 // resetCachedContent();
429 viewport()->update();
433 * @~spanish
434 * Se asigna la herramienta @p tool como la herramienta actual.
436 void PaintArea::setTool(AbstractTool *tool )
438 if ( !scene() ) return;
440 QCursor cursor = tool->action()->cursor();
441 if( (!cursor.pixmap().isNull() && cursor.mask() != 0 && cursor.shape() == Qt::BitmapCursor && cursor.bitmap() != 0 ) || cursor.shape() != Qt::BitmapCursor )
442 viewport()->setCursor(cursor);
444 d->toolsConfigBar->clear();
445 tool->setupConfigBar(d->toolsConfigBar);
447 d->photogram->setTool(tool);
451 * @~spanish
452 * Retorna si esta activo el dibujo de la grilla.
454 bool PaintArea::drawGrid() const
456 return d->drawGrid;
459 void PaintArea::mousePressEvent( QMouseEvent * event )
461 if ( !canPaint() ) return;
463 QGraphicsItem *item = d->photogram->itemAt( mapToScene(event->pos()) );
465 d->effectsConfigBar->clear();
466 if( item )
468 if( YAMF::Effect::Filter *filter = dynamic_cast<YAMF::Effect::Filter *>(item) )
470 filter->setupConfigBar(d->effectsConfigBar);
474 if ( event->buttons() == Qt::RightButton )
477 QMenu *menu = this->createMenu();
479 if( item )
481 // Add effects
483 QMenu *effects = menu->addMenu(tr("Effects"));
485 QAction *blur = effects->addAction(tr("Blur"));
486 blur->setData("blur");
488 QAction *swirl = effects->addAction(tr("Swirl"));
489 swirl->setData("swirl");
491 connect(effects, SIGNAL(triggered(QAction *)), this, SLOT(applyFilter(QAction *)));
494 item->setFlag(QGraphicsItem::ItemIsSelectable, true);
495 item->setSelected(true);
497 menu->addAction(d->actionManager.find("recorditem", "item"));
500 if( d->photogram->recorded() )
502 menu->addAction(d->actionManager.find("stoprecorditem", "item"));
505 menu->addSeparator();
507 if( qgraphicsitem_cast<Model::LibraryItem *>(item) )
509 menu->addAction(d->actionManager.find("applysymbol", "library"));
511 else
513 menu->addAction(d->actionManager.find("addtolibrary", "library"));
516 menu->addSeparator();
518 checkActions();
520 menu->exec(event->globalPos());
522 delete menu;
524 else
526 d->photogram->aboutToMousePress();
527 QGraphicsView::mousePressEvent(event);
530 foreach(QGraphicsItem *item , d->photogram->selectedItems() )
532 if( item->flags() & QGraphicsItem::ItemIsMovable )
534 Private::ItemProperties prop;
535 prop.item = item;
537 QDomDocument doc;
538 doc.appendChild(Item::Serializer::properties(item, doc));
540 prop.properties = doc.toString();
541 d->properties << prop;
546 void PaintArea::mouseMoveEvent( QMouseEvent * event )
548 if ( !canPaint()) return;
550 // Rotate
551 if( !d->photogram->isDrawing() && event->buttons() == Qt::LeftButton && (event->modifiers () == (Qt::ShiftModifier | Qt::ControlModifier)))
553 setUpdatesEnabled(false);
555 QGraphicsView::DragMode dragMode = this->dragMode();
556 setDragMode(QGraphicsView::NoDrag);
558 QPointF p1 = event->pos();
559 QPointF p2 = d->drawingRect.center();
561 d->rotator->rotateTo( (int)(-(180*DGraphics::Algorithm::angleForPos(p1,p2))/M_PI) );
563 setDragMode(dragMode);
565 setUpdatesEnabled(true);
567 else
569 QGraphicsView::mouseMoveEvent(event);
571 if( !d->photogram->mouseGrabberItem() && d->photogram->isDrawing() ) // HACK
573 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
574 mouseEvent.setWidget(viewport());
576 mouseEvent.setPos( event->pos() );
577 mouseEvent.setScenePos(mapToScene(event->pos()));
579 mouseEvent.setScreenPos(event->globalPos());
580 mouseEvent.setButtons(event->buttons());
581 mouseEvent.setButton(event->button());
582 mouseEvent.setModifiers(event->modifiers());
583 mouseEvent.setAccepted(false);
584 d->photogram->mouseMoved(&mouseEvent);
588 emit cursorMoved( mapToScene( event->pos() ) );
591 void PaintArea::mouseReleaseEvent(QMouseEvent *event)
593 QGraphicsView::mouseReleaseEvent(event);
595 if( ! d->photogram->mouseGrabberItem() && d->photogram->isDrawing() ) // HACK
597 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseRelease);
598 mouseEvent.setWidget(viewport());
599 mouseEvent.setPos( event->pos() );
600 mouseEvent.setScenePos(mapToScene(event->pos()));
601 mouseEvent.setScreenPos(event->globalPos());
602 mouseEvent.setButtons(event->buttons());
603 mouseEvent.setButton(event->button());
604 mouseEvent.setModifiers(event->modifiers());
605 mouseEvent.setAccepted(false);
606 // QApplication::sendEvent(d->photogram, &mouseEvent);
607 d->photogram->mouseReleased(&mouseEvent);
611 Model::Object *recorded = d->photogram->recorded();
612 QGraphicsItem *ritem = 0;
613 if( recorded )
615 ritem = recorded->item();
618 foreach(Private::ItemProperties prop, d->properties)
620 if(currentFrame()->logicalIndexOf(prop.item) > -1 || ritem == prop.item)
622 QDomDocument doc;
623 doc.appendChild(Item::Serializer::properties(prop.item, doc));
626 if( prop.item == ritem )
628 d->recordIt();
630 else if( doc.toString() != prop.properties )
632 Command::ModifyItem *current = new Command::ModifyItem( prop.item, prop.properties, currentFrame() );
633 addCommand( current );
638 d->properties.clear();
640 checkActions();
643 void PaintArea::tabletEvent( QTabletEvent * event )
645 QGraphicsView::tabletEvent(event );
649 * Función reimplementada para dibujar el fondo del area de dibujo, mostrando el area que va a aparecer en la animación y la grilla si esta activa la opción.
651 void PaintArea::drawBackground(QPainter *painter, const QRectF &rect)
653 QGraphicsView::drawBackground(painter, rect);
655 if( ! currentFrame() ) return;
657 painter->save();
659 bool hasAntialiasing = painter->renderHints() & QPainter::Antialiasing;
661 painter->setRenderHint(QPainter::Antialiasing, false);
663 painter->setPen( QPen(QColor(0,0,0,180), 3) );
665 painter->fillRect( d->drawingRect, Qt::white );
666 painter->drawRect( d->drawingRect );
668 QPointF origin = painter->matrix().map(QPoint(0, 0));
670 if( origin != d->origin )
672 d->origin = origin;
673 emit originChanged( d->origin );
676 if ( d->drawGrid )
678 int sx = (int)painter->matrix().m11();
679 int sy = (int)painter->matrix().m22();
681 painter->resetMatrix();
682 painter->scale(sx, sy);
683 painter->setPen( QPen(QColor(0,0,180, 50), 1) );
685 for(int i = 0; i < qMax(width(), height()); i+= 10 )
687 painter->drawLine(i, 0, i, height() );
688 painter->drawLine(0, i, width(), i );
692 painter->setRenderHint(QPainter::Antialiasing, hasAntialiasing);
695 painter->restore();
699 * @~spanish
700 * Función reimplementada para mostrar si el frame actual esta bloqueado.
702 void PaintArea::drawForeground( QPainter *painter, const QRectF &rect )
704 if ( Model::Frame *frame = currentFrame() )
706 if ( frame->isLocked() )
708 painter->fillRect(rect, QColor(201,201,201, 200));
710 painter->setFont(QFont("Arial", 30) );
711 QFontMetricsF fm(painter->font());
712 QString text = tr("Locked");
714 painter->drawText(QPointF(d->photogram->sceneRect().topRight().x() - fm.width(text), (d->photogram->sceneRect().topRight().y() + fm.height()) / 2), text);
720 * @~spanish
721 * Retorna verdadero si se puede dibujar sobre el area de dibujo y falso si no.
723 bool PaintArea::canPaint() const
725 if( d->photogram )
727 Model::Frame *frame = currentFrame();
729 if( frame )
731 return !frame->isLocked() && !frame->layer()->isLocked();
735 return false;
739 * @~spanish
740 * Centra la vista del fotograma.
742 void PaintArea::centerDrawingArea()
744 centerOn(d->drawingRect.center());
748 * @internal
750 void PaintArea::onHistoryChanged()
752 if( Model::Scene *scene = d->photogram->scene() )
754 if( scene->logicalIndex() < 0 )
755 d->photogram->setCurrentScene(0);
758 d->photogram->drawCurrentPhotogram();
759 viewport()->update();
763 * @internal
765 void PaintArea::applyFilter(QAction *act)
767 QList<QGraphicsItem *> selected = d->photogram->selectedItems();
769 if( selected.isEmpty() ) return;
771 QGraphicsItem *item = selected.first();
772 QString filter = act->data().toString();
773 Model::Frame *frame = currentFrame();
775 if( frame && item && !filter.isEmpty())
777 Model::Object *object = frame->graphic(frame->logicalIndexOf(item));
779 if( object )
781 YAMF::Effect::Filter *effect = YAMF::Effect::Factory::create(filter);
783 d->effectsConfigBar->clear();
784 effect->setupConfigBar(d->effectsConfigBar);
787 YAMF::Command::AddItemFilter *cmd = new YAMF::Command::AddItemFilter(object, effect);
788 addCommand(cmd);
793 void PaintArea::wheelEvent(QWheelEvent *event)
795 if(event->modifiers () == Qt::ControlModifier)
797 scaleView(pow(( double)2, -event->delta() / 240.0));
799 else
801 QGraphicsView::wheelEvent(event);
805 bool PaintArea::viewportEvent(QEvent *e)
807 bool ret = QGraphicsView::viewportEvent(e);
809 if( e->type() == QEvent::Show )
811 if( d->photogram->items().isEmpty() )
813 d->photogram->drawCurrentPhotogram();
817 return ret;
821 * @~spanish
822 * Escala la vista sobre el fotograma en un factor @p scaleFactor.
824 void PaintArea::scaleView(double scaleFactor)
826 qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
827 if (factor < 0.07 || factor > 100)
828 return;
831 d->lastScaleFactor *= scaleFactor;
832 scale(scaleFactor, scaleFactor);
834 emit scaled(d->lastScaleFactor);
838 * @~spanish
839 * Hace aumento sobre el fotograma actual en un porcentaje @p percent.
841 void PaintArea::setZoom(int percent)
843 double factor = (double)percent / 100.0;
845 if( factor == d->lastScaleFactor ) return;
847 double restoreFactor = 1.0/d->lastScaleFactor;
849 if( d->lastScaleFactor > 1.0 )
851 scale(restoreFactor, restoreFactor);
853 else if ( d->lastScaleFactor < 1.0)
855 scale(restoreFactor, restoreFactor);
858 d->lastScaleFactor = factor;
860 scale(factor, factor);
862 emit scaled(factor);
866 * @~spanish
867 * Rota la vista sobre el fotograma.
869 void PaintArea::setRotationAngle(int angle)
871 rotate(angle - d->angle );
872 d->angle = angle;
876 * @~spanish
877 * Retorna el manejador de brochas del area de dibujo.
879 BrushManager *PaintArea::brushManager() const
881 return d->photogram->brushManager();
885 * @~spanish
886 * Retorna el area en la cual va aparecer en la animación.
888 QRectF PaintArea::drawingRect() const
890 return d->drawingRect;
894 * @~spanish
895 * Retorna el fotograma actual.
897 Photogram *PaintArea::photogram() const
899 return d->photogram;
903 * @~spanish
904 * Cambia el frame actual.
906 void PaintArea::setCurrentFrame(int sceneIndex, int layerIndex, int frameIndex)
908 // dfDebug << "scene = " << sceneIndex << " layer = " << layerIndex << "frame = " << frameIndex;
909 Model::Scene *scene = d->project->scene(sceneIndex);
911 // if( scene )
913 d->photogram->setCurrentScene(scene);
914 d->photogram->setCurrent(frameIndex);
915 d->framePosition.layer = layerIndex;
916 d->framePosition.frame = frameIndex;
918 d->photogram->drawCurrentPhotogram();
919 viewport()->update();
923 * @~spanish
924 * Retorna el proyecto asociado al area de dibujo.
926 Model::Project *PaintArea::project() const
928 return d->project;
932 * @~spanish
933 * Retorna la escena actual.
935 Model::Scene *PaintArea::currentScene() const
937 return d->photogram->scene();
941 * @~spanish
942 * Retorna la capa actual.
944 Model::Layer *PaintArea::currentLayer() const
946 Model::Scene *scene = d->photogram->scene();
948 if( scene )
950 return scene->layer(d->framePosition.layer);
954 return 0;
958 * @~spanish
959 * Retorna el frame actual.
961 Model::Frame *PaintArea::currentFrame() const
963 Model::Layer *layer = currentLayer();
965 if( layer )
967 return layer->frame(d->framePosition.frame);
971 return 0;
975 * @~spanish
978 void PaintArea::addCommand(Command::Base *command)
980 d->project->commandManager()->addCommand(command);
984 * @~spanish
985 * Retorna la historia de comandos
986 * @return
988 DGui::CommandHistory *PaintArea::history() const
990 return d->history;
994 * @~spanish
995 * Retorna la acción que permite remover los elementos seleccionados en el area.
996 * @return
998 QAction *PaintArea::removeAction()
1000 return d->actionManager.find("remove", "edit");
1004 * @~spanish
1005 * Retorna la acción que permite agrupar los elementos seleccionados en el area.
1006 * @return
1008 QAction *PaintArea::groupAction()
1010 return d->actionManager.find("group", "object");
1014 * @~spanish
1015 * Retorna la acción que permite des-agrupar los elementos seleccionados en el area.
1016 * @return
1018 QAction *PaintArea::ungroupAction()
1020 return d->actionManager.find("ungroup", "object");
1024 * @~spanish
1025 * Retorna la acción que permite enviar al fondo los elementos seleccionados en el area.
1026 * @return
1028 QAction *PaintArea::sendToBackAction()
1030 return d->actionManager.find( "sendtoback", "object-order");
1034 * @~spanish
1035 * Retorna la acción que permite enviar al frente los elementos seleccionados en el area.
1036 * @return
1038 QAction *PaintArea::bringToFrontAction()
1040 return d->actionManager.find( "bringtofront", "object-order");
1045 * @~spanish
1046 * Retorna la acción que permite enviar hacia atras una unidad los elementos seleccionados en el area.
1047 * @return
1049 QAction *PaintArea::sendBackwardsAction()
1051 return d->actionManager.find( "sendbackwards", "object-order");
1055 * @~spanish
1056 * Retorna la acción que permite enviar hacia adelante una unidad los elementos seleccionados en el area.
1058 QAction *PaintArea::bringForwardsAction()
1060 return d->actionManager.find( "bringforwards", "object-order");
1064 * @~spanish
1065 * Retorna la acción que permite copiar los elementos seleccionados en el area.
1067 QAction *PaintArea::copyAction()
1069 return d->actionManager.find( "copy", "edit");
1073 * @~spanish
1074 * Retorna la acción que permite pegar los elementos que estan en el portapapeles en el area.
1076 QAction *PaintArea::pasteAction()
1078 return d->actionManager.find( "paste", "edit");
1082 * @~spanish
1083 * Retorna la acción que permite cortar los elementos seleccionados en el area.
1085 QAction *PaintArea::cutAction()
1087 return d->actionManager.find( "cut", "edit");
1091 * @~spanish
1092 * Retorna la acción que permite seleccionar todos los elementos en el area.
1094 QAction *PaintArea::selectAllAction()
1096 return d->actionManager.find("selectall", "edit");
1100 * @~spanish
1101 * Crea el menu contextual de el area de dibujo.
1103 QMenu *PaintArea::createMenu()
1105 QMenu *menu = new QMenu(tr("Drawing area"), this);
1107 Command::Manager *manager = d->project->commandManager();
1109 menu->addAction(d->history->undoAction()->icon(), d->history->undoAction()->text(), d->history, SLOT(undo()))->setEnabled(d->history->undoAction()->isEnabled());
1110 menu->addAction(d->history->redoAction()->icon(), d->history->redoAction()->text(), d->history, SLOT(redo()))->setEnabled(d->history->redoAction()->isEnabled());
1112 menu->addSeparator();
1113 d->actionManager.setupMenu(menu, "edit", false);
1114 menu->addSeparator();
1116 QMenu *order = new QMenu(tr("Order"));
1117 d->actionManager.setupMenu(order, "object-order");
1119 menu->addMenu (order);
1120 menu->addSeparator();
1122 if ( AbstractTool *tool = d->photogram->currentTool() )
1124 if( QMenu *toolMenu = tool->menu() )
1126 menu->addSeparator();
1127 menu->addMenu(toolMenu);
1131 return menu;
1135 * @~spanish
1136 * Retorna la barra de herramientas que provee la interfaz grafica para la configuración de las herramientas.
1138 QToolBar *PaintArea::toolsConfigBar() const
1140 return d->toolsConfigBar;
1144 * @~spanish
1145 * Retorna la barra de herramientas que provee la interfaz grafica para la configuración de los efectos.
1147 QToolBar *PaintArea::effectsConfigBar() const
1149 return d->effectsConfigBar;
1152 void PaintArea::checkActions()
1154 if(! scene()->selectedItems().isEmpty())
1156 d->actionManager.setEnabled("object-order", true);
1157 d->actionManager.find("remove", "edit")->setEnabled(true);
1158 d->actionManager.find("cut", "edit")->setEnabled(true);
1159 d->actionManager.find("copy", "edit")->setEnabled(true);
1160 d->actionManager.find("addtolibrary", "library")->setEnabled(true);
1162 else
1164 d->actionManager.setEnabled("object-order", false);
1165 d->actionManager.find("remove", "edit")->setEnabled(false);
1166 d->actionManager.find("cut", "edit")->setEnabled(false);
1167 d->actionManager.find("copy", "edit")->setEnabled(false);
1168 d->actionManager.find("addtolibrary", "library")->setEnabled(false);
1171 QString xml = QApplication::clipboard()->mimeData()->data("yamf-graphics");
1172 if ( !xml.isEmpty() )
1174 d->actionManager.find("paste", "edit")->setEnabled(true);
1176 else
1178 d->actionManager.find("paste", "edit")->setEnabled(false);
1183 * @~spanish
1184 * Remueve los elementos seleccionados.
1186 void PaintArea::removeSelectedObjects()
1188 QList<QGraphicsItem *> items = d->photogram->selectedItems();
1189 if( items.count() > 0 )
1191 currentFrame()->removeItems(items);
1192 this->checkActions();
1198 * @~spanish
1199 * Agrupa los elementos seleccionados.
1201 void PaintArea::groupSelectedObjects()
1203 QList<QGraphicsItem *> items = d->photogram->selectedItems();
1204 if( items.count() > 0 )
1206 addCommand(new Command::GroupItem(items, currentFrame()));
1211 * @~spanish
1212 * Desagrupa los elementos seleccionados.
1214 void PaintArea::ungroupSelectedObject()
1216 QList<QGraphicsItem *> items = d->photogram->selectedItems();
1217 QList<Item::Group *> groups;
1219 Model::Frame *frame = currentFrame();
1221 foreach(QGraphicsItem *item, items)
1223 if( Item::Group *group = qgraphicsitem_cast<Item::Group *>(item) )
1225 addCommand(new Command::UngroupItem(group, currentFrame()));
1231 * @~spanish
1232 * Envia atras los elementos seleccionados.
1234 void PaintArea::sendToBackSelectedObjects()
1236 QList<QGraphicsItem *> items = photogram()->selectedItems();
1238 DGraphics::Algorithm::sort(items, DGraphics::Algorithm::ZAxis);
1240 Model::Frame *frame = currentFrame();
1241 foreach(QGraphicsItem *item, items )
1243 addCommand(new Command::SendToBackItem(frame->graphic(item)));
1248 * @~spanish
1249 * Trae adelante los elementos seleccionados.
1251 void PaintArea::bringToFrontSelectedObjects()
1253 QList<QGraphicsItem *> items = photogram()->selectedItems();
1255 DGraphics::Algorithm::sort(items, DGraphics::Algorithm::ZAxis);
1257 QList<QGraphicsItem *>::iterator it = items.end();
1259 Model::Frame *frame = currentFrame();
1261 while(it != items.begin())
1263 --it;
1264 addCommand(new Command::BringToFrontItem(frame->graphic(*it)));
1269 * @~spanish
1270 * Envia atras una unidad los elementos seleccionados.
1272 void PaintArea::sendBackwardsSelectedObjects()
1274 QList<QGraphicsItem *> items = photogram()->selectedItems();
1276 DGraphics::Algorithm::sort(items, DGraphics::Algorithm::ZAxis);
1278 Model::Frame *frame = currentFrame();
1279 foreach(QGraphicsItem *item, items )
1281 addCommand(new Command::SendBackwardsItem(frame->graphic(item)));
1287 * @~spanish
1288 * Trae al frente una unidad los elementos seleccionados.
1290 void PaintArea::bringForwardsSelectedObjects()
1292 QList<QGraphicsItem *> items = photogram()->selectedItems();
1294 DGraphics::Algorithm::sort(items, DGraphics::Algorithm::ZAxis);
1296 QList<QGraphicsItem *>::iterator it = items.end();
1298 Model::Frame *frame = currentFrame();
1300 while(it != items.begin())
1302 --it;
1303 addCommand(new Command::BringForwardsItem(frame->graphic(*it)));
1308 * @~spanish
1309 * Copia los elementos seleccionados.
1311 void PaintArea::copySelectedObjects()
1313 QList<QGraphicsItem *> selecteds = scene()->selectedItems();
1315 QDomDocument orig;
1316 QDomElement root = orig.createElement("yamf-graphics");
1318 foreach(QGraphicsItem *item, selecteds)
1320 int index = currentFrame()->logicalIndexOf( item );
1322 if(index > -1)
1324 Model::Object *graphic = currentFrame()->graphic(index);
1325 root.appendChild(graphic->toXml( orig ));
1329 orig.appendChild(root);
1331 QMimeData *mimeData = new QMimeData;
1333 mimeData->setData("yamf-graphics", orig.toString().toLocal8Bit());
1334 //TODO: image/svg+xml
1335 QApplication::clipboard()->setMimeData( mimeData );
1339 * @~spanish
1340 * Pega los elementos en el portapapeles.
1342 void PaintArea::pasteObjects()
1344 if( !currentFrame() ) return;
1346 const QMimeData *mimeData = QApplication::clipboard()->mimeData();
1348 QString xml = mimeData->data("yamf-graphics");
1350 QDomDocument doc;
1351 if(!doc.setContent(xml))
1353 return;
1356 // TODO: image/svg+xml
1358 QDomElement docElem = doc.documentElement();
1359 QDomNode n = docElem.firstChild();
1361 while(!n.isNull())
1363 QDomElement e = n.toElement();
1364 if(!e.isNull())
1366 QString xml;
1367 QTextStream ts(&xml);
1368 ts << e;
1370 Model::Object *object = new Model::Object(currentFrame());
1371 object->fromXml(xml);
1373 currentFrame()->addObject(object);
1375 n = n.nextSibling();
1377 d->photogram->drawCurrentPhotogram();
1381 * @~spanish
1382 * Corta los elementos seleccionados.
1384 void PaintArea::cutSelectedObjects()
1386 copySelectedObjects();
1387 removeSelectedObjects();
1391 * @~spanish
1392 * Selecciona todos los elementos en el area.
1394 void PaintArea::selectAllObjects()
1396 foreach(QGraphicsItem *item, photogram()->items() )
1398 item->setFlag(QGraphicsItem::ItemIsSelectable);
1399 item->setSelected(true);
1404 * @~spanish
1405 * Añade lso elementos seleccionados a la biblioteca de objetos.
1407 void PaintArea::addToLibrary()
1409 QList<QGraphicsItem *> selecteds = scene()->selectedItems();
1411 if ( selecteds.isEmpty() )
1413 DGui::Osd::self()->display(tr("No items selected"), DGui::Osd::Error);
1414 return;
1417 YAMF::Drawing::Private::AddSymbolDialog addSymbolDialog;
1419 YAMF::Model::Library *library = d->project->library();
1421 QList<QGraphicsItem *> symbols;
1423 foreach(QGraphicsItem *item, selecteds)
1425 if( YAMF::Common::AbstractSerializable *serializable = dynamic_cast<YAMF::Common::AbstractSerializable *>(item) )
1427 addSymbolDialog.addSymbol(item);
1431 if( addSymbolDialog.exec() == QDialog::Accepted )
1433 for(int i = 0; i < addSymbolDialog.symbolCount(); i++)
1435 library->addItemSymbol(addSymbolDialog.symbol(i), addSymbolDialog.symbolName(i));
1440 void PaintArea::applyCurrentSymbol()
1442 if( d->photogram->selectedItems().count() > 0 )
1444 if( Model::LibraryItem *libraryItem = qgraphicsitem_cast<Model::LibraryItem *>( d->photogram->selectedItems().first()) )
1446 YAMF::Command::ModifySymbol *cmd = new YAMF::Command::ModifySymbol(libraryItem);
1448 addCommand(cmd);
1454 * @~spanish
1455 * Añade un simbolo de la biblioteca identificado con @p id a el area .
1457 void PaintArea::addSymbol(const QString &id)
1459 YAMF::Model::LibraryObject *object = d->project->library()->findObject(id);
1460 if( object )
1462 addSymbol(object);
1467 * @~spanish
1468 * Añade un simbolo @p object de la biblioteca a el area .
1470 void PaintArea::addSymbol(YAMF::Model::LibraryObject *object)
1472 YAMF::Model::Frame *frame = currentFrame();
1473 YAMF::Model::Scene *scene = currentScene();
1475 switch(object->type())
1477 case YAMF::Model::LibraryObject::Sound:
1479 Model::LibrarySoundObject *soundObject = dynamic_cast<Model::LibrarySoundObject *>(object);
1480 if ( scene != 0 )
1482 YAMF::Model::AudioLayer *layer = scene->createAudioLayer();
1483 layer->fromSymbol(soundObject);
1486 break;
1487 case YAMF::Model::LibraryObject::Svg:
1488 case YAMF::Model::LibraryObject::Item:
1489 case YAMF::Model::LibraryObject::Image:
1490 case YAMF::Model::LibraryObject::Text:
1492 if( frame != 0 )
1494 YAMF::Model::LibraryItem *item = new YAMF::Model::LibraryItem(object);
1495 frame->addItem(item);
1498 break;
1503 * @~spanish
1505 void PaintArea::recordItem()
1507 Model::Frame *frame = currentFrame();
1509 if( frame && d->photogram->selectedItems().count() > 0 )
1511 QGraphicsItem *item = d->photogram->selectedItems().first();
1513 int logicalIndex = frame->logicalIndexOf(item);
1515 if( logicalIndex > -1 )
1517 d->photogram->recordObject(frame->graphic(logicalIndex));
1519 d->recordIt();
1525 * @~spanish
1527 void PaintArea::stopRecordItem()
1529 Model::Object *object = d->photogram->recorded();
1530 Model::Frame *frame = currentFrame();
1532 int framePos = frame->visualIndex();
1533 int objectPos = object->frame()->visualIndex();
1535 if( object && framePos > objectPos )
1537 int stepsCount = framePos - objectPos;
1539 Item::Tweener *tweener = new Item::Tweener(stepsCount, object);
1541 foreach(Private::RecordStep rs, d->steps)
1543 tweener->addStep(*rs.step);
1544 delete rs.step;
1547 object->setTweener(tweener);
1550 d->photogram->recordObject(0);
1551 d->steps.clear();