[krita] /: [4.1 only] Implement frames management action
Dmitry Kazakov
null at kde.org
Tue Apr 10 15:55:59 UTC 2018
Git commit 25cea389c460c37e91867c812ebf39adbe19cb59 by Dmitry Kazakov.
Committed on 10/04/2018 at 15:53.
Pushed by dkazakov into branch 'master'.
[4.1 only] Implement frames management action
The full list of new actions:
1) Insert Keyframe Right
2) Insert Keyframe Left
3) Insert N Keyframes Right
4) Insert N Keyframes Left
5) Remove Frame and Shift
6) Remove Frame
7) Insert Column Right
8) Insert Column Left
9) Insert N Columns Right
10) Insert N Columns Left
11) Remove Column and Shift
12) Remove Column
I will probably change the naming of some actions in the future when
other planned actions like "Add/Remove hold frames" is implemented.
CC:kimageshop at kde.org
M +158 -12 krita/krita.action
M +7 -3 plugins/dockers/animation/kis_animation_utils.cpp
M +1 -0 plugins/dockers/animation/kis_animation_utils.h
M +22 -0 plugins/dockers/animation/kis_time_based_item_model.cpp
M +2 -0 plugins/dockers/animation/kis_time_based_item_model.h
M +0 -10 plugins/dockers/animation/timeline_docker.cpp
M +52 -0 plugins/dockers/animation/timeline_frames_model.cpp
M +2 -0 plugins/dockers/animation/timeline_frames_model.h
M +278 -40 plugins/dockers/animation/timeline_frames_view.cpp
M +25 -3 plugins/dockers/animation/timeline_frames_view.h
M +39 -64 plugins/dockers/animation/timeline_ruler_header.cpp
M +8 -5 plugins/dockers/animation/timeline_ruler_header.h
https://commits.kde.org/krita/25cea389c460c37e91867c812ebf39adbe19cb59
diff --git a/krita/krita.action b/krita/krita.action
index 0deae46fbdf..cdca2e1f2b5 100644
--- a/krita/krita.action
+++ b/krita/krita.action
@@ -2129,18 +2129,6 @@
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
- <Action name="add_blank_frame">
- <icon></icon>
- <text>Add blank frame</text>
- <whatsThis></whatsThis>
- <toolTip>Add blank frame</toolTip>
- <iconText>Add blank frame</iconText>
- <activationFlags>100000</activationFlags>
- <activationConditions>0</activationConditions>
- <shortcut></shortcut>
- <isCheckable>false</isCheckable>
- <statusTip></statusTip>
- </Action>
<Action name="show_in_timeline">
<icon></icon>
<text>Show in Timeline</text>
@@ -2199,6 +2187,164 @@
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
+
+ <Action name="insert_keyframes_right">
+ <icon></icon>
+ <text>Insert Keyframe Right</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert keyframes to the right of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_keyframes_left">
+ <icon></icon>
+ <text>Insert Keyframe Left</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert keyframes to the left of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_n_keyframes_right">
+ <icon></icon>
+ <text>Insert N Keyframes Right</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert several keyframes to the right of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_n_keyframes_left">
+ <icon></icon>
+ <text>Insert N Keyframes Left</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert several keyframes to the left of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="remove_frames_and_shift">
+ <icon></icon>
+ <text>Remove Frame and Shift</text>
+ <whatsThis></whatsThis>
+ <toolTip>Remove keyframes moving the tail of animation to the left</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="remove_frames">
+ <icon></icon>
+ <text>Remove Frame</text>
+ <whatsThis></whatsThis>
+ <toolTip>Just remove keyframes without moving anything around</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_columns_right">
+ <icon></icon>
+ <text>Insert Column Right</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert keyframes to the right of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_columns_left">
+ <icon></icon>
+ <text>Insert Column Left</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert column to the left of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_n_columns_right">
+ <icon></icon>
+ <text>Insert N Columns Right</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert several columns to the right of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="insert_n_columns_left">
+ <icon></icon>
+ <text>Insert N Columns Left</text>
+ <whatsThis></whatsThis>
+ <toolTip>Insert several columns to the left of selection moving the tail of animation to the right</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="remove_columns_and_shift">
+ <icon></icon>
+ <text>Remove Column and Shift</text>
+ <whatsThis></whatsThis>
+ <toolTip>Remove columns moving the tail of animation to the left</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+ <Action name="remove_columns">
+ <icon></icon>
+ <text>Remove Column</text>
+ <whatsThis></whatsThis>
+ <toolTip>Just remove columns without moving anything around</toolTip>
+ <iconText></iconText>
+ <activationFlags>100000</activationFlags>
+ <activationConditions>0</activationConditions>
+ <shortcut></shortcut>
+ <isCheckable>false</isCheckable>
+ <statusTip></statusTip>
+ </Action>
+
+
</Actions>
diff --git a/plugins/dockers/animation/kis_animation_utils.cpp b/plugins/dockers/animation/kis_animation_utils.cpp
index 82979e9b83c..85f61620a3a 100644
--- a/plugins/dockers/animation/kis_animation_utils.cpp
+++ b/plugins/dockers/animation/kis_animation_utils.cpp
@@ -50,12 +50,11 @@ namespace KisAnimationUtils {
const QString removeOpacityKeyframeActionName = i18n("Remove opacity keyframe");
const QString removeTransformKeyframeActionName = i18n("Remove transform keyframe");
- void createKeyframeLazy(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy) {
- KIS_SAFE_ASSERT_RECOVER_RETURN(!image->locked());
-
+ KUndo2Command* createKeyframeCommand(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy, KUndo2Command *parentCommand) {
KUndo2Command *cmd = new KisCommandUtils::LambdaCommand(
copy ? kundo2_i18n("Copy Keyframe") :
kundo2_i18n("Add Keyframe"),
+ parentCommand,
[image, node, channelId, time, copy] () mutable -> KUndo2Command* {
bool result = false;
@@ -101,6 +100,11 @@ namespace KisAnimationUtils {
return result ? new KisCommandUtils::SkipFirstRedoWrapper(cmd.take()) : nullptr;
});
+ return cmd;
+ }
+
+ void createKeyframeLazy(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy) {
+ KUndo2Command *cmd = createKeyframeCommand(image, node, channelId, time, copy);
KisProcessingApplicator::runSingleCommandStroke(image, cmd, KisStrokeJobData::BARRIER);
}
diff --git a/plugins/dockers/animation/kis_animation_utils.h b/plugins/dockers/animation/kis_animation_utils.h
index 902ffca80f2..9b3cd4712f7 100644
--- a/plugins/dockers/animation/kis_animation_utils.h
+++ b/plugins/dockers/animation/kis_animation_utils.h
@@ -25,6 +25,7 @@
namespace KisAnimationUtils
{
+ KUndo2Command* createKeyframeCommand(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy, KUndo2Command *parentCommand = 0);
void createKeyframeLazy(KisImageSP image, KisNodeSP node, const QString &channel, int time, bool copy);
struct FrameItem {
diff --git a/plugins/dockers/animation/kis_time_based_item_model.cpp b/plugins/dockers/animation/kis_time_based_item_model.cpp
index 46705bf75c5..ceb44a88673 100644
--- a/plugins/dockers/animation/kis_time_based_item_model.cpp
+++ b/plugins/dockers/animation/kis_time_based_item_model.cpp
@@ -335,6 +335,28 @@ bool KisTimeBasedItemModel::offsetFrames(QModelIndexList srcIndexes, const QPoin
return cmd;
}
+bool KisTimeBasedItemModel::removeFramesAndOffset(const QModelIndexList &indexes)
+{
+ if (indexes.isEmpty()) return true;
+
+ KUndo2Command *parentCommand = new KUndo2Command(kundo2_i18np("Remove frame and shift", "Remove %1 frames and shift", indexes.size()));
+
+ {
+ KisImageBarrierLockerWithFeedback locker(m_d->image);
+
+ Q_FOREACH (const QModelIndex &index, indexes) {
+ QModelIndexList movedIndexes;
+ for (int column = index.column() + 1; column < columnCount(); column++) {
+ movedIndexes << this->index(index.row(), column);
+ }
+ createOffsetFramesCommand(movedIndexes, QPoint(-1, 0), false, parentCommand);
+ }
+ }
+
+ KisProcessingApplicator::runSingleCommandStroke(m_d->image, parentCommand, KisStrokeJobData::BARRIER);
+ return true;
+}
+
void KisTimeBasedItemModel::slotInternalScrubPreviewRequested(int time)
{
if (m_d->animationPlayer && !m_d->animationPlayer->isPlaying()) {
diff --git a/plugins/dockers/animation/kis_time_based_item_model.h b/plugins/dockers/animation/kis_time_based_item_model.h
index 08428c54fae..25626e82e31 100644
--- a/plugins/dockers/animation/kis_time_based_item_model.h
+++ b/plugins/dockers/animation/kis_time_based_item_model.h
@@ -54,6 +54,8 @@ public:
bool removeFrames(const QModelIndexList &indexes);
bool offsetFrames(QModelIndexList srcIndexes, const QPoint &offset, bool copyFrames);
+ bool removeFramesAndOffset(const QModelIndexList &indexes);
+
void setScrubState(bool active);
void scrubTo(int time, bool preview);
diff --git a/plugins/dockers/animation/timeline_docker.cpp b/plugins/dockers/animation/timeline_docker.cpp
index acff860c8ae..b166ff7db6f 100644
--- a/plugins/dockers/animation/timeline_docker.cpp
+++ b/plugins/dockers/animation/timeline_docker.cpp
@@ -144,16 +144,6 @@ void TimelineDocker::setMainWindow(KisViewManager *view)
{
KisActionManager *actionManager = view->actionManager();
- QMap<QString, KisAction*> actions = m_d->view->globalActions();
-
- QMap<QString, KisAction*>::const_iterator it = actions.constBegin();
- QMap<QString, KisAction*>::const_iterator end = actions.constEnd();
-
- for (; it != end; ++it) {
- actionManager->addAction(it.key(), it.value());
- }
-
m_d->view->setShowInTimeline(actionManager->actionByName("show_in_timeline"));
-
m_d->view->setActionManager(actionManager);
}
diff --git a/plugins/dockers/animation/timeline_frames_model.cpp b/plugins/dockers/animation/timeline_frames_model.cpp
index 65ec9653dc8..6e28cc872ed 100644
--- a/plugins/dockers/animation/timeline_frames_model.cpp
+++ b/plugins/dockers/animation/timeline_frames_model.cpp
@@ -40,6 +40,7 @@
#include "kundo2command.h"
#include "kis_post_execution_undo_adapter.h"
#include <commands/kis_node_property_list_command.h>
+#include <commands_new/kis_switch_current_time_command.h>
#include "kis_animation_utils.h"
#include "timeline_color_scheme.h"
@@ -50,6 +51,9 @@
#include "kis_node_view_color_scheme.h"
#include "krita_utils.h"
#include <QApplication>
+#include "kis_processing_applicator.h"
+#include <KisImageBarrierLockerWithFeedback.h>
+
struct TimelineFramesModel::Private
{
@@ -688,6 +692,54 @@ bool TimelineFramesModel::copyFrame(const QModelIndex &dstIndex)
return m_d->addKeyframe(dstIndex.row(), dstIndex.column(), true);
}
+bool TimelineFramesModel::insertFrames(int dstColumn, const QList<int> &dstRows, int count)
+{
+ if (dstRows.isEmpty() || count <= 0) return true;
+
+ KUndo2Command *parentCommand = new KUndo2Command(kundo2_i18np("Insert frame", "Insert %1 frames", count));
+
+ {
+ KisImageBarrierLockerWithFeedback locker(m_d->image);
+
+ QModelIndexList indexes;
+
+ Q_FOREACH (int row, dstRows) {
+ for (int column = dstColumn; column < columnCount(); column++) {
+ indexes << index(row, column);
+ }
+ }
+
+ setLastVisibleFrame(columnCount() + count - 1);
+
+
+ createOffsetFramesCommand(indexes, QPoint(count, 0), false, parentCommand);
+
+ Q_FOREACH (int row, dstRows) {
+ KisNodeDummy *dummy = m_d->converter->dummyFromRow(row);
+ if (!dummy) continue;
+
+ KisNodeSP node = dummy->node();
+ if (!KisAnimationUtils::supportsContentFrames(node)) continue;
+
+ for (int column = dstColumn; column < dstColumn + count; column++) {
+ KisAnimationUtils::createKeyframeCommand(m_d->image, node, KisKeyframeChannel::Content.id(), column, false, parentCommand);
+ }
+ }
+
+ const int oldTime = m_d->image->animationInterface()->currentUITime();
+ const int newTime = dstColumn > oldTime ? dstColumn : dstColumn + count - 1;
+
+ new KisSwitchCurrentTimeCommand(m_d->image->animationInterface(),
+ oldTime,
+ newTime, parentCommand);
+ }
+
+ KisProcessingApplicator::runSingleCommandStroke(m_d->image, parentCommand, KisStrokeJobData::BARRIER);
+
+ return true;
+}
+
+
QString TimelineFramesModel::audioChannelFileName() const
{
return m_d->image ? m_d->image->animationInterface()->audioChannelFileName() : QString();
diff --git a/plugins/dockers/animation/timeline_frames_model.h b/plugins/dockers/animation/timeline_frames_model.h
index af086b11671..2c7908438fe 100644
--- a/plugins/dockers/animation/timeline_frames_model.h
+++ b/plugins/dockers/animation/timeline_frames_model.h
@@ -51,6 +51,8 @@ public:
bool createFrame(const QModelIndex &dstIndex);
bool copyFrame(const QModelIndex &dstIndex);
+ bool insertFrames(int dstColumn, const QList<int> &dstRows, int count);
+
QString audioChannelFileName() const;
void setAudioChannelFileName(const QString &fileName);
diff --git a/plugins/dockers/animation/timeline_frames_view.cpp b/plugins/dockers/animation/timeline_frames_view.cpp
index d42f1c582d7..d9a769bf9a6 100644
--- a/plugins/dockers/animation/timeline_frames_view.cpp
+++ b/plugins/dockers/animation/timeline_frames_view.cpp
@@ -61,6 +61,7 @@
#include <KoIconToolTip.h>
#include <QStandardPaths>
#include <QWidgetAction>
+#include <QInputDialog>
#include "config-qtmultimedia.h"
@@ -110,12 +111,6 @@ struct TimelineFramesView::Private
QMenu *layerEditingMenu;
QMenu *existingLayersMenu;
- QMenu *frameCreationMenu;
- QMenu *frameEditingMenu;
-
- QMenu *multipleFrameEditingMenu;
- QMap<QString, KisAction*> globalActions;
-
KisZoomButton *zoomDragButton;
bool dragInProgress;
@@ -158,6 +153,15 @@ TimelineFramesView::TimelineFramesView(QWidget *parent)
m_d->horizontalRuler = new TimelineRulerHeader(this);
this->setHorizontalHeader(m_d->horizontalRuler);
+ connect(m_d->horizontalRuler, SIGNAL(sigInsertColumnsLeft()), SLOT(slotInsertColumnsLeft()));
+ connect(m_d->horizontalRuler, SIGNAL(sigInsertColumnsRight()), SLOT(slotInsertColumnsRight()));
+
+ connect(m_d->horizontalRuler, SIGNAL(sigInsertColumnsLeftCustom()), SLOT(slotInsertColumnsLeftCustom()));
+ connect(m_d->horizontalRuler, SIGNAL(sigInsertColumnsRightCustom()), SLOT(slotInsertColumnsRightCustom()));
+
+ connect(m_d->horizontalRuler, SIGNAL(sigRemoveColumns()), SLOT(slotRemoveColumns()));
+ connect(m_d->horizontalRuler, SIGNAL(sigRemoveColumnsAndShift()), SLOT(slotRemoveColumnsAndShift()));
+
m_d->layersHeader = new TimelineLayersHeader(this);
m_d->layersHeader->setSectionResizeMode(QHeaderView::Fixed);
@@ -239,28 +243,16 @@ TimelineFramesView::TimelineFramesView(QWidget *parent)
/********** Frame Editing Context Menu ***********************************************/
- m_d->frameCreationMenu = new QMenu(this);
- m_d->frameCreationMenu->addAction(KisAnimationUtils::addFrameActionName, this, SLOT(slotNewFrame()));
- m_d->frameCreationMenu->addAction(KisAnimationUtils::duplicateFrameActionName, this, SLOT(slotCopyFrame()));
-
m_d->colorSelector = new KisColorLabelSelectorWidget(this);
m_d->colorSelectorAction = new QWidgetAction(this);
m_d->colorSelectorAction->setDefaultWidget(m_d->colorSelector);
connect(m_d->colorSelector, &KisColorLabelSelectorWidget::currentIndexChanged, this, &TimelineFramesView::slotColorLabelChanged);
- m_d->frameEditingMenu = new QMenu(this);
- m_d->frameEditingMenu->addAction(KisAnimationUtils::removeFrameActionName, this, SLOT(slotRemoveFrame()));
- m_d->frameEditingMenu->addAction(m_d->colorSelectorAction);
-
m_d->multiframeColorSelector = new KisColorLabelSelectorWidget(this);
m_d->multiframeColorSelectorAction = new QWidgetAction(this);
m_d->multiframeColorSelectorAction->setDefaultWidget(m_d->multiframeColorSelector);
connect(m_d->multiframeColorSelector, &KisColorLabelSelectorWidget::currentIndexChanged, this, &TimelineFramesView::slotColorLabelChanged);
- m_d->multipleFrameEditingMenu = new QMenu(this);
- m_d->multipleFrameEditingMenu->addAction(KisAnimationUtils::removeFramesActionName, this, SLOT(slotRemoveFrame()));
- m_d->multipleFrameEditingMenu->addAction(m_d->multiframeColorSelectorAction);
-
/********** Zoom Button **************************************************************/
m_d->zoomDragButton = new KisZoomButton(this);
@@ -283,28 +275,61 @@ TimelineFramesView::~TimelineFramesView()
{
}
-QMap<QString, KisAction*> TimelineFramesView::globalActions() const
-{
- return m_d->globalActions;
-}
-
void TimelineFramesView::setShowInTimeline(KisAction* action)
{
m_d->showHideLayerAction = action;
m_d->layerEditingMenu->addAction(m_d->showHideLayerAction);
}
-
void TimelineFramesView::setActionManager( KisActionManager * actionManager)
{
m_d->actionMan = actionManager;
m_d->horizontalRuler->setActionManager(actionManager);
+
+
+ if (actionManager) {
+ KisAction *action = 0;
+
+ // TODO: move here!
+ // "add_blank_frame" is initialized in AnimationDocker
+ // "add_duplicate_frame" is initialized in AnimationDocker
+
+ action = m_d->actionMan->createAction("insert_keyframes_right");
+ connect(action, SIGNAL(triggered()), SLOT(slotInsertKeyframesRight()));
+
+ action = m_d->actionMan->createAction("insert_n_keyframes_right");
+ connect(action, SIGNAL(triggered()), SLOT(slotInsertKeyframesRightCustom()));
+
+ action = m_d->actionMan->createAction("insert_keyframes_left");
+ connect(action, SIGNAL(triggered()), SLOT(slotInsertKeyframesLeft()));
+
+ action = m_d->actionMan->createAction("insert_n_keyframes_left");
+ connect(action, SIGNAL(triggered()), SLOT(slotInsertKeyframesLeftCustom()));
+
+ action = m_d->actionMan->createAction("remove_frames_and_shift");
+ connect(action, SIGNAL(triggered()), SLOT(slotRemoveFramesAndShift()));
+
+ action = m_d->actionMan->createAction("remove_frames");
+ connect(action, SIGNAL(triggered()), SLOT(slotRemoveFrame()));
+ }
}
+void TimelineFramesView::createFrameEditingMenu()
+{
+}
+
+KisAction *TimelineFramesView::addActionToMenu(QMenu *menu, const QString &actionId)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->actionMan, 0);
+ KisAction *action = m_d->actionMan->actionByName(actionId);
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(action, 0);
+ menu->addAction(action);
+ return action;
+}
void resizeToMinimalSize(QAbstractButton *w, int minimalSize) {
QSize buttonSize = w->sizeHint();
@@ -626,7 +651,7 @@ void TimelineFramesView::slotDataChanged(const QModelIndex &topLeft, const QMode
if (selectedColumn != index.column() && !m_d->dragInProgress) {
int row= index.isValid() ? index.row() : 0;
- setCurrentIndex(m_d->model->index(row, selectedColumn));
+ selectionModel()->setCurrentIndex(m_d->model->index(row, selectedColumn), QItemSelectionModel::ClearAndSelect);
}
}
@@ -901,9 +926,41 @@ void TimelineFramesView::mousePressEvent(QMouseEvent *event)
m_d->colorSelector->setCurrentIndex(labelIndex);
}
- m_d->frameEditingMenu->exec(event->globalPos());
+ QMenu menu;
+ addActionToMenu(&menu, "insert_keyframes_right");
+ addActionToMenu(&menu, "insert_keyframes_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "insert_n_keyframes_right");
+ addActionToMenu(&menu, "insert_n_keyframes_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "remove_frames");
+ addActionToMenu(&menu, "remove_frames_and_shift");
+ menu.addSeparator();
+ menu.addAction(m_d->colorSelectorAction);
+ menu.exec(event->globalPos());
+
} else {
- m_d->frameCreationMenu->exec(event->globalPos());
+ {
+ KisSignalsBlocker b(m_d->colorSelector);
+ KisImageConfig cfg;
+ const int labelIndex = cfg.defaultFrameColorLabel();
+ m_d->colorSelector->setCurrentIndex(labelIndex);
+ }
+
+ QMenu menu;
+ addActionToMenu(&menu, "add_blank_frame");
+ addActionToMenu(&menu, "add_duplicate_frame");
+ menu.addSeparator();
+ addActionToMenu(&menu, "insert_keyframes_right");
+ addActionToMenu(&menu, "insert_keyframes_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "insert_n_keyframes_right");
+ addActionToMenu(&menu, "insert_n_keyframes_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "remove_frames_and_shift");
+ menu.addSeparator();
+ menu.addAction(m_d->colorSelectorAction);
+ menu.exec(event->globalPos());
}
} else if (numSelectedItems > 1) {
int labelIndex = -1;
@@ -923,15 +980,27 @@ void TimelineFramesView::mousePressEvent(QMouseEvent *event)
}
}
- if (!haveFrames) {
- m_d->multiframeColorSelectorAction->setVisible(false);
- } else {
+ if (haveFrames) {
KisSignalsBlocker b(m_d->multiframeColorSelector);
m_d->multiframeColorSelector->setCurrentIndex(labelIndex);
- m_d->multiframeColorSelectorAction->setVisible(true);
}
- m_d->multipleFrameEditingMenu->exec(event->globalPos());
+ QMenu menu;
+ addActionToMenu(&menu, "insert_keyframes_right");
+ addActionToMenu(&menu, "insert_keyframes_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "insert_n_keyframes_right");
+ addActionToMenu(&menu, "insert_n_keyframes_left");
+ menu.addSeparator();
+ if (haveFrames) {
+ addActionToMenu(&menu, "remove_frames");
+ }
+ addActionToMenu(&menu, "remove_frames_and_shift");
+ if (haveFrames) {
+ menu.addSeparator();
+ menu.addAction(m_d->multiframeColorSelectorAction);
+ }
+ menu.exec(event->globalPos());
}
} else if (event->button() == Qt::MidButton) {
QModelIndex index = model()->buddy(indexAt(event->pos()));
@@ -1061,6 +1130,8 @@ void TimelineFramesView::slotRemoveLayer()
model()->removeRow(index.row());
}
+
+// TODO: this method is unused atm, please forward the actions from Animation Docker here!
void TimelineFramesView::slotNewFrame()
{
QModelIndex index = currentIndex();
@@ -1073,6 +1144,7 @@ void TimelineFramesView::slotNewFrame()
m_d->model->createFrame(index);
}
+// TODO: this method is unused atm, please forward the actions from Animation Docker here!
void TimelineFramesView::slotCopyFrame()
{
QModelIndex index = currentIndex();
@@ -1085,23 +1157,189 @@ void TimelineFramesView::slotCopyFrame()
m_d->model->copyFrame(index);
}
-void TimelineFramesView::slotRemoveFrame()
+void TimelineFramesView::calculateSelectionMetrics(int &minColumn, int &maxColumn, QSet<int> &rows)
{
- QModelIndexList indexes = selectionModel()->selectedIndexes();
+ minColumn = std::numeric_limits<int>::max();
+ maxColumn = std::numeric_limits<int>::min();
- for (auto it = indexes.begin(); it != indexes.end(); /*noop*/) {
- if (!m_d->model->data(*it, TimelineFramesModel::FrameEditableRole).toBool()) {
- it = indexes.erase(it);
- } else {
- ++it;
+ Q_FOREACH (const QModelIndex &index, selectionModel()->selectedIndexes()) {
+ if (!m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) continue;
+
+ rows.insert(index.row());
+ minColumn = qMin(minColumn, index.column());
+ maxColumn = qMax(maxColumn, index.column());
+ }
+}
+
+void TimelineFramesView::insertFramesImpl(int insertAtColumn, int count, QSet<int> rows, bool forceEntireColumn)
+{
+ if (forceEntireColumn) {
+ rows.clear();
+ for (int i = 0; i < m_d->model->rowCount(); i++) {
+ if (!m_d->model->data(m_d->model->index(i, insertAtColumn), TimelineFramesModel::FrameEditableRole).toBool()) continue;
+ rows.insert(i);
+ }
+ }
+
+ if (!rows.isEmpty()) {
+ m_d->model->insertFrames(insertAtColumn, rows.toList(), count);
+ }
+}
+
+void TimelineFramesView::slotInsertKeyframesLeft(int count, bool forceEntireColumn)
+{
+ QSet<int> rows;
+ int minColumn = 0;
+ int maxColumn = 0;
+
+ calculateSelectionMetrics(minColumn, maxColumn, rows);
+
+ if (count <= 0) {
+ count = qMax(1, maxColumn - minColumn + 1);
+ }
+
+ insertFramesImpl(minColumn, count, rows, forceEntireColumn);
+}
+
+void TimelineFramesView::slotInsertKeyframesRight(int count, bool forceEntireColumn)
+{
+ QSet<int> rows;
+ int minColumn = 0;
+ int maxColumn = 0;
+
+ calculateSelectionMetrics(minColumn, maxColumn, rows);
+
+ if (count <= 0) {
+ count = qMax(1, maxColumn - minColumn + 1);
+ }
+
+ insertFramesImpl(maxColumn + 1, count, rows, forceEntireColumn);
+}
+
+void TimelineFramesView::slotInsertColumnsLeft(int count)
+{
+ slotInsertKeyframesLeft(count, true);
+}
+
+void TimelineFramesView::slotInsertColumnsRight(int count)
+{
+ slotInsertKeyframesRight(count, true);
+}
+
+void TimelineFramesView::slotInsertKeyframesLeftCustom()
+{
+ bool ok = false;
+
+ // TODO: save previous entered value till the end of the session
+ const int count = QInputDialog::getInt(this,
+ i18nc("@title:window", "Insert left"),
+ i18nc("@label:spinbox", "Enter number of frames"),
+ 1, 1, 10000, 1, &ok);
+
+ if (ok) {
+ slotInsertKeyframesLeft(count);
+ }
+}
+
+
+void TimelineFramesView::slotInsertKeyframesRightCustom()
+{
+ bool ok = false;
+
+ // TODO: save previous entered value till the end of the session
+ const int count = QInputDialog::getInt(this,
+ i18nc("@title:window", "Insert right"),
+ i18nc("@label:spinbox", "Enter number of frames"),
+ 1, 1, 10000, 1, &ok);
+
+ if (ok) {
+ slotInsertKeyframesRight(count);
+ }
+}
+
+void TimelineFramesView::slotInsertColumnsLeftCustom()
+{
+ bool ok = false;
+
+ // TODO: save previous entered value till the end of the session
+ const int count = QInputDialog::getInt(this,
+ i18nc("@title:window", "Insert left"),
+ i18nc("@label:spinbox", "Enter number of columns"),
+ 1, 1, 10000, 1, &ok);
+
+ if (ok) {
+ slotInsertColumnsLeft(count);
+ }
+}
+
+
+void TimelineFramesView::slotInsertColumnsRightCustom()
+{
+ bool ok = false;
+
+ // TODO: save previous entered value till the end of the session
+ const int count = QInputDialog::getInt(this,
+ i18nc("@title:window", "Insert right"),
+ i18nc("@label:spinbox", "Enter number of columns"),
+ 1, 1, 10000, 1, &ok);
+
+ if (ok) {
+ slotInsertColumnsRight(count);
+ }
+}
+
+void TimelineFramesView::slotRemoveFrame(bool forceEntireColumn, bool needsOffset)
+{
+ QModelIndexList indexes;
+
+ if (forceEntireColumn) {
+ QSet<int> rows;
+ int minColumn = 0;
+ int maxColumn = 0;
+
+ calculateSelectionMetrics(minColumn, maxColumn, rows);
+
+ rows.clear();
+ for (int i = 0; i < m_d->model->rowCount(); i++) {
+ if (!m_d->model->data(m_d->model->index(i, minColumn), TimelineFramesModel::FrameEditableRole).toBool()) continue;
+
+ for (int column = minColumn; column <= maxColumn; column++) {
+ indexes << m_d->model->index(i, column);
+ }
+ }
+ } else {
+ Q_FOREACH (const QModelIndex &index, selectionModel()->selectedIndexes()) {
+ if (m_d->model->data(index, TimelineFramesModel::FrameEditableRole).toBool()) {
+ indexes << index;
+ }
}
}
if (!indexes.isEmpty()) {
- m_d->model->removeFrames(indexes);
+ if (needsOffset) {
+ m_d->model->removeFramesAndOffset(indexes);
+ } else {
+ m_d->model->removeFrames(indexes);
+ }
}
}
+void TimelineFramesView::slotRemoveColumns()
+{
+ slotRemoveFrame(true);
+}
+
+void TimelineFramesView::slotRemoveFramesAndShift(bool forceEntireColumn)
+{
+ slotRemoveFrame(forceEntireColumn, true);
+}
+
+void TimelineFramesView::slotRemoveColumnsAndShift()
+{
+ slotRemoveFramesAndShift(true);
+}
+
+
bool TimelineFramesView::viewportEvent(QEvent *event)
{
if (event->type() == QEvent::ToolTip && model()) {
diff --git a/plugins/dockers/animation/timeline_frames_view.h b/plugins/dockers/animation/timeline_frames_view.h
index 4742154ff5f..1290068e81e 100644
--- a/plugins/dockers/animation/timeline_frames_view.h
+++ b/plugins/dockers/animation/timeline_frames_view.h
@@ -39,8 +39,6 @@ public:
void updateGeometries() override;
- QMap<QString, KisAction*> globalActions() const;
-
void setShowInTimeline(KisAction *action);
void setActionManager( KisActionManager * actionManager);
@@ -62,7 +60,25 @@ private Q_SLOTS:
void slotNewFrame();
void slotCopyFrame();
- void slotRemoveFrame();
+
+
+ void slotInsertKeyframesLeft(int count = -1, bool forceEntireColumn = false);
+ void slotInsertKeyframesRight(int count = -1, bool forceEntireColumn = false);
+
+ void slotInsertKeyframesLeftCustom();
+ void slotInsertKeyframesRightCustom();
+
+ void slotRemoveFrame(bool forceEntireColumn = false, bool needsOffset = false);
+ void slotRemoveFramesAndShift(bool forceEntireColumn = false);
+
+ void slotInsertColumnsLeft(int count = -1);
+ void slotInsertColumnsLeftCustom();
+
+ void slotInsertColumnsRight(int count = -1);
+ void slotInsertColumnsRightCustom();
+
+ void slotRemoveColumns();
+ void slotRemoveColumnsAndShift();
void slotReselectCurrentIndex();
@@ -85,6 +101,12 @@ private Q_SLOTS:
private:
void setFramesPerSecond(int fps);
+ void calculateSelectionMetrics(int &minColumn, int &maxColumn, QSet<int> &rows);
+
+ void createFrameEditingMenu();
+
+ KisAction* addActionToMenu(QMenu *menu, const QString &actionId);
+ void insertFramesImpl(int insertAtColumn, int count, QSet<int> rows, bool forceEntireColumn);
protected:
QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index,
diff --git a/plugins/dockers/animation/timeline_ruler_header.cpp b/plugins/dockers/animation/timeline_ruler_header.cpp
index 95588f29ed6..67df7dedc63 100644
--- a/plugins/dockers/animation/timeline_ruler_header.cpp
+++ b/plugins/dockers/animation/timeline_ruler_header.cpp
@@ -39,12 +39,6 @@ struct TimelineRulerHeader::Private
int fps;
- QMenu *columnEditingMenu;
- KisAction *insertLeftAction;
- KisAction *insertRightAction;
- KisAction *removeAction;
- KisAction *clearAction;
-
KisTimeBasedItemModel *model;
int lastPressSectionIndex;
@@ -76,24 +70,27 @@ void TimelineRulerHeader::setActionManager( KisActionManager * actionManager)
{
m_d->actionMan = actionManager;
- m_d->insertLeftAction = actionManager->createAction("insert_n_frames_left");
- connect(m_d->insertLeftAction, SIGNAL(triggered()), SLOT(slotInsertColumnLeft()));
+ if (actionManager) {
+ KisAction *action;
+
+ action = actionManager->createAction("insert_columns_right");
+ connect(action, SIGNAL(triggered()), SIGNAL(sigInsertColumnsRight()));
- m_d->insertRightAction = actionManager->createAction("insert_n_frames_right");
- connect(m_d->insertRightAction, SIGNAL(triggered()), SLOT(slotInsertColumnRight()));
+ action = actionManager->createAction("insert_n_columns_right");
+ connect(action, SIGNAL(triggered()), SIGNAL(sigInsertColumnsRightCustom()));
- m_d->clearAction = actionManager->createAction("clear_animation_columns");
- connect(m_d->clearAction, SIGNAL(triggered()), SLOT(slotClearColumns()));
+ action = actionManager->createAction("insert_columns_left");
+ connect(action, SIGNAL(triggered()), SIGNAL(sigInsertColumnsLeft()));
- m_d->removeAction = actionManager->createAction("remove_animation_columns");
- connect(m_d->removeAction, SIGNAL(triggered()), SLOT(slotRemoveColumns()));
+ action = actionManager->createAction("insert_n_columns_left");
+ connect(action, SIGNAL(triggered()), SIGNAL(sigInsertColumnsLeftCustom()));
+ action = actionManager->createAction("remove_columns_and_shift");
+ connect(action, SIGNAL(triggered()), SIGNAL(sigRemoveColumnsAndShift()));
- m_d->columnEditingMenu = new QMenu(this);
- m_d->columnEditingMenu->addAction(static_cast<QAction*>(m_d->insertLeftAction));
- m_d->columnEditingMenu->addAction(static_cast<QAction*>(m_d->insertRightAction));
- m_d->columnEditingMenu->addAction(static_cast<QAction*>(m_d->clearAction));
- m_d->columnEditingMenu->addAction(static_cast<QAction*>(m_d->removeAction));
+ action = actionManager->createAction("remove_columns");
+ connect(action, SIGNAL(triggered()), SIGNAL(sigRemoveColumns()));
+ }
}
@@ -403,6 +400,19 @@ int getColumnCount(const QModelIndexList &indexes, int *leftmostCol, int *rightm
return columns.size();
}
+KisAction *TimelineRulerHeader::addActionToMenu(QMenu *menu, const QString &actionId)
+{
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->actionMan, 0);
+
+ KisAction *action = m_d->actionMan->actionByName(actionId);
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(action, 0);
+
+ menu->addAction(action);
+
+ return action;
+}
+
+
void TimelineRulerHeader::mousePressEvent(QMouseEvent *e)
{
int logical = logicalIndexAt(e->pos());
@@ -415,13 +425,18 @@ void TimelineRulerHeader::mousePressEvent(QMouseEvent *e)
model()->setHeaderData(logical, orientation(), true, KisTimeBasedItemModel::ActiveFrameRole);
}
+ QMenu menu;
+ addActionToMenu(&menu, "insert_columns_right");
+ addActionToMenu(&menu, "insert_columns_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "insert_n_columns_right");
+ addActionToMenu(&menu, "insert_n_columns_left");
+ menu.addSeparator();
+ addActionToMenu(&menu, "remove_columns");
+ addActionToMenu(&menu, "remove_columns_and_shift");
- m_d->insertLeftAction->setText(i18n("Insert %1 left", numSelectedColumns));
- m_d->insertRightAction->setText(i18n("Insert %1 right", numSelectedColumns));
- m_d->clearAction->setText(i18n("Clear %1 columns", numSelectedColumns));
- m_d->removeAction->setText(i18n("Remove %1 columns", numSelectedColumns));
+ menu.exec(e->globalPos());
- m_d->columnEditingMenu->exec(e->globalPos());
return;
} else if (e->button() == Qt::LeftButton) {
@@ -486,43 +501,3 @@ QModelIndexList TimelineRulerHeader::Private::prepareFramesSlab(int startCol, in
return frames;
}
-
-void TimelineRulerHeader::slotInsertColumnLeft()
-{
- QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
- int leftmostCol = 0, rightmostCol = 0;
- int numColumns = getColumnCount(selectedIndexes, &leftmostCol, &rightmostCol);
-
- QModelIndexList movingFrames = m_d->prepareFramesSlab(leftmostCol, m_d->model->columnCount() - 1);
- m_d->model->offsetFrames(movingFrames, QPoint(numColumns, 0), false);
-}
-
-void TimelineRulerHeader::slotInsertColumnRight()
-{
- QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
- int leftmostCol = 0, rightmostCol = 0;
- int numColumns = getColumnCount(selectedIndexes, &leftmostCol, &rightmostCol);
-
- QModelIndexList movingFrames = m_d->prepareFramesSlab(rightmostCol + 1, m_d->model->columnCount() - 1);
- m_d->model->offsetFrames(movingFrames, QPoint(numColumns, 0), false);
-}
-
-void TimelineRulerHeader::slotClearColumns(bool removeColumns)
-{
- QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
- int leftmostCol = 0, rightmostCol = 0;
- int numColumns = getColumnCount(selectedIndexes, &leftmostCol, &rightmostCol);
-
- QModelIndexList movingFrames = m_d->prepareFramesSlab(leftmostCol, rightmostCol);
- m_d->model->removeFrames(movingFrames);
-
- if (removeColumns) {
- QModelIndexList movingFrames = m_d->prepareFramesSlab(rightmostCol + 1, m_d->model->columnCount() - 1);
- m_d->model->offsetFrames(movingFrames, QPoint(-numColumns, 0), false);
- }
-}
-
-void TimelineRulerHeader::slotRemoveColumns()
-{
- slotClearColumns(true);
-}
diff --git a/plugins/dockers/animation/timeline_ruler_header.h b/plugins/dockers/animation/timeline_ruler_header.h
index f0bd04b72fa..818015564db 100644
--- a/plugins/dockers/animation/timeline_ruler_header.h
+++ b/plugins/dockers/animation/timeline_ruler_header.h
@@ -50,6 +50,7 @@ protected:
void changeEvent(QEvent *event) override;
private:
+ KisAction *addActionToMenu(QMenu *menu, const QString &actionId);
void updateMinimumSize();
void paintSpan(QPainter *painter, int userFrameId,
@@ -60,11 +61,13 @@ private:
const QPalette &palette,
const QPen &gridPen) const;
-private Q_SLOTS:
- void slotInsertColumnLeft();
- void slotInsertColumnRight();
- void slotClearColumns(bool removeColumns = false);
- void slotRemoveColumns();
+Q_SIGNALS:
+ void sigInsertColumnsLeft();
+ void sigInsertColumnsRight();
+ void sigInsertColumnsLeftCustom();
+ void sigInsertColumnsRightCustom();
+ void sigRemoveColumns();
+ void sigRemoveColumnsAndShift();
private:
struct Private;
More information about the kimageshop
mailing list