[multimedia/kdenlive] src/titler: Allow drag & drop image files into titler widget
Jean-Baptiste Mardelle <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit c42997854e6c97c30bf68fe5390a44fe61630f1b by Jean-Baptiste Mardelle.
Committed on 18/08/2026 at 08:21.
Pushed by mardelle into branch 'master'.
Allow drag & drop image files into titler widget
M +41 -0 src/titler/graphicsscenerectmove.cpp
M +5 -0 src/titler/graphicsscenerectmove.h
M +35 -18 src/titler/titlewidget.cpp
M +3 -0 src/titler/titlewidget.h
https://invent.kde.org/multimedia/kdenlive/-/commit/c42997854e6c97c30bf68fe5390a44fe61630f1b
diff --git a/src/titler/graphicsscenerectmove.cpp b/src/titler/graphicsscenerectmove.cpp
index 4ae73af4aa..f2081e39e3 100644
--- a/src/titler/graphicsscenerectmove.cpp
+++ b/src/titler/graphicsscenerectmove.cpp
@@ -18,6 +18,8 @@ SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QGraphicsView>
#include <QKeyEvent>
#include <QList>
+#include <QMimeData>
+#include <QMimeDatabase>
#include <QScrollBar>
#include <QTextBlock>
#include <QTextCursor>
@@ -728,6 +730,45 @@ void GraphicsSceneRectMove::contextMenuEvent(QGraphicsSceneContextMenuEvent *)
// Disable QGraphicsScene standard context menu that was crashing
}
+void GraphicsSceneRectMove::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
+{
+ m_dragAllowed = false;
+ if (event->mimeData()->hasUrls()) {
+ QList<QUrl> urls = event->mimeData()->urls();
+ bool imageOnly = true;
+ for (auto &u : urls) {
+ auto mime = QMimeDatabase().mimeTypeForFile(u.toLocalFile());
+ if (!mime.name().startsWith(QStringLiteral("image/"))) {
+ imageOnly = false;
+ break;
+ }
+ }
+ if (imageOnly) {
+ m_dragAllowed = true;
+ event->acceptProposedAction();
+ }
+ } else {
+ QGraphicsScene::dragEnterEvent(event);
+ }
+}
+
+void GraphicsSceneRectMove::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
+{
+ event->setAccepted(m_dragAllowed);
+}
+
+void GraphicsSceneRectMove::dropEvent(QGraphicsSceneDragDropEvent *event)
+{
+ event->setAccepted(m_dragAllowed);
+ QPoint pos = event->scenePos().toPoint();
+ QList<QUrl> urls = event->mimeData()->urls();
+ for (auto &u : urls) {
+ Q_EMIT addImage(u, pos);
+ pos.setX(pos.x() + 10);
+ pos.setY(pos.y() + 10);
+ }
+}
+
void GraphicsSceneRectMove::setSelectedItem(QGraphicsItem *item)
{
clearSelection();
diff --git a/src/titler/graphicsscenerectmove.h b/src/titler/graphicsscenerectmove.h
index 408dd0b011..84b9b0de81 100644
--- a/src/titler/graphicsscenerectmove.h
+++ b/src/titler/graphicsscenerectmove.h
@@ -157,6 +157,9 @@ protected:
void wheelEvent(QGraphicsSceneWheelEvent *wheelEvent) override;
void drawForeground(QPainter *painter, const QRectF &rect) override;
void contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent) override;
+ void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override;
+ void dragMoveEvent(QGraphicsSceneDragDropEvent *event) override;
+ void dropEvent(QGraphicsSceneDragDropEvent *event) override;
private:
void setCursor(const QCursor &);
@@ -179,6 +182,7 @@ private:
QList<QGraphicsItem *> m_lastSnapPreviews;
int m_frameWidth;
int m_frameHeight;
+ bool m_dragAllowed{false};
Q_SIGNALS:
void itemMoved();
@@ -191,4 +195,5 @@ Q_SIGNALS:
void doubleClickEvent();
void copy();
void paste();
+ void addImage(const QUrl &url, const QPoint p);
};
diff --git a/src/titler/titlewidget.cpp b/src/titler/titlewidget.cpp
index c0331a5867..acfe642d31 100644
--- a/src/titler/titlewidget.cpp
+++ b/src/titler/titlewidget.cpp
@@ -435,12 +435,12 @@ TitleWidget::TitleWidget(const QUrl &url, QString projectTitlePath, Monitor *mon
m_buttonLoad = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open Title…"));
m_buttonLoad->setCheckable(false);
m_buttonLoad->setShortcut(Qt::CTRL | Qt::Key_O);
- connect(m_buttonLoad, SIGNAL(triggered()), this, SLOT(loadTitle()));
+ connect(m_buttonLoad, &QAction::triggered, this, [this]() { loadTitle(); }, Qt::QueuedConnection);
m_buttonSave = m_toolbar->addAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18n("Save Title As…"));
m_buttonSave->setCheckable(false);
m_buttonSave->setShortcut(Qt::CTRL | Qt::Key_S);
- connect(m_buttonSave, &QAction::triggered, this, [this]() { saveTitle(); });
+ connect(m_buttonSave, &QAction::triggered, this, [this]() { saveTitle(); }, Qt::QueuedConnection);
m_buttonDownload = new KNSWidgets::Action(i18n("Download New Title Templates…"), QStringLiteral(":data/kdenlive_titles.knsrc"), this);
m_buttonDownload->setShortcut(Qt::ALT | Qt::Key_D);
@@ -457,6 +457,7 @@ TitleWidget::TitleWidget(const QUrl &url, QString projectTitlePath, Monitor *mon
// initialize graphic scene
m_scene = new GraphicsSceneRectMove(TITLERVERSION, m_frameWidth, m_frameHeight, this);
graphicsView->setScene(m_scene);
+ graphicsView->setAcceptDrops(true);
graphicsView->setMouseTracking(true);
graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
@@ -465,6 +466,7 @@ TitleWidget::TitleWidget(const QUrl &url, QString projectTitlePath, Monitor *mon
connect(m_scene, &QGraphicsScene::changed, this, &TitleWidget::slotChanged);
connect(m_scene, &GraphicsSceneRectMove::copy, this, &TitleWidget::slotCopy);
connect(m_scene, &GraphicsSceneRectMove::paste, this, &TitleWidget::slotPaste);
+ connect(m_scene, &GraphicsSceneRectMove::addImage, this, &TitleWidget::addImageToScene);
connect(font_size, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), m_scene, &GraphicsSceneRectMove::slotUpdateFontSize);
connect(use_grid, &QAbstractButton::toggled, m_scene, &GraphicsSceneRectMove::slotUseGrid);
@@ -949,23 +951,38 @@ void TitleWidget::slotImageTool()
QUrl url = QUrl::fromLocalFile(dialog.selectedFiles().at(0));
if (url.isValid()) {
KRecentDirs::add(QStringLiteral(":KdenliveImageFolder"), url.adjusted(QUrl::RemoveFilename).toLocalFile());
- if (url.toLocalFile().endsWith(QLatin1String(".svg"))) {
- MySvgItem *svg = new MySvgItem(url.toLocalFile());
- svg->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
- svg->setZValue(m_count++);
- svg->setData(Qt::UserRole, url.toLocalFile());
- m_scene->addNewItem(svg);
- prepareTools(svg);
- } else {
- QPixmap pix(url.toLocalFile());
- auto *image = new MyPixmapItem(pix);
- image->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
- image->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
- image->setData(Qt::UserRole, url.toLocalFile());
- image->setZValue(m_count++);
- m_scene->addNewItem(image);
- prepareTools(image);
+ addImageToScene(url);
+ } else {
+ m_scene->setTool(GraphicsSceneRectMove::TITLE_SELECT);
+ showToolbars(GraphicsSceneRectMove::TITLE_SELECT);
+ checkButton(GraphicsSceneRectMove::TITLE_SELECT);
+ }
+}
+
+void TitleWidget::addImageToScene(const QUrl url, QPoint pos)
+{
+ if (url.toLocalFile().endsWith(QLatin1String(".svg"))) {
+ MySvgItem *svg = new MySvgItem(url.toLocalFile());
+ svg->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
+ svg->setZValue(m_count++);
+ svg->setData(Qt::UserRole, url.toLocalFile());
+ m_scene->addNewItem(svg);
+ if (!pos.isNull()) {
+ setItemPosition(svg, pos.x(), pos.y());
}
+ prepareTools(svg);
+ } else {
+ QPixmap pix(url.toLocalFile());
+ auto *image = new MyPixmapItem(pix);
+ image->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
+ image->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
+ image->setData(Qt::UserRole, url.toLocalFile());
+ image->setZValue(m_count++);
+ m_scene->addNewItem(image);
+ if (!pos.isNull()) {
+ setItemPosition(image, pos.x(), pos.y());
+ }
+ prepareTools(image);
}
m_scene->setTool(GraphicsSceneRectMove::TITLE_SELECT);
showToolbars(GraphicsSceneRectMove::TITLE_SELECT);
diff --git a/src/titler/titlewidget.h b/src/titler/titlewidget.h
index 988782caba..4ba07a5e8d 100644
--- a/src/titler/titlewidget.h
+++ b/src/titler/titlewidget.h
@@ -343,6 +343,9 @@ private Q_SLOTS:
void setCurrentItem(QGraphicsItem *item);
+ /** @brief Adds an image from its url */
+ void addImageToScene(const QUrl url, QPoint pos = QPoint());
+
void slotTextTool();
void slotRectTool();
void slotEllipseTool();