From 3948b7754385e6a8a50c2cfced21b051c233b27b Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 23 Jul 2022 13:49:02 -0700 Subject: [PATCH] viewer: allow customizing subtitle font Fixes #1980 --- app/config/config.cpp | 5 ++ app/widget/viewer/viewer.cpp | 37 +++++++++++++-- app/widget/viewer/viewer.h | 2 + app/widget/viewer/viewerdisplay.cpp | 73 +++++++++++++++++++++-------- 4 files changed, 93 insertions(+), 24 deletions(-) diff --git a/app/config/config.cpp b/app/config/config.cpp index 4b62bbacc..ce3888875 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -108,6 +108,11 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("DefaultAudioTransition"), NodeValue::kText, QStringLiteral("org.olivevideoeditor.Olive.crossdissolve")); SetEntryInternal(QStringLiteral("DefaultTransitionLength"), NodeValue::kRational, QVariant::fromValue(rational(1))); + SetEntryInternal(QStringLiteral("DefaultSubtitleSize"), NodeValue::kInt, 48); + SetEntryInternal(QStringLiteral("DefaultSubtitleFamily"), NodeValue::kText, QString()); + SetEntryInternal(QStringLiteral("DefaultSubtitleWeight"), NodeValue::kInt, QFont::Bold); + SetEntryInternal(QStringLiteral("AntialiasSubtitles"), NodeValue::kBoolean, true); + SetEntryInternal(QStringLiteral("AutoCacheDelay"), NodeValue::kInt, 1000); SetEntryInternal(QStringLiteral("CatColor0"), NodeValue::kInt, ColorCoding::kRed); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 82c3a2459..2a9135780 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -21,6 +21,7 @@ #include "viewer.h" #include +#include #include #include #include @@ -32,7 +33,6 @@ #include "audio/audiomanager.h" #include "common/clamp.h" -#include "common/power.h" #include "common/ratiodialog.h" #include "common/timecodefunctions.h" #include "config/config.h" @@ -41,10 +41,9 @@ #include "node/generator/shape/shapenodebase.h" #include "node/project/project.h" #include "render/rendermanager.h" -#include "task/taskmanager.h" #include "viewerpreventsleep.h" +#include "widget/audiomonitor/audiomonitor.h" #include "widget/menu/menu.h" -#include "window/mainwindow/mainwindow.h" #include "widget/nodeparamview/nodeparamviewundo.h" #include "widget/timelinewidget/tool/add.h" #include "widget/timeruler/timeruler.h" @@ -547,6 +546,20 @@ void ViewerWidget::HandleFirstRequeueDestroy() } } +void ViewerWidget::ShowSubtitleProperties() +{ + QFont f(OLIVE_CONFIG("DefaultSubtitleFamily").toString(), OLIVE_CONFIG("DefaultSubtitleSize").toInt(), OLIVE_CONFIG("DefaultSubtitleWeight").toInt()); + QFontDialog fd(f, this); + + if (fd.exec() == QDialog::Accepted) { + f = fd.selectedFont(); + OLIVE_CONFIG("DefaultSubtitleSize") = f.pointSize(); + OLIVE_CONFIG("DefaultSubtitleFamily") = f.family(); + OLIVE_CONFIG("DefaultSubtitleWeight") = f.weight(); + display_widget_->update(); + } +} + void ViewerWidget::CloseAudioProcessor() { audio_processor_.Close(); @@ -1309,10 +1322,26 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) } if (context_menu_widget_ == display_widget_) { - QAction* show_subtitles_action = menu.addAction(tr("Show Subtitles")); + auto subtitle_menu = new Menu(tr("Subtitles"), &menu); + menu.addMenu(subtitle_menu); + + QAction* show_subtitles_action = subtitle_menu->addAction(tr("Show Subtitles")); show_subtitles_action->setCheckable(true); show_subtitles_action->setChecked(display_widget_->GetShowSubtitles()); connect(show_subtitles_action, &QAction::triggered, display_widget_, &ViewerDisplayWidget::SetShowSubtitles); + + subtitle_menu->addSeparator(); + + auto subtitle_font_properties = subtitle_menu->addAction(tr("Subtitle Properties")); + connect(subtitle_font_properties, &QAction::triggered, this, &ViewerWidget::ShowSubtitleProperties); + + auto subtitle_antialias = subtitle_menu->addAction(tr("Use Anti-aliasing")); + subtitle_antialias->setCheckable(true); + subtitle_antialias->setChecked(OLIVE_CONFIG("AntialiasSubtitles").toBool()); + connect(subtitle_antialias, &QAction::triggered, this, [this](bool e){ + OLIVE_CONFIG("AntialiasSubtitles") = e; + display_widget_->update(); + }); } menu.exec(static_cast(sender())->mapToGlobal(pos)); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index f1aefcb85..1c5f126e0 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -352,6 +352,8 @@ private slots: void HandleFirstRequeueDestroy(); + void ShowSubtitleProperties(); + }; } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 5ccb9bbff..8c0b42334 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -463,45 +463,78 @@ void ViewerDisplayWidget::OnPaint() const QVector &subtitle_tracklist = subtitle_tracks_->track_list(Track::kSubtitle)->GetTracks(); if (!subtitle_tracklist.empty()) { - QPainter p(paint_device()); + QPainterPath path; QTransform transform = GenerateWorldTransform(); QRect bounding_box = transform.mapRect(rect()); + QFont f; + qreal font_sz = OLIVE_CONFIG("DefaultSubtitleSize").toInt(); + { + // Scale font size by transform + QTransform display_transform = GenerateDisplayTransform(); + font_sz *= display_transform.m11(); + } + f.setPointSizeF(font_sz); + + QString family = OLIVE_CONFIG("DefaultSubtitleFamily").toString(); + if (!family.isEmpty()) { + f.setFamily(family); + } + + f.setWeight(OLIVE_CONFIG("DefaultSubtitleWeight").toInt()); + bounding_box.adjust(bounding_box.width()/10, bounding_box.height()/10, -bounding_box.width()/10, -bounding_box.height()/10); - QFont f = p.font(); - int font_sz = bounding_box.height() / 18; - f.setStyleHint(QFont::SansSerif); - f.setFamily(f.defaultFamily()); - f.setPointSize(font_sz); - f.setWeight(QFont::Bold); - p.setFont(f); - p.setPen(Qt::white); - - QPainterPath path; - - int text_line = 1; + QFontMetrics fm(f); for (int j=subtitle_tracklist.size()-1; j>=0; j--) { Track *sub_track = subtitle_tracklist.at(j); if (!sub_track->IsMuted()) { if (SubtitleBlock *sub = dynamic_cast(sub_track->BlockAtTime(time_))) { // Split into lines - QStringList list = QtUtils::WordWrapString(sub->GetText(), p.fontMetrics(), bounding_box.width()); + QStringList list = QtUtils::WordWrapString(sub->GetText(), fm, bounding_box.width()); for (int i=list.size()-1; i>=0; i--) { - int w = QtUtils::QFontMetricsWidth(p.fontMetrics(), list.at(i)); - path.addText(bounding_box.x() + bounding_box.width()/2 - w/2, bounding_box.y() + bounding_box.height() - p.fontMetrics().height() * text_line + p.fontMetrics().ascent(), p.font(), list.at(i)); - text_line++; + int w = QtUtils::QFontMetricsWidth(fm, list.at(i)); + path.addText(bounding_box.width()/2 - w/2, bounding_box.height() - fm.height() * (list.size() - i) + fm.ascent(), f, list.at(i)); } } } } - p.setPen(QPen(Qt::black, font_sz / 16)); - p.setBrush(Qt::white); - p.drawPath(path); + bool antialias = OLIVE_CONFIG("AntialiasSubtitles").toBool(); + + QPixmap *aa_pixmap; + QPainter *text_painter; + if (antialias) { + // QPainter only supports anti-aliasing in software, so to achieve it, we draw to a + // software buffer first and then draw that onto the hardware + aa_pixmap = new QPixmap(bounding_box.width(), bounding_box.height()); + aa_pixmap->fill(Qt::transparent); + text_painter = new QPainter(aa_pixmap); + } else { + // Just draw straight to the hardware + text_painter = new QPainter(paint_device()); + + // Offset path by however much is necessary + path.translate(bounding_box.x(), bounding_box.y()); + } + + text_painter->setPen(QPen(Qt::black, f.pointSizeF() / 16)); + text_painter->setBrush(Qt::white); + text_painter->setRenderHint(QPainter::Antialiasing); + + text_painter->drawPath(path); + + delete text_painter; + + if (antialias) { + // We just drew to a software buffer, now draw this image onto the hardware device + QPainter p(paint_device()); + p.drawPixmap(bounding_box.x(), bounding_box.y(), *aa_pixmap); + delete aa_pixmap; + } } }