diff --git a/stuff/profiles/layouts/rooms/Default/menubar_template.xml b/stuff/profiles/layouts/rooms/Default/menubar_template.xml
index 8218e71a..93d26779 100644
--- a/stuff/profiles/layouts/rooms/Default/menubar_template.xml
+++ b/stuff/profiles/layouts/rooms/Default/menubar_template.xml
@@ -232,6 +232,8 @@
MI_PrevDrawing
MI_NextDrawing
+ MI_PrevKeyframe
+ MI_NextKeyframe
MI_Link
diff --git a/toonz/sources/include/toonz/tframehandle.h b/toonz/sources/include/toonz/tframehandle.h
index b3c37efb..4c5c4fd7 100644
--- a/toonz/sources/include/toonz/tframehandle.h
+++ b/toonz/sources/include/toonz/tframehandle.h
@@ -103,6 +103,13 @@ public:
int getStartFrame() { return m_frame0; }
int getEndFrame() { return m_frame1; }
+ void emitTriggerNextKeyframe(QWidget *panel) {
+ emit triggerNextKeyframe(panel);
+ }
+ void emitTriggerPrevKeyframe(QWidget *panel) {
+ emit triggerPrevKeyframe(panel);
+ }
+
public slots:
void nextFrame(TFrameId = 0);
@@ -118,6 +125,9 @@ signals:
void frameTypeChanged();
void isPlayingStatusChanged();
+ void triggerNextKeyframe(QWidget *panel);
+ void triggerPrevKeyframe(QWidget *panel);
+
protected:
void timerEvent(QTimerEvent *event) override;
};
diff --git a/toonz/sources/include/toonzqt/functiontoolbar.h b/toonz/sources/include/toonzqt/functiontoolbar.h
index 28694dee..445bd25b 100644
--- a/toonz/sources/include/toonzqt/functiontoolbar.h
+++ b/toonz/sources/include/toonzqt/functiontoolbar.h
@@ -95,6 +95,9 @@ public slots:
void setCurve(TDoubleParam *curve);
void setFrame(double frame);
+ void onNextKeyframe(QWidget *panel);
+ void onPrevKeyframe(QWidget *panel);
+
private slots:
void onValueFieldChanged();
diff --git a/toonz/sources/include/toonzqt/keyframenavigator.h b/toonz/sources/include/toonzqt/keyframenavigator.h
index 7760e7ec..d327a06c 100644
--- a/toonz/sources/include/toonzqt/keyframenavigator.h
+++ b/toonz/sources/include/toonzqt/keyframenavigator.h
@@ -43,6 +43,8 @@ class DVAPI KeyframeNavigator : public QToolBar {
TFrameHandle *m_frameHandle;
+ QWidget *m_panel;
+
public:
KeyframeNavigator(QWidget *parent = 0, TFrameHandle *frameHandle = 0);
@@ -63,6 +65,9 @@ public slots:
}
void update();
+ void onNextKeyframe(QWidget *panel);
+ void onPrevKeyframe(QWidget *panel);
+
protected slots:
void toggleKeyAct() {
toggle();
diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp
index 5c13cdf4..2e57a35a 100644
--- a/toonz/sources/toonz/mainwindow.cpp
+++ b/toonz/sources/toonz/mainwindow.cpp
@@ -1904,6 +1904,9 @@ void MainWindow::defineActions() {
createAction(MI_NextStep, tr("Next Step"), "", PlaybackCommandType);
createAction(MI_PrevStep, tr("Prev Step"), "", PlaybackCommandType);
+ createAction(MI_NextKeyframe, tr("Next Key"), "Ctrl+.", MenuXsheetCommandType);
+ createAction(MI_PrevKeyframe, tr("Prev Key"), "Ctrl+,", MenuXsheetCommandType);
+
createRGBAAction(MI_RedChannel, tr("Red Channel"), "");
createRGBAAction(MI_GreenChannel, tr("Green Channel"), "");
createRGBAAction(MI_BlueChannel, tr("Blue Channel"), "");
diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp
index f7dc0572..80a5a61b 100644
--- a/toonz/sources/toonz/menubar.cpp
+++ b/toonz/sources/toonz/menubar.cpp
@@ -1334,8 +1334,10 @@ QMenuBar *StackedMenuBar::createFullMenuBar() {
addMenuItem(playMenu, MI_PrevStep);
addMenuItem(playMenu, MI_NextStep);
playMenu->addSeparator();
- addMenuItem(playMenu, MI_NextDrawing);
addMenuItem(playMenu, MI_PrevDrawing);
+ addMenuItem(playMenu, MI_NextDrawing);
+ addMenuItem(playMenu, MI_PrevKeyframe);
+ addMenuItem(playMenu, MI_NextKeyframe);
playMenu->addSeparator();
addMenuItem(playMenu, MI_Link);
diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h
index 48828880..8dd23295 100644
--- a/toonz/sources/toonz/menubarcommandids.h
+++ b/toonz/sources/toonz/menubarcommandids.h
@@ -210,6 +210,8 @@
#define MI_PrevDrawing "MI_PrevDrawing"
#define MI_NextStep "MI_NextStep"
#define MI_PrevStep "MI_PrevStep"
+#define MI_NextKeyframe "MI_NextKeyframe"
+#define MI_PrevKeyframe "MI_PrevKeyframe"
#define MI_RedChannel "MI_RedChannel"
#define MI_GreenChannel "MI_GreenChannel"
diff --git a/toonz/sources/toonz/vcrcommand.cpp b/toonz/sources/toonz/vcrcommand.cpp
index e05c9e24..63f3ccfc 100644
--- a/toonz/sources/toonz/vcrcommand.cpp
+++ b/toonz/sources/toonz/vcrcommand.cpp
@@ -3,6 +3,7 @@
// Tnz6 includes
#include "menubarcommandids.h"
#include "tapp.h"
+#include "sceneviewer.h"
// TnzQt includes
#include "toonzqt/menubarcommand.h"
@@ -16,6 +17,8 @@
#include "toonz/tcolumnhandle.h"
#include "toonz/preferences.h"
+#include
+
//**********************************************************************************
// Commands definition
//**********************************************************************************
@@ -127,6 +130,64 @@ public:
}
};
+//-----------------------------------------------------------------------------
+
+class NextKeyframeCommand final : public MenuItemHandler {
+public:
+ NextKeyframeCommand() : MenuItemHandler(MI_NextKeyframe) {}
+
+ void execute() override {
+ QString navControlList[6] = {"LevelPalette", "StudioPalette",
+ "FunctionEditor", "FxSettings",
+ "ComboViewer", "SceneViewer"};
+
+ QWidget *panel = QApplication::focusWidget();
+ if (!panel) panel = TApp::instance()->getActiveViewer();
+ while (panel) {
+ QString pane = panel->objectName();
+ if (panel->windowType() == Qt::WindowType::SubWindow ||
+ panel->windowType() == Qt::WindowType::Tool) {
+ if (std::find(navControlList, navControlList + 6, pane) !=
+ (navControlList + 6)) {
+ TApp::instance()->getCurrentFrame()->emitTriggerNextKeyframe(panel);
+ break;
+ } else
+ panel = TApp::instance()->getActiveViewer()->parentWidget();
+ } else
+ panel = panel->parentWidget();
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+class PrevKeyframeCommand final : public MenuItemHandler {
+public:
+ PrevKeyframeCommand() : MenuItemHandler(MI_PrevKeyframe) {}
+
+ void execute() override {
+ QString navControlList[6] = {"LevelPalette", "StudioPalette",
+ "FunctionEditor", "FxSettings",
+ "ComboViewer", "SceneViewer"};
+
+ QWidget *panel = QApplication::focusWidget();
+ if (!panel) panel = TApp::instance()->getActiveViewer();
+ while (panel) {
+ QString pane = panel->objectName();
+ if (panel->windowType() == Qt::WindowType::SubWindow ||
+ panel->windowType() == Qt::WindowType::Tool) {
+ if (std::find(navControlList, navControlList + 6, pane) !=
+ (navControlList + 6)) {
+ TApp::instance()->getCurrentFrame()->emitTriggerPrevKeyframe(panel);
+ break;
+ } else
+ panel = TApp::instance()->getActiveViewer()->parentWidget();
+ } else
+ panel = panel->parentWidget();
+ }
+ }
+};
+
//**********************************************************************************
// Commands instantiation
//**********************************************************************************
@@ -154,3 +215,6 @@ NextDrawingCommand nextDrawingCommand;
PrevDrawingCommand prevDrawingCommand;
NextStepCommand nextStepCommand;
PrevStepCommand prevStepCommand;
+
+NextKeyframeCommand nextKeyframeCommand;
+PrevKeyframeCommand prevKeyframeCommand;
diff --git a/toonz/sources/toonzqt/functiontoolbar.cpp b/toonz/sources/toonzqt/functiontoolbar.cpp
index c66f7f6c..ddc4760a 100644
--- a/toonz/sources/toonzqt/functiontoolbar.cpp
+++ b/toonz/sources/toonzqt/functiontoolbar.cpp
@@ -150,6 +150,16 @@ void FunctionToolbar::setFrame(double frame) {
m_valueFld->setValue(0);
}
+void FunctionToolbar::onNextKeyframe(QWidget *panel) {
+ m_keyframeNavigator->onNextKeyframe(panel);
+}
+
+//-------------------------------------------------------------------
+
+void FunctionToolbar::onPrevKeyframe(QWidget *panel) {
+ m_keyframeNavigator->onPrevKeyframe(panel);
+}
+
//-------------------------------------------------------------------
void FunctionToolbar::onValueFieldChanged() {
diff --git a/toonz/sources/toonzqt/functionviewer.cpp b/toonz/sources/toonzqt/functionviewer.cpp
index e2771a33..495ddffe 100644
--- a/toonz/sources/toonzqt/functionviewer.cpp
+++ b/toonz/sources/toonzqt/functionviewer.cpp
@@ -172,11 +172,11 @@ FunctionViewer::FunctionViewer(QWidget *parent, Qt::WFlags flags)
bool ret = true;
ret = ret && connect(m_toolbar, SIGNAL(numericalColumnToggled()), this,
SLOT(toggleMode()));
- ret = ret && connect(ftModel, SIGNAL(activeChannelsChanged()),
+ ret = ret && connect(ftModel, SIGNAL(activeChannelsChanged()),
m_functionGraph, SLOT(update()));
- ret = ret && connect(ftModel, SIGNAL(activeChannelsChanged()),
+ ret = ret && connect(ftModel, SIGNAL(activeChannelsChanged()),
m_numericalColumns, SLOT(updateAll()));
- ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_treeView,
+ ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_treeView,
SLOT(update()));
ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_functionGraph,
SLOT(update()));
@@ -241,11 +241,19 @@ void FunctionViewer::showEvent(QShowEvent *) {
ret;
}
- if (m_frameHandle)
+ if (m_frameHandle) {
ret = connect(m_frameHandle, SIGNAL(frameSwitched()), this,
SLOT(propagateExternalSetFrame())) &&
ret;
+ ret = connect(m_frameHandle, SIGNAL(triggerNextKeyframe(QWidget *)),
+ m_toolbar, SLOT(onNextKeyframe(QWidget *))) &&
+ ret;
+ ret = connect(m_frameHandle, SIGNAL(triggerPrevKeyframe(QWidget *)),
+ m_toolbar, SLOT(onPrevKeyframe(QWidget *))) &&
+ ret;
+ }
+
if (m_objectHandle) {
ret = connect(m_objectHandle, SIGNAL(objectSwitched()), this,
SLOT(onStageObjectSwitched())) &&
@@ -303,7 +311,10 @@ void FunctionViewer::showEvent(QShowEvent *) {
void FunctionViewer::hideEvent(QHideEvent *) {
if (m_xshHandle) m_xshHandle->disconnect(this);
- if (m_frameHandle) m_frameHandle->disconnect(this);
+ if (m_frameHandle) {
+ m_frameHandle->disconnect(this);
+ m_frameHandle->disconnect(m_toolbar);
+ }
if (m_objectHandle) m_objectHandle->disconnect(this);
if (m_fxHandle) m_fxHandle->disconnect(this);
if (m_sceneHandle) m_sceneHandle->disconnect(this);
@@ -595,7 +606,7 @@ void FunctionViewer::onStageObjectChanged(bool isDragging) {
void FunctionViewer::onFxSwitched() {
TFx *fx = m_fxHandle->getFx();
TZeraryColumnFx *zfx = dynamic_cast(fx);
- if (zfx) fx = zfx->getZeraryFx();
+ if (zfx) fx = zfx->getZeraryFx();
static_cast(m_treeView->model())->setCurrentFx(fx);
m_treeView->updateAll();
m_functionGraph->update();
diff --git a/toonz/sources/toonzqt/keyframenavigator.cpp b/toonz/sources/toonzqt/keyframenavigator.cpp
index 8abb65a1..b54f1bef 100644
--- a/toonz/sources/toonzqt/keyframenavigator.cpp
+++ b/toonz/sources/toonzqt/keyframenavigator.cpp
@@ -8,6 +8,7 @@
#include "toonz/txshcolumn.h"
#include "toonz/tstageobjectkeyframe.h"
#include "toonz/stageobjectutil.h"
+#include "toonz/tapplication.h"
#include "tpixelutils.h"
#include "tfx.h"
@@ -35,7 +36,7 @@ using namespace std;
//-----------------------------------------------------------------------------
KeyframeNavigator::KeyframeNavigator(QWidget *parent, TFrameHandle *frameHandle)
- : QToolBar(parent), m_frameHandle(frameHandle) {
+ : QToolBar(parent), m_frameHandle(frameHandle), m_panel(0) {
setLayoutDirection(Qt::LeftToRight);
setIconSize(QSize(18, 18));
@@ -124,6 +125,22 @@ void KeyframeNavigator::showEvent(QShowEvent *e) {
update();
if (!m_frameHandle) return;
connect(m_frameHandle, SIGNAL(frameSwitched()), this, SLOT(update()));
+
+ connect(m_frameHandle, SIGNAL(triggerNextKeyframe(QWidget *)), this,
+ SLOT(onNextKeyframe(QWidget *)));
+ connect(m_frameHandle, SIGNAL(triggerPrevKeyframe(QWidget *)), this,
+ SLOT(onPrevKeyframe(QWidget *)));
+ if (!m_panel || m_panel == nullptr) {
+ QWidget *panel = this->parentWidget();
+ while (panel) {
+ if (panel->windowType() == Qt::WindowType::SubWindow ||
+ panel->windowType() == Qt::WindowType::Tool) {
+ m_panel = panel;
+ break;
+ }
+ panel = panel->parentWidget();
+ }
+ }
}
//-----------------------------------------------------------------------------
@@ -133,6 +150,16 @@ void KeyframeNavigator::hideEvent(QHideEvent *e) {
disconnect(m_frameHandle);
}
+void KeyframeNavigator::onNextKeyframe(QWidget *panel) {
+ if (!m_panel || m_panel != panel) return;
+ toggleNextKeyAct();
+}
+
+void KeyframeNavigator::onPrevKeyframe(QWidget *panel) {
+ if (!m_panel || m_panel != panel) return;
+ togglePrevKeyAct();
+}
+
//=============================================================================
// ViewerKeyframeNavigator
//-----------------------------------------------------------------------------