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< Privatem_d
 

Detailed Description

Definition at line 29 of file KisAnimTimelineFramesView.h.

Constructor & Destructor Documentation

◆ KisAnimTimelineFramesView()

KisAnimTimelineFramesView::KisAnimTimelineFramesView ( QWidget * parent)

Definition at line 132 of file KisAnimTimelineFramesView.cpp.

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

290{
291}

Member Function Documentation

◆ calculateActiveLayerSelectedTimes

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

Definition at line 860 of file KisAnimTimelineFramesView.cpp.

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

References KisAnimTimelineFramesModel::ActiveLayerRole, and m_d.

◆ calculateSelectionMetrics()

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

Definition at line 1428 of file KisAnimTimelineFramesView.cpp.

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

References KisTimeBasedItemModel::FrameEditableRole, and m_d.

◆ calculateSelectionSpan()

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

Definition at line 1397 of file KisAnimTimelineFramesView.cpp.

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

1596{
1597 const QModelIndexList selectedIndices = calculateSelectionSpan(entireColumn, false);
1598 if (selectedIndices.isEmpty()) return;
1599
1600 int minColumn = std::numeric_limits<int>::max();
1601 int minRow = std::numeric_limits<int>::max();
1602 Q_FOREACH (const QModelIndex &index, selectedIndices) {
1603 minRow = qMin(minRow, index.row());
1604 minColumn = qMin(minColumn, index.column());
1605 }
1606
1607 const QModelIndex baseIndex = m_d->model->index(minRow, minColumn);
1608 QMimeData *data = m_d->model->mimeDataExtended(selectedIndices,
1609 baseIndex,
1611
1612 if (data) {
1613 QClipboard *cb = QApplication::clipboard();
1614 cb->setMimeData(data);
1615 }
1616}
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 1618 of file KisAnimTimelineFramesView.cpp.

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

1334{
1335 QTableView::currentChanged(current, previous);
1336
1337 if (previous.column() != current.column()) {
1338 m_d->model->setData(previous, false, KisAnimTimelineFramesModel::ActiveFrameRole);
1339 m_d->model->setData(current, true, KisAnimTimelineFramesModel::ActiveFrameRole);
1340 if ( current.column() != m_d->model->currentTime() ) {
1341 m_d->model->setData(current, QVariant(int(SEEK_FINALIZE | SEEK_PUSH_AUDIO)), KisAnimTimelineFramesModel::ScrubToRole);
1342 }
1343 }
1344}
@ 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 1570 of file KisAnimTimelineFramesView.cpp.

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

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

◆ dragEnterEvent()

void KisAnimTimelineFramesView::dragEnterEvent ( QDragEnterEvent * event)
overrideprotected

Definition at line 1229 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ dragLeaveEvent()

void KisAnimTimelineFramesView::dragLeaveEvent ( QDragLeaveEvent * event)
overrideprotected

Definition at line 1262 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ dragMoveEvent()

void KisAnimTimelineFramesView::dragMoveEvent ( QDragMoveEvent * event)
overrideprotected

Definition at line 1237 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ dropEvent()

void KisAnimTimelineFramesView::dropEvent ( QDropEvent * event)
overrideprotected

Definition at line 1270 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ fanSelectedFrames()

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

Definition at line 1540 of file KisAnimTimelineFramesView.cpp.

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

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 1443 of file KisAnimTimelineFramesView.cpp.

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

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

◆ insertMultipleKeyframes()

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

Definition at line 1472 of file KisAnimTimelineFramesView.cpp.

1473{
1474 int count, timing;
1475 TimelineDirection direction;
1476
1477 if (m_d->insertKeyframeDialog->promptUserSettings(count, timing, direction)) {
1478 insertKeyframes(count, timing, direction, entireColumn);
1479 }
1480}
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 1482 of file KisAnimTimelineFramesView.cpp.

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

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

References insertOrRemoveHoldFrames(), and m_d.

◆ mouseDoubleClickEvent()

void KisAnimTimelineFramesView::mouseDoubleClickEvent ( QMouseEvent * event)
overrideprotected

Definition at line 1033 of file KisAnimTimelineFramesView.cpp.

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

◆ mouseMoveEvent()

void KisAnimTimelineFramesView::mouseMoveEvent ( QMouseEvent * e)
overrideprotected

Definition at line 1047 of file KisAnimTimelineFramesView.cpp.

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

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

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

References m_d.

◆ resizeEvent()

void KisAnimTimelineFramesView::resizeEvent ( QResizeEvent * e)
overrideprotected

Definition at line 1320 of file KisAnimTimelineFramesView.cpp.

1321{
1322 Q_UNUSED(event);
1323
1326}

References slotUpdateInfiniteFramesCount(), and updateGeometries().

◆ rowsInserted()

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

Definition at line 1328 of file KisAnimTimelineFramesView.cpp.

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

◆ scrollPositionFromColumn()

int KisAnimTimelineFramesView::scrollPositionFromColumn ( int column)
private

Definition at line 1688 of file KisAnimTimelineFramesView.cpp.

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

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 1346 of file KisAnimTimelineFramesView.cpp.

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

◆ setActionManager()

void KisAnimTimelineFramesView::setActionManager ( KisActionManager * actionManager)

Definition at line 321 of file KisAnimTimelineFramesView.cpp.

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

References clone(), connect(), 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 1391 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ setModel()

void KisAnimTimelineFramesView::setModel ( QAbstractItemModel * model)
override

Definition at line 293 of file KisAnimTimelineFramesView.cpp.

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

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

◆ slotAddBlankFrame

void KisAnimTimelineFramesView::slotAddBlankFrame ( )
slot

Definition at line 662 of file KisAnimTimelineFramesView.cpp.

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

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

◆ slotAddDuplicateFrame

void KisAnimTimelineFramesView::slotAddDuplicateFrame ( )
slot

Definition at line 675 of file KisAnimTimelineFramesView.cpp.

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

References KisTimeBasedItemModel::FrameEditableRole, and m_d.

◆ slotAddExistingLayer

void KisAnimTimelineFramesView::slotAddExistingLayer ( QAction * action)
slot

Definition at line 638 of file KisAnimTimelineFramesView.cpp.

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

References m_d, and value().

◆ slotAddNewLayer

void KisAnimTimelineFramesView::slotAddNewLayer ( )
slot

Definition at line 631 of file KisAnimTimelineFramesView.cpp.

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

◆ slotAudioChannelMute

void KisAnimTimelineFramesView::slotAudioChannelMute ( bool value)
slot

Definition at line 762 of file KisAnimTimelineFramesView.cpp.

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

References m_d, and value().

◆ slotAudioChannelRemove

void KisAnimTimelineFramesView::slotAudioChannelRemove ( )
slot

Definition at line 771 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotAudioVolumeChanged

void KisAnimTimelineFramesView::slotAudioVolumeChanged ( int value)
slot

Definition at line 777 of file KisAnimTimelineFramesView.cpp.

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

References m_d, and value().

◆ slotCanvasUpdate

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

Definition at line 416 of file KisAnimTimelineFramesView.cpp.

417{
418 if (m_d->canvas) {
419 KisCanvas2* canvas2 = dynamic_cast<KisCanvas2*>(m_d->canvas);
420 if (canvas2) {
421 KisCanvasAnimationState* state = canvas2->animationState();
422 state->disconnect(this);
423 }
424 }
425
426 m_d->canvas = canvas;
427
428 horizontalScrollBar()->setEnabled(m_d->canvas != nullptr);
429}
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 709 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotColorLabelChanged

void KisAnimTimelineFramesView::slotColorLabelChanged ( int label)
slot

Definition at line 623 of file KisAnimTimelineFramesView.cpp.

624{
625 Q_FOREACH(QModelIndex index, selectedIndexes()) {
626 m_d->model->setData(index, label, KisAnimTimelineFramesModel::FrameColorLabelIndexRole);
627 }
629}
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 571 of file KisAnimTimelineFramesView.cpp.

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

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

◆ slotEnsureRowVisible

void KisAnimTimelineFramesView::slotEnsureRowVisible ( int row)
slot

Definition at line 833 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotFitViewToFrameRange

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

Definition at line 849 of file KisAnimTimelineFramesView.cpp.

850{
851 QModelIndex startIndex = currentIndex().siblingAtColumn(start);
852 if (!startIndex.isValid() || start < 0) return;
853
854 KIS_ASSERT(start == 0); //TODO: forcing start to 0 for now, next let's scroll bar to also fit starting value correctly.
855
856 m_d->horizontalRuler->zoomToFitFrameRange(start, end);
857 //scrollTo(startIndex, ScrollHint::PositionAtBottom);
858}
#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 607 of file KisAnimTimelineFramesView.cpp.

608{
609 Q_UNUSED(first);
610 Q_UNUSED(last);
611
612 if (orientation == Qt::Horizontal) {
613 const int newFps = m_d->model->headerData(0, Qt::Horizontal, KisAnimTimelineFramesModel::FramesPerSecondRole).toInt();
614
615 if (newFps != m_d->fps) {
616 setFramesPerSecond(newFps);
617 }
618 } else {
619 calculateActiveLayerSelectedTimes(selectedIndexes());
620 }
621}
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 657 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotMakeClonesUnique

void KisAnimTimelineFramesView::slotMakeClonesUnique ( )
slot

Definition at line 734 of file KisAnimTimelineFramesView.cpp.

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

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 700 of file KisAnimTimelineFramesView.cpp.

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

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 713 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotRealignScrollBars

void KisAnimTimelineFramesView::slotRealignScrollBars ( )
slot

Definition at line 813 of file KisAnimTimelineFramesView.cpp.

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

◆ 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 650 of file KisAnimTimelineFramesView.cpp.

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

◆ 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 687 of file KisAnimTimelineFramesView.cpp.

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

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 523 of file KisAnimTimelineFramesView.cpp.

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

References currentChanged().

◆ slotScrollerStateChanged

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

Definition at line 782 of file KisAnimTimelineFramesView.cpp.

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

References m_d, and KisKineticScroller::updateCursor().

◆ slotSelectAudioChannelFile

void KisAnimTimelineFramesView::slotSelectAudioChannelFile ( )
slot

Definition at line 742 of file KisAnimTimelineFramesView.cpp.

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

References KisImportExportManager::askForAudioFileName(), and m_d.

◆ slotSelectionChanged

void KisAnimTimelineFramesView::slotSelectionChanged ( )
slot

Definition at line 498 of file KisAnimTimelineFramesView.cpp.

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

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

◆ slotSetEndTimeToCurrentPosition

void KisAnimTimelineFramesView::slotSetEndTimeToCurrentPosition ( )
slot

Definition at line 548 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotSetStartTimeToCurrentPosition

void KisAnimTimelineFramesView::slotSetStartTimeToCurrentPosition ( )
slot

Definition at line 543 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotTryTransferSelectionBetweenRows

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

Definition at line 529 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotUpdateDragInfiniteFramesCount

void KisAnimTimelineFramesView::slotUpdateDragInfiniteFramesCount ( )
slot

Definition at line 806 of file KisAnimTimelineFramesView.cpp.

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

References m_d, and slotUpdateInfiniteFramesCount().

◆ slotUpdateFrameActions

void KisAnimTimelineFramesView::slotUpdateFrameActions ( )
slot

Definition at line 455 of file KisAnimTimelineFramesView.cpp.

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

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

References KisIconUtils::loadIcon(), and m_d.

◆ slotUpdateInfiniteFramesCount

void KisAnimTimelineFramesView::slotUpdateInfiniteFramesCount ( )
slot

Definition at line 565 of file KisAnimTimelineFramesView.cpp.

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

References m_d.

◆ slotUpdateLayersMenu

void KisAnimTimelineFramesView::slotUpdateLayersMenu ( )
slot

Definition at line 437 of file KisAnimTimelineFramesView.cpp.

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

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

◆ slotUpdatePlaybackRange

void KisAnimTimelineFramesView::slotUpdatePlaybackRange ( )
slot

Definition at line 553 of file KisAnimTimelineFramesView.cpp.

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

References calculateSelectionMetrics(), and m_d.

◆ slotZoom

void KisAnimTimelineFramesView::slotZoom ( qreal zoom)
slot

Definition at line 793 of file KisAnimTimelineFramesView.cpp.

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

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 1113 of file KisAnimTimelineFramesView.cpp.

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

References isIndexDragEnabled(), and m_d.

◆ updateGeometries()

void KisAnimTimelineFramesView::updateGeometries ( )
override

Definition at line 395 of file KisAnimTimelineFramesView.cpp.

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

References m_d, and resizeToMinimalSize().

◆ viewportEvent()

bool KisAnimTimelineFramesView::viewportEvent ( QEvent * event)
overrideprotected

Definition at line 872 of file KisAnimTimelineFramesView.cpp.

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

◆ wheelEvent()

void KisAnimTimelineFramesView::wheelEvent ( QWheelEvent * e)
overrideprotected

Definition at line 1298 of file KisAnimTimelineFramesView.cpp.

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

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: