Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Copy Current Filter" action #1620

Merged
merged 3 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions src/docks/filtersdock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <QtWidgets/QScrollArea>
#include <QQmlEngine>
#include <QDir>
#include <QMenu>
#include <QUrl>
#include <QQmlContext>
#include <QAction>
Expand Down Expand Up @@ -148,6 +149,15 @@ void FiltersDock::openFilterMenu() const
QMetaObject::invokeMethod(m_qview.rootObject(), "openFilterMenu");
}

void FiltersDock::showCopyFilterMenu()
{
QMenu menu;
menu.addAction(Actions["filtersCopyCurrentFilterAction"]);
menu.addAction(Actions["filtersCopyFiltersAction"]);
menu.addAction(Actions["filtersCopyAllFilterAction"]);
menu.exec(QCursor::pos());
}

void FiltersDock::onServiceInChanged(int delta, Mlt::Service *service)
{
if (delta && service && m_producer.producer().is_valid()
Expand Down Expand Up @@ -183,6 +193,8 @@ void FiltersDock::load()

QObject::connect(m_qview.rootObject(), SIGNAL(currentFilterRequested(int)),
SIGNAL(currentFilterRequested(int)));
QObject::connect(m_qview.rootObject(), SIGNAL(copyFilterRequested()),
SLOT(showCopyFilterMenu()));
}

void FiltersDock::setupActions()
Expand Down Expand Up @@ -217,17 +229,30 @@ void FiltersDock::setupActions()
addAction(action);
Actions.add("filtersRemoveFilterAction", action, windowTitle());

action = new QAction(tr("Copy Filters"), this);
action = new QAction(tr("Copy Enabled"), this);
action->setToolTip(tr("Copy checked filters to the clipboard"));
icon = QIcon::fromTheme("edit-copy",
QIcon(":/icons/oxygen/32x32/actions/edit-copy.png"));
action->setIcon(icon);
connect(action, &QAction::triggered, this, [ = ]() {
QmlApplication::singleton().copyFilters();
QmlApplication::singleton().copyEnabledFilters();
});
addAction(action);
Actions.add("filtersCopyFiltersAction", action, windowTitle());

action = new QAction(tr("Copy Current"), this);
action->setToolTip(tr("Copy current filter to the clipboard"));
connect(action, &QAction::triggered, this, [ = ]() {
QmlApplication::singleton().copyCurrentFilter();
});
addAction(action);
Actions.add("filtersCopyCurrentFilterAction", action, windowTitle());

action = new QAction(tr("Copy All"), this);
action->setToolTip(tr("Copy all filters to the clipboard"));
connect(action, &QAction::triggered, this, [ = ]() {
QmlApplication::singleton().copyAllFilters();
});
addAction(action);
Actions.add("filtersCopyAllFilterAction", action, windowTitle());

action = new QAction(tr("Paste Filters"), this);
action->setToolTip(tr("Paste the filters from the clipboard"));
icon = QIcon::fromTheme("edit-paste",
Expand Down
1 change: 1 addition & 0 deletions src/docks/filtersdock.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public slots:
void onSeeked(int position);
void onShowFrame(const SharedFrame &frame);
void openFilterMenu() const;
void showCopyFilterMenu();
void onServiceInChanged(int delta, Mlt::Service *service);
void load();

Expand Down
25 changes: 19 additions & 6 deletions src/mltcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,13 +1117,14 @@ static int indexOfFirstNonGpu(Producer &toProducer)
}

void Controller::copyFilters(Producer &fromProducer, Producer &toProducer, bool fromClipboard,
bool includeDisabled)
int filterIndex)
{
int in = fromProducer.get(kFilterInProperty) ? fromProducer.get_int(kFilterInProperty) :
fromProducer.get_in();
int out = fromProducer.get(kFilterOutProperty) ? fromProducer.get_int(
kFilterOutProperty) : fromProducer.get_out();
int count = fromProducer.filter_count();
int filterCount = 0;

// Get the index of the first non-GPU filter or link in toProducer
int firstNonGpuService = fromClipboard ? indexOfFirstNonGpu(toProducer) : -1;
Expand All @@ -1132,8 +1133,16 @@ void Controller::copyFilters(Producer &fromProducer, Producer &toProducer, bool
QScopedPointer<Mlt::Filter> fromFilter(fromProducer.filter(i));
if (fromFilter && fromFilter->is_valid() && !fromFilter->get_int("_loader")
&& !fromFilter->get_int(kShotcutHiddenProperty)
&& fromFilter->get("mlt_service")
&& (includeDisabled || !fromFilter->get_int("disable"))) {
&& fromFilter->get("mlt_service")) {

filterCount++;
if (filterIndex >= 0 && filterIndex != (filterCount - 1)) {
continue;
}

if (filterIndex == FILTER_INDEX_ENABLED && fromFilter->get_int("disable")) {
continue;
}

// Determine if filter can be added
auto metadata = MAIN.filterController()->metadataForService(fromFilter.data());
Expand Down Expand Up @@ -1177,6 +1186,10 @@ void Controller::copyFilters(Producer &fromProducer, Producer &toProducer, bool
QScopedPointer<Mlt::Link> fromLink(fromChain.link(i));
if (fromLink && fromLink->is_valid() && fromLink->get("mlt_service")
&& !fromLink->get_int("_loader")) {
filterCount++;
if (filterIndex != -1 && filterIndex != (filterCount - 1)) {
continue;
}
Mlt::Link toLink(fromLink->get("mlt_service"));
if (toLink.is_valid()) {
toLink.inherit(*fromLink);
Expand All @@ -1190,14 +1203,14 @@ void Controller::copyFilters(Producer &fromProducer, Producer &toProducer, bool
}
}

void Controller::copyFilters(Mlt::Producer *producer)
void Controller::copyFilters(Mlt::Producer *producer, int filterIndex)
{
if (producer && producer->is_valid()) {
initFiltersClipboard();
copyFilters(*producer, *m_filtersClipboard, false, false);
copyFilters(*producer, *m_filtersClipboard, false, filterIndex);
} else if (m_producer && m_producer->is_valid()) {
initFiltersClipboard();
copyFilters(*m_producer, *m_filtersClipboard, false, false);
copyFilters(*m_producer, *m_filtersClipboard, false, filterIndex);
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/mltcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ class Controller
virtual int reconfigure(bool isMulti) = 0;

public:
enum {
FILTER_INDEX_ALL = -1,
FILTER_INDEX_ENABLED = -2,
};

static Controller &singleton(QObject *parent = nullptr);
virtual ~Controller();
static void destroy();
Expand Down Expand Up @@ -130,8 +135,8 @@ class Controller
void setUuid(Mlt::Properties &properties, QUuid uid) const;
QUuid ensureHasUuid(Mlt::Properties &properties) const;
static void copyFilters(Mlt::Producer &fromProducer, Mlt::Producer &toProducer,
bool fromClipboard = false, bool includeDisabled = true);
void copyFilters(Mlt::Producer *producer = nullptr);
bool fromClipboard = false, int filterIndex = FILTER_INDEX_ENABLED);
void copyFilters(Mlt::Producer *producer = nullptr, int filterIndex = FILTER_INDEX_ENABLED);
void pasteFilters(Mlt::Producer *producer = nullptr, Mlt::Producer *fromProducer = nullptr);
static void adjustFilters(Mlt::Producer &producer, int startIndex = 0);
static void adjustFilter(Mlt::Filter *filter, int in, int out, int inDelta, int outDelta,
Expand Down
2 changes: 1 addition & 1 deletion src/qml/views/filter/CopyFiltersDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Window {
id: nameDialog

function acceptName() {
application.copyFilters();
application.copyEnabledFilters();
let name = nameField.text.trim();
if (name.length) {
metadatamodel.saveFilterSet(name);
Expand Down
5 changes: 3 additions & 2 deletions src/qml/views/filter/filterview.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Rectangle {
property int selectedIndex: Shotcut.Filter.NoCurrentFilter

signal currentFilterRequested(int attachedIndex)
signal copyFilterRequested()

function clearCurrentFilter() {
if (filterConfig.item) {
Expand Down Expand Up @@ -225,10 +226,10 @@ Rectangle {
icon.source: 'qrc:///icons/oxygen/32x32/actions/edit-copy.png'
enabled: selectedIndex > Shotcut.Filter.NoCurrentFilter
opacity: enabled ? 1 : 0.5
onClicked: application.copyFilters()
onClicked: root.copyFilterRequested()

Shotcut.HoverTip {
text: qsTr('Copy checked filters')
text: qsTr('Copy filters')
}
}

Expand Down
27 changes: 25 additions & 2 deletions src/qmltypes/qmlapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,34 @@ bool QmlApplication::hasFiltersOnClipboard()
return MLT.hasFiltersOnClipboard();
}

void QmlApplication::copyFilters()
void QmlApplication::copyEnabledFilters()
{
QScopedPointer<Mlt::Producer> producer(new Mlt::Producer(
MAIN.filterController()->attachedModel()->producer()));
MLT.copyFilters(producer.data());
MLT.copyFilters(producer.data(), MLT.FILTER_INDEX_ENABLED);
QGuiApplication::clipboard()->setText(MLT.filtersClipboardXML());
emit QmlApplication::singleton().filtersCopied();
}

void QmlApplication::copyAllFilters()
{
QScopedPointer<Mlt::Producer> producer(new Mlt::Producer(
MAIN.filterController()->attachedModel()->producer()));
MLT.copyFilters(producer.data(), MLT.FILTER_INDEX_ENABLED);
QGuiApplication::clipboard()->setText(MLT.filtersClipboardXML());
emit QmlApplication::singleton().filtersCopied();
}

void QmlApplication::copyCurrentFilter()
{
int currentIndex = MAIN.filterController()->currentIndex();
if (currentIndex < 0) {
MAIN.showStatusMessage(tr("Select a filter to copy"));
return;
}
QScopedPointer<Mlt::Producer> producer(new Mlt::Producer(
MAIN.filterController()->attachedModel()->producer()));
MLT.copyFilters(producer.data(), currentIndex);
QGuiApplication::clipboard()->setText(MLT.filtersClipboardXML());
emit QmlApplication::singleton().filtersCopied();
}
Expand Down
4 changes: 3 additions & 1 deletion src/qmltypes/qmlapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ class QmlApplication : public QObject
static QString OS();
static QRect mainWinRect();
static bool hasFiltersOnClipboard();
Q_INVOKABLE static void copyFilters();
Q_INVOKABLE static void copyAllFilters();
Q_INVOKABLE static void copyEnabledFilters();
Q_INVOKABLE static void copyCurrentFilter();
Q_INVOKABLE static void pasteFilters();
Q_INVOKABLE static QString clockFromFrames(int frames);
Q_INVOKABLE static QString timeFromFrames(int frames);
Expand Down
Loading