Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAnimTimelineFramesView Class Reference

#include <KisAnimTimelineFramesView.h>

+ Inheritance diagram for KisAnimTimelineFramesView:

Classes

struct  Private
 

Public Slots

void calculateActiveLayerSelectedTimes (const QModelIndexList &selection)
 
void slotAddBlankFrame ()
 
void slotAddDuplicateFrame ()
 
void slotAddExistingLayer (QAction *action)
 
void slotAddNewLayer ()
 
void slotAudioChannelMute (bool value)
 
void slotAudioChannelRemove ()
 
void slotAudioVolumeChanged (int value)
 
void slotCanvasUpdate (class KoCanvasBase *canvas)
 
void slotClearCache ()
 
void slotColorLabelChanged (int)
 
void slotCopyColumns ()
 
void slotCopyFrames ()
 
void slotCutColumns ()
 
void slotCutFrames ()
 
void slotDataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight)
 
void slotEnsureRowVisible (int row)
 
void slotFitViewToFrameRange (int start, int end)
 
void slotHeaderDataChanged (Qt::Orientation orientation, int first, int last)
 
void slotInsertHoldFrame ()
 
void slotInsertHoldFrameColumn ()
 
void slotInsertKeyframeColumnLeft ()
 
void slotInsertKeyframeColumnRight ()
 
void slotInsertKeyframeLeft ()
 
void slotInsertKeyframeRight ()
 
void slotInsertMultipleHoldFrameColumns ()
 
void slotInsertMultipleHoldFrames ()
 
void slotInsertMultipleKeyframeColumns ()
 
void slotInsertMultipleKeyframes ()
 
void slotLayerContextMenuRequested (const QPoint &globalPos)
 
void slotMakeClonesUnique ()
 
void slotMirrorColumns ()
 
void slotMirrorFrames (bool entireColumn=false)
 
void slotPasteColumns ()
 
void slotPasteFrames (bool entireColumn=false)
 
void slotRealignScrollBars ()
 
void slotRemoveHoldFrame ()
 
void slotRemoveHoldFrameColumn ()
 
void slotRemoveLayer ()
 
void slotRemoveMultipleHoldFrameColumns ()
 
void slotRemoveMultipleHoldFrames ()
 
void slotRemoveSelectedColumns ()
 
void slotRemoveSelectedColumnsAndShift ()
 
void slotRemoveSelectedFrames (bool entireColumn=false, bool pull=false)
 
void slotRemoveSelectedFramesAndShift ()
 
void slotReselectCurrentIndex ()
 
void slotScrollerStateChanged (QScroller::State state)
 
void slotSelectAudioChannelFile ()
 
void slotSelectionChanged ()
 
void slotSetEndTimeToCurrentPosition ()
 
void slotSetStartTimeToCurrentPosition ()
 
void slotTryTransferSelectionBetweenRows (int fromRow, int toRow)
 
void slotUpdateDragInfiniteFramesCount ()
 
void slotUpdateFrameActions ()
 
void slotUpdateIcons ()
 
void slotUpdateInfiniteFramesCount ()
 
void slotUpdateLayersMenu ()
 
void slotUpdatePlaybackRange ()
 
void slotZoom (qreal zoom)
 

Public Member Functions

 KisAnimTimelineFramesView (QWidget *parent)
 
void setActionManager (KisActionManager *actionManager)
 
void setModel (QAbstractItemModel *model) override
 
void updateGeometries () override
 
 ~KisAnimTimelineFramesView () override
 

Protected Member Functions

void currentChanged (const QModelIndex &current, const QModelIndex &previous) override
 
void dragEnterEvent (QDragEnterEvent *event) override
 
void dragLeaveEvent (QDragLeaveEvent *event) override
 
void dragMoveEvent (QDragMoveEvent *event) override
 
void dropEvent (QDropEvent *event) override
 
void mouseDoubleClickEvent (QMouseEvent *event) override
 
void mouseMoveEvent (QMouseEvent *e) override
 
void mousePressEvent (QMouseEvent *event) override
 
void mouseReleaseEvent (QMouseEvent *e) override
 
void resizeEvent (QResizeEvent *e) override
 
void rowsInserted (const QModelIndex &parent, int start, int end) override
 
QItemSelectionModel::SelectionFlags selectionCommand (const QModelIndex &index, const QEvent *event) const override
 
void startDrag (Qt::DropActions supportedActions) override
 
bool viewportEvent (QEvent *event) override
 
void wheelEvent (QWheelEvent *e) override
 

Private Member Functions

void calculateSelectionMetrics (int &minColumn, int &maxColumn, QSet< int > &rows, bool ignoreEditability) const
 
QModelIndexList calculateSelectionSpan (bool entireColumn, bool editableOnly=true) const
 
void clone (bool entireColumn)
 
void createFrameEditingMenuActions (QMenu *menu, bool emptyFrame, bool cloneFrameSelected)
 
void cutCopyImpl (bool entireColumn, bool copy)
 
void fanSelectedFrames (const QModelIndexList &selection, int count, bool ignoreKeyless=true)
 
void insertKeyframes (int count=1, int timing=1, TimelineDirection direction=TimelineDirection::LEFT, bool entireColumn=false)
 
void insertMultipleKeyframes (bool entireColumn=false)
 
void insertOrRemoveHoldFrames (int count, bool entireColumn=false)
 
void insertOrRemoveMultipleHoldFrames (bool insertion, bool entireColumn=false)
 
int scrollPositionFromColumn (int column)
 
void setFramesPerSecond (int fps)
 

Private Attributes

const QScopedPointer< Private > m_d
 

Detailed Description

Definition at line 29 of file KisAnimTimelineFramesView.h.

Constructor & Destructor Documentation

◆ KisAnimTimelineFramesView()

KisAnimTimelineFramesView::KisAnimTimelineFramesView ( QWidget * parent)

Definition at line 133 of file KisAnimTimelineFramesView.cpp.

134 : QTableView(parent),
135 m_d(new Private(this))
136{
137 m_d->modifiersCatcher = new KisCustomModifiersCatcher(this);
138 m_d->modifiersCatcher->addModifier("pan-zoom", Qt::Key_Space);
139 m_d->modifiersCatcher->addModifier("offset-frame", Qt::Key_Shift);
140
141 setCornerButtonEnabled(false);
142 setSelectionBehavior(QAbstractItemView::SelectItems);
143 setSelectionMode(QAbstractItemView::ExtendedSelection);
144
145 setItemDelegate(new KisAnimTimelineFrameDelegate(this));
146
147 setDragEnabled(true);
148 setDragDropMode(QAbstractItemView::DragDrop);
149 setAcceptDrops(true);
150 setDropIndicatorShown(true);
151 setDefaultDropAction(Qt::MoveAction);
152
153 m_d->horizontalRuler = new KisAnimTimelineTimeHeader(this);
154 this->setHorizontalHeader(m_d->horizontalRuler);
155
156 connect(m_d->horizontalRuler, SIGNAL(sigInsertColumnLeft()), SLOT(slotInsertKeyframeColumnLeft()));
157 connect(m_d->horizontalRuler, SIGNAL(sigInsertColumnRight()), SLOT(slotInsertKeyframeColumnRight()));
158
159 connect(m_d->horizontalRuler, SIGNAL(sigInsertMultipleColumns()), SLOT(slotInsertMultipleKeyframeColumns()));
160
161 connect(m_d->horizontalRuler, SIGNAL(sigRemoveColumns()), SLOT(slotRemoveSelectedColumns()));
162 connect(m_d->horizontalRuler, SIGNAL(sigRemoveColumnsAndShift()), SLOT(slotRemoveSelectedColumnsAndShift()));
163
164 connect(m_d->horizontalRuler, SIGNAL(sigInsertHoldColumns()), SLOT(slotInsertHoldFrameColumn()));
165 connect(m_d->horizontalRuler, SIGNAL(sigRemoveHoldColumns()), SLOT(slotRemoveHoldFrameColumn()));
166
167 connect(m_d->horizontalRuler, SIGNAL(sigInsertHoldColumnsCustom()), SLOT(slotInsertMultipleHoldFrameColumns()));
168 connect(m_d->horizontalRuler, SIGNAL(sigRemoveHoldColumnsCustom()), SLOT(slotRemoveMultipleHoldFrameColumns()));
169
170 connect(m_d->horizontalRuler, SIGNAL(sigMirrorColumns()), SLOT(slotMirrorColumns()));
171 connect(m_d->horizontalRuler, SIGNAL(sigClearCache()), SLOT(slotClearCache()));
172
173 connect(m_d->horizontalRuler, SIGNAL(sigCopyColumns()), SLOT(slotCopyColumns()));
174 connect(m_d->horizontalRuler, SIGNAL(sigCutColumns()), SLOT(slotCutColumns()));
175 connect(m_d->horizontalRuler, SIGNAL(sigPasteColumns()), SLOT(slotPasteColumns()));
176
177 m_d->layersHeader = new KisAnimTimelineLayersHeader(this);
178
179 m_d->layersHeader->setSectionResizeMode(QHeaderView::Fixed);
180
181 m_d->layersHeader->setDefaultSectionSize(24);
182 m_d->layersHeader->setMinimumWidth(60);
183 m_d->layersHeader->setHighlightSections(true);
184 this->setVerticalHeader(m_d->layersHeader);
185
186 /********** Layer Menu ***********************************************************/
187
188 m_d->layerEditingMenu = new QMenu(this);
189 m_d->layerEditingMenu->addSection(i18n("Edit Layers:"));
190 m_d->layerEditingMenu->addSeparator();
191
192 m_d->layerEditingMenu->addAction(KisAnimUtils::newLayerActionName, this, SLOT(slotAddNewLayer()));
193 m_d->layerEditingMenu->addAction(KisAnimUtils::removeLayerActionName, this, SLOT(slotRemoveLayer()));
194 m_d->layerEditingMenu->addSeparator();
195 m_d->existingLayersMenu = m_d->layerEditingMenu->addMenu(KisAnimUtils::pinExistingLayerActionName);
196
197 connect(m_d->existingLayersMenu, SIGNAL(aboutToShow()), SLOT(slotUpdateLayersMenu()));
198 connect(m_d->existingLayersMenu, SIGNAL(triggered(QAction*)), SLOT(slotAddExistingLayer(QAction*)));
199
200 connect(m_d->layersHeader, SIGNAL(sigRequestContextMenu(QPoint)), SLOT(slotLayerContextMenuRequested(QPoint)));
201
202 m_d->addLayersButton = new QToolButton(this);
203 m_d->addLayersButton->setAutoRaise(true);
204 m_d->addLayersButton->setIcon(KisIconUtils::loadIcon("list-add-22"));
205 m_d->addLayersButton->setIconSize(QSize(22, 22));
206 m_d->addLayersButton->setPopupMode(QToolButton::InstantPopup);
207 m_d->addLayersButton->setMenu(m_d->layerEditingMenu);
208
209 /********** Frame Editing Context Menu ***********************************************/
210
211 m_d->colorSelector = new KisColorLabelSelectorWidgetMenuWrapper(this);
212 MouseClickIgnore* clickIgnore = new MouseClickIgnore(m_d->colorSelector);
213 m_d->colorSelector->installEventFilter(clickIgnore);
214 m_d->colorSelectorAction = new QWidgetAction(this);
215 m_d->colorSelectorAction->setDefaultWidget(m_d->colorSelector);
217
218 m_d->multiframeColorSelector = new KisColorLabelSelectorWidgetMenuWrapper(this);
219 m_d->multiframeColorSelector->installEventFilter(clickIgnore);
220 m_d->multiframeColorSelectorAction = new QWidgetAction(this);
221 m_d->multiframeColorSelectorAction->setDefaultWidget(m_d->multiframeColorSelector);
222 connect(m_d->multiframeColorSelector->colorLabelSelector(), &KisColorLabelSelectorWidget::currentIndexChanged, this, &KisAnimTimelineFramesView::slotColorLabelChanged);
223
224 /********** Insert Keyframes Dialog **************************************************/
225
226 m_d->insertKeyframeDialog = new TimelineInsertKeyframeDialog(this);
227
228 /********** Zoom Button **************************************************************/
229
230 m_d->zoomDragButton = new KisZoomButton(this);
231 m_d->zoomDragButton->setAutoRaise(true);
232 m_d->zoomDragButton->setIcon(KisIconUtils::loadIcon("zoom-horizontal"));
233 m_d->zoomDragButton->setIconSize(QSize(22, 22));
234
235 m_d->zoomDragButton->setToolTip(i18nc("@info:tooltip", "Zoom Timeline. Hold down and drag left or right."));
236 m_d->zoomDragButton->setPopupMode(QToolButton::InstantPopup);
237 connect(m_d->zoomDragButton, SIGNAL(zoom(qreal)), SLOT(slotZoom(qreal)));
238
239 /********** Zoom Scrollbar **************************************************************/
240
241 KisZoomableScrollBar* hZoomableBar = new KisZoomableScrollBar(this);
242 setHorizontalScrollBar(hZoomableBar);
243 setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
244 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
245 setVerticalScrollBar(new KisZoomableScrollBar(this));
246 hZoomableBar->setEnabled(false);
247
248 connect(hZoomableBar, &KisZoomableScrollBar::valueChanged, m_d->horizontalRuler, &KisAnimTimelineTimeHeader::setPixelOffset);
249 connect(hZoomableBar, SIGNAL(zoom(qreal)), this, SLOT(slotZoom(qreal)));
250 connect(hZoomableBar, SIGNAL(overscroll(qreal)), SLOT(slotUpdateInfiniteFramesCount()));
251 connect(hZoomableBar, SIGNAL(sliderReleased()), SLOT(slotUpdateInfiniteFramesCount()));
252
253 /********** Kinetic Scrolling **************************************************************/
254
255 // Kinetic scrolling via left-click renders the timeline effectively
256 // unusable, you end up scrolling the timeline every time you try to move a
257 // key frame or attempt to use the zoom slider. So we don't enable kinetic
258 // scrolling in that case and require the use of the scrollbar instead.
259 if (KisKineticScroller::getConfiguredGestureType() != QScroller::LeftMouseButtonGesture) {
260 QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(this);
261 if (scroller) {
262 connect(scroller, SIGNAL(stateChanged(QScroller::State)),
263 this, SLOT(slotScrollerStateChanged(QScroller::State)));
264
265 connect(&m_d->kineticScrollInfiniteFrameUpdater, &QTimer::timeout, [this, scroller](){
266 slotUpdateInfiniteFramesCount();
267 scroller->resendPrepareEvent();
268 });
269
270 QScrollerProperties props = scroller->scrollerProperties();
271 props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
272 props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
273 scroller->setScrollerProperties(props);
274 }
275 }
276
277 connect(&m_d->selectionChangedCompressor, SIGNAL(timeout()),
278 SLOT(slotSelectionChanged()));
279 connect(&m_d->selectionChangedCompressor, SIGNAL(timeout()),
280 SLOT(slotUpdateFrameActions()));
281
282 {
283 QClipboard *cb = QApplication::clipboard();
284 connect(cb, SIGNAL(dataChanged()), SLOT(slotUpdateFrameActions()));
285 }
286
288}
const QScopedPointer< Private > m_d
void slotScrollerStateChanged(QScroller::State state)
void slotLayerContextMenuRequested(const QPoint &globalPos)
void currentIndexChanged(int index)
The KisCustomModifiersCatcher class is a special utility class that tracks custom modifiers pressed....
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
const QString newLayerActionName
const QString removeLayerActionName
const QString pinExistingLayerActionName
QIcon loadIcon(const QString &name)
KRITAWIDGETUTILS_EXPORT QScroller::ScrollerGestureType getConfiguredGestureType()
KRITAWIDGETUTILS_EXPORT QScroller * createPreconfiguredScroller(QAbstractScrollArea *target)

References KisKineticScroller::createPreconfiguredScroller(), KisColorLabelSelectorWidget::currentIndexChanged(), KisKineticScroller::getConfiguredGestureType(), KisIconUtils::loadIcon(), m_d, KisAnimUtils::newLayerActionName, KisAnimUtils::pinExistingLayerActionName, KisAnimUtils::removeLayerActionName, setFramesPerSecond(), KisAnimTimelineTimeHeader::setPixelOffset(), slotAddExistingLayer(), slotAddNewLayer(), slotClearCache(), slotColorLabelChanged(), slotCopyColumns(), slotCutColumns(), slotInsertHoldFrameColumn(), slotInsertKeyframeColumnLeft(), slotInsertKeyframeColumnRight(), slotInsertMultipleHoldFrameColumns(), slotInsertMultipleKeyframeColumns(), slotLayerContextMenuRequested(), slotMirrorColumns(), slotPasteColumns(), slotRemoveHoldFrameColumn(), slotRemoveLayer(), slotRemoveMultipleHoldFrameColumns(), slotRemoveSelectedColumns(), slotRemoveSelectedColumnsAndShift(), slotScrollerStateChanged(), slotSelectionChanged(), slotUpdateFrameActions(), slotUpdateInfiniteFramesCount(), slotUpdateLayersMenu(), and slotZoom().

◆ ~KisAnimTimelineFramesView()

KisAnimTimelineFramesView::~KisAnimTimelineFramesView ( )
override

Definition at line 290 of file KisAnimTimelineFramesView.cpp.

291{
292}

Member Function Documentation

◆ calculateActiveLayerSelectedTimes

void KisAnimTimelineFramesView::calculateActiveLayerSelectedTimes ( const QModelIndexList & selection)
slot

Definition at line 861 of file KisAnimTimelineFramesView.cpp.

862{
863 QSet<int> activeLayerSelectedTimes;
864 Q_FOREACH (const QModelIndex& index, selection) {
865 if (index.data(KisAnimTimelineFramesModel::ActiveLayerRole).toBool()) {
866 activeLayerSelectedTimes.insert(index.column());
867 }
868 }
869
870 m_d->model->setActiveLayerSelectedTimes(activeLayerSelectedTimes);
871}

References KisAnimTimelineFramesModel::ActiveLayerRole, and m_d.

◆ calculateSelectionMetrics()

void KisAnimTimelineFramesView::calculateSelectionMetrics ( int & minColumn,
int & maxColumn,
QSet< int > & rows,
bool ignoreEditability ) const
private

Definition at line 1429 of file KisAnimTimelineFramesView.cpp.

1430{
1431 minColumn = std::numeric_limits<int>::max();
1432 maxColumn = std::numeric_limits<int>::min();
1433
1434 Q_FOREACH (const QModelIndex &index, selectionModel()->selectedIndexes()) {
1435 if (!ignoreEditability &&
1436 !m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) continue;
1437
1438 rows.insert(index.row());
1439 minColumn = qMin(minColumn, index.column());
1440 maxColumn = qMax(maxColumn, index.column());
1441 }
1442}

References KisTimeBasedItemModel::FrameEditableRole, and m_d.

◆ calculateSelectionSpan()

QModelIndexList KisAnimTimelineFramesView::calculateSelectionSpan ( bool entireColumn,
bool editableOnly = true ) const
private

Definition at line 1398 of file KisAnimTimelineFramesView.cpp.

1399{
1400 QModelIndexList indexes;
1401
1402 if (entireColumn) {
1403 QSet<int> rows;
1404 int minColumn = 0;
1405 int maxColumn = 0;
1406
1407 calculateSelectionMetrics(minColumn, maxColumn, rows, true);
1408
1409 rows.clear();
1410 for (int i = 0; i < m_d->model->rowCount(); i++) {
1411 if (editableOnly &&
1412 !m_d->model->data(m_d->model->index(i, minColumn), KisAnimTimelineFramesModel::FrameEditableRole).toBool()) continue;
1413
1414 for (int column = minColumn; column <= maxColumn; column++) {
1415 indexes << m_d->model->index(i, column);
1416 }
1417 }
1418 } else {
1419 Q_FOREACH (const QModelIndex &index, selectionModel()->selectedIndexes()) {
1420 if (!editableOnly || m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) {
1421 indexes << index;
1422 }
1423 }
1424 }
1425
1426 return indexes;
1427}
void calculateSelectionMetrics(int &minColumn, int &maxColumn, QSet< int > &rows, bool ignoreEditability) const

References calculateSelectionMetrics(), KisTimeBasedItemModel::FrameEditableRole, and m_d.

◆ clone()

void KisAnimTimelineFramesView::clone ( bool entireColumn)
private

Definition at line 1596 of file KisAnimTimelineFramesView.cpp.

1597{
1598 const QModelIndexList selectedIndices = calculateSelectionSpan(entireColumn, false);
1599 if (selectedIndices.isEmpty()) return;
1600
1601 int minColumn = std::numeric_limits<int>::max();
1602 int minRow = std::numeric_limits<int>::max();
1603 Q_FOREACH (const QModelIndex &index, selectedIndices) {
1604 minRow = qMin(minRow, index.row());
1605 minColumn = qMin(minColumn, index.column());
1606 }
1607
1608 const QModelIndex baseIndex = m_d->model->index(minRow, minColumn);
1609 QMimeData *data = m_d->model->mimeDataExtended(selectedIndices,
1610 baseIndex,
1612
1613 if (data) {
1614 QClipboard *cb = QApplication::clipboard();
1615 cb->setMimeData(data);
1616 }
1617}
QModelIndexList calculateSelectionSpan(bool entireColumn, bool editableOnly=true) const

References calculateSelectionSpan(), KisAnimTimelineFramesModel::CloneFramesPolicy, and m_d.

◆ createFrameEditingMenuActions()

void KisAnimTimelineFramesView::createFrameEditingMenuActions ( QMenu * menu,
bool emptyFrame,
bool cloneFrameSelected )
private

Definition at line 1619 of file KisAnimTimelineFramesView.cpp.

1620{
1622
1623 // calculate if selection range is set. This will determine if the update playback range is available
1624 QSet<int> rows;
1625 int minColumn = 0;
1626 int maxColumn = 0;
1627 calculateSelectionMetrics(minColumn, maxColumn, rows, true);
1628 bool selectionExists = minColumn != maxColumn;
1629
1630 menu->addSection(i18n("Edit Frames:"));
1631 menu->addSeparator();
1632
1633 if (selectionExists) {
1634 KisActionManager::safePopulateMenu(menu, "update_playback_range", m_d->actionMan);
1635 } else {
1636 KisActionManager::safePopulateMenu(menu, "set_start_time", m_d->actionMan);
1637 KisActionManager::safePopulateMenu(menu, "set_end_time", m_d->actionMan);
1638 }
1639
1640 menu->addSeparator();
1641
1642 if (!emptyFrame) {
1643 KisActionManager::safePopulateMenu(menu, "cut_frames", m_d->actionMan);
1644 KisActionManager::safePopulateMenu(menu, "copy_frames", m_d->actionMan);
1645 KisActionManager::safePopulateMenu(menu, "copy_frames_as_clones", m_d->actionMan);
1646 }
1647
1648 KisActionManager::safePopulateMenu(menu, "paste_frames", m_d->actionMan);
1649
1650 if (!emptyFrame && cloneFrameSelected) {
1651 KisActionManager::safePopulateMenu(menu, "make_clones_unique", m_d->actionMan);
1652 }
1653
1654 menu->addSeparator();
1655
1656 { //Frames submenu.
1657 QMenu *frames = menu->addMenu(i18nc("@item:inmenu", "Keyframes"));
1658 KisActionManager::safePopulateMenu(frames, "insert_keyframe_left", m_d->actionMan);
1659 KisActionManager::safePopulateMenu(frames, "insert_keyframe_right", m_d->actionMan);
1660 frames->addSeparator();
1661 KisActionManager::safePopulateMenu(frames, "insert_multiple_keyframes", m_d->actionMan);
1662 }
1663
1664 { //Holds submenu.
1665 QMenu *hold = menu->addMenu(i18nc("@item:inmenu", "Hold Frames"));
1666 KisActionManager::safePopulateMenu(hold, "insert_hold_frame", m_d->actionMan);
1667 KisActionManager::safePopulateMenu(hold, "remove_hold_frame", m_d->actionMan);
1668 hold->addSeparator();
1669 KisActionManager::safePopulateMenu(hold, "insert_multiple_hold_frames", m_d->actionMan);
1670 KisActionManager::safePopulateMenu(hold, "remove_multiple_hold_frames", m_d->actionMan);
1671 }
1672
1673 menu->addSeparator();
1674
1675 if (!emptyFrame) {
1676 KisActionManager::safePopulateMenu(menu, "remove_frames", m_d->actionMan);
1677 }
1678 KisActionManager::safePopulateMenu(menu, "remove_frames_and_pull", m_d->actionMan);
1679
1680 menu->addSeparator();
1681
1682 if (emptyFrame) {
1683 KisActionManager::safePopulateMenu(menu, "add_blank_frame", m_d->actionMan);
1684 KisActionManager::safePopulateMenu(menu, "add_duplicate_frame", m_d->actionMan);
1685 menu->addSeparator();
1686 }
1687}
static void safePopulateMenu(QMenu *menu, const QString &actionId, KisActionManager *actionManager)

References calculateSelectionMetrics(), m_d, KisActionManager::safePopulateMenu(), and slotUpdateFrameActions().

◆ currentChanged()

void KisAnimTimelineFramesView::currentChanged ( const QModelIndex & current,
const QModelIndex & previous )
overrideprotected

Definition at line 1334 of file KisAnimTimelineFramesView.cpp.

1335{
1336 QTableView::currentChanged(current, previous);
1337
1338 if (previous.column() != current.column()) {
1339 m_d->model->setData(previous, false, KisAnimTimelineFramesModel::ActiveFrameRole);
1340 m_d->model->setData(current, true, KisAnimTimelineFramesModel::ActiveFrameRole);
1341 if ( current.column() != m_d->model->currentTime() ) {
1342 m_d->model->setData(current, QVariant(int(SEEK_FINALIZE | SEEK_PUSH_AUDIO)), KisAnimTimelineFramesModel::ScrubToRole);
1343 }
1344 }
1345}
@ SEEK_PUSH_AUDIO
@ SEEK_FINALIZE

References KisTimeBasedItemModel::ActiveFrameRole, m_d, KisTimeBasedItemModel::ScrubToRole, SEEK_FINALIZE, and SEEK_PUSH_AUDIO.

◆ cutCopyImpl()

void KisAnimTimelineFramesView::cutCopyImpl ( bool entireColumn,
bool copy )
private

Definition at line 1571 of file KisAnimTimelineFramesView.cpp.

1572{
1573 const QModelIndexList selectedIndices = calculateSelectionSpan(entireColumn, !copy);
1574 if (selectedIndices.isEmpty()) return;
1575
1576 int minColumn = std::numeric_limits<int>::max();
1577 int minRow = std::numeric_limits<int>::max();
1578 Q_FOREACH (const QModelIndex &index, selectedIndices) {
1579 minRow = qMin(minRow, index.row());
1580 minColumn = qMin(minColumn, index.column());
1581 }
1582
1583 const QModelIndex baseIndex = m_d->model->index(minRow, minColumn);
1584 QMimeData *data = m_d->model->mimeDataExtended(selectedIndices,
1585 baseIndex,
1586 copy ?
1588 KisAnimTimelineFramesModel::MoveFramesPolicy);
1589
1590 if (data) {
1591 QClipboard *cb = QApplication::clipboard();
1592 cb->setMimeData(data);
1593 }
1594}

References calculateSelectionSpan(), KisAnimTimelineFramesModel::CopyFramesPolicy, m_d, and KisAnimTimelineFramesModel::MoveFramesPolicy.

◆ dragEnterEvent()

void KisAnimTimelineFramesView::dragEnterEvent ( QDragEnterEvent * event)
overrideprotected

Definition at line 1230 of file KisAnimTimelineFramesView.cpp.

1231{
1232 m_d->dragInProgress = true;
1233 m_d->model->setScrubState(true);
1234
1235 QTableView::dragEnterEvent(event);
1236}

References m_d.

◆ dragLeaveEvent()

void KisAnimTimelineFramesView::dragLeaveEvent ( QDragLeaveEvent * event)
overrideprotected

Definition at line 1263 of file KisAnimTimelineFramesView.cpp.

1264{
1265 m_d->dragInProgress = false;
1266 m_d->model->setScrubState(false);
1267
1268 QAbstractItemView::dragLeaveEvent(event);
1269}

References m_d.

◆ dragMoveEvent()

void KisAnimTimelineFramesView::dragMoveEvent ( QDragMoveEvent * event)
overrideprotected

Definition at line 1238 of file KisAnimTimelineFramesView.cpp.

1239{
1240 m_d->dragInProgress = true;
1241 m_d->model->setScrubState(true);
1242
1243 QAbstractItemView::dragMoveEvent(event);
1244
1245 // Let's check for moving within a selection --
1246 // We want to override the built in qt behavior that
1247 // denies drag events when dragging within a selection...
1248 if (!event->isAccepted() && selectionModel()->isSelected(indexAt(event->pos()))) {
1249 event->setAccepted(true);
1250 }
1251
1252 if (event->isAccepted()) {
1253 QModelIndex index = indexAt(event->pos());
1254
1255 if (!m_d->model->canDropFrameData(event->mimeData(), index)) {
1256 event->ignore();
1257 } else {
1258 selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
1259 }
1260 }
1261}

References m_d.

◆ dropEvent()

void KisAnimTimelineFramesView::dropEvent ( QDropEvent * event)
overrideprotected

Definition at line 1271 of file KisAnimTimelineFramesView.cpp.

1272{
1273 m_d->dragInProgress = false;
1274 m_d->model->setScrubState(false);
1275
1276 if (event->keyboardModifiers() & Qt::ControlModifier) {
1277 event->setDropAction(Qt::CopyAction);
1278 } else if (event->keyboardModifiers() & Qt::AltModifier) {
1279 event->setDropAction(Qt::LinkAction);
1280 }
1281
1282 QAbstractItemView::dropEvent(event);
1283
1284 // Override drop event to accept drops within selected range.0
1285 QModelIndex index = indexAt(event->pos());
1286 if (!event->isAccepted() && selectionModel()->isSelected(index)) {
1287 event->setAccepted(true);
1288 const Qt::DropAction action = event->dropAction();
1289 const int row = event->pos().y();
1290 const int column = event->pos().x();
1291 if (m_d->model->dropMimeData(event->mimeData(), action, row, column, index)) {
1292 event->acceptProposedAction();
1293 }
1294 }
1295
1296 m_d->dragWasSuccessful = event->isAccepted();
1297}

References m_d.

◆ fanSelectedFrames()

void KisAnimTimelineFramesView::fanSelectedFrames ( const QModelIndexList & selection,
int count,
bool ignoreKeyless = true )
private

Definition at line 1541 of file KisAnimTimelineFramesView.cpp.

1541 {
1542 QMap<int, QList<int>> indexMap;
1543
1544 QList<QModelIndex> selectedIndices = selection;
1545
1546 foreach (const QModelIndex &index, selectedIndices) {
1547 if (!indexMap.contains(index.row())) {
1548 indexMap.insert(index.row(), QList<int>());
1549 }
1550
1551 if (m_d->model->data(index, KisAnimTimelineFramesModel::FrameExistsRole).value<bool>() || !ignoreKeyless) {
1552 indexMap[index.row()] << index.column();
1553 }
1554 }
1555
1556 KisSignalsBlocker blockSig(selectionModel());
1557 selectionModel()->clearSelection();
1558 foreach (const int &layer, indexMap.keys()) {
1560 int progressIndex = 0;
1561
1562 std::sort(indexMap[layer].begin(), indexMap[layer].end());
1563 for (it = indexMap[layer].constBegin(); it != indexMap[layer].constEnd(); it++) {
1564 const int offsetColumn = *it + (progressIndex * count);
1565 selectionModel()->select(model()->index(layer, offsetColumn), QItemSelectionModel::Select);
1566 progressIndex++;
1567 }
1568 }
1569}

References KisTimeBasedItemModel::FrameExistsRole, and m_d.

◆ insertKeyframes()

void KisAnimTimelineFramesView::insertKeyframes ( int count = 1,
int timing = 1,
TimelineDirection direction = TimelineDirection::LEFT,
bool entireColumn = false )
private

Insert new keyframes/columns.

count - Number of frames to add. If <0, use number of currently SELECTED frames. timing - Animation timing of frames to be added (on 1s, 2s, 3s, etc.) direction - Insert frames before (left) or after (right) selection scrubber. entireColumn - Create frames on all layers (rows) instead of just the active layer?

Definition at line 1444 of file KisAnimTimelineFramesView.cpp.

1445{
1446 QSet<int> rows;
1447 int minColumn = 0, maxColumn = 0;
1448
1449 calculateSelectionMetrics(minColumn, maxColumn, rows, entireColumn);
1450 if (minColumn > maxColumn) return;
1451
1452 if (count <= 0) { //Negative count? Use number of selected frames.
1453 count = qMax(1, maxColumn - minColumn + 1);
1454 }
1455
1456 const int insertionColumn =
1457 direction == TimelineDirection::RIGHT ?
1458 maxColumn + 1 : minColumn;
1459
1460 if (entireColumn) {
1461 rows.clear();
1462 for (int i = 0; i < m_d->model->rowCount(); i++) {
1463 if (!m_d->model->data(m_d->model->index(i, insertionColumn), KisAnimTimelineFramesModel::FrameEditableRole).toBool()) continue;
1464 rows.insert(i);
1465 }
1466 }
1467
1468 if (!rows.isEmpty()) {
1469 m_d->model->insertFrames(insertionColumn, QList<int>(rows.begin(), rows.end()), count, timing);
1470 }
1471}

References calculateSelectionMetrics(), KisTimeBasedItemModel::FrameEditableRole, m_d, and RIGHT.

◆ insertMultipleKeyframes()

void KisAnimTimelineFramesView::insertMultipleKeyframes ( bool entireColumn = false)
private

Definition at line 1473 of file KisAnimTimelineFramesView.cpp.

1474{
1475 int count, timing;
1476 TimelineDirection direction;
1477
1478 if (m_d->insertKeyframeDialog->promptUserSettings(count, timing, direction)) {
1479 insertKeyframes(count, timing, direction, entireColumn);
1480 }
1481}
void insertKeyframes(int count=1, int timing=1, TimelineDirection direction=TimelineDirection::LEFT, bool entireColumn=false)

References insertKeyframes(), and m_d.

◆ insertOrRemoveHoldFrames()

void KisAnimTimelineFramesView::insertOrRemoveHoldFrames ( int count,
bool entireColumn = false )
private

Definition at line 1483 of file KisAnimTimelineFramesView.cpp.

1484{
1485 QModelIndexList indexes;
1486
1487 // Populate indices..
1488 if (!entireColumn) {
1489 Q_FOREACH (const QModelIndex &index, selectionModel()->selectedIndexes()) {
1490 if (m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) {
1491 indexes << index;
1492 }
1493 }
1494 } else {
1495 const int column = selectionModel()->currentIndex().column();
1496
1497 for (int i = 0; i < m_d->model->rowCount(); i++) {
1498 const QModelIndex index = m_d->model->index(i, column);
1499 if (m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) {
1500 indexes << index;
1501 }
1502 }
1503 }
1504
1505 if (!indexes.isEmpty()) {
1506 m_d->model->insertHoldFrames(indexes, count);
1507
1508 // Fan selection based on insertion or deletion.
1509 // This should allow better UI/UX for insertion of keyframes or hold frames.
1510 fanSelectedFrames(indexes, count);
1511
1512 // bulk adding frames can add too many
1513 // trim timeline to clean up extra frames that might have been added
1515 }
1516}
void fanSelectedFrames(const QModelIndexList &selection, int count, bool ignoreKeyless=true)

References fanSelectedFrames(), KisTimeBasedItemModel::FrameEditableRole, m_d, and slotUpdateInfiniteFramesCount().

◆ insertOrRemoveMultipleHoldFrames()

void KisAnimTimelineFramesView::insertOrRemoveMultipleHoldFrames ( bool insertion,
bool entireColumn = false )
private

Definition at line 1518 of file KisAnimTimelineFramesView.cpp.

1519{
1520 bool ok = false;
1521 const int count = QInputDialog::getInt(this,
1522 i18nc("@title:window", "Insert or Remove Hold Frames"),
1523 i18nc("@label:spinbox", "Enter number of frames"),
1524 insertion ?
1525 m_d->insertKeyframeDialog->defaultTimingOfAddedFrames() :
1526 m_d->insertKeyframeDialog->defaultNumberOfHoldFramesToRemove(),
1527 1, 10000, 1, &ok);
1528
1529 if (ok) {
1530 if (insertion) {
1531 m_d->insertKeyframeDialog->setDefaultTimingOfAddedFrames(count);
1532 insertOrRemoveHoldFrames(count, entireColumn);
1533 } else {
1534 m_d->insertKeyframeDialog->setDefaultNumberOfHoldFramesToRemove(count);
1535 insertOrRemoveHoldFrames(-count, entireColumn);
1536 }
1537
1538 }
1539}
void insertOrRemoveHoldFrames(int count, bool entireColumn=false)

References insertOrRemoveHoldFrames(), and m_d.

◆ mouseDoubleClickEvent()

void KisAnimTimelineFramesView::mouseDoubleClickEvent ( QMouseEvent * event)
overrideprotected

Definition at line 1034 of file KisAnimTimelineFramesView.cpp.

1034 {
1035 QPersistentModelIndex index = indexAt(event->pos());
1036
1037 if (index.isValid()) {
1038 if (event->modifiers() & Qt::AltModifier) {
1039 selectRow(index.row());
1040 } else {
1041 selectColumn(index.column());
1042 }
1043 }
1044
1045 QAbstractItemView::mouseDoubleClickEvent(event);
1046}

◆ mouseMoveEvent()

void KisAnimTimelineFramesView::mouseMoveEvent ( QMouseEvent * e)
overrideprotected

Definition at line 1048 of file KisAnimTimelineFramesView.cpp.

1049{
1050 // Custom keyframe dragging distance based on zoom level.
1051 if (state() == DraggingState &&
1052 (horizontalHeader()->defaultSectionSize() / 2) < QApplication::startDragDistance() ) {
1053
1054 const QPoint dragVector = e->pos() - m_d->initialDragPanPos;
1055 if (dragVector.manhattanLength() >= (horizontalHeader()->defaultSectionSize() / 2)) {
1056 startDrag(model()->supportedDragActions());
1057 setState(NoState);
1058 stopAutoScroll();
1059 }
1060 }
1061
1062 if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) {
1063 if (e->buttons() & Qt::RightButton) {
1064 // m_d->zoomDragButton->continueZoom(e->pos());
1065 } else if (e->buttons() & Qt::LeftButton) {
1066
1067 QPoint diff = e->pos() - m_d->initialDragPanPos;
1068 QPoint offset = QPoint(m_d->initialDragPanValue.x() - diff.x(),
1069 m_d->initialDragPanValue.y() - diff.y());
1070
1071 const int height = m_d->layersHeader->defaultSectionSize();
1072
1073 if (m_d->initialDragPanValue.x() - diff.x() > horizontalScrollBar()->maximum() || m_d->initialDragPanValue.x() - diff.x() > horizontalScrollBar()->minimum() ){
1074 KisZoomableScrollBar* zoombar = static_cast<KisZoomableScrollBar*>(horizontalScrollBar());
1075 zoombar->overscroll(-diff.x());
1076 }
1077
1078 horizontalScrollBar()->setValue(offset.x());
1079 verticalScrollBar()->setValue(offset.y() / height);
1080 }
1081
1082 e->accept();
1083 } else if (e->buttons() == Qt::MiddleButton) {
1084 QModelIndex index = model()->buddy(indexAt(e->pos()));
1085 if (index.isValid()) {
1086#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
1087 QStyleOptionViewItem option = viewOptions();
1088#else
1089 QStyleOptionViewItem option;
1090 initViewItemOption(&option);
1091#endif
1092 option.rect = visualRect(index);
1093 // The offset of the headers is needed to get the correct position inside the view.
1094 m_d->tip.showTip(e->pos() + QPoint(verticalHeader()->width(), horizontalHeader()->height()), option, index);
1095 }
1096
1097 e->accept();
1098 } else {
1099 m_d->model->setScrubState(true);
1100 QTableView::mouseMoveEvent(e);
1101 }
1102}
void startDrag(Qt::DropActions supportedActions) override
void overscroll(qreal delta)

