Commit 45f8623b authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Start implementing clip properties panel and properties editing

parent db7214d9
......@@ -34,6 +34,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dialogs/clipcreationdialog.h"
#include "core.h"
#include "mltcontroller/clipcontroller.h"
#include "mltcontroller/clippropertiescontroller.h"
#include "project/projectcommands.h"
#include "projectsortproxymodel.h"
#include "mlt++/Mlt.h"
......@@ -44,7 +46,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QSlider>
#include <QMenu>
#include <QDebug>
#include <QTableWidget>
#include <QUndoCommand>
#include <KSplitterCollapserButton>
EventEater::EventEater(QObject *parent) : QObject(parent)
......@@ -91,7 +93,6 @@ Bin::Bin(QWidget* parent) :
, m_iconSize(160, 90)
, m_propertiesPanel(NULL)
{
// TODO: proper ui, search line, add menu, ...
QVBoxLayout *layout = new QVBoxLayout(this);
// Create toolbar for buttons
......@@ -145,24 +146,6 @@ Bin::Bin(QWidget* parent) :
listType->setToolBarMode(KSelectAction::MenuMode);
connect(listType, SIGNAL(triggered(QAction*)), this, SLOT(slotInitView(QAction*)));
m_toolbar->addAction(listType);
/*m_addButton = new QToolButton;
m_addButton->setPopupMode(QToolButton::MenuButtonPopup);
m_addButton->setAutoRaise(true);
m_addButton->setIconSize(iconSize);
box->addWidget(m_addButton);
m_editButton = new QToolButton;
m_editButton->setAutoRaise(true);
m_editButton->setIconSize(iconSize);
box->addWidget(m_editButton);
m_deleteButton = new QToolButton;
m_deleteButton->setAutoRaise(true);
m_deleteButton->setIconSize(iconSize);
box->addWidget(m_deleteButton);
frame->setLayout(box);
layout->addWidget(frame);*/
m_eventEater = new EventEater(this);
connect(m_eventEater, SIGNAL(addClip()), this, SLOT(slotAddClip()));
......@@ -177,14 +160,6 @@ Bin::Bin(QWidget* parent) :
layout->addWidget(m_splitter);
m_propertiesPanel = new QWidget(m_splitter);
QVBoxLayout *lay = new QVBoxLayout;
m_propertiesPanel->setLayout(lay);
m_propertiesTable = new QTableWidget(this);
m_propertiesTable->setColumnCount(2);
QHeaderView *header = m_propertiesTable->horizontalHeader();
header->setStretchLastSection(true);
lay->addWidget(m_propertiesTable);
m_splitter->addWidget(m_propertiesPanel);
m_collapser = new KSplitterCollapserButton(m_propertiesPanel, m_splitter);
connect(m_collapser, SIGNAL(clicked(bool)), this, SLOT(slotRefreshClipProperties()));
......@@ -458,10 +433,14 @@ void Bin::selectProxyModel(const QModelIndex &id)
}
}
else {
// No item selected in bin
m_editAction->setEnabled(false);
m_deleteAction->setEnabled(false);
// Hide properties panel
m_collapser->collapse();
showClipProperties(NULL);
// Display black bg in clip monitor
//pCore->projectManager()->current()->bin()->monitor()->open(NULL, ClipMonitor);
m_monitor->openClip(NULL);
}
}
......@@ -606,11 +585,14 @@ void Bin::contextMenuEvent(QContextMenuEvent *event)
void Bin::slotRefreshClipProperties()
{
QModelIndex current = m_proxyModel->selectionModel()->currentIndex();
if (current.isValid() && m_proxyModel->selectionModel()->isSelected(current)) {
ProjectClip *clip = static_cast<ProjectClip *>(m_proxyModel->mapToSource(current).internalPointer());
if (clip && !clip->isFolder()) {
showClipProperties(clip);
QModelIndexList indexes = m_proxyModel->selectionModel()->selectedIndexes();
foreach (const QModelIndex &ix, indexes) {
if (ix.isValid()) {
ProjectClip *clip = static_cast<ProjectClip *>(m_proxyModel->mapToSource(ix).internalPointer());
if (clip && !clip->isFolder()) {
showClipProperties(clip);
break;
}
}
}
}
......@@ -643,35 +625,39 @@ void Bin::slotSwitchClipProperties(const QModelIndex &ix)
void Bin::showClipProperties(ProjectClip *clip)
{
closeEditing();
if (!clip || m_propertiesPanel->width() == 0) return;
QMap <QString, QString> props = clip->properties();
m_propertiesTable->clearContents();
if (props.isEmpty()) {
// Producer for this clip is not ready yet or no properties in this clip
QString panelId = m_propertiesPanel->property("clipId").toString();
if (!clip || m_propertiesPanel->width() == 0) {
m_propertiesPanel->setProperty("clipId", QVariant());
foreach (QWidget * w, m_propertiesPanel->findChildren<ClipPropertiesController*>()) {
delete w;
}
return;
}
if (panelId == clip->clipId()) {
// the properties panel is already displaying current clip, do nothing
return;
}
// TODO: Build proper clip properties widget
//PropertiesView *view = new PropertiesView(clip, m_propertiesPanel);
m_propertiesTable->setRowCount(props.size());
m_propertiesTable->horizontalHeader()->hide();
m_propertiesTable->verticalHeader()->hide();
QTableWidgetItem *keyitem;
QTableWidgetItem *valueitem;
QMapIterator<QString, QString> i(props);
int ix = 0;
while (i.hasNext()) {
i.next();
keyitem = new QTableWidgetItem(i.key());
m_propertiesTable->setItem(ix, 0, keyitem);
valueitem = new QTableWidgetItem(i.value());
m_propertiesTable->setItem(ix, 1, valueitem);
ix++;
}
//m_editedProducer= new Producer(producer, desc, pCore->clipPluginManager());
//connect(m_editedProducer, SIGNAL(updateClip()), this, SLOT(refreshEditedClip()));
//connect(m_editedProducer, SIGNAL(reloadClip(QString)), this, SLOT(reloadClip(QString)));
//connect(m_editedProducer, SIGNAL(editingDone()), this, SLOT(closeEditing()));
// Cleanup widget for new content
foreach (QWidget * w, m_propertiesPanel->findChildren<ClipPropertiesController*>()) {
delete w;
}
m_propertiesPanel->setProperty("clipId", clip->clipId());
QVBoxLayout *lay = (QVBoxLayout*) m_propertiesPanel->layout();
if (lay == 0) {
lay = new QVBoxLayout(m_propertiesPanel);
m_propertiesPanel->setLayout(lay);
}
ClipPropertiesController *panel = clip->buildProperties(m_propertiesPanel);
connect(panel, SIGNAL(updateClipProperties(const QString &, QMap<QString, QString>, QMap<QString, QString>)), this, SLOT(slotEditClipCommand(const QString &, QMap<QString, QString>, QMap<QString, QString>)));
lay->addWidget(panel);
}
void Bin::slotEditClipCommand(const QString &id, QMap<QString, QString>oldProps, QMap<QString, QString>newProps)
{
EditClipCommand *command = new EditClipCommand(m_doc, id, oldProps, newProps, true);
m_doc->commandStack()->push(command);
}
void Bin::reloadClip(const QString &id)
......@@ -855,6 +841,12 @@ void Bin::reloadProducer(const QString &id, QDomElement xml)
pCore->projectManager()->current()->renderer()->getFileProperties(xml, id, 150, true);
}
void Bin::refreshMonitor(const QString &id)
{
if (m_monitor->activeClipId() == id)
m_monitor->refreshMonitor();
}
void Bin::discardJobs(const QString &id, AbstractClipJob::JOBTYPE type)
{
m_jobManager->discardJobs(id, type);
......
......@@ -30,7 +30,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QStyledItemDelegate>
#include <QPainter>
#include <QDomElement>
#include <QSortFilterProxyModel>
class KdenliveDoc;
class ClipController;
......@@ -46,7 +45,6 @@ class Monitor;
class QItemSelectionModel;
class ProjectSortProxyModel;
class JobManager;
class QTableWidget;
namespace Mlt {
class Producer;
......@@ -257,6 +255,9 @@ public:
/** @brief Reload / replace a producer */
void reloadProducer(const QString &id, QDomElement xml);
/** @brief Current producer has changed, refresh monitor */
void refreshMonitor(const QString &id);
/** @brief Some stuff used to notify the Item Model */
void emitAboutToAddItem(AbstractProjectItem* item);
......@@ -320,6 +321,7 @@ private slots:
void slotSaveHeaders();
void slotItemDropped(QStringList ids, const QModelIndex &parent);
void slotItemDropped(const QList<QUrl>&urls, const QModelIndex &parent);
void slotEditClipCommand(const QString &id, QMap<QString, QString>oldProps, QMap<QString, QString>newProps);
public slots:
void slotThumbnailReady(const QString &id, const QImage &img);
......@@ -362,7 +364,6 @@ private:
EventEater *m_eventEater;
QWidget *m_propertiesPanel;
QSlider *m_slider;
QTableWidget *m_propertiesTable;
KSplitterCollapserButton *m_collapser;
Monitor *m_monitor;
QMenu *m_menu;
......
......@@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "projectfolder.h"
#include "bin.h"
#include "mltcontroller/clipcontroller.h"
#include "mltcontroller/clippropertiescontroller.h"
#include <QDomElement>
#include <QFile>
......@@ -165,10 +166,14 @@ QString ProjectClip::serializeClip()
return QString();
}
void ProjectClip::reloadProducer()
void ProjectClip::reloadProducer(bool thumbnailOnly)
{
QDomDocument doc;
QDomElement xml = toXml(doc);
if (thumbnailOnly) {
// set a special flag to request thumbnail only
xml.setAttribute("thumbnailOnly", "1");
}
bin()->reloadProducer(m_id, xml);
}
......@@ -378,7 +383,7 @@ bool ProjectClip::hasProxy() const
return true;
}
void ProjectClip::setProperties(QMap <QString, QString> properties)
void ProjectClip::setProperties(QMap <QString, QString> properties, bool refreshPanel)
{
QMapIterator<QString, QString> i(properties);
bool refreshProducer = false;
......@@ -407,7 +412,19 @@ void ProjectClip::setProperties(QMap <QString, QString> properties)
bin()->startJob(m_id, AbstractClipJob::PROXYJOB);
}
}
//if (refreshProducer) slotRefreshProducer();
else if (properties.contains("resource")) {
// Clip resource changed, update thumbnail
reloadProducer(true);
refreshProducer = true;
}
if (refreshPanel) {
// Some of the clip properties have changed through a command, update properties panel
emit refreshPropertiesPanel();
}
if (refreshProducer) {
// producer has changed, refresh monitor
bin()->refreshMonitor(m_id);
}
}
void ProjectClip::setJobStatus(AbstractClipJob::JOBTYPE jobType, ClipJobStatus status, int progress, const QString &statusMessage)
......@@ -425,3 +442,11 @@ void ProjectClip::setJobStatus(AbstractClipJob::JOBTYPE jobType, ClipJobStatus s
bin()->emitItemUpdated(this);
}
ClipPropertiesController *ProjectClip::buildProperties(QWidget *parent)
{
ClipPropertiesController *panel = new ClipPropertiesController(m_id, clipType(), m_controller->properties(), parent);
connect(this, SIGNAL(refreshPropertiesPanel()), panel, SLOT(slotReloadProperties()));
return panel;
}
......@@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
class ProjectFolder;
class QDomElement;
class ClipController;
class ClipPropertiesController;
namespace Mlt {
class Producer;
......@@ -63,7 +64,7 @@ public:
ProjectClip(const QDomElement &description, ProjectFolder *parent);
virtual ~ProjectClip();
void reloadProducer();
void reloadProducer(bool thumbnailOnly = false);
/** @brief Returns a unique hash identifier used to store clip thumbnails. */
//virtual void hash() = 0;
......@@ -78,6 +79,7 @@ public:
/** @brief Returns the clip type as defined in definitions.h */
ClipType clipType() const;
ClipPropertiesController *buildProperties(QWidget *parent);
//TODO
void setZone(const QPoint &zone);
......@@ -134,7 +136,7 @@ public:
QMap <QString, QString> properties();
/** @brief Set properties on this clip. TODO: should we store all in MLT or use extra m_properties ?. */
void setProperties(QMap <QString, QString> properties);
void setProperties(QMap <QString, QString> properties, bool refreshPanel = false);
/** @brief Get an XML property from MLT produced xml. */
static QString getXmlProperty(const QDomElement &producer, const QString &propertyName);
......@@ -184,6 +186,7 @@ private:
signals:
void gotAudioData();
void refreshPropertiesPanel();
};
#endif
......@@ -91,7 +91,8 @@ enum ClipType {
Text = 6,
SlideShow = 7,
Virtual = 8,
Playlist = 9
Playlist = 9,
WebVfx = 10
};
enum ProjectItemType {
......
......@@ -1920,11 +1920,11 @@ void KdenliveDoc::slotProxyCurrentItem(bool doProxy)
else delete command;
}
void KdenliveDoc::slotUpdateClipProperties(const QString &id, QMap <QString, QString> properties)
void KdenliveDoc::slotUpdateClipProperties(const QString &id, QMap <QString, QString> properties, bool refreshPropertiesPanel)
{
ProjectClip *item = pCore->bin()->getBinClip(id);
if (item) {
item->setProperties(properties);
item->setProperties(properties, refreshPropertiesPanel);
}
}
......
......@@ -175,7 +175,7 @@ public:
const QMap <QString, QString> metadata() const;
/** @brief Set the document metadata (author, copyright, ...) */
void setMetadata(const QMap <QString, QString>& meta);
void slotUpdateClipProperties(const QString &id, QMap <QString, QString> properties);
void slotUpdateClipProperties(const QString &id, QMap <QString, QString> properties, bool refreshPropertiesPanel);
/** @brief Get frame size of the renderer */
const QSize getRenderSize();
/** @brief Add url to the file watcher so that we monitor changes */
......
......@@ -99,7 +99,7 @@ ChooseColorWidget::ChooseColorWidget(const QString &text, const QString &color,
rightSideLayout->setContentsMargins(0, 0, 0, 0);
rightSideLayout->setSpacing(0);
m_button = new KColorButton(stringToColor(color), rightSide);
m_button = new KColorButton(color, rightSide);
if (alphaEnabled) m_button->setAlphaChannelEnabled(alphaEnabled);
// m_button->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
ColorPickerWidget *picker = new ColorPickerWidget(rightSide);
......@@ -112,7 +112,7 @@ ChooseColorWidget::ChooseColorWidget(const QString &text, const QString &color,
connect(picker, SIGNAL(colorPicked(QColor)), this, SLOT(setColor(QColor)));
connect(picker, SIGNAL(displayMessage(QString,int)), this, SIGNAL(displayMessage(QString,int)));
connect(picker, SIGNAL(disableCurrentFilter(bool)), this, SIGNAL(disableCurrentFilter(bool)));
connect(m_button, SIGNAL(changed(QColor)), this, SIGNAL(modified()));
connect(m_button, SIGNAL(changed(QColor)), this, SIGNAL(modified(QColor)));
}
QString ChooseColorWidget::getColor() const
......@@ -127,4 +127,9 @@ void ChooseColorWidget::setColor(const QColor& color)
m_button->setColor(color);
}
void ChooseColorWidget::slotColorModified(const QColor &color)
{
blockSignals(true);
m_button->setColor(color);
blockSignals(false);
}
......@@ -47,13 +47,16 @@ public:
private:
KColorButton *m_button;
public slots:
void slotColorModified(const QColor &color);
private slots:
/** @brief Updates the different color choosing options to have all selected @param color. */
void setColor(const QColor &color);
signals:
/** @brief Emitted whenever a different color was chosen. */
void modified();
void modified(QColor = QColor());
void displayMessage(const QString&, int);
/** @brief When user wants to pick a color, it's better to disable filter so we get proper color values. */
void disableCurrentFilter(bool);
......
......@@ -2,4 +2,5 @@ set(kdenlive_SRCS
${kdenlive_SRCS}
mltcontroller/bincontroller.cpp
mltcontroller/clipcontroller.cpp
mltcontroller/clippropertiescontroller.cpp
PARENT_SCOPE)
\ No newline at end of file
......@@ -107,7 +107,7 @@ public:
@param clipState The state of the clip (if we need an audio only or video only producer).
@param speed If the clip has a speed effect (framebuffer producer), we indicate the speed here
*/
Mlt::Producer *getBinClip(const QString &id, int track, PlaylistState::ClipState clipState = PlaylistState::Original, double speed = 1.0);
Mlt::Producer *getBinClip(const QString &id, int track = -1, PlaylistState::ClipState clipState = PlaylistState::Original, double speed = 1.0);
/** @brief Returns the clip data as rendered by MLT's XML consumer, used to duplicate a clip
* @param producer The clip's original producer
......
......@@ -99,32 +99,33 @@ void ClipController::getInfoForProducer()
m_duration = GenTime(m_masterProducer->get_playtime(), m_binController->fps());
if (m_service == "avformat" || m_service == "avformat-novalidate") {
m_clipType = AV;
m_name = m_url.fileName();
}
else if (m_service == "qimage" || m_service == "pixbuf") {
m_clipType = Image;
m_name = m_url.fileName();
m_hasLimitedDuration = false;
}
else if (m_service == "colour" || m_service == "color") {
m_clipType = Color;
m_name = i18n("Color");
m_hasLimitedDuration = false;
}
else if (m_service == "kdenlivetitle") {
m_clipType = Text;
//m_name = m_url.fileName();
m_name = i18n("Title");
m_hasLimitedDuration = false;
}
else if (m_service == "mlt") {
m_clipType = Playlist;
}
else m_clipType = Unknown;
if (m_clipType == AV || m_clipType == Video || m_clipType == Audio || m_clipType == Image || m_clipType == Playlist) {
m_name = m_url.fileName();
}
else if (m_clipType == Color) {
m_name = i18n("Color");
m_hasLimitedDuration = false;
}
else if (m_clipType == Text) {
m_name = i18n("Title");
m_hasLimitedDuration = false;
else if (m_service == "webvfx") {
m_clipType = WebVfx;
m_name = m_url.fileName();
}
else m_clipType = Unknown;
}
bool ClipController::hasLimitedDuration() const
......@@ -467,4 +468,8 @@ const QString ClipController::getClipHash() const
return property("file_hash");
}
Mlt::Properties &ClipController::properties()
{
return *m_properties;
}
/*
Copyright (C) 2012 Till Theato <root@ttill.de>
This file is part of kdenlive. See www.kdenlive.org.
Copyright (C) 2014 Jean-Baptiste Mardelle <jb@kdenlive.org>
This file is part of Kdenlive. See www.kdenlive.org.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLIPCONTROLLER_H
......@@ -130,6 +142,7 @@ public:
void setZone(const QPoint &zone);
QPoint zone() const;
bool hasLimitedDuration() const;
Mlt::Properties &properties();
private:
Mlt::Producer *m_masterProducer;
......
/*
Copyright (C) 2015 Jean-Baptiste Mardelle <jb@kdenlive.org>
This file is part of Kdenlive. See www.kdenlive.org.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "clippropertiescontroller.h"
#include "bincontroller.h"
#include "effectstack/widgets/choosecolorwidget.h"
#include <KLocalizedString>
#include <QUrl>
#include <QDebug>
#include <QPixmap>
#include <QVBoxLayout>
ClipPropertiesController::ClipPropertiesController(const QString &id, ClipType type, Mlt::Properties &properties, QWidget *parent) : QWidget(parent)
, m_id(id)
, m_type(type)
, m_properties(properties)
{
if (type == Color) {
QVBoxLayout *vbox = new QVBoxLayout;
m_originalProperties.insert("resource", m_properties.get("resource"));
mlt_color color = m_properties.get_color("resource");
ChooseColorWidget *choosecolor = new ChooseColorWidget(i18n("Color"), QColor::fromRgb(color.r, color.g, color.b).name(), false, this);
vbox->addWidget(choosecolor);
connect(choosecolor, SIGNAL(displayMessage(QString,int)), this, SIGNAL(displayMessage(QString,int)));
connect(choosecolor, SIGNAL(modified(QColor)), this, SLOT(slotColorModified(QColor)));
connect(this, SIGNAL(modified(QColor)), choosecolor, SLOT(slotColorModified(QColor)));
setLayout(vbox);
vbox->addStretch(10);
choosecolor->show();
}
}
ClipPropertiesController::~ClipPropertiesController()
{
}
void ClipPropertiesController::slotReloadProperties()
{
if (m_type == Color) {
m_originalProperties.insert("resource", m_properties.get("resource"));
mlt_color color = m_properties.get_color("resource");
emit modified(QColor::fromRgb(color.r, color.g, color.b));
}
}
void ClipPropertiesController::slotColorModified(QColor newcolor)
{
QMap <QString, QString> properties;
properties.insert("resource", newcolor.name(QColor::HexArgb));
emit updateClipProperties(m_id, m_originalProperties, properties);
m_originalProperties = properties;
}
/*
Copyright (C) 2015 Jean-Baptiste Mardelle <jb@kdenlive.org>
This file is part of Kdenlive. See www.kdenlive.org.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLIPPROPERTIESCONTROLLER_H