Commit 23f8c5c8 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Animate track lock icon when trying to perform an operation on a locked track...

Animate track lock icon when trying to perform an operation on a locked track instead of silent failure
parent 5c52d453
Pipeline #272696 passed with stage
in 11 minutes and 19 seconds
......@@ -324,6 +324,10 @@ bool TimelineFunctions::requestClipCutAll(std::shared_ptr<TimelineItemModel> tim
std::pair<int, int> TimelineFunctions::requestSpacerStartOperation(const std::shared_ptr<TimelineItemModel> &timeline, int trackId, int position,
bool ignoreMultiTrackGroups, bool allowGroupBreaking)
{
if (trackId != -1 && timeline->trackIsLocked(trackId)) {
timeline->flashLock(trackId);
return {-1, -1};
}
std::unordered_set<int> clips = timeline->getItemsInRange(trackId, position, -1);
timeline->requestClearSelection();
// Find the first clip on each track to calculate the minimum space operation
......@@ -2244,6 +2248,10 @@ bool TimelineFunctions::requestDeleteBlankAt(const std::shared_ptr<TimelineItemM
}
} else {
// Check we have a blank and that it is in not between 2 grouped clips
if (timeline->trackIsLocked(trackId)) {
timeline->flashLock(trackId);
return false;
}
if (timeline->isSubtitleTrack(trackId)) {
// Subtitle track
if (!timeline->getSubtitleModel()->isBlankAt(position)) {
......@@ -2295,10 +2303,8 @@ bool TimelineFunctions::requestDeleteBlankAt(const std::shared_ptr<TimelineItemM
bool TimelineFunctions::requestDeleteAllBlanksFrom(const std::shared_ptr<TimelineItemModel> &timeline, int trackId, int position)
{
// Abort if track is locked
if (timeline->isSubtitleTrack(trackId) && timeline->getSubtitleModel() && timeline->getSubtitleModel()->isLocked()) {
return false;
}
if (timeline->isTrack(trackId) && timeline->getTrackById_const(trackId)->isLocked()) {
if (timeline->trackIsLocked(trackId)) {
timeline->flashLock(trackId);
return false;
}
// Start undoable command
......@@ -2402,10 +2408,8 @@ bool TimelineFunctions::requestDeleteAllBlanksFrom(const std::shared_ptr<Timelin
bool TimelineFunctions::requestDeleteAllClipsFrom(const std::shared_ptr<TimelineItemModel> &timeline, int trackId, int position)
{
// Abort if track is locked
if (timeline->isSubtitleTrack(trackId) && timeline->getSubtitleModel() && timeline->getSubtitleModel()->isLocked()) {
return false;
}
if (timeline->isTrack(trackId) && timeline->getTrackById_const(trackId)->isLocked()) {
if (timeline->trackIsLocked(trackId)) {
timeline->flashLock(trackId);
return false;
}
// Start undoable command
......
......@@ -6684,3 +6684,12 @@ QByteArray TimelineModel::timelineHash()
QByteArray fileHash = QCryptographicHash::hash(fileData, QCryptographicHash::Md5);
return fileHash;
}
bool TimelineModel::trackIsLocked(int trackId) const
{
Q_ASSERT(isTrack(trackId));
if (isSubtitleTrack(trackId)) {
return m_subtitleModel->isLocked();
}
return getTrackById_const(trackId)->isLocked();
}
......@@ -822,6 +822,8 @@ public:
/** @brief returns the position of the clip start on a playlist */
int getClipStartAt(int tid, int pos, int playlist) const;
int getClipEndAt(int tid, int pos, int playlist) const;
/** @brief returns true if the track trackId is Locked */
bool trackIsLocked(int trackid) const;
protected:
/** @brief Register a new track. This is a call-back meant to be called from TrackModel
......@@ -929,6 +931,8 @@ signals:
void checkTrackDeletion(int tid);
/** @brief Emitted when a clip is deleted to check if it was not used in timeline qml */
void checkItemDeletion(int cid);
/** @brief request animation of the track tid lock icon */
void flashLock(int tid);
protected:
std::unique_ptr<Mlt::Tractor> m_tractor;
......
......@@ -7,6 +7,7 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
Rectangle {
id: trackHeadRoot
......@@ -33,7 +34,7 @@ Rectangle {
nameEdit.selectAll()
}
onIsLockedChanged: {
function animateLock() {
flashLock.restart();
}
......@@ -474,7 +475,10 @@ Rectangle {
width: root.collapsedHeight
height: root.collapsedHeight
focusPolicy: Qt.NoFocus
contentItem: Item {
contentItem: Rectangle {
id: bgRect
color: 'transparent'
anchors.fill: parent
Image {
source: trackHeadRoot.isLocked ? "image://icon/kdenlive-lock" : "image://icon/kdenlive-unlock"
anchors.centerIn: parent
......@@ -498,23 +502,18 @@ Rectangle {
text: isLocked? i18n("Unlock track") : i18n("Lock track")
}
}
SequentialAnimation {
id: flashLock
loops: 1
ScaleAnimator {
target: lockButton
from: 1
to: 1.6
duration: 200
loops: 3
ParallelAnimation {
ScaleAnimator {target: lockButton; from: 1; to: 1.2; duration: 120}
PropertyAnimation {target: bgRect;property: "color"; from: "transparent"; to: "darkred"; duration: 100}
}
ScaleAnimator {
target: lockButton
from: 1.6
to: 1
duration: 200
ParallelAnimation {
ScaleAnimator {target: lockButton; from: 1.6; to: 1; duration: 120}
PropertyAnimation {target: bgRect;property: "color"; from: "darkred"; to: "transparent"; duration: 120}
}
}
}
}
}
Item {
......
......@@ -400,6 +400,15 @@ Rectangle {
return audioCount;
}
function animateLockButton(trackId){
// TODO: fix then multiple subtitles track is implemented
if (trackId == -2) {
flashLock.restart()
} else {
Logic.getTrackHeaderById(trackId).animateLock()
}
}
function getItemAtPos(tk, posx, compositionWanted) {
var track = Logic.getTrackById(tk)
if (track == undefined || track.children == undefined) {
......@@ -1117,7 +1126,10 @@ Rectangle {
width: root.collapsedHeight
height: root.collapsedHeight
focusPolicy: Qt.NoFocus
contentItem: Item {
contentItem: Rectangle {
id: bgRect
anchors.fill: parent
color: "transparent"
Image {
source: root.subtitlesLocked ? "image://icon/kdenlive-lock" : "image://icon/kdenlive-unlock"
anchors.centerIn: parent
......@@ -1143,18 +1155,14 @@ Rectangle {
}
SequentialAnimation {
id: flashLock
loops: 1
ScaleAnimator {
target: lockButton
from: 1
to: 1.6
duration: 200
loops: 3
ParallelAnimation {
ScaleAnimator {target: lockButton; from: 1; to: 1.2; duration: 120}
PropertyAnimation {target: bgRect;property: "color"; from: "transparent"; to: "darkred"; duration: 100}
}
ScaleAnimator {
target: lockButton
from: 1.6
to: 1
duration: 200
ParallelAnimation {
ScaleAnimator {target: lockButton; from: 1.6; to: 1; duration: 120}
PropertyAnimation {target: bgRect;property: "color"; from: "darkred"; to: "transparent"; duration: 120}
}
}
}
......
......@@ -133,6 +133,7 @@ void TimelineController::setModel(std::shared_ptr<TimelineItemModel> model)
connect(m_model.get(), &TimelineModel::selectedMixChanged, this, &TimelineController::selectedMixChanged);
connect(m_model.get(), &TimelineModel::dataChanged, this, &TimelineController::checkClipPosition);
connect(m_model.get(), &TimelineModel::checkTrackDeletion, this, &TimelineController::checkTrackDeletion, Qt::DirectConnection);
connect(m_model.get(), &TimelineModel::flashLock, this, &TimelineController::slotFlashLock);
}
void TimelineController::restoreTargetTracks()
......@@ -604,6 +605,11 @@ int TimelineController::insertComposition(int tid, int position, const QString &
return id;
}
void TimelineController::slotFlashLock(int trackId)
{
QMetaObject::invokeMethod(m_root, "animateLockButton", Qt::QueuedConnection, Q_ARG(QVariant, trackId));
}
void TimelineController::deleteSelectedClips()
{
if (dragOperationRunning()) {
......@@ -612,6 +618,19 @@ void TimelineController::deleteSelectedClips()
return;
}
auto sel = m_model->getCurrentSelection();
// Check if we are operating on a locked track
std::unordered_set<int> trackIds;
for (auto &id : sel) {
if (m_model->isItem(id)) {
trackIds.insert(m_model->getItemTrackId(id));
}
}
for (auto &tid : trackIds) {
if (m_model->trackIsLocked(tid)) {
m_model->flashLock(tid);
return;
}
}
if (sel.empty()) {
// Check if a mix is selected
if (m_model->m_selectedMix > -1 && m_model->isClip(m_model->m_selectedMix)) {
......
......@@ -717,6 +717,8 @@ private slots:
void updateAudioTarget();
/** @brief Dis / enable multi track view. */
void updateMultiTrack();
/** @brief An operation was attempted on a locked track, animate lock icon to make user aware */
void slotFlashLock(int trackId);
public:
/** @brief a list of actions that have to be enabled/disabled depending on the timeline selection */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment