Commit 04ebbe08 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Basic support for subtitle styling (only one style for all subtitles)

Related to #1450
CCBUG: 437159
parent 62cb16b7
Pipeline #184607 passed with stage
in 7 minutes and 11 seconds
......@@ -60,6 +60,20 @@ SubtitleModel::SubtitleModel(Mlt::Tractor *tractor, std::shared_ptr<TimelineItem
connect(this, &SubtitleModel::modelChanged, [this]() { jsontoSubtitle(toJson()); });
}
void SubtitleModel::setStyle(const QString &style)
{
m_subtitleFilter->set("av.force_style", style.toUtf8().constData());
// Force refresh to show the new style
pCore->requestMonitorRefresh();
pCore->setDocumentModified();
}
const QString SubtitleModel::getStyle() const
{
const QString style = m_subtitleFilter->get("av.force_style");
return style;
}
void SubtitleModel::setup()
{
// We connect the signals of the abstractitemmodel to a more generic one.
......@@ -1211,6 +1225,12 @@ void SubtitleModel::loadProperties(const QMap<QString, QString> &subProperties)
}
++i;
}
if (subProperties.contains(QLatin1String("av.force_style"))) {
emit updateSubtitleStyle(subProperties.value(QLatin1String("av.force_style")));
} else {
emit updateSubtitleStyle(QString());
}
qDebug() << "::::: LOADED SUB PROPS " << subProperties;
}
void SubtitleModel::allSnaps(std::vector<int> &snaps)
......
......@@ -138,6 +138,9 @@ public:
void unsetModel();
/** @brief Get in/out of a subtitle item */
QPair<int, int> getInOut(int sid) const;
/** @brief Set subtitle style (font, color, etc) */
void setStyle(const QString &style);
const QString getStyle() const;
public slots:
/** @brief Function that parses through a subtitle file */
......@@ -171,6 +174,7 @@ private:
signals:
void modelChanged();
void updateSubtitleStyle(const QString);
protected:
/** @brief Add time as snap in the registered snap model */
......
......@@ -51,6 +51,7 @@ SubtitleEdit::SubtitleEdit(QWidget *parent)
buttonIn->setIcon(QIcon::fromTheme(QStringLiteral("zone-in")));
buttonOut->setIcon(QIcon::fromTheme(QStringLiteral("zone-out")));
buttonDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
buttonStyle->setIcon(QIcon::fromTheme(QStringLiteral("format-text-color")));
buttonLock->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-lock")));
auto *keyFilter = new ShiftEnterFilter(this);
subText->installEventFilter(keyFilter);
......@@ -66,6 +67,8 @@ SubtitleEdit::SubtitleEdit(QWidget *parent)
}
});
connect(buttonStyle, &QToolButton::toggled, this, [this](bool toggle) { stackedWidget->setCurrentIndex(toggle ? 1 : 0); });
m_position = new TimecodeDisplay(pCore->timecode(), this);
m_endPosition = new TimecodeDisplay(pCore->timecode(), this);
m_duration = new TimecodeDisplay(pCore->timecode(), this);
......@@ -124,7 +127,66 @@ SubtitleEdit::SubtitleEdit(QWidget *parent)
buttonAdd->setToolTip(i18n("Add subtitle"));
buttonCut->setToolTip(i18n("Split subtitle at cursor position"));
buttonApply->setToolTip(i18n("Update subtitle text"));
buttonStyle->setToolTip(i18n("Show style options"));
buttonDelete->setToolTip(i18n("Delete subtitle"));
// Styling dialog
connect(fontSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &SubtitleEdit::updateStyle);
connect(outlineSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &SubtitleEdit::updateStyle);
connect(fontFamily, &QFontComboBox::currentFontChanged, this, &SubtitleEdit::updateStyle);
connect(fontColor, &KColorButton::changed, this, &SubtitleEdit::updateStyle);
connect(outlineColor, &KColorButton::changed, this, &SubtitleEdit::updateStyle);
connect(checkFont, &QCheckBox::toggled, this, &SubtitleEdit::updateStyle);
connect(checkFontSize, &QCheckBox::toggled, this, &SubtitleEdit::updateStyle);
connect(checkFontColor, &QCheckBox::toggled, this, &SubtitleEdit::updateStyle);
connect(checkOutlineColor, &QCheckBox::toggled, this, &SubtitleEdit::updateStyle);
connect(checkOutlineSize, &QCheckBox::toggled, this, &SubtitleEdit::updateStyle);
connect(checkPosition, &QCheckBox::toggled, this, &SubtitleEdit::updateStyle);
alignment->addItem(i18n("Bottom Center"), 2);
alignment->addItem(i18n("Bottom Left"), 1);
alignment->addItem(i18n("Bottom Right"), 3);
alignment->addItem(i18n("Center Left"), 9);
alignment->addItem(i18n("Center"), 10);
alignment->addItem(i18n("Center Right"), 11);
alignment->addItem(i18n("Top Left"), 4);
alignment->addItem(i18n("Top Center"), 6);
alignment->addItem(i18n("Top Right"), 7);
connect(alignment, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SubtitleEdit::updateStyle);
}
void SubtitleEdit::updateStyle()
{
QString styleString;
if (fontFamily->isEnabled()) {
styleString.append(QStringLiteral("Fontname=%1,").arg(fontFamily->currentFont().family()));
}
if (fontSize->isEnabled()) {
styleString.append(QStringLiteral("Fontsize=%1,").arg(fontSize->value()));
}
if (fontColor->isEnabled()) {
QColor color = fontColor->color();
QColor destColor(color.blue(), color.green(), color.red(), 255 - color.alpha());
// Strip # character
QString colorName = destColor.name(QColor::HexArgb);
colorName.remove(0, 1);
styleString.append(QStringLiteral("PrimaryColour=&H%1,").arg(colorName));
}
if (outlineSize->isEnabled()) {
styleString.append(QStringLiteral("Outline=%1,").arg(outlineSize->value()));
}
if (outlineColor->isEnabled()) {
// Qt AARRGGBB must be converted to AABBGGRR where AA is 255-AA
QColor color = outlineColor->color();
QColor destColor(color.blue(), color.green(), color.red(), 255 - color.alpha());
// Strip # character
QString colorName = destColor.name(QColor::HexArgb);
colorName.remove(0, 1);
styleString.append(QStringLiteral("OutlineColour=&H%1,").arg(colorName));
}
if (alignment->isEnabled()) {
styleString.append(QStringLiteral("Alignment=%1,").arg(alignment->currentData().toInt()));
}
m_model->setStyle(styleString);
}
void SubtitleEdit::setModel(std::shared_ptr<SubtitleModel> model)
......@@ -136,7 +198,9 @@ void SubtitleEdit::setModel(std::shared_ptr<SubtitleModel> model)
if (m_model == nullptr) {
QSignalBlocker bk(subText);
subText->clear();
loadStyle(QString());
} else {
connect(m_model.get(), &SubtitleModel::updateSubtitleStyle, this, &SubtitleEdit::loadStyle);
connect(m_model.get(), &SubtitleModel::dataChanged, this, [this](const QModelIndex &start, const QModelIndex &, const QVector<int> &roles) {
if (m_activeSub > -1 && start.row() == m_model->getRowForId(m_activeSub)) {
if (roles.contains(SubtitleModel::SubtitleRole) || roles.contains(SubtitleModel::StartFrameRole) ||
......@@ -148,6 +212,78 @@ void SubtitleEdit::setModel(std::shared_ptr<SubtitleModel> model)
}
}
void SubtitleEdit::loadStyle(const QString &style)
{
QStringList params = style.split(QLatin1Char(','));
// Read style params
QSignalBlocker bk1(checkFont);
QSignalBlocker bk2(checkFontSize);
QSignalBlocker bk3(checkFontColor);
QSignalBlocker bk4(checkOutlineColor);
QSignalBlocker bk5(checkOutlineSize);
QSignalBlocker bk6(checkPosition);
checkFont->setChecked(false);
checkFontSize->setChecked(false);
checkFontColor->setChecked(false);
checkOutlineColor->setChecked(false);
checkOutlineSize->setChecked(false);
checkPosition->setChecked(false);
fontFamily->setEnabled(false);
fontSize->setEnabled(false);
fontColor->setEnabled(false);
outlineColor->setEnabled(false);
outlineSize->setEnabled(false);
alignment->setEnabled(false);
for (const QString &p : params) {
const QString pName = p.section(QLatin1Char('='), 0, 0);
QString pValue = p.section(QLatin1Char('='), 1);
if (pName == QLatin1String("Fontname")) {
checkFont->setChecked(true);
QFont font(pValue);
QSignalBlocker bk(fontFamily);
fontFamily->setEnabled(true);
fontFamily->setCurrentFont(font);
} else if (pName == QLatin1String("Fontsize")) {
checkFontSize->setChecked(true);
QSignalBlocker bk(fontSize);
fontSize->setEnabled(true);
fontSize->setValue(pValue.toInt());
} else if (pName == QLatin1String("OutlineColour")) {
checkOutlineColor->setChecked(true);
pValue.replace(QLatin1String("&H"), QLatin1String("#"));
QColor col(pValue);
QColor result(col.blue(), col.green(), col.red(), 255 - col.alpha());
QSignalBlocker bk(outlineColor);
outlineColor->setEnabled(true);
outlineColor->setColor(result);
} else if (pName == QLatin1String("Outline")) {
checkOutlineSize->setChecked(true);
QSignalBlocker bk(fontSize);
outlineSize->setEnabled(true);
outlineSize->setValue(pValue.toInt());
} else if (pName == QLatin1String("Alignment")) {
checkPosition->setChecked(true);
QSignalBlocker bk(alignment);
alignment->setEnabled(true);
int ix = alignment->findData(pValue.toInt());
if (ix > -1) {
alignment->setCurrentIndex(ix);
}
} else if (pName == QLatin1String("PrimaryColour")) {
checkFontColor->setChecked(true);
pValue.replace(QLatin1String("&H"), QLatin1String("#"));
QColor col(pValue);
QColor result(col.blue(), col.green(), col.red(), 255 - col.alpha());
QSignalBlocker bk(fontColor);
fontColor->setEnabled(true);
fontColor->setColor(result);
}
}
}
void SubtitleEdit::updateSubtitle()
{
if (!buttonApply->isEnabled()) {
......
......@@ -45,6 +45,8 @@ private slots:
void updateSubtitle();
void goToPrevious();
void goToNext();
void updateStyle();
void loadStyle(const QString &style);
private:
std::shared_ptr<SubtitleModel> m_model;
......
......@@ -1012,6 +1012,10 @@ void EffectStackModel::importEffects(const std::weak_ptr<Mlt::Service> &service,
// subProperties.insert(QStringLiteral("av.filename"), filter->get("av.filename"));
subProperties.insert(QStringLiteral("disable"), filter->get("disable"));
subProperties.insert(QStringLiteral("kdenlive:locked"), filter->get("kdenlive:locked"));
const QString style = filter->get("av.force_style");
if (!style.isEmpty()) {
subProperties.insert(QStringLiteral("av.force_style"), style);
}
pCore->window()->slotEditSubtitle(subProperties);
} else if (auto ms = m_masterService.lock()) {
ms->attach(*filter.get());
......
......@@ -6,132 +6,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>246</width>
<height>281</height>
<width>324</width>
<height>322</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>250</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="3">
<widget class="KTextEdit" name="subText">
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
<property name="checkSpellingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QToolButton" name="buttonDelete">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QFrame" name="frame_position">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QToolButton" name="buttonIn">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="2">
<layout class="QHBoxLayout" name="end_box"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="duration_label_2">
<property name="text">
<string>Duration:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="duration_label">
<property name="text">
<string>End:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="duration_box"/>
</item>
<item row="2" column="1">
<widget class="QToolButton" name="buttonLock">
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="buttonOut">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="position_box"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="position_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Position:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="buttonPrev">
......@@ -174,8 +54,292 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="buttonStyle">
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0" colspan="3">
<widget class="QFrame" name="frame_position">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" colspan="3">
<widget class="KTextEdit" name="subText">
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
<property name="checkSpellingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="position_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Position:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="buttonIn">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="2">
<layout class="QHBoxLayout" name="position_box"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="duration_label">
<property name="text">
<string>End:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QToolButton" name="buttonOut">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="end_box"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="duration_label_2">
<property name="text">
<string>Duration:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QToolButton" name="buttonLock">
<property name="text">
<string>...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2">
<layout class="QHBoxLayout" name="duration_box"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="checkFont">
<property name="text">
<string>Custom Font</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QFontComboBox" name="fontFamily">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkFontSize">
<property name="text">
<string>Custom Font Size</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="fontSize">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string>pt</string>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkFontColor">
<property name="text">
<string>Custom Font Color</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkOutlineColor">
<property name="text">
<string>Custom Outline Color</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="checkOutlineSize">
<property name="text">
<string>Custom Outline Size</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QSpinBox" name="outlineSize">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string>px</string>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="checkPosition">
<property name="text">
<string>Custom Position</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QComboBox" name="alignment">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>92</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<widget class="KColorButton" name="fontColor">
<property name="enabled">
<bool>false</bool>
</property>