References m_d, KisZoomableScrollBar::overscroll(), and startDrag().

◆ mousePressEvent()

void KisAnimTimelineFramesView::mousePressEvent ( QMouseEvent * event)
overrideprotected

Definition at line 901 of file KisAnimTimelineFramesView.cpp.

902{
903 QPersistentModelIndex index = indexAt(event->pos());
904
905 if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) {
906 if (event->button() == Qt::RightButton) {
907 // TODO: try calculate index under mouse cursor even when
908 // it is outside any visible row
909 // qreal staticPoint = index.isValid() ? index.column() : currentIndex().column();
910 // m_d->zoomDragButton->beginZoom(event->pos(), staticPoint);
911 } else if (event->button() == Qt::LeftButton) {
912 m_d->initialDragPanPos = event->pos();
913 m_d->initialDragPanValue =
914 QPoint(horizontalScrollBar()->value(),
915 verticalScrollBar()->value());
916 }
917 event->accept();
918
919 } else if (event->button() == Qt::RightButton) {
920 int numSelectedItems = selectionModel()->selectedIndexes().size();
921
922 if (index.isValid() &&
923 numSelectedItems <= 1 &&
924 m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) {
925
926 model()->setData(index, true, KisAnimTimelineFramesModel::ActiveLayerRole);
927 model()->setData(index, true, KisAnimTimelineFramesModel::ActiveFrameRole);
928 model()->setData(index, QVariant(int(SEEK_FINALIZE | SEEK_PUSH_AUDIO)), KisAnimTimelineFramesModel::ScrubToRole);
929 setCurrentIndex(index);
930
931 if (model()->data(index, KisAnimTimelineFramesModel::FrameExistsRole).toBool() ||
932 model()->data(index, KisAnimTimelineFramesModel::SpecialKeyframeExists).toBool()) {
933
934 {
935 KisSignalsBlocker b(m_d->colorSelector->colorLabelSelector());
936 QVariant colorLabel = index.data(KisAnimTimelineFramesModel::FrameColorLabelIndexRole);
937 int labelIndex = colorLabel.isValid() ? colorLabel.toInt() : 0;
938 m_d->colorSelector->colorLabelSelector()->setCurrentIndex(labelIndex);
939 }
940
941 const bool hasClones = model()->data(index, KisAnimTimelineFramesModel::CloneCount).toInt() > 0;
942
943 QMenu menu;
944 createFrameEditingMenuActions(&menu, false, hasClones);
945 menu.addSeparator();
946 menu.addAction(m_d->colorSelectorAction);
947 menu.exec(event->globalPos());
948
949 } else {
950 {
951 KisSignalsBlocker b(m_d->colorSelector->colorLabelSelector());
952 const int labelIndex = KisImageConfig(true).defaultFrameColorLabel();
953 m_d->colorSelector->colorLabelSelector()->setCurrentIndex(labelIndex);
954 }
955
956 QMenu menu;
957 createFrameEditingMenuActions(&menu, true, false);
958 menu.addSeparator();
959 menu.addAction(m_d->colorSelectorAction);
960 menu.exec(event->globalPos());
961 }
962 } else if (numSelectedItems > 1) {
963 int labelIndex = -1;
964 bool firstKeyframe = true;
965 bool hasKeyframes = false;
966 bool containsClones = false;
967 Q_FOREACH(QModelIndex index, selectedIndexes()) {
968 hasKeyframes |= index.data(KisAnimTimelineFramesModel::FrameExistsRole).toBool();
969 containsClones |= (index.data(KisAnimTimelineFramesModel::CloneCount).toInt() > 0);
970
971 QVariant colorLabel = index.data(KisAnimTimelineFramesModel::FrameColorLabelIndexRole);
972 if (colorLabel.isValid()) {
973 if (firstKeyframe) {
974 labelIndex = colorLabel.toInt();
975 } else if (labelIndex != colorLabel.toInt()) {
976 // Mixed colors in selection
977 labelIndex = -1;
978 }
979
980 firstKeyframe = false;
981 }
982
983 if (!firstKeyframe
984 && hasKeyframes
985 && containsClones
986 && labelIndex == -1) {
987 break; // Break out early if we find all of the above.
988 }
989 }
990
991 if (hasKeyframes) {
992 KisSignalsBlocker b(m_d->multiframeColorSelector->colorLabelSelector());
993 m_d->multiframeColorSelector->colorLabelSelector()->setCurrentIndex(labelIndex);
994 }
995
996 QMenu menu;
997 createFrameEditingMenuActions(&menu, false, containsClones);
998 menu.addSeparator();
999 KisActionManager::safePopulateMenu(&menu, "mirror_frames", m_d->actionMan);
1000 menu.addSeparator();
1001 menu.addAction(m_d->multiframeColorSelectorAction);
1002 menu.exec(event->globalPos());
1003 }
1004
1005 } else if (event->button() == Qt::MiddleButton) {
1006 QModelIndex index = model()->buddy(indexAt(event->pos()));
1007 if (index.isValid()) {
1008#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
1009 QStyleOptionViewItem option = viewOptions();
1010#else
1011 QStyleOptionViewItem option;
1012 initViewItemOption(&option);
1013#endif
1014 option.rect = visualRect(index);
1015 // The offset of the headers is needed to get the correct position inside the view.
1016 m_d->tip.showTip(event->pos() + QPoint(verticalHeader()->width(), horizontalHeader()->height()), option, index);
1017 }
1018 event->accept();
1019
1020 } else {
1021 if (index.isValid()) {
1022 m_d->model->setLastClickedIndex(index);
1023 }
1024
1025 m_d->lastPressedPosition = QPoint(horizontalOffset(), verticalOffset()) + event->pos();
1026 m_d->lastPressedModifier = event->modifiers();
1027
1028 m_d->initialDragPanPos = event->pos();
1029
1030 QAbstractItemView::mousePressEvent(event);
1031 }
1032}
float value(const T *src, size_t ch)
void createFrameEditingMenuActions(QMenu *menu, bool emptyFrame, bool cloneFrameSelected)
int defaultFrameColorLabel() const

