Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
editor.cpp
1 /*
2 
3 Pencil - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2017 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 */
17 
18 #include "editor.h"
19 #include <memory>
20 #include <iostream>
21 #include <QApplication>
22 #include <QClipboard>
23 #include <QBoxLayout>
24 #include <QLabel>
25 #include <QTimer>
26 #include <QSvgGenerator>
27 #include <QMessageBox>
28 #include <QImageReader>
29 #include <QComboBox>
30 #include <QSlider>
31 #include <QFileDialog>
32 #include <QInputDialog>
33 #include <QGroupBox>
34 #include <QDialogButtonBox>
35 #include <QDragEnterEvent>
36 #include <QDropEvent>
37 
38 #include "object.h"
39 #include "objectdata.h"
40 #include "vectorimage.h"
41 #include "bitmapimage.h"
42 #include "layerbitmap.h"
43 #include "layervector.h"
44 #include "layersound.h"
45 #include "layercamera.h"
46 #include "keyframefactory.h"
47 
48 #include "colormanager.h"
49 #include "toolmanager.h"
50 #include "layermanager.h"
51 #include "playbackmanager.h"
52 #include "viewmanager.h"
53 #include "preferencemanager.h"
54 #include "soundmanager.h"
55 
56 #include "scribblearea.h"
57 #include "timeline.h"
58 #include "util.h"
59 
60 #define MIN(a,b) ((a)>(b)?(b):(a))
61 
62 
63 static BitmapImage g_clipboardBitmapImage;
64 static VectorImage g_clipboardVectorImage;
65 
66 
67 Editor::Editor( QObject* parent ) : QObject( parent )
68 {
69  mBackupIndex = -1;
70  clipboardBitmapOk = false;
71  clipboardVectorOk = false;
72 }
73 
74 Editor::~Editor()
75 {
76  // a lot more probably needs to be cleaned here...
77  clearUndoStack();
78 }
79 
80 bool Editor::init()
81 {
82  // Initialize managers
83  mColorManager = new ColorManager( this );
84  mLayerManager = new LayerManager( this );
85  mToolManager = new ToolManager( this );
86  mPlaybackManager = new PlaybackManager( this );
87  mViewManager = new ViewManager( this );
88  mPreferenceManager = new PreferenceManager( this );
89  mSoundManager = new SoundManager( this );
90 
91  mAllManagers =
92  {
93  mColorManager,
94  mToolManager,
95  mLayerManager,
96  mPlaybackManager,
97  mViewManager,
98  mPreferenceManager,
99  mSoundManager
100  };
101 
102  for ( BaseManager* pManager : mAllManagers )
103  {
104  pManager->setEditor( this );
105  pManager->init();
106  }
107  //setAcceptDrops( true ); // TODO: drop event
108 
109  makeConnections();
110 
111  mIsAutosave = mPreferenceManager->isOn(SETTING::AUTO_SAVE);
112  autosaveNumber = mPreferenceManager->getInt(SETTING::AUTO_SAVE_NUMBER);
113 
114  //onionPrevFramesNum = mPreferenceManager->getInt(SETTING::ONION_PREV_FRAMES_NUM);
115  //onionNextFramesNum = mPreferenceManager->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
116 
117  return true;
118 }
119 
120 int Editor::currentFrame()
121 {
122  return mFrame;
123 }
124 
125 int Editor::fps()
126 {
127  return mPlaybackManager->fps();
128 }
129 
130 void Editor::makeConnections()
131 {
132  connect( mPreferenceManager, &PreferenceManager::optionChanged, this, &Editor::settingUpdated );
133  connect( QApplication::clipboard(), &QClipboard::dataChanged, this, &Editor::clipboardChanged );
134 }
135 
136 void Editor::dragEnterEvent( QDragEnterEvent* event )
137 {
138  event->acceptProposedAction();
139 }
140 
141 void Editor::dropEvent( QDropEvent* event )
142 {
143  if ( event->mimeData()->hasUrls() )
144  {
145  for ( int i = 0; i < event->mimeData()->urls().size(); i++ )
146  {
147  if ( i > 0 ) scrubForward();
148  QUrl url = event->mimeData()->urls()[ i ];
149  QString filePath = url.toLocalFile();
150  if ( filePath.endsWith( ".png" ) || filePath.endsWith( ".jpg" ) || filePath.endsWith( ".jpeg" ) )
151  importImage( filePath );
152  //if ( filePath.endsWith( ".aif" ) || filePath.endsWith( ".mp3" ) || filePath.endsWith( ".wav" ) )
153  //importSound( filePath );
154  }
155  }
156 }
157 
158 void Editor::settingUpdated(SETTING setting)
159 {
160  switch (setting)
161  {
162  case SETTING::AUTO_SAVE:
163  mIsAutosave = mPreferenceManager->isOn( SETTING::AUTO_SAVE );
164  break;
165  case SETTING::AUTO_SAVE_NUMBER:
166  autosaveNumber = mPreferenceManager->getInt( SETTING::AUTO_SAVE_NUMBER );
167  break;
168  case SETTING::ONION_TYPE:
169  mScribbleArea->updateAllFrames();
170  emit updateTimeLine();
171  break;
172  default:
173  break;
174  }
175 }
176 
177 BackupElement* Editor::currentBackup()
178 {
179  if ( mBackupIndex >= 0 )
180  {
181  return mBackupList[ mBackupIndex ];
182  }
183  else
184  {
185  return nullptr;
186  }
187 }
188 
189 void Editor::backup( QString undoText )
190 {
191  if ( lastModifiedLayer > -1 && lastModifiedFrame > 0 )
192  {
193  backup( lastModifiedLayer, lastModifiedFrame, undoText );
194  }
195  if ( lastModifiedLayer != layers()->currentLayerIndex() || lastModifiedFrame != currentFrame() )
196  {
197  backup( layers()->currentLayerIndex(), currentFrame(), undoText );
198  }
199 }
200 
201 void Editor::backup( int backupLayer, int backupFrame, QString undoText )
202 {
203  while ( mBackupList.size() - 1 > mBackupIndex && mBackupList.size() > 0 )
204  {
205  delete mBackupList.takeLast();
206  }
207  while ( mBackupList.size() > 19 ) // we authorize only 20 levels of cancellation
208  {
209  delete mBackupList.takeFirst();
210  mBackupIndex--;
211  }
212  Layer* layer = mObject->getLayer( backupLayer );
213  if ( layer != NULL )
214  {
215  if ( layer->type() == Layer::BITMAP )
216  {
217  BitmapImage* bitmapImage = ( (LayerBitmap*)layer )->getLastBitmapImageAtFrame( backupFrame, 0 );
218  if ( bitmapImage != NULL )
219  {
220  BackupBitmapElement* element = new BackupBitmapElement(bitmapImage);
221  element->layer = backupLayer;
222  element->frame = backupFrame;
223  element->undoText = undoText;
224  element->somethingSelected = this->getScribbleArea()->somethingSelected;
225  element->mySelection = this->getScribbleArea()->mySelection;
226  element->myTransformedSelection = this->getScribbleArea()->myTransformedSelection;
227  element->myTempTransformedSelection = this->getScribbleArea()->myTempTransformedSelection;
228  mBackupList.append( element );
229  mBackupIndex++;
230  }
231  }
232  else if ( layer->type() == Layer::VECTOR )
233  {
234  VectorImage* vectorImage = ( (LayerVector*)layer )->getLastVectorImageAtFrame( backupFrame, 0 );
235  if ( vectorImage != NULL )
236  {
237  BackupVectorElement* element = new BackupVectorElement(vectorImage);
238  element->layer = backupLayer;
239  element->frame = backupFrame;
240  element->undoText = undoText;
241  element->somethingSelected = this->getScribbleArea()->somethingSelected;
242  element->mySelection = this->getScribbleArea()->mySelection;
243  element->myTransformedSelection = this->getScribbleArea()->myTransformedSelection;
244  element->myTempTransformedSelection = this->getScribbleArea()->myTempTransformedSelection;
245  mBackupList.append( element );
246  mBackupIndex++;
247  }
248  }
249  }
250  emit updateBackup();
251 }
252 
253 void BackupBitmapElement::restore( Editor* editor )
254 {
255  Layer* layer = editor->object()->getLayer( this->layer );
256  if ( layer != NULL )
257  {
258  if ( layer->type() == Layer::BITMAP )
259  {
260  *( ( (LayerBitmap*)layer )->getLastBitmapImageAtFrame( this->frame, 0 ) ) = this->bitmapImage; // restore the image
261  }
262  }
263  editor->getScribbleArea()->somethingSelected = this->somethingSelected;
264  editor->getScribbleArea()->mySelection = this->mySelection;
265  editor->getScribbleArea()->myTransformedSelection = this->myTransformedSelection;
266  editor->getScribbleArea()->myTempTransformedSelection = this->myTempTransformedSelection;
267 
268  editor->updateFrame( this->frame );
269  editor->scrubTo( this->frame );
270 }
271 
272 void BackupVectorElement::restore( Editor* editor )
273 {
274  Layer* layer = editor->object()->getLayer( this->layer );
275  if ( layer != NULL )
276  {
277  if ( layer->type() == Layer::VECTOR )
278  {
279  *( ( (LayerVector*)layer )->getLastVectorImageAtFrame( this->frame, 0 ) ) = this->vectorImage; // restore the image
280  //((LayerVector*)layer)->getLastVectorImageAtFrame(this->frame, 0)->setModified(true); // why?
281  //editor->scribbleArea->setModified(layer, this->frame);
282  }
283  }
284  editor->getScribbleArea()->somethingSelected = this->somethingSelected;
285  editor->getScribbleArea()->mySelection = this->mySelection;
286  editor->getScribbleArea()->myTransformedSelection = this->myTransformedSelection;
287  editor->getScribbleArea()->myTempTransformedSelection = this->myTempTransformedSelection;
288 
289  editor->updateFrameAndVector( this->frame );
290  editor->scrubTo( this->frame );
291 }
292 
293 void Editor::undo()
294 {
295  if ( mBackupList.size() > 0 && mBackupIndex > -1 )
296  {
297  if ( mBackupIndex == mBackupList.size() - 1 )
298  {
299  BackupElement* lastBackupElement = mBackupList[ mBackupIndex ];
300  if ( lastBackupElement->type() == BackupElement::BITMAP_MODIF )
301  {
302  BackupBitmapElement* lastBackupBitmapElement = (BackupBitmapElement*)lastBackupElement;
303  backup( lastBackupBitmapElement->layer, lastBackupBitmapElement->frame, "NoOp" );
304  mBackupIndex--;
305  }
306  if ( lastBackupElement->type() == BackupElement::VECTOR_MODIF )
307  {
308  BackupVectorElement* lastBackupVectorElement = (BackupVectorElement*)lastBackupElement;
309  backup( lastBackupVectorElement->layer, lastBackupVectorElement->frame, "NoOp" );
310  mBackupIndex--;
311  }
312  }
313  //
314  mBackupList[ mBackupIndex ]->restore( this );
315  mBackupIndex--;
316  mScribbleArea->cancelTransformedSelection();
317  mScribbleArea->calculateSelectionRect(); // really ugly -- to improve
318  emit updateBackup();
319  }
320 }
321 
322 void Editor::redo()
323 {
324  if ( mBackupList.size() > 0 && mBackupIndex < mBackupList.size() - 2 )
325  {
326  mBackupIndex++;
327  mBackupList[ mBackupIndex + 1 ]->restore( this );
328  emit updateBackup();
329  }
330 }
331 
332 void Editor::clearUndoStack()
333 {
334  mBackupIndex = -1;
335  while ( !mBackupList.isEmpty() )
336  {
337  delete mBackupList.takeLast();
338  }
339  lastModifiedLayer = -1;
340  lastModifiedFrame = -1;
341 }
342 
343 void Editor::cut()
344 {
345  copy();
346  mScribbleArea->deleteSelection();
347  mScribbleArea->deselectAll();
348 }
349 
350 void Editor::copy()
351 {
352  Layer* layer = mObject->getLayer( layers()->currentLayerIndex() );
353  if ( layer != NULL )
354  {
355  if ( layer->type() == Layer::BITMAP )
356  {
357  if ( mScribbleArea->somethingSelected )
358  {
359  g_clipboardBitmapImage = ( (LayerBitmap*)layer )->getLastBitmapImageAtFrame( currentFrame(), 0 )->copy( mScribbleArea->getSelection().toRect() ); // copy part of the image
360  }
361  else
362  {
363  g_clipboardBitmapImage = ( (LayerBitmap*)layer )->getLastBitmapImageAtFrame( currentFrame(), 0 )->copy(); // copy the whole image
364  }
365  clipboardBitmapOk = true;
366  if ( g_clipboardBitmapImage.image() != NULL ) QApplication::clipboard()->setImage( *g_clipboardBitmapImage.image() );
367  }
368  if ( layer->type() == Layer::VECTOR )
369  {
370  clipboardVectorOk = true;
371  g_clipboardVectorImage = *( ( (LayerVector*)layer )->getLastVectorImageAtFrame( currentFrame(), 0 ) ); // copy the image
372  }
373  }
374 }
375 
376 void Editor::paste()
377 {
378  Layer* layer = mObject->getLayer( layers()->currentLayerIndex() );
379  if ( layer != NULL )
380  {
381  if ( layer->type() == Layer::BITMAP && g_clipboardBitmapImage.image() != NULL )
382  {
383  backup( tr( "Paste" ) );
384  BitmapImage tobePasted = g_clipboardBitmapImage.copy();
385  qDebug() << "to be pasted --->" << tobePasted.image()->size();
386  if ( mScribbleArea->somethingSelected )
387  {
388  QRectF selection = mScribbleArea->getSelection();
389  if ( g_clipboardBitmapImage.width() <= selection.width() && g_clipboardBitmapImage.height() <= selection.height() )
390  {
391  tobePasted.moveTopLeft( selection.topLeft() );
392  }
393  else
394  {
395  tobePasted.transform( selection, true );
396  }
397  }
398  auto pLayerBitmap = static_cast<LayerBitmap*>( layer );
399  pLayerBitmap->getLastBitmapImageAtFrame( currentFrame(), 0 )->paste( &tobePasted ); // paste the clipboard
400  }
401  else if ( layer->type() == Layer::VECTOR && clipboardVectorOk )
402  {
403  backup( tr( "Paste" ) );
404  mScribbleArea->deselectAll();
405  VectorImage* vectorImage = ( (LayerVector*)layer )->getLastVectorImageAtFrame( currentFrame(), 0 );
406  vectorImage->paste( g_clipboardVectorImage ); // paste the clipboard
407  mScribbleArea->setSelection( vectorImage->getSelectionRect(), true );
408  //((LayerVector*)layer)->getLastVectorImageAtFrame(backupFrame, 0)->modification(); ????
409  }
410  }
411  mScribbleArea->updateCurrentFrame();
412 }
413 
414 void Editor::flipSelection(bool flipVertical)
415 {
416  mScribbleArea->flipSelection(flipVertical);
417 }
418 
419 void Editor::deselectAll()
420 {
421  mScribbleArea->deselectAll();
422 }
423 
424 void Editor::clipboardChanged()
425 {
426  if ( clipboardBitmapOk == false )
427  {
428  g_clipboardBitmapImage.setImage( new QImage( QApplication::clipboard()->image() ) );
429  g_clipboardBitmapImage.bounds() = QRect( g_clipboardBitmapImage.topLeft(), g_clipboardBitmapImage.image()->size() );
430  qDebug() << "New clipboard image" << g_clipboardBitmapImage.image()->size();
431  }
432  else
433  {
434  clipboardBitmapOk = false;
435  qDebug() << "The image has been saved in the clipboard";
436  }
437 }
438 
439 int Editor::allLayers()
440 {
441  return mScribbleArea->showAllLayers();
442 }
443 
444 void Editor::toggleMirror()
445 {
446  bool flipX = view()->isFlipHorizontal();
447  view()->flipHorizontal( !flipX );
448 }
449 
450 void Editor::toggleMirrorV()
451 {
452  bool flipY = view()->isFlipVertical();
453  view()->flipVertical( !flipY );
454 }
455 
456 void Editor::toggleShowAllLayers()
457 {
458  mScribbleArea->toggleShowAllLayers();
459  emit updateTimeLine();
460 }
461 
462 void Editor::toogleOnionSkinType()
463 {
464  QString onionSkinState = mPreferenceManager->getString(SETTING::ONION_TYPE);
465  QString newState;
466  if (onionSkinState == "relative")
467  {
468  newState = "absolute";
469  }
470  else
471  {
472  newState = "relative";
473  }
474 
475  mPreferenceManager->set(SETTING::ONION_TYPE, newState);
476 }
477 
478 Status Editor::setObject( Object* newObject )
479 {
480  if ( newObject == nullptr )
481  {
482  Q_ASSERT( false );
483  return Status::INVALID_ARGUMENT;
484  }
485 
486  if ( newObject == mObject.get() )
487  {
488  return Status::SAFE;
489  }
490 
491  mObject.reset( newObject );
492 
493 
494  for ( BaseManager* m : mAllManagers )
495  {
496  m->load( mObject.get() );
497  }
498 
499  g_clipboardVectorImage.setObject( newObject );
500 
501  updateObject();
502 
503  emit objectLoaded();
504 
505  return Status::OK;
506 }
507 
508 void Editor::updateObject()
509 {
510  scrubTo( mObject->data()->getCurrentFrame() );
511  if (layers() != NULL)
512  {
513  layers()->setCurrentLayer( mObject->data()->getCurrentLayer() );
514  }
515 
516  clearUndoStack();
517 
518  if ( mScribbleArea )
519  {
520  mScribbleArea->updateAllFrames();
521  }
522 
523  emit updateLayerCount();
524 }
525 
526 bool Editor::exportSeqCLI( QString filePath, QString format, int width, int height, bool transparency, bool antialias )
527 {
528  // Get the camera layer
529  int cameraLayerId = mLayerManager->getLastCameraLayer();
530  LayerCamera *cameraLayer = dynamic_cast< LayerCamera* >(mObject->getLayer(cameraLayerId));
531 
532  if ( width < 0 )
533  {
534  width = cameraLayer->getViewRect().width();
535  }
536  if ( height < 0 )
537  {
538  height = cameraLayer->getViewRect().height();
539  }
540 
541  QSize exportSize = QSize( width, height );
542  QByteArray exportFormat( format.toLatin1() );
543 
544  //QTransform view = RectMapTransform( mScribbleArea->getViewRect(), QRectF( QPointF( 0, 0 ), exportSize ) );
545  //view = mScribbleArea->getView() * view;
546 
547  int projectLength = mLayerManager->projectLength();
548 
549  mObject->exportFrames( 1,
550  projectLength,
551  cameraLayer,
552  exportSize,
553  filePath,
554  exportFormat,
555  -1,
556  transparency,
557  antialias,
558  NULL,
559  0 );
560 
561  return true;
562 }
563 
564 QString Editor::workingDir() const
565 {
566  return mObject->workingDir();
567 }
568 
569 bool Editor::importBitmapImage( QString filePath )
570 {
571  backup( tr( "Import Image" ) );
572 
573  QImageReader reader( filePath );
574 
575  Q_ASSERT( layers()->currentLayer()->type() == Layer::BITMAP );
576  auto layer = static_cast<LayerBitmap*>( layers()->currentLayer() );
577 
578  QImage img( reader.size(), QImage::Format_ARGB32_Premultiplied );
579  if ( img.isNull() )
580  {
581  return false;
582  }
583 
584  while ( reader.read( &img ) )
585  {
586  if ( !layer->keyExists( currentFrame() ) )
587  {
588  addNewKey();
589  }
590  BitmapImage* bitmapImage = layer->getBitmapImageAtFrame( currentFrame() );
591 
592  QRect boundaries = img.rect();
593  boundaries.moveTopLeft( mScribbleArea->getCentralPoint().toPoint() - QPoint( boundaries.width() / 2, boundaries.height() / 2 ) );
594 
595  BitmapImage importedBitmapImage{boundaries, img};
596  bitmapImage->paste(&importedBitmapImage);
597 
598  scrubTo( currentFrame() + 1 );
599  }
600 
601  return true;
602 }
603 
604 bool Editor::importVectorImage( QString filePath )
605 {
606  Q_ASSERT( layers()->currentLayer()->type() == Layer::VECTOR );
607 
608  backup( tr( "Import Image" ) );
609 
610  auto layer = static_cast<LayerVector*>( layers()->currentLayer() );
611 
612  VectorImage* vectorImage = ( (LayerVector*)layer )->getVectorImageAtFrame( currentFrame() );
613  if ( vectorImage == NULL )
614  {
615  addNewKey();
616  vectorImage = ( (LayerVector*)layer )->getVectorImageAtFrame( currentFrame() );
617  }
618  VectorImage importedVectorImage;
619  bool ok = importedVectorImage.read( filePath );
620  if ( ok )
621  {
622  importedVectorImage.selectAll();
623  vectorImage->paste(importedVectorImage);
624  }
625  /*
626  else
627  {
628  QMessageBox::warning( mMainWindow,
629  tr( "Warning" ),
630  tr( "Unable to load vector image.<br><b>TIP:</b> Use Vector layer to import vectors." ),
631  QMessageBox::Ok,
632  QMessageBox::Ok );
633  }
634  */
635  return ok;
636 }
637 
638 bool Editor::importImage( QString filePath )
639 {
640  Layer* layer = layers()->currentLayer();
641 
642  switch ( layer->type() )
643  {
644  case Layer::BITMAP:
645  return importBitmapImage( filePath );
646 
647  case Layer::VECTOR:
648  return importVectorImage( filePath );
649 
650  default:
651  {
652  //mLastError = Status::ERROR_INVALID_LAYER_TYPE;
653  return false;
654  }
655  }
656 }
657 
658 void Editor::updateFrame( int frameNumber )
659 {
660  mScribbleArea->updateFrame( frameNumber );
661 }
662 
663 void Editor::updateFrameAndVector( int frameNumber )
664 {
665  mScribbleArea->updateAllVectorLayersAt( frameNumber );
666 }
667 
668 void Editor::updateCurrentFrame()
669 {
670  mScribbleArea->updateCurrentFrame();
671 }
672 
673 void Editor::scrubTo( int frame )
674 {
675  if ( frame < 1 )
676  {
677  frame = 1;
678  }
679  int oldFrame = mFrame;
680  mFrame = frame;
681 
682  Q_EMIT currentFrameChanged( frame );
683  Q_EMIT currentFrameChanged( oldFrame );
684 
685  // FIXME: should not emit Timeline update here.
686  // Editor must be an individual class.
687  // Will remove all Timeline related code in Editor class.
688  if ( mPlaybackManager && !mPlaybackManager->isPlaying() )
689  {
690  emit updateTimeLine(); // needs to update the timeline to update onion skin positions
691  }
692 }
693 
694 void Editor::scrubForward()
695 {
696  scrubTo( currentFrame() + 1 );
697 }
698 
699 void Editor::scrubBackward()
700 {
701  if ( currentFrame() > 1 )
702  {
703  scrubTo( currentFrame() - 1 );
704  }
705 }
706 
707 void Editor::moveFrameForward()
708 {
709  Layer* layer = layers()->currentLayer();
710  if ( layer != NULL )
711  {
712  if ( layer->moveKeyFrameForward( currentFrame() ) )
713  {
714  mScribbleArea->updateAllFrames();
715  scrubForward();
716  }
717  }
718 }
719 
720 void Editor::moveFrameBackward()
721 {
722  Layer* layer = layers()->currentLayer();
723  if ( layer != NULL )
724  {
725  if ( layer->moveKeyFrameBackward( currentFrame() ) )
726  {
727  mScribbleArea->updateAllFrames();
728  scrubBackward();
729  }
730  }
731 }
732 
733 KeyFrame* Editor::addNewKey()
734 {
735  return addKeyFame( layers()->currentLayerIndex(), currentFrame() );
736 }
737 
738 void Editor::duplicateKey()
739 {
740  Layer* layer = mObject->getLayer( layers()->currentLayerIndex() );
741  if ( layer != NULL )
742  {
743  if ( layer->type() == Layer::VECTOR || layer->type() == Layer::BITMAP )
744  {
745  // Will copy the selection if any or the entire image if there is none
746  //
747  if(!mScribbleArea->somethingSelected) {
748  mScribbleArea->selectAll();
749  }
750 
751  copy();
752  addNewKey();
753  paste();
754 
755  mScribbleArea->setModified( layers()->currentLayerIndex(), currentFrame() );
756  mScribbleArea->update();
757  }
758  }
759 }
760 
761 KeyFrame* Editor::addKeyFame( int layerNumber, int frameIndex )
762 {
763  Layer* layer = mObject->getLayer( layerNumber );
764  if ( layer == NULL )
765  {
766  Q_ASSERT( false );
767  return nullptr;
768  }
769 
770  bool isOK = false;
771 
772  while ( layer->keyExists( frameIndex ) )
773  {
774  frameIndex += 1;
775  }
776 
777  KeyFrame* keyFrame = KeyFrameFactory::create( layer->type(), mObject.get() );
778  if ( keyFrame != nullptr )
779  {
780  isOK = layer->addKeyFrame( frameIndex, keyFrame );
781  }
782  else
783  {
784  Q_ASSERT( false );
785  }
786 
787  if ( isOK )
788  {
789  scrubTo( frameIndex ); // currentFrameChanged() emit inside.
790  //getScribbleArea()->updateCurrentFrame();
791  }
792 
793  return keyFrame;
794 }
795 
796 void Editor::removeKey()
797 {
798  Layer* layer = layers()->currentLayer();
799  if ( layer != NULL )
800  {
801  layer->removeKeyFrame( currentFrame() );
802 
803  scrubBackward();
804  mScribbleArea->updateCurrentFrame();
805  }
806  Q_EMIT layers()->currentLayerChanged( layers()->currentLayerIndex() ); // trigger timeline repaint.
807 }
808 
809 void Editor::scrubNextKeyFrame()
810 {
811  Layer* layer = layers()->currentLayer();
812  Q_ASSERT( layer );
813 
814  int nextPosition = layer->getNextKeyFramePosition( currentFrame() );
815  scrubTo( nextPosition );
816 }
817 
818 void Editor::scrubPreviousKeyFrame()
819 {
820  Layer* layer = mObject->getLayer( layers()->currentLayerIndex() );
821  Q_ASSERT( layer );
822 
823  int prevPosition = layer->getPreviousKeyFramePosition( currentFrame() );
824  scrubTo( prevPosition );
825 }
826 
827 void Editor::setCurrentLayer( int layerNumber )
828 {
829  layers()->setCurrentLayer( layerNumber );
830  mScribbleArea->updateAllFrames();
831 }
832 
833 void Editor::switchVisibilityOfLayer( int layerNumber )
834 {
835  Layer* layer = mObject->getLayer( layerNumber );
836  if ( layer != NULL ) layer->switchVisibility();
837  mScribbleArea->updateAllFrames();
838 
839  emit updateTimeLine();
840 }
841 
842 void Editor::moveLayer( int i, int j )
843 {
844  mObject->moveLayer( i, j );
845  if ( j < i )
846  {
847  layers()->setCurrentLayer( j );
848  }
849  else
850  {
851  layers()->setCurrentLayer( j - 1 );
852  }
853  emit updateTimeLine();
854  mScribbleArea->updateAllFrames();
855 }
856 
857 void Editor::prepareSave()
858 {
859  for ( auto mgr : mAllManagers )
860  {
861  mgr->save( mObject.get() );
862  }
863 }
864 
865 void Editor::clearCurrentFrame()
866 {
867  mScribbleArea->clearImage();
868 }
Definition: layer.h:32
void flipSelection(bool flipVertical)
ScribbleArea::flipSelection flip selection along the X or Y axis.
Definition: object.h:71
Definition: editor.h:45