diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 846179c1a..2d465f17f 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -309,6 +309,8 @@ void MainWindow2::createMenus() connect(pPlaybackManager, &PlaybackManager::playStateChanged, mTimeLine, &TimeLine::setPlaying); connect(pPlaybackManager, &PlaybackManager::playStateChanged, this, &MainWindow2::changePlayState); connect(pPlaybackManager, &PlaybackManager::playStateChanged, mEditor, &Editor::updateCurrentFrame); + connect(ui->actionFlip_inbetween, &QAction::triggered, pPlaybackManager, &PlaybackManager::playFlipBtwn); + connect(ui->actionFlip_rolling, &QAction::triggered, pPlaybackManager, &PlaybackManager::playFlipRoll); connect(ui->actionAdd_Frame, &QAction::triggered, mCommands, &ActionCommands::addNewKey); connect(ui->actionRemove_Frame, &QAction::triggered, mCommands, &ActionCommands::removeKey); @@ -1152,6 +1154,8 @@ void MainWindow2::setupKeyboardShortcuts() ui->actionRemove_Frame->setShortcut(cmdKeySeq(CMD_REMOVE_FRAME)); ui->actionMove_Frame_Backward->setShortcut(cmdKeySeq(CMD_MOVE_FRAME_BACKWARD)); ui->actionMove_Frame_Forward->setShortcut(cmdKeySeq(CMD_MOVE_FRAME_FORWARD)); + ui->actionFlip_inbetween->setShortcut(cmdKeySeq(CMD_FLIP_INBETWEEN)); + ui->actionFlip_rolling->setShortcut(cmdKeySeq(CMD_FLIP_ROLLING)); ShortcutFilter* shortcutfilter = new ShortcutFilter(ui->scribbleArea, this); ui->actionMove->setShortcut(cmdKeySeq(CMD_TOOL_MOVE)); diff --git a/app/src/preferencesdialog.cpp b/app/src/preferencesdialog.cpp index 397ce0ac5..2147dcbfa 100644 --- a/app/src/preferencesdialog.cpp +++ b/app/src/preferencesdialog.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include #include +#include #include "ui_preferencesdialog.h" #include "ui_generalpage.h" #include "ui_timelinepage.h" @@ -293,12 +294,19 @@ TimelinePage::TimelinePage() ui->setupUi(this); auto spinBoxValueChange = static_cast(&QSpinBox::valueChanged); + auto sliderChanged = static_cast(&QSlider::valueChanged); connect(ui->timelineLength, spinBoxValueChange, this, &TimelinePage::timelineLengthChanged); connect(ui->scrubBox, &QCheckBox::stateChanged, this, &TimelinePage::scrubChanged); connect(ui->radioButtonAddNewKey, &QRadioButton::toggled, this, &TimelinePage::drawEmptyKeyRadioButtonToggled); connect(ui->radioButtonDuplicate, &QRadioButton::toggled, this, &TimelinePage::drawEmptyKeyRadioButtonToggled); connect(ui->radioButtonDrawOnPrev, &QRadioButton::toggled, this, &TimelinePage::drawEmptyKeyRadioButtonToggled); connect(ui->onionWhilePlayback, &QCheckBox::stateChanged, this, &TimelinePage::playbackStateChanged); + connect(ui->flipRollMsecsSlider, sliderChanged, this, &TimelinePage::flipRollMsecSliderChanged); + connect(ui->flipRollMsecsSpinBox, spinBoxValueChange, this, &TimelinePage::flipRollMsecSpinboxChanged); + connect(ui->flipRollNumDrawingsSlider, sliderChanged, this, &TimelinePage::flipRollNumDrawingdSliderChanged); + connect(ui->flipRollNumDrawingsSpinBox, spinBoxValueChange, this, &TimelinePage::flipRollNumDrawingdSpinboxChanged); + connect(ui->flipInBtwnMsecSlider, sliderChanged, this, &TimelinePage::flipInbetweenMsecSliderChanged); + connect(ui->flipInBtwnMsecSpinBox, spinBoxValueChange, this, &TimelinePage::flipInbetweenMsecSpinboxChanged); } TimelinePage::~TimelinePage() @@ -337,6 +345,12 @@ void TimelinePage::updateValues() SignalBlocker b7(ui->onionWhilePlayback); ui->onionWhilePlayback->setChecked(mManager->getInt(SETTING::ONION_WHILE_PLAYBACK)); + ui->flipRollMsecsSlider->setValue(mManager->getInt(SETTING::FLIP_ROLL_MSEC)); + ui->flipRollNumDrawingsSlider->setValue(mManager->getInt(SETTING::FLIP_ROLL_DRAWINGS)); + ui->flipInBtwnMsecSlider->setValue(mManager->getInt(SETTING::FLIP_INBETWEEN_MSEC)); + ui->flipRollMsecsSpinBox->setValue(mManager->getInt(SETTING::FLIP_ROLL_MSEC)); + ui->flipRollNumDrawingsSpinBox->setValue(mManager->getInt(SETTING::FLIP_ROLL_DRAWINGS)); + ui->flipInBtwnMsecSpinBox->setValue(mManager->getInt(SETTING::FLIP_INBETWEEN_MSEC)); } void TimelinePage::timelineLengthChanged(int value) @@ -375,6 +389,43 @@ void TimelinePage::drawEmptyKeyRadioButtonToggled(bool) } } +void TimelinePage::flipRollMsecSliderChanged(int value) +{ + ui->flipRollMsecsSpinBox->setValue(value); + mManager->set(SETTING::FLIP_ROLL_MSEC, value); +} + +void TimelinePage::flipRollMsecSpinboxChanged(int value) +{ + ui->flipRollMsecsSlider->setValue(value); + mManager->set(SETTING::FLIP_ROLL_MSEC, value); +} + +void TimelinePage::flipRollNumDrawingdSliderChanged(int value) +{ + ui->flipRollNumDrawingsSpinBox->setValue(value); + mManager->set(SETTING::FLIP_ROLL_DRAWINGS, value); +} + +void TimelinePage::flipRollNumDrawingdSpinboxChanged(int value) +{ + ui->flipRollNumDrawingsSlider->setValue(value); + mManager->set(SETTING::FLIP_ROLL_DRAWINGS, value); +} + +void TimelinePage::flipInbetweenMsecSliderChanged(int value) +{ + ui->flipInBtwnMsecSpinBox->setValue(value); + mManager->set(SETTING::FLIP_INBETWEEN_MSEC, value); +} + +void TimelinePage::flipInbetweenMsecSpinboxChanged(int value) +{ + ui->flipInBtwnMsecSlider->setValue(value); + mManager->set(SETTING::FLIP_INBETWEEN_MSEC, value); +} + + FilesPage::FilesPage() : ui(new Ui::FilesPage) { @@ -457,3 +508,5 @@ void ToolsPage::onionNextFramesNumChange(int value) { mManager->set(SETTING::ONION_NEXT_FRAMES_NUM, value); } + + diff --git a/app/src/preferencesdialog.h b/app/src/preferencesdialog.h index d9c0dc864..b785eb04b 100644 --- a/app/src/preferencesdialog.h +++ b/app/src/preferencesdialog.h @@ -114,6 +114,12 @@ public slots: void scrubChanged(int); void playbackStateChanged(int); void drawEmptyKeyRadioButtonToggled(bool); + void flipRollMsecSliderChanged(int value); + void flipRollMsecSpinboxChanged(int value); + void flipRollNumDrawingdSliderChanged(int value); + void flipRollNumDrawingdSpinboxChanged(int value); + void flipInbetweenMsecSliderChanged(int value); + void flipInbetweenMsecSpinboxChanged(int value); private: Ui::TimelinePage* ui = nullptr; diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index 30c35d39c..b5a54cde1 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -180,6 +180,9 @@ + + + @@ -961,6 +964,16 @@ 100% + + + Flip inbetween + + + + + Flip rolling + + diff --git a/app/ui/timelinepage.ui b/app/ui/timelinepage.ui index 27cf12fb9..8e4b1b252 100644 --- a/app/ui/timelinepage.ui +++ b/app/ui/timelinepage.ui @@ -6,172 +6,299 @@ 0 0 - 342 - 457 + 349 + 642 - - - 7 - + - - - Timeline + + + Qt::ScrollBarAlwaysOn - - - - - 5 - - - 5 - - - - - - 0 - 0 - - - - Timeline length: - - - - - - - 1 - - - 9999 - - - - - - - - - Short scrub - - - - - - - - - - Drawing + + Qt::ScrollBarAlwaysOff - - - - - When drawing on an empty frame: - - - - - - - Create a new (blank) key-frame and start drawing on it. - - - Create a new (blank) key-frame - - - true - - - - - - - Duplicate the previous key-frame and start drawing on the duplicate. - - - Duplicate the previous key-frame - - - - - - - Keep drawing on the previous key-frame - - - - - - - - 10 - - - - <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> - - - true - - - - - - - - - - - 0 - 60 - + + true - - - 16777215 - 60 - - - - Playback - - + - 10 - 30 - 301 - 16 + 0 + 0 + 315 + 622 - - Show onion skin while playing - + + + + + Timeline + + + + + + 5 + + + 5 + + + + + + 0 + 0 + + + + Timeline length: + + + + + + + 1 + + + 9999 + + + + + + + + + Short scrub + + + + + + + + + + Drawing + + + + + + When drawing on an empty frame: + + + + + + + Create a new (blank) key-frame and start drawing on it. + + + Create a new (blank) key-frame + + + true + + + + + + + Duplicate the previous key-frame and start drawing on the duplicate. + + + Duplicate the previous key-frame + + + + + + + Keep drawing on the previous key-frame + + + + + + + + 10 + + + + <html><head/><body><p>(Applies to Pencil, Erasor, Pen, Polyline, Bucket and Brush tools)</p></body></html> + + + true + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + Playback + + + + + 10 + 30 + 301 + 16 + + + + Show onion skin while playing + + + + + + + + Flip and Roll + + + + + + + + Maximum numbers of drawings in roll + + + + + + + 3 + + + 10 + + + 5 + + + Qt::Horizontal + + + + + + + 100 + + + 400 + + + 200 + + + Qt::Horizontal + + + + + + + 100 + + + 400 + + + 200 + + + + + + + Msecs per drawing in flip inbetween + + + + + + + 100 + + + 400 + + + 200 + + + + + + + 3 + + + 10 + + + 5 + + + + + + + 100 + + + 400 + + + 200 + + + Qt::Horizontal + + + + + + + Msecs per drawing in flip roll + + + + + + + + + - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 30 - - - - diff --git a/app/ui/toolspage.ui b/app/ui/toolspage.ui index 9ab1557e3..d4383fd05 100644 --- a/app/ui/toolspage.ui +++ b/app/ui/toolspage.ui @@ -6,158 +6,189 @@ 0 0 - 278 - 330 + 306 + 586 - + + + 0 + 0 + + + - - - Onion skin + + + Qt::ScrollBarAlwaysOn - - - - - Maximum onion opacity % - - - - - - - - 50 - 0 - - - - - 50 - 16777215 - - - - 100 - - - - - - - Minimum onion opacity % - - - - - - - - 50 - 0 - - - - - 50 - 16777215 - - - - 100 - - - - - - - Number of previous onion frames shown - - - - - - - - 50 - 0 - - - - - 50 - 16777215 - - - - 1 - - - 60 - - - - - - - Number of next onion frames shown - - - - - - - - 50 - 0 - - - - - 50 - 16777215 - - - - 1 - - - 60 - - - - - - - - - - Brush Tools + + Qt::ScrollBarAlwaysOff - - - - - Use Quick Sizing - - - - - - - - - - Qt::Vertical + + true - - - 0 - 0 - - - + + + + 0 + 0 + 286 + 566 + + + + + + + Onion skin + + + + + + Maximum onion opacity % + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + 100 + + + + + + + Minimum onion opacity % + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + 100 + + + + + + + Number of previous onion frames shown + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + 1 + + + 60 + + + + + + + Number of next onion frames shown + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + 1 + + + 60 + + + + + + + + + + Brush Tools + + + + + + Use Quick Sizing + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + diff --git a/core_lib/data/resources/kb.ini b/core_lib/data/resources/kb.ini index 4ebb3155c..976b6b47a 100644 --- a/core_lib/data/resources/kb.ini +++ b/core_lib/data/resources/kb.ini @@ -42,6 +42,8 @@ CmdOnionSkinPrevious=O CmdOnionSkinNext=Alt+O CmdPlay=Ctrl+Return CmdLoop=Ctrl+L +CmdFlipInBetween=Alt+Z +CmdFlipRolling=Alt+X CmdGotoNextFrame=. CmdGotoPreviousFrame="," CmdGotoNextKeyFrame=Alt+. diff --git a/core_lib/src/managers/playbackmanager.cpp b/core_lib/src/managers/playbackmanager.cpp index 4cde41145..9969ef7a2 100644 --- a/core_lib/src/managers/playbackmanager.cpp +++ b/core_lib/src/managers/playbackmanager.cpp @@ -41,11 +41,13 @@ bool PlaybackManager::init() { mTimer = new QTimer(this); mTimer->setTimerType(Qt::PreciseTimer); + mFlipTimer = new QTimer(this); QSettings settings (PENCIL2D, PENCIL2D); mFps = settings.value(SETTING_FPS).toInt(); mElapsedTimer = new QElapsedTimer; connect(mTimer, &QTimer::timeout, this, &PlaybackManager::timerTick); + connect(mFlipTimer, &QTimer::timeout, this, &PlaybackManager::flipTimerTick); return true; } @@ -78,7 +80,7 @@ Status PlaybackManager::save(Object* o) bool PlaybackManager::isPlaying() { - return mTimer->isActive(); + return (mTimer->isActive() || mFlipTimer->isActive()); } void PlaybackManager::play() @@ -122,7 +124,7 @@ void PlaybackManager::play() } } - mTimer->setInterval(1000.f / mFps); + mTimer->setInterval(static_cast(1000.f / mFps)); mTimer->start(); // for error correction, please ref skipFrame() @@ -142,6 +144,61 @@ void PlaybackManager::stop() emit playStateChanged(false); } +void PlaybackManager::playFlipRoll() +{ + if (isPlaying()) { return; } + int start = editor()->currentFrame(); + int tmp = start; + mFlipList.clear(); + QSettings settings(PENCIL2D, PENCIL2D); + mFlipRollMax = settings.value(SETTING_FLIP_ROLL_DRAWINGS).toInt(); + for (int i = 0; i < mFlipRollMax; i++) + { + int prev = editor()->layers()->currentLayer()->getPreviousKeyFramePosition(tmp); + if (prev < tmp) + { + mFlipList.prepend(QString::number(prev)); + tmp = prev; + } + } + if (mFlipList.isEmpty()) { return; } + // run the roll... + mFlipRollInterval = settings.value(SETTING_FLIP_ROLL_MSEC).toInt(); + mFlipList.append(QString::number(start)); + mFlipTimer->setInterval(mFlipRollInterval); + editor()->scrubTo(mFlipList[0].toInt()); + mFlipTimer->start(); + emit playStateChanged(true); +} + +void PlaybackManager::playFlipBtwn() +{ + if (isPlaying()) { return; } + int start = editor()->currentFrame(); + int prev = editor()->layers()->currentLayer()->getPreviousKeyFramePosition(start); + int next = editor()->layers()->currentLayer()->getNextKeyFramePosition(start); + if (editor()->layers()->currentLayer()->keyExists(prev) && + editor()->layers()->currentLayer()->keyExists(next)) + { + mFlipList.clear(); + mFlipList.append(QString::number(prev)); + mFlipList.append(QString::number(start)); + mFlipList.append(QString::number(next)); + mFlipList.append(QString::number(start)); + } + else + { + return; + } + // run the flip inbetween... + QSettings settings(PENCIL2D, PENCIL2D); + mFlipInbetweenInterval = settings.value(SETTING_FLIP_INBETWEEN_MSEC).toInt(); + mFlipTimer->setInterval(mFlipInbetweenInterval); + editor()->scrubTo(mFlipList[0].toInt()); + mFlipTimer->start(); + emit playStateChanged(true); +} + void PlaybackManager::setFps(int fps) { if (mFps != fps) @@ -322,6 +379,22 @@ void PlaybackManager::timerTick() editor()->scrubForward(); } +void PlaybackManager::flipTimerTick() +{ + int curr = editor()->currentFrame(); + int pos = mFlipList.indexOf(QString::number(curr)); + if (pos == mFlipList.count() - 1) + { + mFlipTimer->stop(); + emit playStateChanged(false); + } + else + { + editor()->scrubTo(mFlipList[pos + 1].toInt()); + mFlipList.removeAt(pos); + } +} + void PlaybackManager::setLooping(bool isLoop) { if (mIsLooping != isLoop) diff --git a/core_lib/src/managers/playbackmanager.h b/core_lib/src/managers/playbackmanager.h index d527ca1e4..b9d69ff71 100644 --- a/core_lib/src/managers/playbackmanager.h +++ b/core_lib/src/managers/playbackmanager.h @@ -29,7 +29,7 @@ class PlaybackManager : public BaseManager Q_OBJECT public: explicit PlaybackManager(Editor* editor); - ~PlaybackManager(); + ~PlaybackManager() override; bool init() override; Status load(Object*) override; @@ -41,6 +41,8 @@ class PlaybackManager : public BaseManager void play(); void stop(); + void playFlipRoll(); + void playFlipBtwn(); int fps() { return mFps; } int startFrame() { return mStartFrame; } @@ -67,6 +69,7 @@ class PlaybackManager : public BaseManager private: void timerTick(); + void flipTimerTick(); void playSounds(int frame); bool skipFrame(); @@ -85,13 +88,18 @@ class PlaybackManager : public BaseManager int mActiveSoundFrame = 0; int mFps = 12; + int mFlipRollInterval; + int mFlipInbetweenInterval; + int mFlipRollMax; QTimer* mTimer = nullptr; + QTimer* mFlipTimer = nullptr; QElapsedTimer* mElapsedTimer = nullptr; int mPlayingFrameCounter = 0; // how many frames has passed after pressing play bool mCheckForSoundsHalfway = false; QList mListOfActiveSoundFrames; + QStringList mFlipList; }; #endif // PLAYBACKMANAGER_H diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index 8ac1a1309..e0e60a750 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -105,6 +105,10 @@ void PreferenceManager::loadPrefs() set(SETTING::ONION_WHILE_PLAYBACK, settings.value(SETTING_ONION_WHILE_PLAYBACK, 0).toInt()); set(SETTING::ONION_TYPE, settings.value(SETTING_ONION_TYPE, "relative").toString()); + set(SETTING::FLIP_ROLL_MSEC, settings.value(SETTING_FLIP_ROLL_MSEC, 100).toInt()); + set(SETTING::FLIP_ROLL_DRAWINGS, settings.value(SETTING_FLIP_ROLL_DRAWINGS, 5).toInt()); + set(SETTING::FLIP_INBETWEEN_MSEC, settings.value(SETTING_FLIP_INBETWEEN_MSEC, 100).toInt()); + set(SETTING::LANGUAGE, settings.value(SETTING_LANGUAGE).toString()); } @@ -216,6 +220,15 @@ void PreferenceManager::set(SETTING option, int value) case SETTING::ONION_NEXT_FRAMES_NUM: settings.setValue(SETTING_ONION_NEXT_FRAMES_NUM, value); break; + case SETTING::FLIP_ROLL_MSEC : + settings.setValue(SETTING_FLIP_ROLL_MSEC, value); + break; + case SETTING::FLIP_ROLL_DRAWINGS : + settings.setValue(SETTING_FLIP_ROLL_DRAWINGS, value); + break; + case SETTING::FLIP_INBETWEEN_MSEC : + settings.setValue(SETTING_FLIP_INBETWEEN_MSEC, value); + break; case SETTING::GRID_SIZE_W: settings.setValue(SETTING_GRID_SIZE_W, value); break; diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index e4d86d29c..7407837b0 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -57,6 +57,9 @@ enum class SETTING ONION_NEXT_FRAMES_NUM, ONION_WHILE_PLAYBACK, ONION_TYPE, + FLIP_ROLL_MSEC, + FLIP_ROLL_DRAWINGS, + FLIP_INBETWEEN_MSEC, GRID_SIZE_W, GRID_SIZE_H, QUICK_SIZING, diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index a0c09d6cc..3344b9eda 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -126,6 +126,8 @@ enum StabilizationLevel #define CMD_ONIONSKIN_NEXT "CmdOnionSkinNext" #define CMD_PLAY "CmdPlay" #define CMD_LOOP "CmdLoop" +#define CMD_FLIP_INBETWEEN "CmdFlipInBetween" +#define CMD_FLIP_ROLLING "CmdFlipRolling" #define CMD_GOTO_NEXT_FRAME "CmdGotoNextFrame" #define CMD_GOTO_PREV_FRAME "CmdGotoPreviousFrame" #define CMD_GOTO_NEXT_KEY_FRAME "CmdGotoNextKeyFrame" @@ -215,6 +217,10 @@ enum StabilizationLevel #define SETTING_ONION_NEXT_FRAMES_NUM "OnionNextFramesNum" #define SETTING_ONION_WHILE_PLAYBACK "OnionWhilePlayback" #define SETTING_ONION_TYPE "OnionType" +#define SETTING_FLIP_ROLL_MSEC "FlipRoll" +#define SETTING_FLIP_ROLL_DRAWINGS "FlipRollDrawings" +#define SETTING_FLIP_INBETWEEN_MSEC "FlipInbetween" + #define SETTING_DRAW_ON_EMPTY_FRAME_ACTION "DrawOnEmptyFrameAction"