References KisTimeBasedItemModel::ActiveFrameRole, KisAnimTimelineFramesModel::ActiveLayerRole, KisTimeBasedItemModel::CloneCount, createFrameEditingMenuActions(), KisImageConfig::defaultFrameColorLabel(), KisAnimTimelineFramesModel::FrameColorLabelIndexRole, KisTimeBasedItemModel::FrameEditableRole, KisTimeBasedItemModel::FrameExistsRole, m_d, KisActionManager::safePopulateMenu(), KisTimeBasedItemModel::ScrubToRole, SEEK_FINALIZE, SEEK_PUSH_AUDIO, KisTimeBasedItemModel::SpecialKeyframeExists, and value().

◆ mouseReleaseEvent()

void KisAnimTimelineFramesView::mouseReleaseEvent ( QMouseEvent * e)
overrideprotected

Definition at line 1104 of file KisAnimTimelineFramesView.cpp.

1105{
1106 if (m_d->modifiersCatcher->modifierPressed("pan-zoom")) {
1107 e->accept();
1108 } else {
1109 m_d->model->setScrubState(false);
1110 QTableView::mouseReleaseEvent(e);
1111 }
1112}

References m_d.

◆ resizeEvent()

void KisAnimTimelineFramesView::resizeEvent ( QResizeEvent * e)
overrideprotected

Definition at line 1321 of file KisAnimTimelineFramesView.cpp.

1322{
1323 Q_UNUSED(event);
1324
1327}

References slotUpdateInfiniteFramesCount(), and updateGeometries().

◆ rowsInserted()

void KisAnimTimelineFramesView::rowsInserted ( const QModelIndex & parent,
int start,
int end )
overrideprotected

Definition at line 1329 of file KisAnimTimelineFramesView.cpp.

1330{
1331 QTableView::rowsInserted(parent, start, end);
1332}

◆ scrollPositionFromColumn()

int KisAnimTimelineFramesView::scrollPositionFromColumn ( int column)
private

Definition at line 1689 of file KisAnimTimelineFramesView.cpp.

1689 {
1690 const int sectionWidth = m_d->horizontalRuler->defaultSectionSize();
1691 return sectionWidth * column;
1692}

References m_d.

◆ selectionCommand()

QItemSelectionModel::SelectionFlags KisAnimTimelineFramesView::selectionCommand ( const QModelIndex & index,
const QEvent * event ) const
overrideprotected

Qt has a bug: when we Ctrl+click on an item, the item's selections gets toggled on mouse press, whereas usually it is done on mouse release. Therefore the user cannot do a Ctrl+D&D with the default configuration. This code fixes the problem by manually returning QItemSelectionModel::NoUpdate flag when the user clicks on an item and returning QItemSelectionModel::Toggle on release.

Definition at line 1347 of file KisAnimTimelineFramesView.cpp.

1349{
1350 // WARNING: Copy-pasted from KisNodeView! Please keep in sync!
1351
1362 if (event &&
1363 (event->type() == QEvent::MouseButtonPress ||
1364 event->type() == QEvent::MouseButtonRelease) &&
1365 index.isValid()) {
1366
1367 const QMouseEvent *mevent = static_cast<const QMouseEvent*>(event);
1368
1369 if (mevent->button() == Qt::RightButton &&
1370 selectionModel()->selectedIndexes().contains(index)) {
1371
1372 // Allow calling context menu for multiple layers
1373 return QItemSelectionModel::NoUpdate;
1374 }
1375
1376 if (event->type() == QEvent::MouseButtonPress &&
1377 (mevent->modifiers() & Qt::ControlModifier)) {
1378
1379 return QItemSelectionModel::NoUpdate;
1380 }
1381
1382 if (event->type() == QEvent::MouseButtonRelease &&
1383 (mevent->modifiers() & Qt::ControlModifier)) {
1384
1385 return QItemSelectionModel::Toggle;
1386 }
1387 }
1388
1389 return QAbstractItemView::selectionCommand(index, event);
1390}

◆ setActionManager()

void KisAnimTimelineFramesView::setActionManager ( KisActionManager * actionManager)

Definition at line 322 of file KisAnimTimelineFramesView.cpp.

323{
324 m_d->actionMan = actionManager;
325 m_d->horizontalRuler->setActionManager(actionManager);
326
327 if (actionManager) {
328 KisAction *action = 0;
329
330 action = m_d->actionMan->createAction("add_blank_frame");
331 connect(action, SIGNAL(triggered()), SLOT(slotAddBlankFrame()));
332
333 action = m_d->actionMan->createAction("add_duplicate_frame");
334 connect(action, SIGNAL(triggered()), SLOT(slotAddDuplicateFrame()));
335
336 action = m_d->actionMan->createAction("insert_keyframe_left");
337 connect(action, SIGNAL(triggered()), SLOT(slotInsertKeyframeLeft()));
338
339 action = m_d->actionMan->createAction("insert_keyframe_right");
340 connect(action, SIGNAL(triggered()), SLOT(slotInsertKeyframeRight()));
341
342 action = m_d->actionMan->createAction("insert_multiple_keyframes");
343 connect(action, SIGNAL(triggered()), SLOT(slotInsertMultipleKeyframes()));
344
345 action = m_d->actionMan->createAction("remove_frames_and_pull");
346 connect(action, SIGNAL(triggered()), SLOT(slotRemoveSelectedFramesAndShift()));
347
348 action = m_d->actionMan->createAction("remove_frames");
349 connect(action, SIGNAL(triggered()), SLOT(slotRemoveSelectedFrames()));
350
351 action = m_d->actionMan->createAction("insert_hold_frame");
352 connect(action, SIGNAL(triggered()), SLOT(slotInsertHoldFrame()));
353
354 action = m_d->actionMan->createAction("insert_multiple_hold_frames");
355 connect(action, SIGNAL(triggered()), SLOT(slotInsertMultipleHoldFrames()));
356
357 action = m_d->actionMan->createAction("remove_hold_frame");
358 connect(action, SIGNAL(triggered()), SLOT(slotRemoveHoldFrame()));
359
360 action = m_d->actionMan->createAction("remove_multiple_hold_frames");
361 connect(action, SIGNAL(triggered()), SLOT(slotRemoveMultipleHoldFrames()));
362
363 action = m_d->actionMan->createAction("mirror_frames");
364 connect(action, SIGNAL(triggered()), SLOT(slotMirrorFrames()));
365
366 action = m_d->actionMan->createAction("copy_frames");
367 connect(action, SIGNAL(triggered()), SLOT(slotCopyFrames()));
368
369 action = m_d->actionMan->createAction("copy_frames_as_clones");
370 connect(action, &KisAction::triggered, [this](){clone(false);});
371
372 action = m_d->actionMan->createAction("make_clones_unique");
373 connect(action, SIGNAL(triggered()), SLOT(slotMakeClonesUnique()));
374
375 action = m_d->actionMan->createAction("cut_frames");
376 connect(action, SIGNAL(triggered()), SLOT(slotCutFrames()));
377
378 action = m_d->actionMan->createAction("paste_frames");
379 connect(action, SIGNAL(triggered()), SLOT(slotPasteFrames()));
380
381 action = m_d->actionMan->createAction("set_start_time");
382 connect(action, SIGNAL(triggered()), SLOT(slotSetStartTimeToCurrentPosition()));
383
384 action = m_d->actionMan->createAction("set_end_time");
385 connect(action, SIGNAL(triggered()), SLOT(slotSetEndTimeToCurrentPosition()));
386
387 action = m_d->actionMan->createAction("update_playback_range");
388 connect(action, SIGNAL(triggered()), SLOT(slotUpdatePlaybackRange()));
389
390 action = m_d->actionMan->actionByName("pin_to_timeline");
391 m_d->pinLayerToTimelineAction = action;
392 m_d->layerEditingMenu->addAction(action);
393 }
394}
void slotRemoveSelectedFrames(bool entireColumn=false, bool pull=false)
void slotMirrorFrames(bool entireColumn=false)
void slotPasteFrames(bool entireColumn=false)

References clone(), m_d, slotAddBlankFrame(), slotAddDuplicateFrame(), slotCopyFrames(), slotCutFrames(), slotInsertHoldFrame(), slotInsertKeyframeLeft(), slotInsertKeyframeRight(), slotInsertMultipleHoldFrames(), slotInsertMultipleKeyframes(), slotMakeClonesUnique(), slotMirrorFrames(), slotPasteFrames(), slotRemoveHoldFrame(), slotRemoveMultipleHoldFrames(), slotRemoveSelectedFrames(), slotRemoveSelectedFramesAndShift(), slotSetEndTimeToCurrentPosition(), slotSetStartTimeToCurrentPosition(), and slotUpdatePlaybackRange().

◆ setFramesPerSecond()

void KisAnimTimelineFramesView::setFramesPerSecond ( int fps)
private

Definition at line 1392 of file KisAnimTimelineFramesView.cpp.

1393{
1394 m_d->fps = fps;
1395 m_d->horizontalRuler->setFramePerSecond(fps);
1396}

References m_d.

◆ setModel()

void KisAnimTimelineFramesView::setModel ( QAbstractItemModel * model)
override

Definition at line 294 of file KisAnimTimelineFramesView.cpp.

295{
296 KisAnimTimelineFramesModel *framesModel = qobject_cast<KisAnimTimelineFramesModel*>(model);
297 m_d->model = framesModel;
298
299 QTableView::setModel(model);
300
301 connect(m_d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
302 this, SLOT(slotHeaderDataChanged(Qt::Orientation,int,int)));
303
304 connect(m_d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
305 this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
306
307 connect(m_d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
308 this, SLOT(slotReselectCurrentIndex()));
309
310 connect(m_d->model, SIGNAL(sigInfiniteTimelineUpdateNeeded()),
311 this, SLOT(slotUpdateInfiniteFramesCount()));
312
313 connect(m_d->model, SIGNAL(requestTransferSelectionBetweenRows(int,int)),
314 this, SLOT(slotTryTransferSelectionBetweenRows(int,int)));
315
316 connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
317 &m_d->selectionChangedCompressor, SLOT(start()));
318
319 connect(m_d->model, SIGNAL(sigEnsureRowVisible(int)), SLOT(slotEnsureRowVisible(int)));
320}
void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
void slotHeaderDataChanged(Qt::Orientation orientation, int first, int last)
void slotTryTransferSelectionBetweenRows(int fromRow, int toRow)

References m_d, slotDataChanged(), slotEnsureRowVisible(), slotHeaderDataChanged(), slotReselectCurrentIndex(), slotTryTransferSelectionBetweenRows(), and slotUpdateInfiniteFramesCount().

◆ slotAddBlankFrame

void KisAnimTimelineFramesView::slotAddBlankFrame ( )
slot

Definition at line 663 of file KisAnimTimelineFramesView.cpp.

664{
665 QModelIndexList selectedIndices = calculateSelectionSpan(false);
666 Q_FOREACH(const QModelIndex &index, selectedIndices) {
667 if (!index.isValid() ||
668 !m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) {
669 selectedIndices.removeOne(index);
670 }
671 }
672
673 m_d->model->createFrame(selectedIndices);
674}

References calculateSelectionSpan(), KisTimeBasedItemModel::FrameEditableRole, and m_d.

◆ slotAddDuplicateFrame

void KisAnimTimelineFramesView::slotAddDuplicateFrame ( )
slot

