Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
actioncommands.cpp
1 /*
2 
3 Pencil - Traditional Animation Software
4 Copyright (C) 2012-2017 Matthew Chiawen Chang
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; version 2 of the License.
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 */
16 
17 #include "actioncommands.h"
18 
19 #include <QInputDialog>
20 #include <QMessageBox>
21 #include <QProgressDialog>
22 #include <QApplication>
23 #include <QDesktopServices>
24 
25 #include "pencildef.h"
26 #include "editor.h"
27 #include "object.h"
28 #include "viewmanager.h"
29 #include "layermanager.h"
30 #include "soundmanager.h"
31 #include "playbackmanager.h"
32 #include "preferencemanager.h"
33 #include "util.h"
34 
35 //#include "layerbitmap.h"
36 //#include "layervector.h"
37 #include "layercamera.h"
38 #include "layersound.h"
39 #include "bitmapimage.h"
40 #include "vectorimage.h"
41 #include "soundclip.h"
42 
43 #include "movieexporter.h"
44 #include "filedialogex.h"
45 #include "exportmoviedialog.h"
46 
47 
48 
49 ActionCommands::ActionCommands( QWidget* parent ) : QObject( parent )
50 {
51  mParent = parent;
52 }
53 
54 ActionCommands::~ActionCommands() {}
55 
56 Status ActionCommands::importSound()
57 {
58  Layer* layer = mEditor->layers()->currentLayer();
59  Q_ASSERT( layer );
60  NULLReturn( layer, Status::FAIL );
61 
62  if ( layer->type() != Layer::SOUND )
63  {
64  QMessageBox msg;
65  msg.setText( tr( "No sound layer exists as a destination for your import. Create a new sound layer?" ) );
66  msg.addButton( tr( "Create sound layer" ), QMessageBox::AcceptRole );
67  msg.addButton( tr( "Don't create layer" ), QMessageBox::RejectRole );
68 
69  int buttonClicked = msg.exec();
70  if ( buttonClicked != QMessageBox::AcceptRole )
71  {
72  return Status::SAFE;
73  }
74 
75  // Create new sound layer.
76  bool ok = false;
77  QString strLayerName = QInputDialog::getText( mParent, tr( "Layer Properties" ),
78  tr( "Layer name:" ), QLineEdit::Normal,
79  tr( "Sound Layer" ), &ok );
80  if ( ok && !strLayerName.isEmpty() )
81  {
82  Layer* newLayer = mEditor->layers()->createSoundLayer( strLayerName );
83  mEditor->layers()->setCurrentLayer( newLayer );
84  }
85  else
86  {
87  Q_ASSERT( false );
88  return Status::FAIL;
89  }
90  }
91 
92  layer = mEditor->layers()->currentLayer();
93 
94  if ( layer->keyExists( mEditor->currentFrame() ) )
95  {
96  QMessageBox::warning( nullptr,
97  "",
98  tr( "A sound clip already exists on this frame! Please select another frame or layer." ) );
99  return Status::SAFE;
100  }
101 
102  FileDialog fileDialog( mParent );
103  QString strSoundFile = fileDialog.openFile( FileType::SOUND );
104 
105  Status st = mEditor->sound()->loadSound( layer, mEditor->currentFrame(), strSoundFile );
106 
107  return st;
108 }
109 
110 Status ActionCommands::exportMovie()
111 {
112  ExportMovieDialog exportDialog( mParent );
113 
114  std::vector< std::pair<QString, QSize > > camerasInfo;
115  auto cameraLayers = mEditor->object()->getLayersByType< LayerCamera >();
116  for ( LayerCamera* i : cameraLayers )
117  {
118  camerasInfo.push_back( std::make_pair( i->name(), i->getViewSize() ) );
119  }
120 
121  auto currLayer = mEditor->layers()->currentLayer();
122  if ( currLayer->type() == Layer::CAMERA )
123  {
124  QString strName = currLayer->name();
125  auto it = std::find_if( camerasInfo.begin(), camerasInfo.end(),
126  [strName] ( std::pair<QString, QSize> p )
127  {
128  return p.first == strName;
129  } );
130 
131  Q_ASSERT(it != camerasInfo.end());
132 
133  std::swap( camerasInfo[ 0 ], *it );
134  }
135 
136  exportDialog.setCamerasInfo( camerasInfo );
137  exportDialog.setDefaultRange( 1, mEditor->layers()->projectLength() );
138  exportDialog.exec();
139  if ( exportDialog.result() == QDialog::Rejected )
140  {
141  return Status::SAFE;
142  }
143  QString strMoviePath = exportDialog.getFilePath();
144 
145  ExportMovieDesc desc;
146  desc.strFileName = strMoviePath;
147  desc.startFrame = exportDialog.getStartFrame();
148  desc.endFrame = exportDialog.getEndFrame();
149  desc.fps = mEditor->playback()->fps();
150  desc.exportSize = exportDialog.getExportSize();
151  desc.strCameraName = exportDialog.getSelectedCameraName();
152 
153  QProgressDialog progressDlg;
154  progressDlg.setWindowModality( Qt::WindowModal );
155  progressDlg.setLabelText( tr("Exporting movie...") );
156  Qt::WindowFlags eFlags = Qt::Dialog | Qt::WindowTitleHint;
157  progressDlg.setWindowFlags( eFlags );
158  progressDlg.show();
159 
160  MovieExporter ex;
161 
162  connect( &progressDlg, &QProgressDialog::canceled, [&ex]
163  {
164  ex.cancel();
165  } );
166 
167  Status st = ex.run( mEditor->object(), desc, [ &progressDlg ]( float f )
168  {
169  progressDlg.setValue( (int)(f * 100.f) );
170  QApplication::processEvents( QEventLoop::ExcludeUserInputEvents );
171  } );
172 
173  if ( st.ok() && QFile::exists( strMoviePath ) )
174  {
175  auto btn = QMessageBox::question( mParent,
176  "Pencil2D",
177  tr( "Finished. Open movie now?" ) );
178  if ( btn == QMessageBox::Yes )
179  {
180  QDesktopServices::openUrl( QUrl::fromLocalFile( strMoviePath ) );
181  }
182  }
183 
184  return Status::OK;
185 }
186 
187 void ActionCommands::ZoomIn()
188 {
189  mEditor->view()->scaleUp();
190 }
191 
192 void ActionCommands::ZoomOut()
193 {
194  mEditor->view()->scaleDown();
195 }
196 
197 void ActionCommands::flipSelectionX()
198 {
199  bool flipVertical = false;
200  mEditor->flipSelection(flipVertical);
201 }
202 
203 void ActionCommands::flipSelectionY()
204 {
205  bool flipVertical = true;
206  mEditor->flipSelection(flipVertical);
207 }
208 
209 void ActionCommands::rotateClockwise()
210 {
211  float currentRotation = mEditor->view()->rotation();
212  mEditor->view()->rotate(currentRotation + 15.f);
213 }
214 
215 void ActionCommands::rotateCounterClockwise()
216 {
217  float currentRotation = mEditor->view()->rotation();
218  mEditor->view()->rotate(currentRotation - 15.f);
219 }
220 
221 void ActionCommands::showGrid( bool bShow )
222 {
223  auto prefs = mEditor->preference();
224  if ( bShow )
225  prefs->turnOn( SETTING::GRID );
226  else
227  prefs->turnOff( SETTING::GRID );
228 }
229 
230 void ActionCommands::PlayStop()
231 {
232  PlaybackManager* playback = mEditor->playback();
233  if ( playback->isPlaying() )
234  {
235  playback->stop();
236  }
237  else
238  {
239  playback->play();
240  }
241 }
242 
243 void ActionCommands::GotoNextFrame()
244 {
245  mEditor->scrubForward();
246 }
247 
248 void ActionCommands::GotoPrevFrame()
249 {
250  mEditor->scrubBackward();
251 }
252 
253 void ActionCommands::GotoNextKeyFrame()
254 {
255  mEditor->scrubNextKeyFrame();
256 }
257 
258 void ActionCommands::GotoPrevKeyFrame()
259 {
260  mEditor->scrubPreviousKeyFrame();
261 }
262 
263 void ActionCommands::addNewKey()
264 {
265  KeyFrame* key = mEditor->addNewKey();
266 
267  SoundClip* clip = dynamic_cast< SoundClip* >( key );
268  if ( clip )
269  {
270  FileDialog fileDialog( mParent );
271  QString strSoundFile = fileDialog.openFile( FileType::SOUND );
272 
273  if ( strSoundFile.isEmpty() )
274  {
275  mEditor->removeKey();
276  return;
277  }
278  Status st = mEditor->sound()->loadSound( clip, strSoundFile );
279  Q_ASSERT( st.ok() );
280  }
281 }
282 
283 void ActionCommands::removeKey()
284 {
285  mEditor->removeKey();
286 
287  Layer* layer = mEditor->layers()->currentLayer();
288  if ( layer->keyFrameCount() == 0 )
289  {
290  switch ( layer->type() )
291  {
292  case Layer::BITMAP:
293  case Layer::VECTOR:
294  case Layer::CAMERA:
295  layer->addNewEmptyKeyAt( 1 );
296  break;
297  default:
298  break;
299  }
300  }
301 }
302 
303 Status ActionCommands::addNewBitmapLayer()
304 {
305  bool ok;
306  QString text = QInputDialog::getText( nullptr, tr( "Layer Properties" ),
307  tr( "Layer name:" ), QLineEdit::Normal,
308  tr( "Bitmap Layer" ), &ok );
309  if ( ok && !text.isEmpty() )
310  {
311  mEditor->layers()->createBitmapLayer( text );
312  }
313  return Status::OK;
314 }
315 
316 Status ActionCommands::addNewVectorLayer()
317 {
318  bool ok;
319  QString text = QInputDialog::getText( nullptr, tr( "Layer Properties" ),
320  tr( "Layer name:" ), QLineEdit::Normal,
321  tr( "Vector Layer" ), &ok );
322  if ( ok && !text.isEmpty() )
323  {
324  mEditor->layers()->createVectorLayer( text );
325  }
326 
327  return Status::OK;
328 }
329 
330 Status ActionCommands::addNewCameraLayer()
331 {
332  bool ok;
333  QString text = QInputDialog::getText( nullptr, tr( "Layer Properties" ),
334  tr( "Layer name:" ), QLineEdit::Normal,
335  tr( "Camera Layer" ), &ok );
336  if ( ok && !text.isEmpty() )
337  {
338  mEditor->layers()->createCameraLayer( text );
339  }
340 
341  return Status::OK;
342 
343 }
344 
345 Status ActionCommands::addNewSoundLayer()
346 {
347  bool ok = false;
348  QString strLayerName = QInputDialog::getText( nullptr, tr( "Layer Properties" ),
349  tr( "Layer name:" ), QLineEdit::Normal,
350  tr( "Sound Layer" ), &ok );
351  if ( ok && !strLayerName.isEmpty() )
352  {
353  Layer* layer = mEditor->layers()->createSoundLayer( strLayerName );
354  mEditor->layers()->setCurrentLayer( layer );
355 
356  return Status::OK;
357  }
358  return Status::FAIL;
359 }
Definition: layer.h:32