Add option to delete all effects in selected clip/s

Fixes #271
parent 109a0954
......@@ -113,6 +113,63 @@ void EffectStackModel::removeCurrentEffect()
}
}
void EffectStackModel::removeAllEffects(Fun &undo, Fun & redo)
{
QWriteLocker locker(&m_lock);
int current = -1;
if (auto srv = m_masterService.lock()) {
current = srv->get_int("kdenlive:activeeffect");
}
while (rootItem->childCount() > 0) {
std::shared_ptr<EffectItemModel> effect = std::static_pointer_cast<EffectItemModel>(rootItem->child(0));
int parentId = -1;
if (auto ptr = effect->parentItem().lock()) parentId = ptr->getId();
Fun local_undo = addItem_lambda(effect, parentId);
Fun local_redo = removeItem_lambda(effect->getId());
local_redo();
UPDATE_UNDO_REDO(local_redo, local_undo, undo, redo);
}
std::unordered_set<int> fadeIns = m_fadeIns;
std::unordered_set<int> fadeOuts = m_fadeOuts;
Fun undo_current = [this, current, fadeIns, fadeOuts]() {
if (auto srv = m_masterService.lock()) {
srv->set("kdenlive:activeeffect", current);
}
m_fadeIns = fadeIns;
m_fadeOuts = fadeOuts;
QVector<int> roles = {TimelineModel::EffectNamesRole};
if (!m_fadeIns.empty()) {
roles << TimelineModel::FadeInRole;
}
if (!m_fadeOuts.empty()) {
roles << TimelineModel::FadeOutRole;
}
emit dataChanged(QModelIndex(), QModelIndex(), roles);
pCore->updateItemKeyframes(m_ownerId);
return true;
};
Fun redo_current = [this]() {
if (auto srv = m_masterService.lock()) {
srv->set("kdenlive:activeeffect", -1);
}
QVector<int> roles = {TimelineModel::EffectNamesRole};
if (!m_fadeIns.empty()) {
roles << TimelineModel::FadeInRole;
}
if (!m_fadeOuts.empty()) {
roles << TimelineModel::FadeOutRole;
}
m_fadeIns.clear();
m_fadeOuts.clear();
emit dataChanged(QModelIndex(), QModelIndex(), roles);
pCore->updateItemKeyframes(m_ownerId);
return true;
};
redo_current();
PUSH_LAMBDA(redo_current, redo);
PUSH_LAMBDA(undo_current, undo);
}
void EffectStackModel::removeEffect(const std::shared_ptr<EffectItemModel> &effect)
{
qDebug() << "* * ** REMOVING EFFECT FROM STACK!!!\n!!!!!!!!!";
......
......@@ -144,6 +144,9 @@ public:
/* @brief Return true if an asset id is already added to this effect stack */
bool hasEffect(const QString &assetId) const;
/* @brief Remove all effects for this stack */
void removeAllEffects(Fun &undo, Fun & redo);
public slots:
/* @brief Delete an effect from the stack */
......
......@@ -67,6 +67,7 @@
<Action name="delete_all_clip_markers" />
</Menu>
<Action name="auto_transition" />
<Action name="delete_effects" />
<Menu name="extract_audio" ><text>Extract Audio</text>
<ActionList name="audio_transcoders_list" />
</Menu>
......
......@@ -555,6 +555,7 @@ void MainWindow::init()
QMenu *timelineClipMenu = new QMenu(this);
timelineClipMenu->addAction(actionCollection()->action(QStringLiteral("edit_copy")));
timelineClipMenu->addAction(actionCollection()->action(QStringLiteral("paste_effects")));
timelineClipMenu->addAction(actionCollection()->action(QStringLiteral("delete_effects")));
timelineClipMenu->addAction(actionCollection()->action(QStringLiteral("group_clip")));
timelineClipMenu->addAction(actionCollection()->action(QStringLiteral("ungroup_clip")));
timelineClipMenu->addAction(actionCollection()->action(QStringLiteral("edit_item_duration")));
......@@ -1630,6 +1631,16 @@ void MainWindow::setupActions()
pasteEffects->setEnabled(false);
// "C" as data means this action should only be available for clips - not for compositions
pasteEffects->setData('C');
QAction *delEffects = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete Effects"), this);
addAction(QStringLiteral("delete_effects"), delEffects, QKeySequence(), clipActionCategory);
delEffects->setEnabled(false);
// "C" as data means this action should only be available for clips - not for compositions
delEffects->setData('C');
connect(delEffects, &QAction::triggered, [this]() {
getMainTimeline()->controller()->deleteEffects();
});
QAction *groupClip = addAction(QStringLiteral("group_clip"), i18n("Group Clips"), this, SLOT(slotGroupClips()),
QIcon::fromTheme(QStringLiteral("object-group")), Qt::CTRL + Qt::Key_G, clipActionCategory);
......
......@@ -2750,39 +2750,72 @@ void TimelineController::selectCurrentTrack()
m_model->requestSetSelection(ids);
}
void TimelineController::pasteEffects(int targetId)
void TimelineController::deleteEffects(int targetId)
{
std::unordered_set<int> targetIds;
std::unordered_set<int> sel;
if (targetId == -1) {
std::unordered_set<int> sel = m_model->getCurrentSelection();
if (sel.empty()) {
pCore->displayMessage(i18n("No clip selected"), InformationMessage, 500);
sel = m_model->getCurrentSelection();
} else {
if (m_model->m_groups->isInGroup(targetId)) {
sel = {m_model->m_groups->getRootId(targetId)};
} else {
sel = {targetId};
}
for (int s : sel) {
if (m_model->isGroup(s)) {
std::unordered_set<int> sub = m_model->m_groups->getLeaves(s);
for (int current_id : sub) {
if (m_model->isClip(current_id)) {
targetIds.insert(current_id);
}
}
if (sel.empty()) {
pCore->displayMessage(i18n("No clip selected"), InformationMessage, 500);
}
for (int s : sel) {
if (m_model->isGroup(s)) {
std::unordered_set<int> sub = m_model->m_groups->getLeaves(s);
for (int current_id : sub) {
if (m_model->isClip(current_id)) {
targetIds.insert(current_id);
}
} else if (m_model->isClip(s)) {
targetIds.insert(s);
}
} else if (m_model->isClip(s)) {
targetIds.insert(s);
}
}
if (targetIds.empty()) {
pCore->displayMessage(i18n("No clip selected"), InformationMessage, 500);
}
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
for (int target : targetIds) {
std::shared_ptr<EffectStackModel> destStack = m_model->getClipEffectStackModel(target);
destStack->removeAllEffects(undo, redo);
}
pCore->pushUndo(undo, redo, i18n("Delete effects"));
}
void TimelineController::pasteEffects(int targetId)
{
std::unordered_set<int> targetIds;
std::unordered_set<int> sel;
if (targetId == -1) {
sel = m_model->getCurrentSelection();
} else {
if (m_model->m_groups->isInGroup(targetId)) {
targetId = m_model->m_groups->getRootId(targetId);
sel = {m_model->m_groups->getRootId(targetId)};
} else {
sel = {targetId};
}
if (m_model->isGroup(targetId)) {
std::unordered_set<int> sub = m_model->m_groups->getLeaves(targetId);
}
if (sel.empty()) {
pCore->displayMessage(i18n("No clip selected"), InformationMessage, 500);
}
for (int s : sel) {
if (m_model->isGroup(s)) {
std::unordered_set<int> sub = m_model->m_groups->getLeaves(s);
for (int current_id : sub) {
if (m_model->isClip(current_id)) {
targetIds.insert(current_id);
}
}
} else if (m_model->isClip(targetId)) {
targetIds.insert(targetId);
} else if (m_model->isClip(s)) {
targetIds.insert(s);
}
}
if (targetIds.empty()) {
......
......@@ -413,6 +413,7 @@ public:
/* @brief Seeks to selected clip start / end
*/
Q_INVOKABLE void pasteEffects(int targetId = -1);
Q_INVOKABLE void deleteEffects(int targetId = -1);
Q_INVOKABLE double fps() const;
Q_INVOKABLE void addEffectKeyframe(int cid, int frame, double val);
Q_INVOKABLE void removeEffectKeyframe(int cid, int frame);
......
Markdown is supported
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