Definition at line 676 of file KisAnimTimelineFramesView.cpp.

677{
678 QModelIndex index = currentIndex();
679 if (!index.isValid() ||
680 !m_d->model->data(index, KisAnimTimelineFramesModel::FrameEditableRole).toBool()) {
681
682 return;
683 }
684
685 m_d->model->copyFrame(index);
686}

References KisTimeBasedItemModel::FrameEditableRole, and m_d.

◆ slotAddExistingLayer

void KisAnimTimelineFramesView::slotAddExistingLayer ( QAction * action)
slot

Definition at line 639 of file KisAnimTimelineFramesView.cpp.

640{
641 QVariant value = action->data();
642
643 if (value.isValid()) {
644 QModelIndex index = currentIndex();
645 const int newRow = index.isValid() ? index.row() + 1 : 0;
646
647 m_d->model->insertOtherLayer(value.toInt(), newRow);
648 }
649}

References m_d, and value().

◆ slotAddNewLayer

void KisAnimTimelineFramesView::slotAddNewLayer ( )
slot

Definition at line 632 of file KisAnimTimelineFramesView.cpp.

633{
634 QModelIndex index = currentIndex();
635 const int newRow = index.isValid() ? index.row() : 0;
636 model()->insertRow(newRow);
637}

◆ slotAudioChannelMute

void KisAnimTimelineFramesView::slotAudioChannelMute ( bool value)
slot

Definition at line 763 of file KisAnimTimelineFramesView.cpp.

764{
765 if (!m_d->model) return;
766
767 if (value != m_d->model->isAudioMuted()) {
768 m_d->model->setAudioMuted(value);
769 }
770}

References m_d, and value().

◆ slotAudioChannelRemove

void KisAnimTimelineFramesView::slotAudioChannelRemove ( )
slot

Definition at line 772 of file KisAnimTimelineFramesView.cpp.

773{
774 if (!m_d->model) return;
775 m_d->model->setAudioChannelFileName(QFileInfo());
776}

References m_d.

◆ slotAudioVolumeChanged

void KisAnimTimelineFramesView::slotAudioVolumeChanged ( int value)
slot

Definition at line 778 of file KisAnimTimelineFramesView.cpp.

779{
780 m_d->model->setAudioVolume(qreal(value) / 100.0);
781}

References m_d, and value().

◆ slotCanvasUpdate

void KisAnimTimelineFramesView::slotCanvasUpdate ( class KoCanvasBase * canvas)
slot

Definition at line 417 of file KisAnimTimelineFramesView.cpp.

418{
419 if (m_d->canvas) {
420 KisCanvas2* canvas2 = dynamic_cast<KisCanvas2*>(m_d->canvas);
421 if (canvas2) {
422 KisCanvasAnimationState* state = canvas2->animationState();
423 state->disconnect(this);
424 }
425 }
426
427 m_d->canvas = canvas;
428
429 horizontalScrollBar()->setEnabled(m_d->canvas != nullptr);
430}
KisCanvasAnimationState * animationState() const
The KisCanvasAnimationState class stores all of the canvas-specific animation state.

References KisCanvas2::animationState(), and m_d.

◆ slotClearCache

void KisAnimTimelineFramesView::slotClearCache ( )
slot

Definition at line 710 of file KisAnimTimelineFramesView.cpp.

710 {
711 m_d->model->clearEntireCache();
712}

References m_d.

◆ slotColorLabelChanged

void KisAnimTimelineFramesView::slotColorLabelChanged ( int label)
slot

Definition at line 624 of file KisAnimTimelineFramesView.cpp.

625{
626 Q_FOREACH(QModelIndex index, selectedIndexes()) {
627 m_d->model->setData(index, label, KisAnimTimelineFramesModel::FrameColorLabelIndexRole);
628 }
630}
void setDefaultFrameColorLabel(int label)

References KisAnimTimelineFramesModel::FrameColorLabelIndexRole, m_d, and KisImageConfig::setDefaultFrameColorLabel().

◆ slotCopyColumns

void KisAnimTimelineFramesView::slotCopyColumns ( )
inlineslot

Definition at line 110 of file KisAnimTimelineFramesView.h.

110{cutCopyImpl(true, true);}
void cutCopyImpl(bool entireColumn, bool copy)

◆ slotCopyFrames

void KisAnimTimelineFramesView::slotCopyFrames ( )
inlineslot

Definition at line 107 of file KisAnimTimelineFramesView.h.

107{cutCopyImpl(false, true);}

◆ slotCutColumns

void KisAnimTimelineFramesView::slotCutColumns ( )
inlineslot

Definition at line 111 of file KisAnimTimelineFramesView.h.

111{cutCopyImpl(true, false);}

◆ slotCutFrames

void KisAnimTimelineFramesView::slotCutFrames ( )
inlineslot

Definition at line 108 of file KisAnimTimelineFramesView.h.

108{cutCopyImpl(false, false);}

◆ slotDataChanged

void KisAnimTimelineFramesView::slotDataChanged ( const QModelIndex & topLeft,
const QModelIndex & bottomRight )
slot

Definition at line 572 of file KisAnimTimelineFramesView.cpp.

573{
574 if (m_d->model->isPlaybackActive()) return;
575
576 int selectedColumn = -1;
577
578 for (int j = topLeft.column(); j <= bottomRight.column(); j++) {
579 QVariant value = m_d->model->data(
580 m_d->model->index(topLeft.row(), j),
582
583 if (value.isValid() && value.toBool()) {
584 selectedColumn = j;
585 break;
586 }
587 }
588
589 QModelIndex index = currentIndex();
590
591 if (!index.isValid() && selectedColumn < 0) {
592 return;
593 }
594
595 if (selectionModel()->selectedIndexes().count() > 1) return;
596
597 if (selectedColumn == -1) {
598 selectedColumn = index.column();
599 }
600
601 if (selectedColumn != index.column() && !m_d->dragInProgress && !m_d->model->isScrubbing()) {
602 int row = index.isValid() ? index.row() : 0;
603 // Todo: This is causing double audio pushes. We should fix this eventually.
604 selectionModel()->setCurrentIndex(m_d->model->index(row, selectedColumn), QItemSelectionModel::ClearAndSelect);
605 }
606}

References KisTimeBasedItemModel::ActiveFrameRole, m_d, and value().

◆ slotEnsureRowVisible

void KisAnimTimelineFramesView::slotEnsureRowVisible ( int row)
slot

Definition at line 834 of file KisAnimTimelineFramesView.cpp.

835{
836 QModelIndex index = currentIndex();
837 if (!index.isValid() || row < 0) return;
838
839 index = m_d->model->index(row, index.column());
840
841 // WORKAROUND BUG:437029
842 // Delay's UI scrolling by 1/60 of a second to compensate for
843 // inconsistent dummy indexing caused by a brief period where
844 // two unpinned dummies exist on the timeline simultaneously.
845 QTimer::singleShot(16, Qt::PreciseTimer, this, [this, index](){
846 scrollTo(index);
847 });
848}

References m_d.

◆ slotFitViewToFrameRange

void KisAnimTimelineFramesView::slotFitViewToFrameRange ( int start,
int end )
slot

Definition at line 850 of file KisAnimTimelineFramesView.cpp.

851{
852 QModelIndex startIndex = currentIndex().siblingAtColumn(start);
853 if (!startIndex.isValid() || start < 0) return;
854
855 KIS_ASSERT(start == 0); //TODO: forcing start to 0 for now, next let's scroll bar to also fit starting value correctly.
856
857 m_d->horizontalRuler->zoomToFitFrameRange(start, end);
858 //scrollTo(startIndex, ScrollHint::PositionAtBottom);
859}
#define KIS_ASSERT(cond)
Definition kis_assert.h:33

References KIS_ASSERT, and m_d.

◆ slotHeaderDataChanged

void KisAnimTimelineFramesView::slotHeaderDataChanged ( Qt::Orientation orientation,
int first,
int last )
slot

Definition at line 608 of file KisAnimTimelineFramesView.cpp.

609{
610 Q_UNUSED(first);
611 Q_UNUSED(last);
612
613 if (orientation == Qt::Horizontal) {
614 const int newFps = m_d->model->headerData(0, Qt::Horizontal, KisAnimTimelineFramesModel::FramesPerSecondRole).toInt();
615
616 if (newFps != m_d->fps) {
617 setFramesPerSecond(newFps);
618 }
619 } else {
620 calculateActiveLayerSelectedTimes(selectedIndexes());
621 }
622}
void calculateActiveLayerSelectedTimes(const QModelIndexList &selection)

References calculateActiveLayerSelectedTimes(), KisTimeBasedItemModel::FramesPerSecondRole, m_d, and setFramesPerSecond().

◆ slotInsertHoldFrame

void KisAnimTimelineFramesView::slotInsertHoldFrame ( )
inlineslot

Definition at line 90 of file KisAnimTimelineFramesView.h.

◆ slotInsertHoldFrameColumn

void KisAnimTimelineFramesView::slotInsertHoldFrameColumn ( )
inlineslot

Definition at line 93 of file KisAnimTimelineFramesView.h.

◆ slotInsertKeyframeColumnLeft

void KisAnimTimelineFramesView::slotInsertKeyframeColumnLeft ( )
inlineslot

Definition at line 78 of file KisAnimTimelineFramesView.h.

References LEFT.

◆ slotInsertKeyframeColumnRight

void KisAnimTimelineFramesView::slotInsertKeyframeColumnRight ( )
inlineslot

Definition at line 79 of file KisAnimTimelineFramesView.h.

References RIGHT.

◆ slotInsertKeyframeLeft

void KisAnimTimelineFramesView::slotInsertKeyframeLeft ( )
inlineslot

Definition at line 75 of file KisAnimTimelineFramesView.h.

References LEFT.

◆ slotInsertKeyframeRight

void KisAnimTimelineFramesView::slotInsertKeyframeRight ( )
inlineslot

Definition at line 76 of file KisAnimTimelineFramesView.h.

References RIGHT.

◆ slotInsertMultipleHoldFrameColumns

void KisAnimTimelineFramesView::slotInsertMultipleHoldFrameColumns ( )
inlineslot

Definition at line 99 of file KisAnimTimelineFramesView.h.

void insertOrRemoveMultipleHoldFrames(bool insertion, bool entireColumn=false)

◆ slotInsertMultipleHoldFrames

void KisAnimTimelineFramesView::slotInsertMultipleHoldFrames ( )
inlineslot

Definition at line 96 of file KisAnimTimelineFramesView.h.

◆ slotInsertMultipleKeyframeColumns

void KisAnimTimelineFramesView::slotInsertMultipleKeyframeColumns ( )
inlineslot

Definition at line 82 of file KisAnimTimelineFramesView.h.

void insertMultipleKeyframes(bool entireColumn=false)

◆ slotInsertMultipleKeyframes

void KisAnimTimelineFramesView::slotInsertMultipleKeyframes ( )
inlineslot

Definition at line 81 of file KisAnimTimelineFramesView.h.

◆ slotLayerContextMenuRequested

void KisAnimTimelineFramesView::slotLayerContextMenuRequested ( const QPoint & globalPos)
slot

Definition at line 658 of file KisAnimTimelineFramesView.cpp.

659{
660 m_d->layerEditingMenu->exec(globalPos);
661}

References m_d.

◆ slotMakeClonesUnique

void KisAnimTimelineFramesView::slotMakeClonesUnique ( )
slot

Definition at line 735 of file KisAnimTimelineFramesView.cpp.

736{
737 if (!m_d->model) return;
738
739 const QModelIndexList indices = calculateSelectionSpan(false);
740 m_d->model->makeClonesUnique(indices);
741}

References calculateSelectionSpan(), and m_d.

◆ slotMirrorColumns

void KisAnimTimelineFramesView::slotMirrorColumns ( )
inlineslot

Definition at line 103 of file KisAnimTimelineFramesView.h.

103{slotMirrorFrames(true);}

◆ slotMirrorFrames

void KisAnimTimelineFramesView::slotMirrorFrames ( bool entireColumn = false)
slot

Definition at line 701 of file KisAnimTimelineFramesView.cpp.

702{
703 const QModelIndexList indexes = calculateSelectionSpan(entireColumn);
704
705 if (!indexes.isEmpty()) {
706 m_d->model->mirrorFrames(indexes);
707 }
708}

References calculateSelectionSpan(), and m_d.

◆ slotPasteColumns

void KisAnimTimelineFramesView::slotPasteColumns ( )
inlineslot

Definition at line 114 of file KisAnimTimelineFramesView.h.

114{slotPasteFrames(true);}

◆ slotPasteFrames

void KisAnimTimelineFramesView::slotPasteFrames ( bool entireColumn = false)
slot

Definition at line 714 of file KisAnimTimelineFramesView.cpp.

715{
716 const QModelIndex currentIndex =
717 !entireColumn ? this->currentIndex() : m_d->model->index(0, this->currentIndex().column());
718
719 if (!currentIndex.isValid()) return;
720
721 QClipboard *cb = QApplication::clipboard();
722 const QMimeData *data = cb->mimeData();
723
724 if (data && data->hasFormat("application/x-krita-frame")) {
725
726 bool dataMoved = false;
727 bool result = m_d->model->dropMimeDataExtended(data, Qt::MoveAction, currentIndex, &dataMoved);
728
729 if (result && dataMoved) {
730 cb->clear();
731 }
732 }
733}

References m_d.

◆ slotRealignScrollBars

void KisAnimTimelineFramesView::slotRealignScrollBars ( )
slot

Definition at line 814 of file KisAnimTimelineFramesView.cpp.

814 {
815 QScrollBar* hBar = horizontalScrollBar();
816 QScrollBar* vBar = verticalScrollBar();
817
818 QSize desiredScrollArea = QSize(width() - verticalHeader()->width(), height() - horizontalHeader()->height());
819
820 // Compensate for corner gap...
821 if (hBar->isVisible() && vBar->isVisible()) {
822 desiredScrollArea -= QSize(vBar->width(), hBar->height());
823 }
824
825 hBar->parentWidget()->layout()->setAlignment(Qt::AlignRight);
826 hBar->setMaximumWidth(desiredScrollArea.width());
827 hBar->setMinimumWidth(desiredScrollArea.width());
828
829 vBar->parentWidget()->layout()->setAlignment(Qt::AlignBottom);
830 vBar->setMaximumHeight(desiredScrollArea.height());
831 vBar->setMinimumHeight(desiredScrollArea.height());
832}

◆ slotRemoveHoldFrame

void KisAnimTimelineFramesView::slotRemoveHoldFrame ( )
inlineslot

Definition at line 91 of file KisAnimTimelineFramesView.h.

◆ slotRemoveHoldFrameColumn

void KisAnimTimelineFramesView::slotRemoveHoldFrameColumn ( )
inlineslot

Definition at line 94 of file KisAnimTimelineFramesView.h.

◆ slotRemoveLayer

void KisAnimTimelineFramesView::slotRemoveLayer ( )
slot

Definition at line 651 of file KisAnimTimelineFramesView.cpp.

652{
653 QModelIndex index = currentIndex();
654 if (!index.isValid()) return;
655 model()->removeRow(index.row());
656}

◆ slotRemoveMultipleHoldFrameColumns

void KisAnimTimelineFramesView::slotRemoveMultipleHoldFrameColumns ( )
inlineslot

Definition at line 100 of file KisAnimTimelineFramesView.h.

◆ slotRemoveMultipleHoldFrames

void KisAnimTimelineFramesView::slotRemoveMultipleHoldFrames ( )
inlineslot

Definition at line 97 of file KisAnimTimelineFramesView.h.

◆ slotRemoveSelectedColumns

void KisAnimTimelineFramesView::slotRemoveSelectedColumns ( )
inlineslot

Definition at line 87 of file KisAnimTimelineFramesView.h.

◆ slotRemoveSelectedColumnsAndShift

void KisAnimTimelineFramesView::slotRemoveSelectedColumnsAndShift ( )
inlineslot

Definition at line 88 of file KisAnimTimelineFramesView.h.

88{slotRemoveSelectedFrames(true, true);}

◆ slotRemoveSelectedFrames

void KisAnimTimelineFramesView::slotRemoveSelectedFrames ( bool entireColumn = false,
bool pull = false )
slot

Definition at line 688 of file KisAnimTimelineFramesView.cpp.

689{
690 const QModelIndexList selectedIndices = calculateSelectionSpan(entireColumn);
691
692 if (!selectedIndices.isEmpty()) {
693 if (pull) {
694 m_d->model->removeFramesAndOffset(selectedIndices);
695 } else {
696 m_d->model->removeFrames(selectedIndices);
697 }
698 }
699}

References calculateSelectionSpan(), and m_d.

◆ slotRemoveSelectedFramesAndShift

void KisAnimTimelineFramesView::slotRemoveSelectedFramesAndShift ( )
inlineslot

Definition at line 85 of file KisAnimTimelineFramesView.h.

85{slotRemoveSelectedFrames(false, true);}

◆ slotReselectCurrentIndex

void KisAnimTimelineFramesView::slotReselectCurrentIndex ( )
slot

Definition at line 524 of file KisAnimTimelineFramesView.cpp.

525{
526 QModelIndex index = currentIndex();
527 currentChanged(index, index);
528}
void currentChanged(const QModelIndex &current, const QModelIndex &previous) override

References currentChanged().

◆ slotScrollerStateChanged

void KisAnimTimelineFramesView::slotScrollerStateChanged ( QScroller::State state)
slot

Definition at line 783 of file KisAnimTimelineFramesView.cpp.

783 {
784
785 if (state == QScroller::Dragging || state == QScroller::Scrolling ) {
786 m_d->kineticScrollInfiniteFrameUpdater.start(16);
787 } else {
788 m_d->kineticScrollInfiniteFrameUpdater.stop();
789 }
790
792}
KRITAWIDGETUTILS_EXPORT void updateCursor(QWidget *source, QScroller::State state)

References m_d, and KisKineticScroller::updateCursor().

◆ slotSelectAudioChannelFile

void KisAnimTimelineFramesView::slotSelectAudioChannelFile ( )
slot

Definition at line 743 of file KisAnimTimelineFramesView.cpp.

744{
745 if (!m_d->model) return;
746
747 QString defaultDir = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
748
749 const QString currentFile = m_d->model->audioChannelFileName();
750 QDir baseDir = QFileInfo(currentFile).absoluteDir();
751 if (baseDir.exists()) {
752 defaultDir = baseDir.absolutePath();
753 }
754
755 const QString result = KisImportExportManager::askForAudioFileName(defaultDir, this);
756 const QFileInfo info(result);
757
758 if (info.exists()) {
759 m_d->model->setAudioChannelFileName(info);
760 }
761}
static QString askForAudioFileName(const QString &defaultDir, QWidget *parent)

References KisImportExportManager::askForAudioFileName(), and m_d.

◆ slotSelectionChanged

void KisAnimTimelineFramesView::slotSelectionChanged ( )
slot

Definition at line 499 of file KisAnimTimelineFramesView.cpp.

500{
501 int minColumn = std::numeric_limits<int>::max();
502 int maxColumn = std::numeric_limits<int>::min();
503
504 calculateActiveLayerSelectedTimes(selectedIndexes());
505
506 foreach (const QModelIndex &idx, selectedIndexes()) {
507 if (idx.column() > maxColumn) {
508 maxColumn = idx.column();
509 }
510
511 if (idx.column() < minColumn) {
512 minColumn = idx.column();
513 }
514 }
515
516 KisTimeSpan range;
517 if (maxColumn > minColumn) {
518 range = KisTimeSpan::fromTimeWithDuration(minColumn, maxColumn - minColumn + 1);
519 }
520
521 m_d->model->setPlaybackRange(range);
522}
static KisTimeSpan fromTimeWithDuration(int start, int duration)

References calculateActiveLayerSelectedTimes(), KisTimeSpan::fromTimeWithDuration(), and m_d.

◆ slotSetEndTimeToCurrentPosition

void KisAnimTimelineFramesView::slotSetEndTimeToCurrentPosition ( )
slot

Definition at line 549 of file KisAnimTimelineFramesView.cpp.

550{
551 m_d->model->setDocumentClipRangeEnd(this->currentIndex().column());
552}

References m_d.

◆ slotSetStartTimeToCurrentPosition

void KisAnimTimelineFramesView::slotSetStartTimeToCurrentPosition ( )
slot

Definition at line 544 of file KisAnimTimelineFramesView.cpp.

545{
546 m_d->model->setDocumentClipRangeStart(this->currentIndex().column());
547}

References m_d.

◆ slotTryTransferSelectionBetweenRows

void KisAnimTimelineFramesView::slotTryTransferSelectionBetweenRows ( int fromRow,
int toRow )
slot

Definition at line 530 of file KisAnimTimelineFramesView.cpp.

531{
532 //If there's only one selected index, or less, just select the current index if valid...
533 QModelIndex current = model()->index(toRow, m_d->model->currentTime());
534 if (selectedIndexes().count() <= 1) {
535 if (selectedIndexes().count() != 1 ||
536 (selectedIndexes().first().column() == current.column() &&
537 selectedIndexes().first().row() == fromRow)) {
538 setCurrentIndex(current);
539 }
540
541 }
542}

References m_d.

◆ slotUpdateDragInfiniteFramesCount

void KisAnimTimelineFramesView::slotUpdateDragInfiniteFramesCount ( )
slot

Definition at line 807 of file KisAnimTimelineFramesView.cpp.

807 {
808 if(m_d->dragInProgress ||
809 (m_d->model->isScrubbing() && horizontalScrollBar()->sliderPosition() == horizontalScrollBar()->maximum()) ) {
811 }
812}

References m_d, and slotUpdateInfiniteFramesCount().

◆ slotUpdateFrameActions

void KisAnimTimelineFramesView::slotUpdateFrameActions ( )
slot

Definition at line 456 of file KisAnimTimelineFramesView.cpp.

457{
458 if (!m_d->actionMan) return;
459
460 const QModelIndexList editableIndexes = calculateSelectionSpan(false, true);
461 const bool hasEditableFrames = !editableIndexes.isEmpty();
462
463 bool hasExistingFrames = false;
464 Q_FOREACH (const QModelIndex &index, editableIndexes) {
465 if (model()->data(index, KisAnimTimelineFramesModel::FrameExistsRole).toBool()) {
466 hasExistingFrames = true;
467 break;
468 }
469 }
470
471 auto enableAction = [this] (const QString &id, bool value) {
472 KisAction *action = m_d->actionMan->actionByName(id);
474 action->setEnabled(value);
475 };
476
477 enableAction("add_blank_frame", hasEditableFrames);
478 enableAction("add_duplicate_frame", hasEditableFrames);
479
480 enableAction("insert_keyframe_left", hasEditableFrames);
481 enableAction("insert_keyframe_right", hasEditableFrames);
482 enableAction("insert_multiple_keyframes", hasEditableFrames);
483
484 enableAction("remove_frames", hasEditableFrames && hasExistingFrames);
485 enableAction("remove_frames_and_pull", hasEditableFrames);
486
487 enableAction("insert_hold_frame", hasEditableFrames);
488 enableAction("insert_multiple_hold_frames", hasEditableFrames);
489
490 enableAction("remove_hold_frame", hasEditableFrames);
491 enableAction("remove_multiple_hold_frames", hasEditableFrames);
492
493 enableAction("mirror_frames", hasEditableFrames && editableIndexes.size() > 1);
494
495 enableAction("copy_frames", true);
496 enableAction("cut_frames", hasEditableFrames);
497}
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References calculateSelectionSpan(), KisTimeBasedItemModel::FrameExistsRole, KIS_SAFE_ASSERT_RECOVER_RETURN, m_d, and value().

◆ slotUpdateIcons

void KisAnimTimelineFramesView::slotUpdateIcons ( )
slot

Definition at line 432 of file KisAnimTimelineFramesView.cpp.

433{
434 m_d->addLayersButton->setIcon(KisIconUtils::loadIcon("list-add-22"));
435 m_d->zoomDragButton->setIcon(KisIconUtils::loadIcon("zoom-horizontal"));
436}

References KisIconUtils::loadIcon(), and m_d.

◆ slotUpdateInfiniteFramesCount

void KisAnimTimelineFramesView::slotUpdateInfiniteFramesCount ( )
slot

Definition at line 566 of file KisAnimTimelineFramesView.cpp.

567{
568 const int lastVisibleFrame = m_d->horizontalRuler->estimateLastVisibleColumn();
569 m_d->model->setLastVisibleFrame(lastVisibleFrame);
570}

References m_d.

◆ slotUpdateLayersMenu

void KisAnimTimelineFramesView::slotUpdateLayersMenu ( )
slot

Definition at line 438 of file KisAnimTimelineFramesView.cpp.

439{
440 QAction *action = 0;
441
442 m_d->existingLayersMenu->clear();
443
444 QVariant value = model()->headerData(0, Qt::Vertical, KisAnimTimelineFramesModel::OtherLayersRole);
445 if (value.isValid()) {
447
448 int i = 0;
449 Q_FOREACH (const KisAnimTimelineFramesModel::OtherLayer &l, list) {
450 action = m_d->existingLayersMenu->addAction(l.name);
451 action->setData(i++);
452 }
453 }
454}

References m_d, TimelineNodeListKeeper::OtherLayer::name, KisAnimTimelineFramesModel::OtherLayersRole, and value().

◆ slotUpdatePlaybackRange

void KisAnimTimelineFramesView::slotUpdatePlaybackRange ( )
slot

Definition at line 554 of file KisAnimTimelineFramesView.cpp.

555{
556 QSet<int> rows;
557 int minColumn = 0;
558 int maxColumn = 0;
559
560 calculateSelectionMetrics(minColumn, maxColumn, rows, true);
561
562 m_d->model->setDocumentClipRangeStart(minColumn);
563 m_d->model->setDocumentClipRangeEnd(maxColumn);
564}

References calculateSelectionMetrics(), and m_d.

◆ slotZoom

void KisAnimTimelineFramesView::slotZoom ( qreal zoom)
slot

Definition at line 794 of file KisAnimTimelineFramesView.cpp.

795{
796 const int originalFirstColumn = m_d->horizontalRuler->estimateFirstVisibleColumn();
797 if (m_d->horizontalRuler->setZoom(m_d->horizontalRuler->zoom() + zoom)) {
798 const int newLastColumn = m_d->horizontalRuler->estimateFirstVisibleColumn();
799 if (newLastColumn >= m_d->model->columnCount()) {
801 }
802 viewport()->update();
803 horizontalScrollBar()->setValue(scrollPositionFromColumn(originalFirstColumn));
804 }
805}

References m_d, scrollPositionFromColumn(), and slotUpdateInfiniteFramesCount().

◆ startDrag()

void KisAnimTimelineFramesView::startDrag ( Qt::DropActions supportedActions)
overrideprotected

Workaround for Qt5's bug: if we start a dragging action right during Shift-selection, Qt will get crazy. We cannot workaround it easily, because we would need to fork mouseMoveEvent() for that (where the decision about drag state is done). So we just abort dragging in that case.

BUG:373067

Workaround for Qt5's bugs:

1) Qt doesn't treat selection the selection on D&D correctly, so we save it in advance and restore afterwards.

