39#include "klocalizedstring.h"
55#include <QItemSelection>
86 sbSpeed->setPrefix(i18nc(
"preview playback speed percentage prefix",
"Speed: "));
88 sbSpeed->setToolTip(i18n(
"Preview playback speed"));
95 QWidget *widget =
new QWidget(
this);
96 QHBoxLayout *layout =
new QHBoxLayout(widget);
97 layout->setSpacing(0);
98 layout->setContentsMargins(0,0,0,0);
147 btnZoomHori->setToolTip(i18n(
"Zoom horizontally"));
161 QWidget *widget =
new QWidget(
this);
163 QHBoxLayout *layout =
new QHBoxLayout(widget);
164 layout->setSpacing(0);
191 QWidget *settingsMenuWidget =
new QWidget(
this);
192 QHBoxLayout *settingsMenuLayout =
new QHBoxLayout(settingsMenuWidget);
194 QWidget *fields =
new QWidget(settingsMenuWidget);
195 QFormLayout *fieldsLayout =
new QFormLayout(fields);
199 fieldsLayout->addRow(i18n(
"Clip Start: "),
sbStartFrame);
203 fieldsLayout->addRow(i18n(
"Clip End: "),
sbEndFrame);
208 fieldsLayout->addRow(i18n(
"Frame Rate: "),
sbFrameRate);
210 QWidget *
buttons =
new QWidget(settingsMenuWidget);
211 QVBoxLayout *buttonsLayout =
new QVBoxLayout(
buttons);
212 buttonsLayout->setAlignment(Qt::AlignTop);
214 settingsMenuLayout->addWidget(fields);
215 settingsMenuLayout->addWidget(
buttons);
219 QMenu *settingsPopMenu =
new QMenu(
this);
220 QWidgetAction *settingsMenuAction =
new QWidgetAction(
this);
221 settingsMenuAction->setDefaultWidget(settingsMenuWidget);
222 settingsPopMenu->addAction(settingsMenuAction);
264 : QDockWidget(i18n(
"Animation Curves"))
267 QWidget *mainWidget =
new QWidget(0);
268 mainWidget->setLayout(
new QVBoxLayout());
269 setWidget(mainWidget);
271 QSplitter *mainSplitter =
new QSplitter(
this);
272 mainWidget->layout()->addWidget(mainSplitter);
275 m_d->channelTreeView->setModel(
m_d->channelTreeModel);
276 m_d->channelTreeView->setHeaderHidden(
true);
278 m_d->channelTreeView->setItemDelegate(listDelegate);
281 m_d->channelTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
284 m_d->channelTreeMenuChannels->addSection(i18n(
"Channel Operations"));
285 m_d->channelTreeMenuLayers->addSection(i18n(
"Layer Operations"));
288 QAction* action =
new QAction(i18n(
"Reset Channel"),
this);
290 m_d->channelTreeMenuChannels->addAction(action);
294 QAction* action =
new QAction(i18n(
"Reset All Channels"),
this);
296 m_d->channelTreeMenuLayers->addAction(action);
301 m_d->curvesView->setModel(
m_d->curvesModel);
304 mainSplitter->addWidget(
m_d->channelTreeView);
305 mainSplitter->setStretchFactor(0, 1);
306 mainSplitter->addWidget(
m_d->curvesView);
307 mainSplitter->setStretchFactor(1, 10);
312 connect(scroller, SIGNAL(stateChanged(QScroller::State)),
316 connect(
m_d->channelTreeModel, &KisAnimCurvesChannelsModel::rowsInserted,
320 setTitleBarWidget(
m_d->titlebar);
323 connect(
m_d->titlebar->btnOnionSkinsMenu, &QToolButton::released, [
this](){
324 if (m_d->mainWindow) {
325 QDockWidget *docker = m_d->mainWindow->dockWidget(
"OnionSkinsDocker");
327 docker->setVisible(!docker->isVisible());
333 if (m_d->curvesView) {
334 m_d->curvesView->changeZoom(Qt::Horizontal, zoomDelta);
339 if (m_d->curvesView) {
340 m_d->curvesView->changeZoom(Qt::Vertical, zoomDelta);
344 connect(m_d->curvesView, SIGNAL(activated(QModelIndex)),
this, SLOT(slotActiveNodeUpdate(QModelIndex)));
345 connect(m_d->curvesView, SIGNAL(activeDataChanged(QModelIndex)),
this, SLOT(slotActiveNodeUpdate(QModelIndex)));
346 connect(m_d->titlebar->sbValueRegister, SIGNAL(valueChanged(
double)),
this, SLOT(slotValueRegisterChanged(
double)));
350 connectControl(m_d->titlebar->sbSpeed, &m_d->controlsModel,
"playbackSpeedDenorm");
363 if (canvas &&
m_d->
canvas == canvas)
return;
366 m_d->canvasConnections.clear();
367 m_d->canvas->disconnectCanvasObserver(
this);
369 m_d->canvas->animationState()->disconnect(
this);
370 m_d->titlebar->transport->disconnect(
m_d->canvas->animationState());
371 m_d->titlebar->transport->setPlaying(
false);
372 m_d->titlebar->sbFrameRegister->disconnect(
m_d->canvas->animationState());
374 if (
m_d->canvas->image()) {
375 m_d->canvas->image()->animationInterface()->disconnect(
this);
376 m_d->titlebar->sbStartFrame->disconnect(
m_d->canvas->image()->animationInterface());
377 m_d->titlebar->sbEndFrame->disconnect(
m_d->canvas->image()->animationInterface());
378 m_d->titlebar->sbFrameRate->disconnect(
m_d->canvas->image()->animationInterface());
381 m_d->curvesModel->setImage(0);
385 setEnabled(
m_d->canvas != 0);
390 m_d->channelTreeModel->setDummiesFacade(kritaShapeController);
393 m_d->curvesModel->setFrameCache(
m_d->canvas->frameCache());
394 m_d->curvesModel->setAnimationPlayer(
m_d->canvas->animationState());
396 m_d->canvasConnections.addConnection(
397 m_d->canvas->viewManager()->nodeManager(), SIGNAL(sigUiNeedChangeSelectedNodes(
KisNodeList)),
401 m_d->canvasConnections.addConnection(
402 m_d->canvas->viewManager()->nodeManager(), SIGNAL(sigNodeActivated(
KisNodeSP)),
406 m_d->channelTreeModel->clear();
407 m_d->channelTreeModel->selectedNodesChanged(
m_d->canvas->viewManager()->nodeManager()->selectedNodes());
411 m_d->titlebar->sbEndFrame,
412 m_d->titlebar->sbFrameRate,
413 m_d->titlebar->sbFrameRegister,
414 m_d->titlebar->sbValueRegister);
419 m_d->titlebar->sbFrameRate->setValue(animinterface->
framerate());
420 m_d->titlebar->sbFrameRegister->setValue(animinterface->
currentTime());
422 QModelIndex activeIndex =
m_d->curvesView->currentIndex();
423 m_d->titlebar->sbValueRegister->setEnabled(activeIndex.isValid());
424 m_d->titlebar->sbValueRegister->setValue( activeIndex.isValid() ?
430 connect(
m_d->titlebar->sbFrameRate, SIGNAL(valueChanged(
int)),
m_d->canvas->image()->animationInterface(), SLOT(setFramerate(
int)));
431 connect(
m_d->titlebar->sbStartFrame, SIGNAL(valueChanged(
int)),
m_d->canvas->image()->animationInterface(), SLOT(setDocumentRangeStartFrame(
int)));
432 connect(
m_d->titlebar->sbEndFrame, SIGNAL(valueChanged(
int)),
m_d->canvas->image()->animationInterface(), SLOT(setDocumentRangeEndFrame(
int)));
435 m_d->titlebar->transport->setPlaying(p_state == PlaybackState::PLAYING);
436 m_d->titlebar->sbFrameRegister->setDisabled(p_state == PlaybackState::PLAYING);
438 if (p_state == PlaybackState::STOPPED) {
439 updateFrameRegister();
448 if (!m_d->canvas || !m_d->canvas->image()) return;
450 KisImageAnimationInterface *animInterface = m_d->canvas->image()->animationInterface();
452 m_d->titlebar->sbStartFrame->setValue(animInterface->documentPlaybackRange().start());
453 m_d->titlebar->sbEndFrame->setValue(animInterface->documentPlaybackRange().end());
458 m_d->controlsModel.connectAnimationState(
m_d->canvas->animationState());
478 connect(action, SIGNAL(triggered(
bool)),
480 m_d->titlebar->btnAddKey->setDefaultAction(action);
481 m_d->titlebar->btnAddKey->setIconSize(QSize(22, 22));
483 action = actionManager->
createAction(
"remove_scalar_keyframe");
485 connect(action, SIGNAL(triggered(
bool)),
487 m_d->titlebar->btnRemoveKey->setDefaultAction(action);
488 m_d->titlebar->btnRemoveKey->setIconSize(QSize(22, 22));
490 action = actionManager->
createAction(
"interpolation_constant");
492 action->setToolTip(i18n(
"Hold constant value. No interpolation."));
493 connect(action, &KisAction::triggered,
495 m_d->titlebar->btnGroupInterpolation->addAction(action);
497 action = actionManager->
createAction(
"interpolation_linear");
499 action->setToolTip(i18n(
"Linear interpolation."));
500 connect(action, &KisAction::triggered,
502 m_d->titlebar->btnGroupInterpolation->addAction(action);
504 action = actionManager->
createAction(
"interpolation_bezier");
506 action->setToolTip(i18n(
"Bezier curve interpolation."));
507 connect(action, &KisAction::triggered,
509 m_d->titlebar->btnGroupInterpolation->addAction(action);
513 action->setToolTip(i18n(
"Sharp interpolation tangents."));
514 connect(action, &KisAction::triggered,
516 m_d->titlebar->btnGroupTangents->addAction(action);
518 action = actionManager->
createAction(
"tangents_smooth");
520 action->setToolTip(i18n(
"Smooth interpolation tangents."));
521 connect(action, &KisAction::triggered,
523 m_d->titlebar->btnGroupTangents->addAction(action);
525 action = actionManager->
createAction(
"zoom_to_fit_range");
527 action->setToolTip(i18n(
"Zoom view to fit channel range."));
528 connect(action, &KisAction::triggered,
530 m_d->titlebar->btnGroupZoomFit->addAction(action);
532 action = actionManager->
createAction(
"zoom_to_fit_curve");
534 action->setToolTip(i18n(
"Zoom view to fit curve."));
535 connect(action, &KisAction::triggered,
537 m_d->titlebar->btnGroupZoomFit->addAction(action);
541 m_d->titlebar->btnDropFrames->setDefaultAction(action);
542 m_d->titlebar->btnDropFrames->setIconSize(QSize(22, 22));
545 connectControl(action, &
m_d->controlsModel,
"dropFramesMode");
551 if (!playbackEngine)
return;
554 connect(
m_d->titlebar->transport, SIGNAL(skipBack()), playbackEngine, SLOT(previousKeyframe()));
555 connect(
m_d->titlebar->transport, SIGNAL(back()), playbackEngine, SLOT(previousFrame()));
556 connect(
m_d->titlebar->transport, SIGNAL(stop()), playbackEngine, SLOT(stop()));
557 connect(
m_d->titlebar->transport, SIGNAL(playPause()), playbackEngine, SLOT(playPause()));
558 connect(
m_d->titlebar->transport, SIGNAL(forward()), playbackEngine, SLOT(nextFrame()));
559 connect(
m_d->titlebar->transport, SIGNAL(skipForward()), playbackEngine, SLOT(nextKeyframe()));
561 connect(
m_d->titlebar->sbFrameRegister, SIGNAL(valueChanged(
int)), playbackEngine, SLOT(seek(
int)));
563 m_d->controlsModel.connectPlaybackEngine(playbackEngine);
568 if (!
m_d->canvas)
return;
579 if (!
m_d->canvas)
return;
590 if (!
m_d->canvas)
return;
595 QItemSelectionModel* selectionModel =
m_d->curvesView->selectionModel();
598 if (selected.count() > 0) {
599 Q_FOREACH(
const QModelIndex& selection, selected) {
603 const int time =
m_d->canvas->image()->animationInterface()->currentTime();
626 m_d->titlebar->btnAddKey->setEnabled(supported);
630 if (!
m_d->canvas && !
m_d->canvas->image()) {
634 const int frame =
m_d->canvas->animationState()->displayProxy()->activeFrame();
636 QSignalBlocker blocker(
m_d->titlebar->sbFrameRegister);
637 m_d->titlebar->sbFrameRegister->setValue(frame);
642 if (!
m_d->canvas || !
m_d->canvas->image())
return;
645 m_d->titlebar->sbFrameRate->setValue(animInterface->
framerate());
679 Q_FOREACH(
const KoID& koid, ids ) {
685 if (
m_d->canvas &&
m_d->canvas->image()) {
713 QItemSelectionModel* selectionModel =
m_d->curvesView->selectionModel();
718 if (selected.count() > 0) {
719 Q_FOREACH(
const QModelIndex& selection, selected) {
725 const QString identifier = data.toString();
726 const int time = selection.column();
730 const int time =
m_d->canvas->image()->animationInterface()->currentTime();
731 for(
int channelIndex = 0; channelIndex <
m_d->curvesModel->rowCount(); channelIndex++) {
732 QModelIndex chanIndex =
m_d->curvesModel->index(channelIndex, time);
733 if (!chanIndex.isValid())
740 const QString identifier = data.toString();
745 if (
m_d->canvas &&
m_d->canvas->image()) {
765 for (
int r=first; r<=last; r++) {
766 QModelIndex index =
m_d->channelTreeModel->index(r, 0, parentIndex);
767 m_d->channelTreeView->expand(index);
772 if (!
m_d->curvesModel)
775 QModelIndex current =
m_d->curvesView->currentIndex();
777 if (current.isValid() &&
m_d->curvesView->indexHasKey(current)) {
786 if (index.isValid() &&
m_d->curvesView->indexHasKey(index)) {
788 m_d->titlebar->sbValueRegister->setEnabled(variant.isValid());
789 m_d->titlebar->sbValueRegister->setValue(variant.isValid() ? variant.toReal() : 0.0);
791 m_d->titlebar->sbValueRegister->setEnabled(
false);
797 if (
m_d->channelTreeView->selectionModel()->selectedIndexes().size() == 0) {
800 QModelIndex selected =
m_d->channelTreeView->selectionModel()->selectedIndexes().first();
803 m_d->channelTreeMenuChannels->popup(
m_d->channelTreeView->mapToGlobal(point));
805 m_d->channelTreeMenuLayers->popup(
m_d->channelTreeView->mapToGlobal(point));
812 Q_FOREACH(
const QModelIndex& index, selected) {
813 m_d->channelTreeModel->reset(index);
float value(const T *src, size_t ch)
QList< QModelIndex > QModelIndexList
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
A KisActionManager class keeps track of KisActions. These actions are always associated with the GUI....
KisAction * createAction(const QString &name)
A customized titlebar for the Animation Curves Docker that's packed with useful widgets and menus.
KisIntParseSpinBox * sbStartFrame
KisIntParseSpinBox * sbFrameRate
QToolButton * btnAudioMenu
QToolButton * btnDropFrames
QToolButton * btnOnionSkinsMenu
KisCollapsibleButtonGroup * btnGroupTangents
QToolButton * btnRemoveKey
KisCollapsibleButtonGroup * btnGroupZoomFit
KisIntParseSpinBox * sbFrameRegister
KisTransportControls * transport
KisSliderSpinBox * sbSpeed
KisDoubleParseSpinBox * sbValueRegister
QToolButton * btnSettingsMenu
KisZoomButton * btnZoomHori
KisAnimCurvesDockerTitlebar(QWidget *parent=nullptr)
KisIntParseSpinBox * sbEndFrame
KisCollapsibleButtonGroup * btnGroupInterpolation
KisZoomButton * btnZoomVert
void setCanvas(KoCanvasBase *canvas) override
void slotListRowsInserted(const QModelIndex &parentIndex, int first, int last)
const QScopedPointer< Private > m_d
void resetChannelTreeSelection()
void setViewManager(KisViewManager *kisview) override
void slotActiveNodeUpdate(const QModelIndex index)
void unsetCanvas() override
void handleFrameRateChange()
void addKeyframeQuick(const QString &channelIdentity)
void setPlaybackEngine(KisPlaybackEngine *playbackEngine)
void removeKeyframe(const QString &channel)
void slotAddAllEnabledKeys()
void requestChannelMenuAt(const QPoint &point)
void slotRemoveOpacityKey()
void slotNodeActivated(KisNodeSP node)
void slotRemoveSelectedKeys()
void addKeyframeCommandToParent(const QString &channelIdentity, KUndo2Command *parentCMD)
void slotScrollerStateChanged(QScroller::State state)
void slotValueRegisterChanged(double value)
void updateFrameRegister()
~KisAnimCurvesDocker() override
KisImageWSP image() const
KisViewManager * viewManager() const
void sigPlaybackStateChanged(PlaybackState state)
KisShapeController * shapeController
The KisDoubleParseSpinBox class is a cleverer doubleSpinBox, able to parse arithmetic expressions.
KisImageWSP image() const
void sigPlaybackRangeChanged()
const KisTimeSpan & documentPlaybackRange() const
documentPlaybackRange
KisImageAnimationInterface * animationInterface() const
The KisIntParseSpinBox class is a cleverer SpinBox, able to parse arithmetic expressions.
static const KoID RotationY
static const KoID RotationZ
static const KoID Opacity
static const KoID RotationX
static const KoID PositionX
static const KoID PositionY
static KisPart * instance()
void playbackEngineChanged(KisPlaybackEngine *newPlaybackEngine)
Krita's base animation playback engine for producing image frame changes and associated audio.
static void runSingleCommandStroke(KisImageSP image, KUndo2Command *cmd, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
runSingleCommandStroke creates a stroke and runs cmd in it. The text() field of cmd is used as a titl...
void setImage(KisImageWSP image, KisNodeSP activeNode) override
This class is a spinbox in which you can click and drag to set the value. A slider like bar is displa...
void setValue(int newValue)
void setRange(int newMinimum, int newMaximum, bool computeNewFastSliderStep=true)
Set the minimum and the maximum values of the range, computing a new "fast slider step" based on the ...
The KisTransportControls class provides a simple, reusable widget for common transport controls,...
A special utility titlebar with a title and controls, as well as a central area for adding frequently...
QHBoxLayout * widgetAreaLayout
KisMainWindow * mainWindow() const
KisActionManager * actionManager() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
QString buttons(const T &ev)
QList< KisNodeSP > KisNodeList
KUndo2MagicString kundo2_i18n(const char *text)
void removeKeyframes(KisImageSP image, const FrameItemList &frames)
void createKeyframeLazy(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy)
void removeKeyframe(KisImageSP image, KisNodeSP node, const QString &channel, int time)
KUndo2Command * createKeyframeCommand(KisImageSP image, KisNodeSP node, const QString &channelId, int time, bool copy, KUndo2Command *parentCommand)
QIcon loadIcon(const QString &name)
QMenu * channelTreeMenuChannels
KisAnimCurvesChannelsModel * channelTreeModel
QTreeView * channelTreeView
QPointer< KisCanvas2 > canvas
KisAnimationPlaybackControlsModel controlsModel
KisSignalAutoConnectionsStore canvasConnections
KisAnimCurvesModel * curvesModel
KisAnimCurvesView * curvesView
KisMainWindow * mainWindow
KisAnimCurvesDockerTitlebar * titlebar
QMenu * channelTreeMenuLayers
virtual bool supportsKeyframeChannel(const QString &id)