All Classes Namespaces Functions Variables Enumerations Properties Pages
mainwindow2.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2008-2009 Mj Mendoza IV
6 Copyright (C) 2012-2020 Matthew Chiawen Chang
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; version 2 of the License.
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 */
18 
19 #include "mainwindow2.h"
20 #include "ui_mainwindow2.h"
21 
22 // Qt headers
23 #include <QDir>
24 #include <QList>
25 #include <QMenu>
26 #include <QFile>
27 #include <QMessageBox>
28 #include <QProgressDialog>
29 #include <QTabletEvent>
30 #include <QStandardPaths>
31 #include <QDateTime>
32 #include <QLabel>
33 
34 // core_lib headers
35 #include "pencildef.h"
36 #include "pencilsettings.h"
37 #include "object.h"
38 #include "editor.h"
39 
40 #include "filemanager.h"
41 #include "colormanager.h"
42 #include "layermanager.h"
43 #include "toolmanager.h"
44 #include "playbackmanager.h"
45 #include "selectionmanager.h"
46 #include "soundmanager.h"
47 #include "viewmanager.h"
48 
49 #include "actioncommands.h"
50 #include "fileformat.h" //contains constants used by Pencil File Format
51 #include "util.h"
52 #include "backupelement.h"
53 
54 // app headers
55 #include "colorbox.h"
56 #include "colorinspector.h"
57 #include "colorpalettewidget.h"
58 #include "displayoptionwidget.h"
59 #include "tooloptionwidget.h"
60 #include "preferencesdialog.h"
61 #include "timeline.h"
62 #include "toolbox.h"
63 #include "onionskinwidget.h"
64 
65 //#include "preview.h"
66 //#include "timeline2.h"
67 #include "errordialog.h"
68 #include "filedialog.h"
69 #include "importimageseqdialog.h"
70 #include "importlayersdialog.h"
71 #include "importpositiondialog.h"
72 #include "recentfilemenu.h"
73 #include "shortcutfilter.h"
74 #include "app_util.h"
75 #include "presetdialog.h"
76 #include "pegbaralignmentdialog.h"
77 
78 
79 #ifdef GIT_TIMESTAMP
80 #define BUILD_DATE S__GIT_TIMESTAMP
81 #else
82 #define BUILD_DATE __DATE__
83 #endif
84 
85 #if defined(PENCIL2D_RELEASE_BUILD)
86 #define PENCIL_WINDOW_TITLE QString("[*]Pencil2D v%1").arg(APP_VERSION)
87 #elif defined(PENCIL2D_NIGHTLY_BUILD)
88 #define PENCIL_WINDOW_TITLE QString("[*]Pencil2D Nightly Build %1").arg(BUILD_DATE)
89 #else
90 #define PENCIL_WINDOW_TITLE QString("[*]Pencil2D Development Build %1").arg(BUILD_DATE)
91 #endif
92 
93 
94 
95 MainWindow2::MainWindow2(QWidget* parent) :
96  QMainWindow(parent),
97  ui(new Ui::MainWindow2)
98 {
99  ui->setupUi(this);
100 
101  // Initialize order
102  // 1. editor 2. object 3. scribble area 4. other widgets
103  mEditor = new Editor(this);
104  mEditor->setScribbleArea(ui->scribbleArea);
105  mEditor->init();
106 
107  newObject();
108 
109  ui->scribbleArea->setEditor(mEditor);
110  ui->scribbleArea->init();
111 
112  mEditor->setScribbleArea(ui->scribbleArea);
113  makeConnections(mEditor, ui->scribbleArea);
114 
115  mCommands = new ActionCommands(this);
116  mCommands->setCore(mEditor);
117 
118  createDockWidgets();
119  createMenus();
120  setupKeyboardShortcuts();
121 
122  readSettings();
123 
124  mZoomLabel = new QLabel("");
125  ui->statusbar->addWidget(mZoomLabel);
126 
127  updateZoomLabel();
128  selectionChanged();
129 
130  connect(mEditor, &Editor::needSave, this, &MainWindow2::autoSave);
131  connect(mToolBox, &ToolBoxWidget::clearButtonClicked, mEditor, &Editor::clearCurrentFrame);
132  connect(mEditor->view(), &ViewManager::viewChanged, this, &MainWindow2::updateZoomLabel);
133 
134  mEditor->tools()->setDefaultTool();
135  ui->background->init(mEditor->preference());
136 
137  setWindowTitle(PENCIL_WINDOW_TITLE);
138 }
139 
140 MainWindow2::~MainWindow2()
141 {
142  delete ui;
143 }
144 
145 void MainWindow2::createDockWidgets()
146 {
147  mTimeLine = new TimeLine(this);
148  mTimeLine->setObjectName("TimeLine");
149 
150  mColorBox = new ColorBox(this);
151  mColorBox->setToolTip(tr("color palette:<br>use <b>(C)</b><br>toggle at cursor"));
152  mColorBox->setObjectName("ColorWheel");
153 
154  mColorInspector = new ColorInspector(this);
155  mColorInspector->setToolTip(tr("Color inspector"));
156  mColorInspector->setObjectName("Color Inspector");
157 
158  mColorPalette = new ColorPaletteWidget(this);
159  mColorPalette->setCore(mEditor);
160  mColorPalette->setObjectName("ColorPalette");
161 
162  mDisplayOptionWidget = new DisplayOptionWidget(this);
163  mDisplayOptionWidget->setObjectName("DisplayOption");
164 
165  mOnionSkinWidget = new OnionSkinWidget(this);
166  mOnionSkinWidget->setObjectName("Onion Skin");
167 
168  mToolOptions = new ToolOptionWidget(this);
169  mToolOptions->setObjectName("ToolOption");
170 
171  mToolBox = new ToolBoxWidget(this);
172  mToolBox->setObjectName("ToolBox");
173 
174  /*
175  mTimeline2 = new Timeline2;
176  mTimeline2->setObjectName( "Timeline2" );
177  mDockWidgets.append( mTimeline2 );
178  */
179 
180  mDockWidgets
181  << mTimeLine
182  << mColorBox
183  << mColorInspector
184  << mColorPalette
185  << mDisplayOptionWidget
186  << mOnionSkinWidget
187  << mToolOptions
188  << mToolBox;
189 
190  mStartIcon = QIcon(":icons/controls/play.png");
191  mStopIcon = QIcon(":icons/controls/stop.png");
192 
193  for (BaseDockWidget* pWidget : mDockWidgets)
194  {
195  pWidget->setAllowedAreas(Qt::AllDockWidgetAreas);
196  pWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
197  pWidget->setFocusPolicy(Qt::NoFocus);
198 
199  pWidget->setEditor(mEditor);
200  pWidget->initUI();
201  pWidget->show();
202  qDebug() << "Init Dock widget: " << pWidget->objectName();
203  }
204 
205  addDockWidget(Qt::RightDockWidgetArea, mColorBox);
206  addDockWidget(Qt::RightDockWidgetArea, mColorInspector);
207  addDockWidget(Qt::RightDockWidgetArea, mColorPalette);
208  addDockWidget(Qt::LeftDockWidgetArea, mToolBox);
209  addDockWidget(Qt::LeftDockWidgetArea, mToolOptions);
210  addDockWidget(Qt::LeftDockWidgetArea, mDisplayOptionWidget);
211  addDockWidget(Qt::LeftDockWidgetArea, mOnionSkinWidget);
212  addDockWidget(Qt::BottomDockWidgetArea, mTimeLine);
213  setDockNestingEnabled(true);
214 
215  /*
216  mPreview = new PreviewWidget( this );
217  mPreview->setImage( mScribbleArea->mBufferImg );
218  mPreview->setFeatures( QDockWidget::DockWidgetFloatable );
219  mPreview->setFocusPolicy( Qt::NoFocus );
220  addDockWidget( Qt::RightDockWidgetArea, mPreview );
221  */
222 
223  makeConnections(mEditor);
224  makeConnections(mEditor, mTimeLine);
225  makeConnections(mEditor, mColorBox);
226  makeConnections(mEditor, mColorInspector);
227  makeConnections(mEditor, mColorPalette);
228  makeConnections(mEditor, mToolOptions);
229  makeConnections(mEditor, mDisplayOptionWidget);
230 
231  for (BaseDockWidget* w : mDockWidgets)
232  {
233  w->updateUI();
234  w->setFloating(false);
235  }
236 }
237 
238 void MainWindow2::createMenus()
239 {
240  //--- File Menu ---
241  connect(ui->actionNew, &QAction::triggered, this, &MainWindow2::newDocument);
242  connect(ui->actionOpen, &QAction::triggered, this, &MainWindow2::openDocument);
243  connect(ui->actionSave_as, &QAction::triggered, this, &MainWindow2::saveAsNewDocument);
244  connect(ui->actionSave, &QAction::triggered, this, &MainWindow2::saveDocument);
245  connect(ui->actionExit, &QAction::triggered, this, &MainWindow2::close);
246 
247  //--- Export Menu ---
248  //connect( ui->actionExport_X_sheet, &QAction::triggered, mEditor, &Editor::exportX );
249  connect(ui->actionExport_Image, &QAction::triggered, mCommands, &ActionCommands::exportImage);
250  connect(ui->actionExport_ImageSeq, &QAction::triggered, mCommands, &ActionCommands::exportImageSequence);
251  connect(ui->actionExport_Movie, &QAction::triggered, mCommands, &ActionCommands::exportMovie);
252  connect(ui->actionExport_Animated_GIF, &QAction::triggered, mCommands, &ActionCommands::exportGif);
253 
254  connect(ui->actionExport_Palette, &QAction::triggered, this, &MainWindow2::exportPalette);
255 
256  //--- Import Menu ---
257  //connect( ui->actionExport_Svg_Image, &QAction::triggered, editor, &Editor::saveSvg );
258  connect(ui->actionImport_Image, &QAction::triggered, this, &MainWindow2::importImage);
259  connect(ui->actionImport_ImageSeq, &QAction::triggered, this, &MainWindow2::importImageSequence);
260  connect(ui->actionImport_ImageSeqNum, &QAction::triggered, this, &MainWindow2::importPredefinedImageSet);
261  connect(ui->actionImportLayers_from_pclx, &QAction::triggered, this, &MainWindow2::importLayers);
262  connect(ui->actionImport_MovieVideo, &QAction::triggered, this, &MainWindow2::importMovieVideo);
263  connect(ui->actionImport_Gif, &QAction::triggered, this, &MainWindow2::importGIF);
264 
265  connect(ui->actionImport_Sound, &QAction::triggered, mCommands, &ActionCommands::importSound);
266  connect(ui->actionImport_MovieAudio, &QAction::triggered, mCommands, &ActionCommands::importMovieAudio);
267 
268  connect(ui->actionImport_Append_Palette, &QAction::triggered, this, &MainWindow2::importPalette);
269  connect(ui->actionImport_Replace_Palette, &QAction::triggered, this, &MainWindow2::openPalette);
270 
271  //--- Edit Menu ---
272  connect(ui->actionUndo, &QAction::triggered, mEditor, &Editor::undo);
273  connect(ui->actionRedo, &QAction::triggered, mEditor, &Editor::redo);
274  connect(ui->actionCut, &QAction::triggered, mEditor, &Editor::cut);
275  connect(ui->actionCopy, &QAction::triggered, mEditor, &Editor::copy);
276  connect(ui->actionPaste, &QAction::triggered, mEditor, &Editor::paste);
277  connect(ui->actionClearFrame, &QAction::triggered, mEditor, &Editor::clearCurrentFrame);
278  connect(mEditor->select(), &SelectionManager::selectionChanged, this, &MainWindow2::selectionChanged);
279  connect(ui->actionFlip_X, &QAction::triggered, mCommands, &ActionCommands::flipSelectionX);
280  connect(ui->actionFlip_Y, &QAction::triggered, mCommands, &ActionCommands::flipSelectionY);
281  connect(ui->actionPegbarAlignment, &QAction::triggered, this, &MainWindow2::openPegAlignDialog);
282  connect(ui->actionSelect_All, &QAction::triggered, mCommands, &ActionCommands::selectAll);
283  connect(ui->actionDeselect_All, &QAction::triggered, mCommands, &ActionCommands::deselectAll);
284  connect(ui->actionPreference, &QAction::triggered, [=] { preferences(); });
285 
286  //--- Layer Menu ---
287  connect(ui->actionNew_Bitmap_Layer, &QAction::triggered, mCommands, &ActionCommands::addNewBitmapLayer);
288  connect(ui->actionNew_Vector_Layer, &QAction::triggered, mCommands, &ActionCommands::addNewVectorLayer);
289  connect(ui->actionNew_Sound_Layer, &QAction::triggered, mCommands, &ActionCommands::addNewSoundLayer);
290  connect(ui->actionNew_Camera_Layer, &QAction::triggered, mCommands, &ActionCommands::addNewCameraLayer);
291  connect(ui->actionDelete_Current_Layer, &QAction::triggered, mCommands, &ActionCommands::deleteCurrentLayer);
292  connect(ui->actionChangeLineColorCurrent_keyframe, &QAction::triggered, mCommands, &ActionCommands::changeKeyframeLineColor);
293  connect(ui->actionChangeLineColorAll_keyframes_on_layer, &QAction::triggered, mCommands, &ActionCommands::changeallKeyframeLineColor);
294 
295  QList<QAction*> visibilityActions = ui->menuLayer_Visibility->actions();
296  auto visibilityGroup = new QActionGroup(this);
297  visibilityGroup->setExclusive(true);
298  for (int i = 0; i < visibilityActions.size(); i++) {
299  QAction* action = visibilityActions[i];
300  visibilityGroup->addAction(action);
301  connect(action, &QAction::triggered, [=] { mCommands->setLayerVisibilityIndex(i); });
302  }
303  visibilityActions[mEditor->preference()->getInt(SETTING::LAYER_VISIBILITY)]->setChecked(true);
304  connect(mEditor->preference(), &PreferenceManager::optionChanged, [=](SETTING e) {
305  if (e == SETTING::LAYER_VISIBILITY) {
306  visibilityActions[mEditor->preference()->getInt(SETTING::LAYER_VISIBILITY)]->setChecked(true);
307  }
308  });
309 
310  // --- View Menu ---
311  connect(ui->actionZoom_In, &QAction::triggered, mCommands, &ActionCommands::ZoomIn);
312  connect(ui->actionZoom_Out, &QAction::triggered, mCommands, &ActionCommands::ZoomOut);
313  connect(ui->actionRotate_Clockwise, &QAction::triggered, mCommands, &ActionCommands::rotateClockwise);
314  connect(ui->actionRotate_Anticlockwise, &QAction::triggered, mCommands, &ActionCommands::rotateCounterClockwise);
315  connect(ui->actionReset_Rotation, &QAction::triggered, mEditor->view(), &ViewManager::resetRotation);
316  connect(ui->actionReset_View, &QAction::triggered, mEditor->view(), &ViewManager::resetView);
317  connect(ui->actionCenter_View, &QAction::triggered, mEditor->view(), &ViewManager::centerView);
318  connect(ui->actionZoom400, &QAction::triggered, mEditor->view(), &ViewManager::scale400);
319  connect(ui->actionZoom300, &QAction::triggered, mEditor->view(), &ViewManager::scale300);
320  connect(ui->actionZoom200, &QAction::triggered, mEditor->view(), &ViewManager::scale200);
321  connect(ui->actionZoom100, &QAction::triggered, mEditor->view(), &ViewManager::scale100);
322  connect(ui->actionZoom50, &QAction::triggered, mEditor->view(), &ViewManager::scale50);
323  connect(ui->actionZoom33, &QAction::triggered, mEditor->view(), &ViewManager::scale33);
324  connect(ui->actionZoom25, &QAction::triggered, mEditor->view(), &ViewManager::scale25);
325  connect(ui->actionHorizontal_Flip, &QAction::triggered, mEditor->view(), &ViewManager::flipHorizontal);
326  connect(ui->actionVertical_Flip, &QAction::triggered, mEditor->view(), &ViewManager::flipVertical);
327  connect(mEditor->view(), &ViewManager::viewFlipped, this, &MainWindow2::viewFlipped);
328 
329  PreferenceManager* prefs = mEditor->preference();
330  bindPreferenceSetting(ui->actionGrid, prefs, SETTING::GRID);
331  bindPreferenceSetting(ui->actionOnionPrev, prefs, SETTING::PREV_ONION);
332  bindPreferenceSetting(ui->actionOnionNext, prefs, SETTING::NEXT_ONION);
333 
334  //--- Animation Menu ---
335  PlaybackManager* pPlaybackManager = mEditor->playback();
336  connect(ui->actionPlay, &QAction::triggered, mCommands, &ActionCommands::PlayStop);
337 
338  connect(ui->actionLoop, &QAction::triggered, pPlaybackManager, &PlaybackManager::setLooping);
339  connect(ui->actionLoopControl, &QAction::triggered, pPlaybackManager, &PlaybackManager::enableRangedPlayback);
340  connect(pPlaybackManager, &PlaybackManager::loopStateChanged, ui->actionLoop, &QAction::setChecked);
341  connect(pPlaybackManager, &PlaybackManager::loopStateChanged, mTimeLine, &TimeLine::setLoop);
342  connect(pPlaybackManager, &PlaybackManager::rangedPlaybackStateChanged, ui->actionLoopControl, &QAction::setChecked);
343  connect(pPlaybackManager, &PlaybackManager::rangedPlaybackStateChanged, mTimeLine, &TimeLine::setRangeState);
344  connect(pPlaybackManager, &PlaybackManager::playStateChanged, mTimeLine, &TimeLine::setPlaying);
345  connect(pPlaybackManager, &PlaybackManager::playStateChanged, this, &MainWindow2::changePlayState);
346  connect(pPlaybackManager, &PlaybackManager::playStateChanged, mEditor, &Editor::updateCurrentFrame);
347  connect(ui->actionFlip_inbetween, &QAction::triggered, pPlaybackManager, &PlaybackManager::playFlipInBetween);
348  connect(ui->actionFlip_rolling, &QAction::triggered, pPlaybackManager, &PlaybackManager::playFlipRoll);
349 
350  connect(ui->actionAdd_Frame, &QAction::triggered, mCommands, &ActionCommands::addNewKey);
351  connect(ui->actionRemove_Frame, &QAction::triggered, mCommands, &ActionCommands::removeKey);
352  connect(ui->actionNext_Frame, &QAction::triggered, mCommands, &ActionCommands::GotoNextFrame);
353  connect(ui->actionPrevious_Frame, &QAction::triggered, mCommands, &ActionCommands::GotoPrevFrame);
354  connect(ui->actionNext_KeyFrame, &QAction::triggered, mCommands, &ActionCommands::GotoNextKeyFrame);
355  connect(ui->actionPrev_KeyFrame, &QAction::triggered, mCommands, &ActionCommands::GotoPrevKeyFrame);
356  connect(ui->actionDuplicate_Frame, &QAction::triggered, mCommands, &ActionCommands::duplicateKey);
357  connect(ui->actionMove_Frame_Forward, &QAction::triggered, mCommands, &ActionCommands::moveFrameForward);
358  connect(ui->actionMove_Frame_Backward, &QAction::triggered, mCommands, &ActionCommands::moveFrameBackward);
359 
360  //--- Tool Menu ---
361  connect(ui->actionMove, &QAction::triggered, mToolBox, &ToolBoxWidget::moveOn);
362  connect(ui->actionSelect, &QAction::triggered, mToolBox, &ToolBoxWidget::selectOn);
363  connect(ui->actionBrush, &QAction::triggered, mToolBox, &ToolBoxWidget::brushOn);
364  connect(ui->actionPolyline, &QAction::triggered, mToolBox, &ToolBoxWidget::polylineOn);
365  connect(ui->actionSmudge, &QAction::triggered, mToolBox, &ToolBoxWidget::smudgeOn);
366  connect(ui->actionPen, &QAction::triggered, mToolBox, &ToolBoxWidget::penOn);
367  connect(ui->actionHand, &QAction::triggered, mToolBox, &ToolBoxWidget::handOn);
368  connect(ui->actionPencil, &QAction::triggered, mToolBox, &ToolBoxWidget::pencilOn);
369  connect(ui->actionBucket, &QAction::triggered, mToolBox, &ToolBoxWidget::bucketOn);
370  connect(ui->actionEyedropper, &QAction::triggered, mToolBox, &ToolBoxWidget::eyedropperOn);
371  connect(ui->actionEraser, &QAction::triggered, mToolBox, &ToolBoxWidget::eraserOn);
372  connect(ui->actionResetToolsDefault, &QAction::triggered, mEditor->tools(), &ToolManager::resetAllTools);
373 
374  //--- Window Menu ---
375  QMenu* winMenu = ui->menuWindows;
376  const std::vector<QAction*> actions
377  {
378  mToolBox->toggleViewAction(),
379  mToolOptions->toggleViewAction(),
380  mColorBox->toggleViewAction(),
381  mColorPalette->toggleViewAction(),
382  mTimeLine->toggleViewAction(),
383  mDisplayOptionWidget->toggleViewAction(),
384  mColorInspector->toggleViewAction(),
385  mOnionSkinWidget->toggleViewAction()
386  };
387 
388  for (QAction* action : actions)
389  {
390  action->setMenuRole(QAction::NoRole);
391  winMenu->addAction(action);
392  }
393  connect(ui->actionResetWindows, &QAction::triggered, this, &MainWindow2::resetAndDockAllSubWidgets);
394  connect(ui->actionLockWindows, &QAction::toggled, this, &MainWindow2::lockWidgets);
395  bindPreferenceSetting(ui->actionLockWindows, prefs, SETTING::LAYOUT_LOCK);
396 
397  //--- Help Menu ---
398  connect(ui->actionHelp, &QAction::triggered, mCommands, &ActionCommands::help);
399  connect(ui->actionQuick_Guide, &QAction::triggered, mCommands, &ActionCommands::quickGuide);
400  connect(ui->actionWebsite, &QAction::triggered, mCommands, &ActionCommands::website);
401  connect(ui->actionForum, &QAction::triggered, mCommands, &ActionCommands::forum);
402  connect(ui->actionDiscord, &QAction::triggered, mCommands, &ActionCommands::discord);
403  connect(ui->actionCheck_for_Updates, &QAction::triggered, mCommands, &ActionCommands::checkForUpdates);
404  connect(ui->actionReport_Bug, &QAction::triggered, mCommands, &ActionCommands::reportbug);
405  connect(ui->actionOpen_Temporary_Directory, &QAction::triggered, mCommands, &ActionCommands::openTemporaryDirectory);
406  connect(ui->actionAbout, &QAction::triggered, mCommands, &ActionCommands::about);
407 
408  //--- Menus ---
409  mRecentFileMenu = new RecentFileMenu(tr("Open Recent"), this);
410  mRecentFileMenu->loadFromDisk();
411  ui->menuFile->insertMenu(ui->actionSave, mRecentFileMenu);
412 
413  connect(mRecentFileMenu, &RecentFileMenu::loadRecentFile, this, &MainWindow2::openFile);
414 
415  connect(ui->menuEdit, &QMenu::aboutToShow, this, &MainWindow2::undoActSetText);
416  connect(ui->menuEdit, &QMenu::aboutToHide, this, &MainWindow2::undoActSetEnabled);
417 }
418 
419 void MainWindow2::setOpacity(int opacity)
420 {
421  mEditor->preference()->set(SETTING::WINDOW_OPACITY, 100 - opacity);
422  setWindowOpacity(opacity / 100.0);
423 }
424 
425 void MainWindow2::updateSaveState()
426 {
427  setWindowModified(mEditor->currentBackup() != mBackupAtSave);
428 }
429 
430 void MainWindow2::clearRecentFilesList()
431 {
432  QStringList recentFilesList = mRecentFileMenu->getRecentFiles();
433  if (!recentFilesList.isEmpty())
434  {
435  mRecentFileMenu->clear();
436  mRecentFileMenu->saveToDisk();
437  QMessageBox::information(this, nullptr,
438  tr("\n\n You have successfully cleared the list"),
440  }
441  getPrefDialog()->updateRecentListBtn(!recentFilesList.isEmpty());
442 }
443 
444 void MainWindow2::openPegAlignDialog()
445 {
446  if (mPegAlign != nullptr)
447  {
448  QMessageBox::information(this, nullptr,
449  tr("Dialog is already open!"),
451  return;
452  }
453 
454  mPegAlign = new PegBarAlignmentDialog(mEditor, this);
455  mPegAlign->setAttribute(Qt::WA_DeleteOnClose);
456  mPegAlign->updatePegRegLayers();
457  mPegAlign->setRefLayer(mEditor->layers()->currentLayer()->name());
458  mPegAlign->setRefKey(mEditor->currentFrame());
459 
460  Qt::WindowFlags flags = mPegAlign->windowFlags();
461  flags |= Qt::WindowStaysOnTopHint;
462  flags &= (~Qt::WindowContextHelpButtonHint);
463  mPegAlign->setWindowFlags(flags);
464  mPegAlign->show();
466  {
467  mPegAlign = nullptr;
468  });
469 }
470 
471 void MainWindow2::currentLayerChanged()
472 {
473  bool isBitmap = (mEditor->layers()->currentLayer()->type() == Layer::BITMAP);
474  ui->menuChange_line_color->setEnabled(isBitmap);
475 }
476 
477 void MainWindow2::selectionChanged()
478 {
479  bool somethingSelected = mEditor->select()->somethingSelected();
480  ui->menuSelection->setEnabled(somethingSelected);
481 }
482 
483 void MainWindow2::viewFlipped()
484 {
485  ui->actionHorizontal_Flip->setChecked(mEditor->view()->isFlipHorizontal());
486  ui->actionVertical_Flip->setChecked(mEditor->view()->isFlipVertical());
487 }
488 
489 void MainWindow2::closeEvent(QCloseEvent* event)
490 {
491  if (m2ndCloseEvent)
492  {
493  // https://bugreports.qt.io/browse/QTBUG-43344
494  event->accept();
495  return;
496  }
497 
498  if (!maybeSave())
499  {
500  event->ignore();
501  return;
502  }
503  writeSettings();
504  event->accept();
505  m2ndCloseEvent = true;
506 }
507 
508 void MainWindow2::showEvent(QShowEvent*)
509 {
510  static bool firstShowEvent = true;
511  if (!firstShowEvent)
512  {
513  return;
514  }
515  firstShowEvent = false;
516  if (tryRecoverUnsavedProject() || loadMostRecent() || tryLoadPreset()) { return; }
517  newObject();
518 }
519 
520 void MainWindow2::tabletEvent(QTabletEvent* event)
521 {
522  event->ignore();
523 }
524 
525 void MainWindow2::newDocument()
526 {
527  if (maybeSave() && !tryLoadPreset())
528  {
529  newObject();
530  }
531 }
532 
533 void MainWindow2::openDocument()
534 {
535  if (!maybeSave())
536  {
537  return;
538  }
539  QString fileName = FileDialog::getOpenFileName(this, FileType::ANIMATION);
540  if (!fileName.isEmpty())
541  {
542  openObject(fileName);
543  }
544 }
545 
546 bool MainWindow2::saveAsNewDocument()
547 {
548  QString fileName = FileDialog::getSaveFileName(this, FileType::ANIMATION);
549  if (fileName.isEmpty())
550  {
551  return false;
552  }
553  return saveObject(fileName);
554 }
555 
556 void MainWindow2::openFile(const QString& filename)
557 {
558  if (maybeSave())
559  {
560  openObject(filename);
561  }
562 }
563 
564 bool MainWindow2::openObject(const QString& strFilePath)
565 {
566  // Check for potential issues with the file
567  QFileInfo fileInfo(strFilePath);
568  if (fileInfo.isDir())
569  {
570  ErrorDialog errorDialog(tr("Could not open file"),
571  tr("The file you have selected is a directory, so we are unable to open it. "
572  "If you are are trying to open a project that uses the old structure, "
573  "please open the file ending with .pcl, not the data folder."),
574  QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fileInfo.absoluteFilePath()));
575  errorDialog.exec();
576  return false;
577  }
578  if (!fileInfo.exists())
579  {
580  ErrorDialog errorDialog(tr("Could not open file"),
581  tr("The file you have selected does not exist, so we are unable to open it. "
582  "Please make sure that you've entered the correct path and that the file is accessible and try again."),
583  QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fileInfo.absoluteFilePath()));
584  errorDialog.exec();
585  return false;
586  }
587  if (!fileInfo.isReadable())
588  {
589  ErrorDialog errorDialog(tr("Could not open file"),
590  tr("This program does not have permission to read the file you have selected. "
591  "Please check that you have read permissions for this file and try again."),
592  QString("Raw file path: %1\nResolved file path: %2\nPermissions: 0x%3") \
593  .arg(strFilePath, fileInfo.absoluteFilePath(), QString::number(fileInfo.permissions(), 16)));
594  errorDialog.exec();
595  return false;
596  }
597  if (!fileInfo.isWritable())
598  {
599  QMessageBox::warning(this, tr("Warning"),
600  tr("This program does not currently have permission to write to the file you have selected. "
601  "Please make sure you have write permission for this file before attempting to save it. "
602  "Alternatively, you can use the Save As... menu option to save to a writable location."),
604  }
605 
606  QProgressDialog progress(tr("Opening document..."), tr("Abort"), 0, 100, this);
607 
608  // Don't show progress bar if running without a GUI (aka. when rendering from command line)
609  if (isVisible())
610  {
611  hideQuestionMark(progress);
612  progress.setWindowModality(Qt::WindowModal);
613  progress.show();
614  }
615 
616 
617  FileManager fm(this);
618  connect(&fm, &FileManager::progressChanged, [&progress](int p)
619  {
620  progress.setValue(p);
622  });
623  connect(&fm, &FileManager::progressRangeChanged, [&progress](int max)
624  {
625  progress.setRange(0, max + 3);
626  });
627 
628  QString fullPath = fileInfo.absoluteFilePath();
629 
630  Object* object = fm.load(fullPath);
631 
632  if (!fm.error().ok())
633  {
634  Status error = fm.error();
635  DebugDetails dd;
636  dd << QString("Raw file path: ").append(strFilePath)
637  << QString("Resolved file path: ").append(fileInfo.absoluteFilePath());
638  dd.collect(error.details());
639  ErrorDialog errorDialog(error.title(), error.description(), dd.str());
640  errorDialog.exec();
641  emptyDocumentWhenErrorOccurred();
642  return false;
643  }
644 
645  if (object == nullptr)
646  {
647  ErrorDialog errorDialog(tr("Could not open file"),
648  tr("An unknown error occurred while trying to load the file and we are not able to load your file."),
649  QString("Raw file path: %1\nResolved file path: %2").arg(strFilePath, fullPath));
650  errorDialog.exec();
651  emptyDocumentWhenErrorOccurred();
652  return false;
653  }
654 
655  mEditor->setObject(object);
656 
657  QSettings settings(PENCIL2D, PENCIL2D);
658  settings.setValue(LAST_PCLX_PATH, object->filePath());
659 
660  // Add to recent file list, but only if we are
661  if (!object->filePath().isEmpty())
662  {
663  mRecentFileMenu->addRecentFile(object->filePath());
664  mRecentFileMenu->saveToDisk();
665  }
666 
667  setWindowTitle(object->filePath().prepend("[*]"));
668  setWindowModified(false);
669 
670  progress.setValue(progress.value() + 1);
671 
672  mEditor->layers()->notifyAnimationLengthChanged();
673  mEditor->setFps(mEditor->playback()->fps());
674 
675  progress.setValue(progress.maximum());
676 
677  updateSaveState();
678  return true;
679 }
680 
681 bool MainWindow2::saveObject(QString strSavedFileName)
682 {
683  QProgressDialog progress(tr("Saving document..."), tr("Abort"), 0, 100, this);
684  hideQuestionMark(progress);
685  progress.setWindowModality(Qt::WindowModal);
686  progress.show();
687 
688  mEditor->prepareSave();
689 
690  FileManager fm(this);
691 
692  connect(&fm, &FileManager::progressChanged, [&progress](int p)
693  {
694  progress.setValue(p);
696  });
697  connect(&fm, &FileManager::progressRangeChanged, [&progress](int max)
698  {
699  progress.setRange(0, max + 3);
700  });
701 
702  Status st = fm.save(mEditor->object(), strSavedFileName);
703 
704 
705  if (!st.ok())
706  {
707 #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
709 #else
711 #endif
712  errorLogFolder.mkpath("./logs");
713  errorLogFolder.cd("logs");
714 
716  dt.setTimeSpec(Qt::UTC);
717  QFile eLog(errorLogFolder.absoluteFilePath(QString("error-%1.txt").arg(dt.toString(Qt::ISODate))));
718  if (eLog.open(QIODevice::WriteOnly | QIODevice::Text))
719  {
720  QTextStream out(&eLog);
721  out << st.details().str();
722  }
723  eLog.close();
724 
725  ErrorDialog errorDialog(st.title(),
726  st.description().append(tr("<br><br>An error has occurred and your file may not have saved successfully."
727  "If you believe that this error is an issue with Pencil2D, please create a new issue at:"
728  "<br><a href='https://github.com/pencil2d/pencil/issues'>https://github.com/pencil2d/pencil/issues</a><br>"
729  "Please be sure to include the following details in your issue:")), st.details().html());
730  errorDialog.exec();
731  return false;
732  }
733 
734  mEditor->object()->setFilePath(strSavedFileName);
735  mEditor->object()->setModified(false);
736 
737  mEditor->clearTemporary();
738 
739  QSettings settings(PENCIL2D, PENCIL2D);
740  settings.setValue(LAST_PCLX_PATH, strSavedFileName);
741 
742  mRecentFileMenu->addRecentFile(strSavedFileName);
743  mRecentFileMenu->saveToDisk();
744 
745  mTimeLine->updateContent();
746 
747  setWindowTitle(strSavedFileName.prepend("[*]"));
748  mBackupAtSave = mEditor->currentBackup();
749  updateSaveState();
750 
751  progress.setValue(progress.maximum());
752 
753  mEditor->resetAutoSaveCounter();
754 
755  return true;
756 }
757 
758 bool MainWindow2::saveDocument()
759 {
760  if (!mEditor->object()->filePath().isEmpty())
761  return saveObject(mEditor->object()->filePath());
762  else
763  return saveAsNewDocument();
764 }
765 
766 bool MainWindow2::maybeSave()
767 {
768  if (mEditor->currentBackup() == mBackupAtSave)
769  {
770  return true;
771  }
772 
773  int ret = QMessageBox::warning(this, tr("Warning"),
774  tr("This animation has been modified.\n Do you want to save your changes?"),
776  if (ret == QMessageBox::Save)
777  return saveDocument();
778  else
779  return ret == QMessageBox::Discard;
780 }
781 
782 bool MainWindow2::autoSave()
783 {
784  if (!mEditor->object()->filePath().isEmpty())
785  {
786  return saveDocument();
787  }
788 
789  if (mEditor->autoSaveNeverAskAgain())
790  return false;
791 
792  if(mSuppressAutoSaveDialog)
793  return false;
794 
795  QMessageBox msgBox(this);
796  msgBox.setIcon(QMessageBox::Question);
797  msgBox.setWindowTitle(tr("AutoSave Reminder"));
798  msgBox.setText(tr("The animation is not saved yet.\n Do you want to save now?"));
799  msgBox.addButton(tr("Never ask again", "AutoSave reminder button"), QMessageBox::RejectRole);
800  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
801  msgBox.setDefaultButton(QMessageBox::Yes);
802 
803  int ret = msgBox.exec();
804  if (ret == QMessageBox::Yes)
805  {
806  return saveDocument();
807  }
808  if (ret != QMessageBox::No) // Never ask again
809  {
810  mEditor->dontAskAutoSave(true);
811  }
812 
813  return false;
814 }
815 
816 void MainWindow2::emptyDocumentWhenErrorOccurred()
817 {
818  newObject();
819 
820  setWindowTitle(PENCIL_WINDOW_TITLE);
821  updateSaveState();
822 }
823 
824 void MainWindow2::importImage()
825 {
826  QString strFilePath = FileDialog::getOpenFileName(this, FileType::IMAGE);
827 
828  if (strFilePath.isEmpty()) { return; }
829  if (!QFile::exists(strFilePath)) { return; }
830 
831  ImportPositionDialog* positionDialog = new ImportPositionDialog(this);
832  OnScopeExit(delete positionDialog)
833 
834  positionDialog->setCore(mEditor);
835  positionDialog->exec();
836 
837  if (positionDialog->result() != QDialog::Accepted)
838  {
839  return;
840  }
841 
842  bool ok = mEditor->importImage(strFilePath);
843  if (!ok)
844  {
846  tr("Warning"),
847  tr("Unable to import image.<br><b>TIP:</b> Use Bitmap layer to import bitmaps."),
850  return;
851  }
852 
853  ui->scribbleArea->updateCurrentFrame();
854  mTimeLine->updateContent();
855 }
856 
857 void MainWindow2::importImageSequence()
858 {
859  mSuppressAutoSaveDialog = true;
860 
861  ImportImageSeqDialog* imageSeqDialog = new ImportImageSeqDialog(this);
862  OnScopeExit(delete imageSeqDialog)
863  imageSeqDialog->setCore(mEditor);
864 
865  connect(imageSeqDialog, &ImportImageSeqDialog::notifyAnimationLengthChanged, mEditor, &Editor::notifyAnimationLengthChanged);
866 
867  imageSeqDialog->exec();
868  if (imageSeqDialog->result() == QDialog::Rejected)
869  {
870  return;
871  }
872 
873  ImportPositionDialog* positionDialog = new ImportPositionDialog(this);
874  OnScopeExit(delete positionDialog)
875 
876  positionDialog->setCore(mEditor);
877  positionDialog->exec();
878  if (positionDialog->result() != QDialog::Accepted)
879  {
880  return;
881  }
882 
883  imageSeqDialog->importArbitrarySequence();
884 
885  mSuppressAutoSaveDialog = false;
886 }
887 
888 void MainWindow2::importPredefinedImageSet()
889 {
890  ImportImageSeqDialog* imageSeqDialog = new ImportImageSeqDialog(this, ImportExportDialog::Import, FileType::IMAGE, ImportCriteria::PredefinedSet);
891  OnScopeExit(delete imageSeqDialog)
892  imageSeqDialog->setCore(mEditor);
893 
894  connect(imageSeqDialog, &ImportImageSeqDialog::notifyAnimationLengthChanged, mEditor, &Editor::notifyAnimationLengthChanged);
895 
896  mSuppressAutoSaveDialog = true;
897  imageSeqDialog->exec();
898  if (imageSeqDialog->result() == QDialog::Rejected)
899  {
900  return;
901  }
902 
903  ImportPositionDialog* positionDialog = new ImportPositionDialog(this);
904  OnScopeExit(delete positionDialog)
905 
906  positionDialog->setCore(mEditor);
907  positionDialog->exec();
908  if (positionDialog->result() != QDialog::Accepted)
909  {
910  return;
911  }
912 
913  imageSeqDialog->importPredefinedSet();
914  mSuppressAutoSaveDialog = false;
915 }
916 
917 void MainWindow2::importLayers()
918 {
919  ImportLayersDialog* importLayers = new ImportLayersDialog(this);
920  importLayers->setCore(mEditor);
921  importLayers->setAttribute(Qt::WA_DeleteOnClose);
922  importLayers->open();
923 }
924 
925 void MainWindow2::importGIF()
926 {
927  auto gifDialog = new ImportImageSeqDialog(this, ImportExportDialog::Import, FileType::GIF);
928  gifDialog->exec();
929  if (gifDialog->result() == QDialog::Rejected)
930  {
931  return;
932  }
933 
934  // Flag this so we don't prompt the user about auto-save in the middle of the import.
935  mSuppressAutoSaveDialog = true;
936 
937  ImportPositionDialog* positionDialog = new ImportPositionDialog(this);
938  OnScopeExit(delete positionDialog)
939 
940  positionDialog->setCore(mEditor);
941  positionDialog->exec();
942  if (positionDialog->result() != QDialog::Accepted)
943  {
944  return;
945  }
946 
947  int space = gifDialog->getSpace();
948 
949  // Show a progress dialog, as this could take a while if the gif is huge
950  QProgressDialog progress(tr("Importing Animated GIF..."), tr("Abort"), 0, 100, this);
951  hideQuestionMark(progress);
952  progress.setWindowModality(Qt::WindowModal);
953  progress.show();
954 
955  QString strImgFileLower = gifDialog->getFilePath();
956  bool importOK = strImgFileLower.toLower().endsWith(".gif");
957 
958  if (importOK)
959  {
960  bool ok = mEditor->importGIF(strImgFileLower, space);
961  if (!ok)
962  importOK = false;
963 
964  progress.setValue(50);
965  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // Required to make progress bar update
966  }
967 
968  if (!importOK)
969  {
971  tr("Warning"),
972  tr("was unable to import %1").arg(strImgFileLower),
975  }
976 
977  progress.setValue(100);
978  progress.close();
979 
980  mSuppressAutoSaveDialog = false;
981 }
982 
983 void MainWindow2::lockWidgets(bool shouldLock)
984 {
986 
987  for (QDockWidget* d : mDockWidgets)
988  {
989  d->setFeatures(feat);
990 
991  // https://doc.qt.io/qt-5/qdockwidget.html#setTitleBarWidget
992  // A empty QWidget looks like the tittle bar is hidden.
993  // nullptr means removing the custom title bar and restoring the default one
994  QWidget* customTitleBarWidget = shouldLock ? (new QWidget) : nullptr;
995  d->setTitleBarWidget(customTitleBarWidget);
996  }
997 }
998 
999 void MainWindow2::preferences()
1000 {
1001  if (mPrefDialog)
1002  {
1003  mPrefDialog->activateWindow();
1004  mPrefDialog->raise();
1005  return;
1006  }
1007  mPrefDialog = new PreferencesDialog(this);
1008  mPrefDialog->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
1009  mPrefDialog->setAttribute(Qt::WA_DeleteOnClose);
1010  mPrefDialog->init(mEditor->preference());
1011 
1012  connect(mPrefDialog, &PreferencesDialog::windowOpacityChange, this, &MainWindow2::setOpacity);
1013  connect(mPrefDialog, &PreferencesDialog::soundScrubChanged, mEditor->playback(), &PlaybackManager::setSoundScrubActive);
1014  connect(mPrefDialog, &PreferencesDialog::soundScrubMsecChanged, mEditor->playback(), &PlaybackManager::setSoundScrubMsec);
1015  connect(mPrefDialog, &PreferencesDialog::finished, [&]
1016  {
1017  clearKeyboardShortcuts();
1018  setupKeyboardShortcuts();
1019  ui->scribbleArea->updateCanvasCursor();
1020  mPrefDialog = nullptr;
1021  });
1022 
1023  mPrefDialog->show();
1024 }
1025 
1026 void MainWindow2::resetAndDockAllSubWidgets()
1027 {
1028  QSettings settings(PENCIL2D, PENCIL2D);
1029  settings.remove(SETTING_WINDOW_GEOMETRY);
1030  settings.remove(SETTING_WINDOW_STATE);
1031 
1032  for (BaseDockWidget* dock : mDockWidgets)
1033  {
1034  dock->setFloating(false);
1035  dock->raise();
1036  dock->show();
1037  }
1038 
1039  addDockWidget(Qt::RightDockWidgetArea, mColorBox);
1040  addDockWidget(Qt::RightDockWidgetArea, mColorInspector);
1041  addDockWidget(Qt::RightDockWidgetArea, mColorPalette);
1042  addDockWidget(Qt::LeftDockWidgetArea, mToolBox);
1043  addDockWidget(Qt::LeftDockWidgetArea, mToolOptions);
1044  addDockWidget(Qt::LeftDockWidgetArea, mDisplayOptionWidget);
1045  addDockWidget(Qt::LeftDockWidgetArea, mOnionSkinWidget);
1046  addDockWidget(Qt::BottomDockWidgetArea, mTimeLine);
1047 }
1048 
1049 void MainWindow2::newObject() const
1050 {
1051  auto object = new Object();
1052  object->init();
1053  object->createDefaultLayers();
1054  mEditor->setObject(object);
1055 }
1056 
1057 bool MainWindow2::newObjectFromPresets(int presetIndex)
1058 {
1059  QString presetFilePath = PresetDialog::getPresetPath(presetIndex);
1060 
1061  if (presetFilePath.isEmpty())
1062  {
1063  return false;
1064  }
1065 
1066  FileManager fm(this);
1067  Object* object = fm.load(presetFilePath);
1068 
1069  if (!fm.error().ok() || object == nullptr)
1070  {
1071  return false;
1072  }
1073 
1074  mEditor->setObject(object);
1075  object->setFilePath(QString());
1076 
1077  setWindowTitle(PENCIL_WINDOW_TITLE);
1078  updateSaveState();
1079 
1080  return true;
1081 }
1082 
1083 bool MainWindow2::loadMostRecent()
1084 {
1085  if(!mEditor->preference()->isOn(SETTING::LOAD_MOST_RECENT))
1086  {
1087  return false;
1088  }
1089 
1090  QSettings settings(PENCIL2D, PENCIL2D);
1091  QString myPath = settings.value(LAST_PCLX_PATH, QVariant("")).toString();
1092  if (myPath.isEmpty() || !QFile::exists(myPath))
1093  {
1094  return false;
1095  }
1096  return openObject(myPath);
1097 }
1098 
1099 bool MainWindow2::tryLoadPreset()
1100 {
1101  if (!mEditor->preference()->isOn(SETTING::ASK_FOR_PRESET))
1102  {
1103  int defaultPreset = mEditor->preference()->getInt(SETTING::DEFAULT_PRESET);
1104  return newObjectFromPresets(defaultPreset);
1105  }
1106 
1107  PresetDialog* presetDialog = new PresetDialog(mEditor->preference(), this);
1108  presetDialog->setAttribute(Qt::WA_DeleteOnClose);
1109  connect(presetDialog, &PresetDialog::finished, [=](int result)
1110  {
1111  if (result != QDialog::Accepted)
1112  {
1113  return;
1114  }
1115 
1116  int presetIndex = presetDialog->getPresetIndex();
1117  if (presetDialog->shouldAlwaysUse())
1118  {
1119  mEditor->preference()->set(SETTING::ASK_FOR_PRESET, false);
1120  mEditor->preference()->set(SETTING::DEFAULT_PRESET, presetIndex);
1121  }
1122  if (!newObjectFromPresets(presetIndex))
1123  {
1124  newObject();
1125  }
1126  });
1127  presetDialog->open();
1128  return true;
1129 }
1130 
1131 void MainWindow2::readSettings()
1132 {
1133  QSettings settings(PENCIL2D, PENCIL2D);
1134 
1135  QVariant winGeometry = settings.value(SETTING_WINDOW_GEOMETRY);
1136  restoreGeometry(winGeometry.toByteArray());
1137 
1138  QVariant winState = settings.value(SETTING_WINDOW_STATE);
1139  restoreState(winState.toByteArray());
1140 
1141  int opacity = mEditor->preference()->getInt(SETTING::WINDOW_OPACITY);
1142  setOpacity(100 - opacity);
1143 
1144  bool isWindowsLocked = mEditor->preference()->isOn(SETTING::LAYOUT_LOCK);
1145  lockWidgets(isWindowsLocked);
1146 }
1147 
1148 void MainWindow2::writeSettings()
1149 {
1150  QSettings settings(PENCIL2D, PENCIL2D);
1151  settings.setValue(SETTING_WINDOW_GEOMETRY, saveGeometry());
1152  settings.setValue(SETTING_WINDOW_STATE, saveState());
1153 }
1154 
1155 void MainWindow2::setupKeyboardShortcuts()
1156 {
1157  checkExistingShortcuts();
1158 
1159  auto cmdKeySeq = [](QString strCommandName) -> QKeySequence
1160  {
1161  strCommandName = QString("shortcuts/") + strCommandName;
1162  QKeySequence keySequence(pencilSettings().value(strCommandName).toString());
1163  return keySequence;
1164  };
1165 
1166  ui->actionNew->setShortcut(cmdKeySeq(CMD_NEW_FILE));
1167  ui->actionOpen->setShortcut(cmdKeySeq(CMD_OPEN_FILE));
1168  ui->actionSave->setShortcut(cmdKeySeq(CMD_SAVE_FILE));
1169  ui->actionSave_as->setShortcut(cmdKeySeq(CMD_SAVE_AS));
1170 
1171  ui->actionImport_Image->setShortcut(cmdKeySeq(CMD_IMPORT_IMAGE));
1172  ui->actionImport_ImageSeq->setShortcut(cmdKeySeq(CMD_IMPORT_IMAGE_SEQ));
1173  ui->actionImport_MovieVideo->setShortcut(cmdKeySeq(CMD_IMPORT_MOVIE_VIDEO));
1174  ui->actionImport_MovieAudio->setShortcut(cmdKeySeq(CMD_IMPORT_MOVIE_AUDIO));
1175  ui->actionImport_Append_Palette->setShortcut(cmdKeySeq(CMD_IMPORT_PALETTE));
1176  ui->actionImport_Sound->setShortcut(cmdKeySeq(CMD_IMPORT_SOUND));
1177 
1178  ui->actionExport_Image->setShortcut(cmdKeySeq(CMD_EXPORT_IMAGE));
1179  ui->actionExport_ImageSeq->setShortcut(cmdKeySeq(CMD_EXPORT_IMAGE_SEQ));
1180  ui->actionExport_Movie->setShortcut(cmdKeySeq(CMD_EXPORT_MOVIE));
1181  ui->actionExport_Palette->setShortcut(cmdKeySeq(CMD_EXPORT_PALETTE));
1182 
1183  // edit menu
1184  ui->actionUndo->setShortcut(cmdKeySeq(CMD_UNDO));
1185  ui->actionRedo->setShortcut(cmdKeySeq(CMD_REDO));
1186  ui->actionCut->setShortcut(cmdKeySeq(CMD_CUT));
1187  ui->actionCopy->setShortcut(cmdKeySeq(CMD_COPY));
1188  ui->actionPaste->setShortcut(cmdKeySeq(CMD_PASTE));
1189  ui->actionClearFrame->setShortcut(cmdKeySeq(CMD_CLEAR_FRAME));
1190  ui->actionSelect_All->setShortcut(cmdKeySeq(CMD_SELECT_ALL));
1191  ui->actionDeselect_All->setShortcut(cmdKeySeq(CMD_DESELECT_ALL));
1192  ui->actionPreference->setShortcut(cmdKeySeq(CMD_PREFERENCE));
1193 
1194  // View menu
1195  ui->actionResetWindows->setShortcut(cmdKeySeq(CMD_RESET_WINDOWS));
1196  ui->actionReset_View->setShortcut(cmdKeySeq(CMD_RESET_ZOOM_ROTATE));
1197  ui->actionCenter_View->setShortcut(cmdKeySeq(CMD_CENTER_VIEW));
1198  ui->actionZoom_In->setShortcut(cmdKeySeq(CMD_ZOOM_IN));
1199  ui->actionZoom_Out->setShortcut(cmdKeySeq(CMD_ZOOM_OUT));
1200  ui->actionZoom400->setShortcut(cmdKeySeq(CMD_ZOOM_400));
1201  ui->actionZoom300->setShortcut(cmdKeySeq(CMD_ZOOM_300));
1202  ui->actionZoom200->setShortcut(cmdKeySeq(CMD_ZOOM_200));
1203  ui->actionZoom100->setShortcut(cmdKeySeq(CMD_ZOOM_100));
1204  ui->actionZoom50->setShortcut(cmdKeySeq(CMD_ZOOM_50));
1205  ui->actionZoom33->setShortcut(cmdKeySeq(CMD_ZOOM_33));
1206  ui->actionZoom25->setShortcut(cmdKeySeq(CMD_ZOOM_25));
1207  ui->actionRotate_Clockwise->setShortcut(cmdKeySeq(CMD_ROTATE_CLOCK));
1208  ui->actionRotate_Anticlockwise->setShortcut(cmdKeySeq(CMD_ROTATE_ANTI_CLOCK));
1209  ui->actionReset_Rotation->setShortcut(cmdKeySeq(CMD_RESET_ROTATION));
1210  ui->actionHorizontal_Flip->setShortcut(cmdKeySeq(CMD_FLIP_HORIZONTAL));
1211  ui->actionVertical_Flip->setShortcut(cmdKeySeq(CMD_FLIP_VERTICAL));
1212  ui->actionPreview->setShortcut(cmdKeySeq(CMD_PREVIEW));
1213  ui->actionGrid->setShortcut(cmdKeySeq(CMD_GRID));
1214  ui->actionOnionPrev->setShortcut(cmdKeySeq(CMD_ONIONSKIN_PREV));
1215  ui->actionOnionNext->setShortcut(cmdKeySeq(CMD_ONIONSKIN_NEXT));
1216 
1217  ui->actionPlay->setShortcut(cmdKeySeq(CMD_PLAY));
1218  ui->actionLoop->setShortcut(cmdKeySeq(CMD_LOOP));
1219  ui->actionPrevious_Frame->setShortcut(cmdKeySeq(CMD_GOTO_PREV_FRAME));
1220  ui->actionNext_Frame->setShortcut(cmdKeySeq(CMD_GOTO_NEXT_FRAME));
1221  ui->actionPrev_KeyFrame->setShortcut(cmdKeySeq(CMD_GOTO_PREV_KEY_FRAME));
1222  ui->actionNext_KeyFrame->setShortcut(cmdKeySeq(CMD_GOTO_NEXT_KEY_FRAME));
1223  ui->actionAdd_Frame->setShortcut(cmdKeySeq(CMD_ADD_FRAME));
1224  ui->actionDuplicate_Frame->setShortcut(cmdKeySeq(CMD_DUPLICATE_FRAME));
1225  ui->actionRemove_Frame->setShortcut(cmdKeySeq(CMD_REMOVE_FRAME));
1226  ui->actionMove_Frame_Backward->setShortcut(cmdKeySeq(CMD_MOVE_FRAME_BACKWARD));
1227  ui->actionMove_Frame_Forward->setShortcut(cmdKeySeq(CMD_MOVE_FRAME_FORWARD));
1228  ui->actionFlip_inbetween->setShortcut(cmdKeySeq(CMD_FLIP_INBETWEEN));
1229  ui->actionFlip_rolling->setShortcut(cmdKeySeq(CMD_FLIP_ROLLING));
1230 
1231  ShortcutFilter* shortcutFilter = new ShortcutFilter(ui->scribbleArea, this);
1232  ui->actionMove->setShortcut(cmdKeySeq(CMD_TOOL_MOVE));
1233  ui->actionSelect->setShortcut(cmdKeySeq(CMD_TOOL_SELECT));
1234  ui->actionBrush->setShortcut(cmdKeySeq(CMD_TOOL_BRUSH));
1235  ui->actionPolyline->setShortcut(cmdKeySeq(CMD_TOOL_POLYLINE));
1236  ui->actionSmudge->setShortcut(cmdKeySeq(CMD_TOOL_SMUDGE));
1237  ui->actionPen->setShortcut(cmdKeySeq(CMD_TOOL_PEN));
1238  ui->actionHand->setShortcut(cmdKeySeq(CMD_TOOL_HAND));
1239  ui->actionPencil->setShortcut(cmdKeySeq(CMD_TOOL_PENCIL));
1240  ui->actionBucket->setShortcut(cmdKeySeq(CMD_TOOL_BUCKET));
1241  ui->actionEyedropper->setShortcut(cmdKeySeq(CMD_TOOL_EYEDROPPER));
1242  ui->actionEraser->setShortcut(cmdKeySeq(CMD_TOOL_ERASER));
1243 
1244  ui->actionMove->installEventFilter(shortcutFilter);
1245  ui->actionMove->installEventFilter(shortcutFilter);
1246  ui->actionSelect->installEventFilter(shortcutFilter);
1247  ui->actionBrush->installEventFilter(shortcutFilter);
1248  ui->actionPolyline->installEventFilter(shortcutFilter);
1249  ui->actionSmudge->installEventFilter(shortcutFilter);
1250  ui->actionPen->installEventFilter(shortcutFilter);
1251  ui->actionHand->installEventFilter(shortcutFilter);
1252  ui->actionPencil->installEventFilter(shortcutFilter);
1253  ui->actionBucket->installEventFilter(shortcutFilter);
1254  ui->actionEyedropper->installEventFilter(shortcutFilter);
1255  ui->actionEraser->installEventFilter(shortcutFilter);
1256 
1257  ui->actionNew_Bitmap_Layer->setShortcut(cmdKeySeq(CMD_NEW_BITMAP_LAYER));
1258  ui->actionNew_Vector_Layer->setShortcut(cmdKeySeq(CMD_NEW_VECTOR_LAYER));
1259  ui->actionNew_Camera_Layer->setShortcut(cmdKeySeq(CMD_NEW_CAMERA_LAYER));
1260  ui->actionNew_Sound_Layer->setShortcut(cmdKeySeq(CMD_NEW_SOUND_LAYER));
1261  ui->actionDelete_Current_Layer->setShortcut(cmdKeySeq(CMD_DELETE_CUR_LAYER));
1262 
1263  ui->actionVisibilityCurrentLayerOnly->setShortcut(cmdKeySeq(CMD_CURRENT_LAYER_VISIBILITY));
1264  ui->actionVisibilityRelative->setShortcut(cmdKeySeq(CMD_RELATIVE_LAYER_VISIBILITY));
1265  ui->actionVisibilityAll->setShortcut(cmdKeySeq(CMD_ALL_LAYER_VISIBILITY));
1266 
1267  mToolBox->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TOOLBOX));
1268  mToolOptions->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TOOL_OPTIONS));
1269  mColorBox->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_WHEEL));
1270  mColorPalette->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_LIBRARY));
1271  mTimeLine->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TIMELINE));
1272  mDisplayOptionWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_DISPLAY_OPTIONS));
1273  mColorInspector->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_INSPECTOR));
1274  mOnionSkinWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_ONION_SKIN));
1275 
1276  ui->actionHelp->setShortcut(cmdKeySeq(CMD_HELP));
1277  ui->actionExit->setShortcut(cmdKeySeq(CMD_EXIT));
1278 }
1279 
1280 void MainWindow2::clearKeyboardShortcuts()
1281 {
1282  QList<QAction*> actionList = findChildren<QAction*>();
1283  for (QAction* action : actionList)
1284  {
1285  action->setShortcut(QKeySequence(0));
1286  }
1287 }
1288 
1289 void MainWindow2::undoActSetText()
1290 {
1291  if (mEditor->mBackupIndex < 0)
1292  {
1293  ui->actionUndo->setText(tr("Undo", "Menu item text"));
1294  ui->actionUndo->setEnabled(false);
1295  }
1296  else
1297  {
1298  ui->actionUndo->setText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text"))
1299  .arg(QString::number(mEditor->mBackupIndex + 1))
1300  .arg(mEditor->mBackupList.at(mEditor->mBackupIndex)->undoText));
1301  ui->actionUndo->setEnabled(true);
1302  }
1303 
1304  if (mEditor->mBackupIndex + 2 < mEditor->mBackupList.size())
1305  {
1306  ui->actionRedo->setText(QString("%1 %2 %3").arg(tr("Redo", "Menu item text"))
1307  .arg(QString::number(mEditor->mBackupIndex + 2))
1308  .arg(mEditor->mBackupList.at(mEditor->mBackupIndex + 1)->undoText));
1309  ui->actionRedo->setEnabled(true);
1310  }
1311  else
1312  {
1313  ui->actionRedo->setText(tr("Redo", "Menu item text"));
1314  ui->actionRedo->setEnabled(false);
1315  }
1316 }
1317 
1318 void MainWindow2::undoActSetEnabled()
1319 {
1320  ui->actionUndo->setEnabled(true);
1321  ui->actionRedo->setEnabled(true);
1322 }
1323 
1324 void MainWindow2::exportPalette()
1325 {
1326  QString filePath = FileDialog::getSaveFileName(this, FileType::PALETTE);
1327  if (!filePath.isEmpty())
1328  {
1329  mEditor->object()->exportPalette(filePath);
1330  }
1331 }
1332 
1333 void MainWindow2::importPalette()
1334 {
1335  QString filePath = FileDialog::getOpenFileName(this, FileType::PALETTE);
1336  if (!filePath.isEmpty())
1337  {
1338  mEditor->object()->importPalette(filePath);
1339  mColorPalette->refreshColorList();
1340  mColorPalette->adjustSwatches();
1341  mEditor->color()->setColorNumber(0);
1342  }
1343 }
1344 
1345 void MainWindow2::openPalette()
1346 {
1347  for (int i = 0; i < mEditor->object()->getColorCount(); i++)
1348  {
1349  if (!mEditor->object()->isColorInUse(i))
1350  {
1351  continue;
1352  }
1353 
1354  QMessageBox msgBox;
1355  msgBox.setText(tr("Opening a palette will replace the old palette.\n"
1356  "Color(s) in strokes will be altered by this action!"));
1357  msgBox.addButton(tr("Open Palette"), QMessageBox::AcceptRole);
1359 
1360  if (msgBox.exec() == QMessageBox::Cancel) {
1361  return;
1362  }
1363  break;
1364  }
1365 
1366  QString filePath = FileDialog::getOpenFileName(this, FileType::PALETTE);
1367  if (filePath.isEmpty())
1368  {
1369  return;
1370  }
1371 
1372  mEditor->object()->openPalette(filePath);
1373  mColorPalette->refreshColorList();
1374  mEditor->color()->setColorNumber(0);
1375 }
1376 
1377 void MainWindow2::makeConnections(Editor* editor)
1378 {
1379  connect(editor, &Editor::updateBackup, this, &MainWindow2::updateSaveState);
1380  connect(editor, &Editor::needDisplayInfo, this, &MainWindow2::displayMessageBox);
1381  connect(editor, &Editor::needDisplayInfoNoTitle, this, &MainWindow2::displayMessageBoxNoTitle);
1382  connect(editor->layers(), &LayerManager::currentLayerChanged, this, &MainWindow2::currentLayerChanged);
1383 }
1384 
1385 void MainWindow2::makeConnections(Editor* editor, ColorBox* colorBox)
1386 {
1387  connect(colorBox, &ColorBox::colorChanged, editor->color(), &ColorManager::setColor);
1388  connect(editor->color(), &ColorManager::colorChanged, colorBox, &ColorBox::setColor);
1389 }
1390 
1391 void MainWindow2::makeConnections(Editor* editor, ColorInspector* colorInspector)
1392 {
1393  connect(colorInspector, &ColorInspector::colorChanged, editor->color(), &ColorManager::setColor);
1394  connect(editor->color(), &ColorManager::colorChanged, colorInspector, &ColorInspector::setColor);
1395 }
1396 
1397 void MainWindow2::makeConnections(Editor* editor, ScribbleArea* scribbleArea)
1398 {
1399  connect(editor->tools(), &ToolManager::toolChanged, scribbleArea, &ScribbleArea::setCurrentTool);
1400  connect(editor->tools(), &ToolManager::toolPropertyChanged, scribbleArea, &ScribbleArea::updateToolCursor);
1401  connect(editor->layers(), &LayerManager::currentLayerChanged, scribbleArea, &ScribbleArea::updateAllFramesIfNeeded);
1402  connect(editor->layers(), &LayerManager::layerDeleted, scribbleArea, &ScribbleArea::updateAllFrames);
1403 
1404  connect(editor, &Editor::currentFrameChanged, scribbleArea, &ScribbleArea::updateCurrentFrame);
1405 
1406  connect(editor->view(), &ViewManager::viewChanged, scribbleArea, &ScribbleArea::updateAllFrames);
1407 }
1408 
1409 void MainWindow2::makeConnections(Editor* pEditor, TimeLine* pTimeline)
1410 {
1411  PlaybackManager* pPlaybackManager = pEditor->playback();
1412  connect(pTimeline, &TimeLine::duplicateKeyClick, mCommands, &ActionCommands::duplicateKey);
1413 
1414  connect(pTimeline, &TimeLine::soundClick, pPlaybackManager, &PlaybackManager::enableSound);
1415  connect(pTimeline, &TimeLine::fpsChanged, pPlaybackManager, &PlaybackManager::setFps);
1416  connect(pTimeline, &TimeLine::fpsChanged, pEditor, &Editor::setFps);
1417 
1418  connect(pTimeline, &TimeLine::addKeyClick, mCommands, &ActionCommands::addNewKey);
1419  connect(pTimeline, &TimeLine::removeKeyClick, mCommands, &ActionCommands::removeKey);
1420 
1421  connect(pTimeline, &TimeLine::newBitmapLayer, mCommands, &ActionCommands::addNewBitmapLayer);
1422  connect(pTimeline, &TimeLine::newVectorLayer, mCommands, &ActionCommands::addNewVectorLayer);
1423  connect(pTimeline, &TimeLine::newSoundLayer, mCommands, &ActionCommands::addNewSoundLayer);
1424  connect(pTimeline, &TimeLine::newCameraLayer, mCommands, &ActionCommands::addNewCameraLayer);
1425 
1426  connect(mTimeLine, &TimeLine::playButtonTriggered, mCommands, &ActionCommands::PlayStop);
1427 
1428  connect(pEditor->layers(), &LayerManager::currentLayerChanged, pTimeline, &TimeLine::updateUI);
1429  connect(pEditor->layers(), &LayerManager::layerCountChanged, pTimeline, &TimeLine::updateUI);
1430  connect(pEditor->layers(), &LayerManager::animationLengthChanged, pTimeline, &TimeLine::extendLength);
1431  connect(pEditor->sound(), &SoundManager::soundClipDurationChanged, pTimeline, &TimeLine::updateUI);
1432 
1433  connect(pEditor, &Editor::objectLoaded, pTimeline, &TimeLine::onObjectLoaded);
1434  connect(pEditor, &Editor::updateTimeLine, pTimeline, &TimeLine::updateUI);
1435 
1436  connect(pEditor->layers(), &LayerManager::currentLayerChanged, mToolOptions, &ToolOptionWidget::updateUI);
1437 }
1438 
1439 void MainWindow2::makeConnections(Editor* editor, DisplayOptionWidget* displayWidget)
1440 {
1441  connect(editor->layers(), &LayerManager::currentLayerChanged, displayWidget, &DisplayOptionWidget::updateUI);
1442 }
1443 
1444 void MainWindow2::makeConnections(Editor*, OnionSkinWidget*)
1445 {
1446 }
1447 
1448 void MainWindow2::makeConnections(Editor* editor, ToolOptionWidget* toolOptions)
1449 {
1450  toolOptions->makeConnectionToEditor(editor);
1451 }
1452 
1453 void MainWindow2::makeConnections(Editor* pEditor, ColorPaletteWidget* pColorPalette)
1454 {
1455  connect(pEditor, &Editor::objectLoaded, pColorPalette, &ColorPaletteWidget::updateUI);
1456 
1457  ColorManager* pColorManager = pEditor->color();
1458  ScribbleArea* pScribbleArea = pEditor->getScribbleArea();
1459 
1460  connect(pColorPalette, &ColorPaletteWidget::colorChanged, pColorManager, &ColorManager::setColor);
1461  connect(pColorPalette, &ColorPaletteWidget::colorNumberChanged, pColorManager, &ColorManager::setColorNumber);
1462 
1463  connect(pColorPalette, &ColorPaletteWidget::colorChanged, pScribbleArea, &ScribbleArea::paletteColorChanged);
1464 
1465  connect(pColorManager, &ColorManager::colorChanged, pColorPalette, &ColorPaletteWidget::setColor);
1466  connect(pColorManager, &ColorManager::colorNumberChanged, pColorPalette, &ColorPaletteWidget::selectColorNumber);
1467 }
1468 
1469 void MainWindow2::updateZoomLabel()
1470 {
1471  qreal zoom = mEditor->view()->scaling() * 100.f;
1472  mZoomLabel->setText(tr("Zoom: %0%").arg(zoom, 0, 'f', 1));
1473 }
1474 
1475 void MainWindow2::changePlayState(bool isPlaying)
1476 {
1477  if (isPlaying)
1478  {
1479  ui->actionPlay->setText(tr("Stop"));
1480  ui->actionPlay->setIcon(mStopIcon);
1481  }
1482  else
1483  {
1484  ui->actionPlay->setText(tr("Play"));
1485  ui->actionPlay->setIcon(mStartIcon);
1486  }
1487  update();
1488 }
1489 
1490 void MainWindow2::importMovieVideo()
1491 {
1492  // Flag this so we don't prompt the user about auto-save in the middle of the import.
1493  mSuppressAutoSaveDialog = true;
1494 
1495  mCommands->importMovieVideo();
1496 
1497  mSuppressAutoSaveDialog = false;
1498 }
1499 
1500 void MainWindow2::displayMessageBox(const QString& title, const QString& body)
1501 {
1502  QMessageBox::information(this, tr(qPrintable(title)), tr(qPrintable(body)), QMessageBox::Ok);
1503 }
1504 
1505 void MainWindow2::displayMessageBoxNoTitle(const QString& body)
1506 {
1507  QMessageBox::information(this, nullptr, tr(qPrintable(body)), QMessageBox::Ok);
1508 }
1509 
1510 bool MainWindow2::tryRecoverUnsavedProject()
1511 {
1512  FileManager fm;
1513  QStringList recoverables = fm.searchForUnsavedProjects();
1514 
1515  if (recoverables.empty())
1516  {
1517  return false;
1518  }
1519 
1520  QString caption = tr("Restore Project?");
1521  QString text = tr("Pencil2D didn't close correctly. Would you like to restore the project?");
1522 
1523  QString recoverPath = recoverables[0];
1524 
1525  QMessageBox* msgBox = new QMessageBox(this);
1526  msgBox->setWindowTitle(tr("Restore project"));
1529  msgBox->setIconPixmap(QPixmap(":/icons/logo.png"));
1530  msgBox->setText(QString("<h4>%1</h4>%2").arg(caption).arg(text));
1531  msgBox->setInformativeText(QString("<b>%1</b>").arg(retrieveProjectNameFromTempPath(recoverPath)));
1533  msgBox->setProperty("RecoverPath", recoverPath);
1534  hideQuestionMark(*msgBox);
1535 
1536  connect(msgBox, &QMessageBox::finished, this, &MainWindow2::startProjectRecovery);
1537  msgBox->open();
1538  return true;
1539 }
1540 
1541 void MainWindow2::startProjectRecovery(int result)
1542 {
1543  const QMessageBox* msgBox = dynamic_cast<QMessageBox*>(QObject::sender());
1544  const QString recoverPath = msgBox->property("RecoverPath").toString();
1545 
1546  if (result == QMessageBox::Discard)
1547  {
1548  // The user presses discard
1549  QDir(recoverPath).removeRecursively();
1550  tryLoadPreset();
1551  return;
1552  }
1553  Q_ASSERT(result == QMessageBox::Open);
1554 
1555  FileManager fm;
1556  Object* o = fm.recoverUnsavedProject(recoverPath);
1557  if (!fm.error().ok())
1558  {
1559  Q_ASSERT(o == nullptr);
1560  const QString title = tr("Recovery Failed.");
1561  const QString text = tr("Sorry! Pencil2D is unable to restore your project");
1562  QMessageBox::information(this, title, QString("<h4>%1</h4>%2").arg(title).arg(text));
1563  return;
1564  }
1565 
1566  Q_ASSERT(o);
1567  mEditor->setObject(o);
1568  updateSaveState();
1569 
1570  const QString title = tr("Recovery Succeeded!");
1571  const QString text = tr("Please save your work immediately to prevent loss of data");
1572  QMessageBox::information(this, title, QString("<h4>%1</h4>%2").arg(title).arg(text));
1573 }
void clear()
virtual void open()
QString toString(Qt::DateFormat format) const const
QByteArray toByteArray() const const
bool close()
void aboutToHide()
void triggered(bool checked)
QString & append(QChar ch)
void setupUi(QWidget *widget)
void setIconPixmap(const QPixmap &pixmap)
QString writableLocation(QStandardPaths::StandardLocation type)
QObject * sender() const const
void setChecked(bool)
QString & prepend(QChar ch)
void setMenuRole(QAction::MenuRole menuRole)
const T & at(int i) const const
AllDockWidgetAreas
bool removeRecursively()
bool isVisible() const const
void setAttribute(Qt::WidgetAttribute attribute, bool on)
T value() const const
virtual int exec()
bool exists() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
void toggled(bool checked)
QMessageBox::StandardButton information(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
void update()
int size() const const
void setWindowModified(bool)
void finished(int result)
void setTimeSpec(Qt::TimeSpec spec)
QString number(int n, int base)
void processEvents(QEventLoop::ProcessEventsFlags flags)
void aboutToShow()
void updateAllFramesIfNeeded()
Check if the cache should be invalidated for all frames since the last paint operation.
QVariant property(const char *name) const const
bool empty() const const
void setWindowOpacity(qreal level)
bool restoreGeometry(const QByteArray &geometry)
void setWindowTitle(const QString &title)
bool isEmpty() const const
bool isEmpty() const const
void setText(const QString &text)
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
void setInformativeText(const QString &text)
int result() const const
void setStandardButtons(QMessageBox::StandardButtons buttons)
QString toLower() const const
virtual int exec() override
void setShortcut(const QKeySequence &shortcut)
static QString getOpenFileName(QWidget *parent, FileType fileType, const QString &caption=QString())
Shows a file dialog which allows the user to select a file to open.
Definition: filedialog.cpp:27
WA_DeleteOnClose
QDateTime currentDateTime()
char * toString(const T &value)
QByteArray saveGeometry() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void setWindowTitle(const QString &)
QWidget(QWidget *parent, Qt::WindowFlags f)
void extendLength(int frame)
Extends the timeline frame length if necessary.
Definition: timeline.cpp:254
void keySequence(QWindow *window, const QKeySequence &keySequence)
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
Definition: object.h:54
bool setProperty(const char *name, const QVariant &value)
void addButton(QAbstractButton *button, QMessageBox::ButtonRole role)
void setWindowModality(Qt::WindowModality windowModality)
static QString getSaveFileName(QWidget *parent, FileType fileType, const QString &caption=QString())
Shows a file dialog which allows the user to select a file save path.
Definition: filedialog.cpp:65
Definition: editor.h:51
WindowModal
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QAction * > actions() const const
void open(QObject *receiver, const char *member)
QString toString() const const
virtual bool event(QEvent *event) override
typedef WindowFlags