2) There is a private variable in QAbstractItemView: QAbstractItemView::Private::currentSelectionStartIndex. It is initialized only when the setCurrentIndex() is called explicitly on the view object, not on the selection model. Therefore we should explicitly call setCurrentIndex() after D&D, even if it already has correct value!

2) We should also call selectionModel()->select() explicitly. There are two reasons for it: 1) Qt doesn't maintain selection over D&D; 2) when reselecting single element after D&D, Qt goes crazy, because it tries to read global keyboard modifiers. Therefore if we are dragging with Shift or Ctrl pressed it'll get crazy. So just reset it explicitly.

Definition at line 1114 of file KisAnimTimelineFramesView.cpp.

1115{
1116 QModelIndexList indexes = selectionModel()->selectedIndexes();
1117
1118 if (!indexes.isEmpty() && m_d->modifiersCatcher->modifierPressed("offset-frame")) {
1119 QVector<int> rows;
1120 int leftmostColumn = std::numeric_limits<int>::max();
1121
1122 Q_FOREACH (const QModelIndex &index, indexes) {
1123 leftmostColumn = qMin(leftmostColumn, index.column());
1124 if (!rows.contains(index.row())) {
1125 rows.append(index.row());
1126 }
1127 }
1128
1129 const int lastColumn = m_d->model->columnCount() - 1;
1130
1131 selectionModel()->clear();
1132 Q_FOREACH (const int row, rows) {
1133 QItemSelection sel(m_d->model->index(row, leftmostColumn), m_d->model->index(row, lastColumn));
1134 selectionModel()->select(sel, QItemSelectionModel::Select);
1135 }
1136
1137 supportedActions = Qt::MoveAction;
1138
1139 {
1140 QModelIndexList indexes = selectedIndexes();
1141 for(int i = indexes.count() - 1 ; i >= 0; --i) {
1142 if (!isIndexDragEnabled(m_d->model, indexes.at(i)))
1143 indexes.removeAt(i);
1144 }
1145
1146 selectionModel()->clear();
1147
1148 if (indexes.count() > 0) {
1149 QMimeData *data = m_d->model->mimeData(indexes);
1150 if (!data)
1151 return;
1152 QRect rect;
1153 QPixmap pixmap = m_d->renderToPixmap(indexes, &rect);
1154 rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
1155 QDrag *drag = new QDrag(this);
1156 drag->setPixmap(pixmap);
1157 drag->setMimeData(data);
1158 drag->setHotSpot(m_d->lastPressedPosition - rect.topLeft());
1159 drag->exec(supportedActions, Qt::MoveAction);
1160 setCurrentIndex(currentIndex());
1161 }
1162 }
1163 } else {
1173 if (m_d->lastPressedModifier & Qt::ShiftModifier) {
1174 return;
1175 }
1176
1200 QModelIndexList selectionBefore = selectionModel()->selectedIndexes();
1201 QModelIndex currentBefore = selectionModel()->currentIndex();
1202
1203 // initialize a global status variable
1204 m_d->dragWasSuccessful = false;
1205 QAbstractItemView::startDrag(supportedActions);
1206
1207 QModelIndex newCurrent;
1208 QPoint selectionOffset;
1209
1210 if (m_d->dragWasSuccessful) {
1211 newCurrent = currentIndex();
1212 selectionOffset = QPoint(newCurrent.column() - currentBefore.column(),
1213 newCurrent.row() - currentBefore.row());
1214 } else {
1215 newCurrent = currentBefore;
1216 selectionOffset = QPoint();
1217 }
1218
1219 setCurrentIndex(newCurrent);
1220 selectionModel()->clearSelection();
1221 Q_FOREACH (const QModelIndex &idx, selectionBefore) {
1222 QModelIndex newIndex =
1223 model()->index(idx.row() + selectionOffset.y(),
1224 idx.column() + selectionOffset.x());
1225 selectionModel()->select(newIndex, QItemSelectionModel::Select);
1226 }
1227 }
1228}
bool isIndexDragEnabled(QAbstractItemModel *model, const QModelIndex &index)

References isIndexDragEnabled(), and m_d.

◆ updateGeometries()

void KisAnimTimelineFramesView::updateGeometries ( )
override

Definition at line 396 of file KisAnimTimelineFramesView.cpp.

397{
398 QTableView::updateGeometries();
399
400 const int availableHeight = m_d->horizontalRuler->height();
401 const int margin = 2;
402 const int minimalSize = availableHeight - 2 * margin;
403
404 resizeToMinimalSize(m_d->addLayersButton, minimalSize);
405 resizeToMinimalSize(m_d->zoomDragButton, minimalSize);
406
407 int x = 2 * margin;
408 int y = (availableHeight - minimalSize) / 2;
409 m_d->addLayersButton->move(x, 2 * y);
410
411 const int availableWidth = m_d->layersHeader->width();
412
413 x = availableWidth - margin - minimalSize;
414 m_d->zoomDragButton->move(x, 2 * y);
415}
void resizeToMinimalSize(QAbstractButton *w, int minimalSize)

References m_d, and resizeToMinimalSize().

◆ viewportEvent()

bool KisAnimTimelineFramesView::viewportEvent ( QEvent * event)
overrideprotected

Definition at line 873 of file KisAnimTimelineFramesView.cpp.

874{
875 // Seems to have been copied over from KisResourceItemListView.
876 // These tooltips currently give bogus info (empty thumbnail and resource location), so removed for now.
877 // TODO: Implement meaningful tooltips if there's demand, probably including frame thumbnails.
878
879 /*
880 if (event->type() == QEvent::ToolTip && model()) {
881 QHelpEvent *he = static_cast<QHelpEvent *>(event);
882 QModelIndex index = model()->buddy(indexAt(he->pos()));
883 if (index.isValid()) {
884#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
885 QStyleOptionViewItem option = viewOptions();
886#else
887 QStyleOptionViewItem option;
888 initViewItemOption(&option);
889#endif
890 option.rect = visualRect(index);
891 // The offset of the headers is needed to get the correct position inside the view.
892 m_d->tip.showTip(this, he->pos() + QPoint(verticalHeader()->width(), horizontalHeader()->height()), option, index);
893 return true;
894 }
895 }
896 */
897
898 return QTableView::viewportEvent(event);
899}

◆ wheelEvent()

void KisAnimTimelineFramesView::wheelEvent ( QWheelEvent * e)
overrideprotected

Definition at line 1299 of file KisAnimTimelineFramesView.cpp.

1300{
1301 const int scrollDirection = e->angleDelta().y() > 0 ? 1 : -1;
1302 bool mouseOverLayerPanel = verticalHeader()->geometry().contains(verticalHeader()->mapFromGlobal(e->globalPosition().toPoint()));
1303
1304 if (mouseOverLayerPanel) {
1305 QTableView::wheelEvent(e);
1306 } else { // Mouse is over frames table view...
1307 QModelIndex index = currentIndex();
1308 int column= -1;
1309
1310 if (index.isValid()) {
1311 column = index.column() + scrollDirection;
1312 }
1313
1314 if (column >= 0 && !m_d->dragInProgress) {
1316 setCurrentIndex(m_d->model->index(index.row(), column));
1317 }
1318 }
1319}

References m_d, and slotUpdateInfiniteFramesCount().

Member Data Documentation

◆ m_d

const QScopedPointer<Private> KisAnimTimelineFramesView::m_d
private

Definition at line 186 of file KisAnimTimelineFramesView.h.


The documentation for this class was generated from the following files: