Fix crash loading some ass subtitles, add basic widget for subtitle edit...

Fix crash loading some ass subtitles, add basic widget for subtitle edit otherwise the feature was not much usable
parent 2c0ce2de
......@@ -53,6 +53,14 @@ SubtitleModel::SubtitleModel(Mlt::Tractor *tractor, std::shared_ptr<TimelineItem
m_tractor->attach(*m_subtitleFilter.get());
}
setup();
QSize frameSize = pCore->getCurrentFrameDisplaySize();
int fontSize = frameSize.height() / 15;
int fontMargin = frameSize.height() - (2 *fontSize);
scriptInfoSection = QString("[Script Info]\n; This is a Sub Station Alpha v4 script.\n;\nScriptType: v4.00\nCollisions: Normal\nPlayResX: %1\nPlayResY: %2\nTimer: 100.0000\n").arg(frameSize.width()).arg(frameSize.height());
styleSection = QString("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\nStyle: Default,Consolas,%1,16777215,65535,255,0,-1,0,1,2,2,6,40,40,%2,0,1\n").arg(fontSize).arg(fontMargin);
eventSection = QStringLiteral("[Events]\n");
styleName = QStringLiteral("Default");
}
void SubtitleModel::setup()
......@@ -86,7 +94,7 @@ void SubtitleModel::importSubtitle(const QString filePath, int offset)
if (filePath.isEmpty())
return;
GenTime subtitleOffset(offset, pCore->getCurrentFps());
if (filePath.contains(".srt")) {
if (filePath.endsWith(".srt")) {
QFile srtFile(filePath);
if (!srtFile.exists() || !srtFile.open(QIODevice::ReadOnly)) {
qDebug() << " File not found " << filePath;
......@@ -98,7 +106,7 @@ void SubtitleModel::importSubtitle(const QString filePath, int offset)
QString line;
while (stream.readLineInto(&line)) {
line = line.simplified();
if (line.compare("")) {
if (!line.isEmpty()) {
if (!turn) {
// index=atoi(line.toStdString().c_str());
turn++;
......@@ -133,7 +141,7 @@ void SubtitleModel::importSubtitle(const QString filePath, int offset)
}
}
srtFile.close();
} else if (filePath.contains(".ass")) {
} else if (filePath.endsWith(".ass")) {
qDebug()<< "ass File";
QString startTime,endTime,text;
QString EventFormat, section;
......@@ -147,9 +155,12 @@ void SubtitleModel::importSubtitle(const QString filePath, int offset)
QTextStream stream(&assFile);
QString line;
qDebug() << " correct ass file " << filePath;
scriptInfoSection.clear();
styleSection.clear();
eventSection.clear();
while (stream.readLineInto(&line)) {
line = line.simplified();
if (line.compare("")) {
if (!line.isEmpty()) {
if (!turn) {
//qDebug() << " turn = 0 " << line;
//check if it is script info, event,or v4+ style
......@@ -168,12 +179,15 @@ void SubtitleModel::importSubtitle(const QString filePath, int offset)
turn++;
//qDebug()<< "turn" << turn;
continue;
} else {
} else if (line.contains("Events")) {
turn++;
section = "Events";
eventSection += line +"\n";
//qDebug()<< "turn" << turn;
continue;
} else {
//unknown section
}
}
if (section.contains("Script Info")) {
......@@ -374,6 +388,39 @@ SubtitledTime SubtitleModel::getSubtitle(GenTime startFrame) const
return SubtitledTime(GenTime(), QString(), GenTime());
}
QString SubtitleModel::getText(int id) const
{
if (m_timeline->m_allSubtitles.find( id ) == m_timeline->m_allSubtitles.end()) {
return QString();
}
GenTime start = m_timeline->m_allSubtitles.at(id);
return m_subtitleList.at(start).first;
}
bool SubtitleModel::setText(int id, const QString text)
{
if (m_timeline->m_allSubtitles.find( id ) == m_timeline->m_allSubtitles.end()) {
return false;
}
GenTime start = m_timeline->m_allSubtitles.at(id);
GenTime end = m_subtitleList.at(start).second;
QString oldText = m_subtitleList.at(start).first;
m_subtitleList[start].first = text;
Fun local_redo = [this, start, end, text]() {
editSubtitle(start, text, end);
pCore->refreshProjectRange({start.frames(pCore->getCurrentFps()), end.frames(pCore->getCurrentFps())});
return true;
};
Fun local_undo = [this, start, end, oldText]() {
editSubtitle(start, oldText, end);
pCore->refreshProjectRange({start.frames(pCore->getCurrentFps()), end.frames(pCore->getCurrentFps())});
return true;
};
local_redo();
pCore->pushUndo(local_undo, local_redo, i18n("Edit subtitle"));
return true;
}
std::unordered_set<int> SubtitleModel::getItemsInRange(int startFrame, int endFrame) const
{
GenTime startTime(startFrame, pCore->getCurrentFps());
......@@ -658,6 +705,42 @@ int SubtitleModel::getIdForStartPos(GenTime startTime) const
return -1;
}
GenTime SubtitleModel::getStartPosForId(int id) const
{
if (m_timeline->m_allSubtitles.count(id) == 0) {
return GenTime();
};
return m_timeline->m_allSubtitles.at(id);
}
int SubtitleModel::getPreviousSub(int id) const
{
GenTime start = getStartPosForId(id);
int row = static_cast<int>(std::distance(m_subtitleList.begin(), m_subtitleList.find(start)));
if (row > 0) {
row--;
auto it = m_subtitleList.begin();
std::advance(it, row);
const GenTime res = it->first;
return getIdForStartPos(res);
}
return -1;
}
int SubtitleModel::getNextSub(int id) const
{
GenTime start = getStartPosForId(id);
int row = static_cast<int>(std::distance(m_subtitleList.begin(), m_subtitleList.find(start)));
if (row < static_cast<int>(m_subtitleList.size()) - 1) {
row++;
auto it = m_subtitleList.begin();
std::advance(it, row);
const GenTime res = it->first;
return getIdForStartPos(res);
}
return -1;
}
QString SubtitleModel::toJson()
{
//qDebug()<< "to JSON";
......@@ -681,8 +764,10 @@ void SubtitleModel::jsontoSubtitle(const QString &data, QString updatedFileName)
if (outFile.isEmpty()) {
outFile = pCore->currentDoc()->subTitlePath(); // use srt format as default unless file is imported (m_subFilePath)
}
if (!outFile.contains(".ass"))
bool assFormat = outFile.endsWith(".ass");
if (!assFormat) {
qDebug()<< "srt file import"; // if imported file isn't .ass, it is .srt format
}
QFile outF(outFile);
//qDebug()<< "Import from JSON";
......@@ -696,7 +781,7 @@ void SubtitleModel::jsontoSubtitle(const QString &data, QString updatedFileName)
auto list = json.array();
if (outF.open(QIODevice::WriteOnly)) {
QTextStream out(&outF);
if (outFile.contains(".ass")) {
if (assFormat) {
out<<scriptInfoSection<<endl;
out<<styleSection<<endl;
out<<eventSection;
......@@ -754,11 +839,10 @@ void SubtitleModel::jsontoSubtitle(const QString &data, QString updatedFileName)
.arg(seconds, 2, 10, QChar('0'))
.arg(millisec,3,10,QChar('0'));
line++;
if (outFile.contains(".ass")) {
if (assFormat) {
//Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text
out <<"Dialogue: 0,"<<startTimeString<<","<<endTimeString<<","<<styleName<<",,0000,0000,0000,,"<<dialogue<<endl;
}
if (outFile.contains(".srt")) {
} else {
out<<line<<"\n"<<startTimeStringSRT<<" --> "<<endTimeStringSRT<<"\n"<<dialogue<<"\n"<<endl;
}
......@@ -783,6 +867,16 @@ void SubtitleModel::updateSub(int id, QVector <int> roles)
emit dataChanged(index(row), index(row), roles);
}
int SubtitleModel::getRowForId(int id) const
{
if (m_timeline->m_allSubtitles.find( id ) == m_timeline->m_allSubtitles.end()) {
return -1;
}
GenTime startPos = m_timeline->m_allSubtitles.at(id);
int row = static_cast<int>(std::distance(m_subtitleList.begin(), m_subtitleList.find(startPos)));
return row;
}
int SubtitleModel::getSubtitlePlaytime(int id) const
{
GenTime startPos = m_timeline->m_allSubtitles.at(id);
......
......@@ -121,6 +121,11 @@ public:
/** @brief Cut a subtitle */
void cutSubtitle(int position);
bool cutSubtitle(int position, Fun &undo, Fun &redo);
QString getText(int id) const;
int getRowForId(int id) const;
GenTime getStartPosForId(int id) const;
int getPreviousSub(int id) const;
int getNextSub(int id) const;
public slots:
/** @brief Function that parses through a subtitle file */
......@@ -128,6 +133,8 @@ public slots:
/** @brief Import model to a temporary subtitle file to which the Subtitle effect is applied*/
void jsontoSubtitle(const QString &data, QString updatedFileName = QString());
/** @brief Update a subtitle text*/
bool setText(int id, const QString text);
private:
std::shared_ptr<TimelineItemModel> m_timeline;
......
......@@ -29,6 +29,7 @@ the Free Software Foundation, either version 3 of the License, or
#include "timeline2/model/timelineitemmodel.hpp"
#include "timeline2/view/timelinecontroller.h"
#include "timeline2/view/timelinewidget.h"
#include "dialogs/subtitleedit.h"
#include <mlt++/MltRepository.h>
#include <KMessageBox>
......@@ -179,6 +180,7 @@ void Core::initGUI(const QUrl &Url, const QString &clipsToLoad)
m_projectManager = new ProjectManager(this);
m_binWidget = new Bin(m_projectItemModel, m_mainWindow);
m_library = new LibraryWidget(m_projectManager, m_mainWindow);
m_subtitleWidget = new SubtitleEdit(m_mainWindow);
m_mixerWidget = new MixerManager(m_mainWindow);
connect(m_library, SIGNAL(addProjectClips(QList<QUrl>)), m_binWidget, SLOT(droppedUrls(QList<QUrl>)));
connect(this, &Core::updateLibraryPath, m_library, &LibraryWidget::slotUpdateLibraryPath);
......@@ -278,6 +280,11 @@ LibraryWidget *Core::library()
return m_library;
}
SubtitleEdit *Core::subtitleWidget()
{
return m_subtitleWidget;
}
MixerManager *Core::mixer()
{
return m_mixerWidget;
......
......@@ -20,6 +20,7 @@ the Free Software Foundation, either version 3 of the License, or
#include <QUrl>
#include <memory>
#include <QPoint>
#include <QTextEdit>
#include <KSharedDataCache>
#include <unordered_set>
#include "timecode.h"
......@@ -38,6 +39,7 @@ class MonitorManager;
class ProfileModel;
class ProjectItemModel;
class ProjectManager;
class SubtitleEdit;
namespace Mlt {
class Repository;
......@@ -113,6 +115,8 @@ public:
std::shared_ptr<JobManager> jobManager();
/** @brief Returns a pointer to the library. */
LibraryWidget *library();
/** @brief Returns a pointer to the subtitle edit. */
SubtitleEdit *subtitleWidget();
/** @brief Returns a pointer to the audio mixer. */
MixerManager *mixer();
......@@ -247,6 +251,7 @@ private:
std::shared_ptr<JobManager> m_jobManager;
Bin *m_binWidget{nullptr};
LibraryWidget *m_library{nullptr};
SubtitleEdit *m_subtitleWidget{nullptr};
MixerManager *m_mixerWidget{nullptr};
/** @brief Current project's profile path */
QString m_currentProfile;
......
......@@ -6,6 +6,7 @@ set(kdenlive_SRCS
dialogs/markerdialog.cpp
dialogs/profilesdialog.cpp
dialogs/renderwidget.cpp
dialogs/subtitleedit.cpp
dialogs/titletemplatedialog.cpp
dialogs/wizard.cpp
dialogs/splash.cpp
......
/***************************************************************************
* Copyright (C) 2020 by Jean-Baptiste Mardelle *
* 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 "subtitleedit.h"
#include "bin/model/subtitlemodel.hpp"
#include "monitor/monitor.h"
#include "core.h"
#include "kdenlivesettings.h"
#include "klocalizedstring.h"
#include "QTextEdit"
#include <QEvent>
#include <QKeyEvent>
#include <QToolButton>
ShiftEnterFilter::ShiftEnterFilter(QObject *parent)
: QObject(parent)
{}
bool ShiftEnterFilter::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast <QKeyEvent*> (event);
if((keyEvent->modifiers() & Qt::ShiftModifier) && ((keyEvent->key() == Qt::Key_Enter) || (keyEvent->key() == Qt::Key_Return))) {
emit triggerUpdate();
return true;
}
}
return QObject::eventFilter(obj, event);
}
SubtitleEdit::SubtitleEdit(QWidget *parent)
: QWidget(parent)
, m_model(nullptr)
, m_activeSub(-1)
{
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
setupUi(this);
buttonApply->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok-apply")));
auto *keyFilter = new ShiftEnterFilter(this);
subText->installEventFilter(keyFilter);
connect(keyFilter, &ShiftEnterFilter::triggerUpdate, this, &SubtitleEdit::updateSubtitle);
connect(subText, &QPlainTextEdit::textChanged, [this]() {
buttonApply->setEnabled(true);
});
connect(buttonApply, &QToolButton::clicked, this, &SubtitleEdit::updateSubtitle);
connect(buttonPrev, &QToolButton::clicked, this, &SubtitleEdit::goToPrevious);
connect(buttonNext, &QToolButton::clicked, this, &SubtitleEdit::goToNext);
sub_list->setVisible(false);
}
void SubtitleEdit::setModel(std::shared_ptr<SubtitleModel> model)
{
m_model = model;
m_activeSub = -1;
subText->setEnabled(false);
buttonApply->setEnabled(false);
connect(m_model.get(), &SubtitleModel::dataChanged, [this](const QModelIndex &start, const QModelIndex &, const QVector <int>&roles) {
if (m_activeSub > -1 && start.row() == m_model->getRowForId(m_activeSub && roles.contains(SubtitleModel::SubtitleRole))) {
setActiveSubtitle(m_activeSub);
}
});
}
void SubtitleEdit::updateSubtitle()
{
if (m_activeSub > -1 && m_model) {
m_model->setText(m_activeSub, subText->toPlainText());
}
}
void SubtitleEdit::setActiveSubtitle(int id)
{
m_activeSub = id;
if (m_model && id > -1) {
subText->setEnabled(true);
buttonApply->setEnabled(false);
QSignalBlocker bk(subText);
subText->setPlainText(m_model->getText(id));
} else {
subText->setEnabled(false);
buttonApply->setEnabled(false);
QSignalBlocker bk(subText);
subText->clear();
}
}
void SubtitleEdit::goToPrevious()
{
if (m_model) {
int id = m_model->getPreviousSub(m_activeSub);
if (id > -1) {
if (buttonApply->isEnabled()) {
updateSubtitle();
}
GenTime prev = m_model->getStartPosForId(id);
pCore->getMonitor(Kdenlive::ProjectMonitor)->requestSeek(prev.frames(pCore->getCurrentFps()));
setActiveSubtitle(id);
}
}
}
void SubtitleEdit::goToNext()
{
if (m_model) {
int id = m_model->getNextSub(m_activeSub);
if (id > -1) {
if (buttonApply->isEnabled()) {
updateSubtitle();
}
GenTime prev = m_model->getStartPosForId(id);
pCore->getMonitor(Kdenlive::ProjectMonitor)->requestSeek(prev.frames(pCore->getCurrentFps()));
setActiveSubtitle(id);
}
}
}
/***************************************************************************
* Copyright (C) 2020 by Jean-Baptiste Mardelle *
* 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 SUBTITLEEDIT_H
#define SUBTITLEEDIT_H
#include "ui_editsub_ui.h"
#include "definitions.h"
class SubtitleModel;
class ShiftEnterFilter : public QObject
{
Q_OBJECT
public:
ShiftEnterFilter(QObject *parent = 0);
protected:
virtual bool eventFilter(QObject *obj, QEvent *event) override;
signals:
void triggerUpdate();
};
/**
* @class SubtitleEdit: Subtitle edit widget
* @brief A dialog for editing markers and guides.
* @author Jean-Baptiste Mardelle
*/
class SubtitleEdit : public QWidget, public Ui::SubEdit_UI
{
Q_OBJECT
public:
explicit SubtitleEdit(QWidget *parent = nullptr);
void setModel(std::shared_ptr<SubtitleModel> model);
public slots:
void setActiveSubtitle(int id);
private slots:
void updateSubtitle();
void goToPrevious();
void goToNext();
private:
std::shared_ptr<SubtitleModel> m_model;
int m_activeSub;
};
#endif
......@@ -775,7 +775,7 @@ void KdenliveDoc::updateSubtitle(QString newUrl)
QFileInfo info(newUrl);
subPath = info.dir().absoluteFilePath(QString("%1.srt").arg(info.fileName()));
}
qDebug()<<"===== SAVING SUBTITLE TO NEW ATH: "<<subPath;
qDebug()<<"===== SAVING SUBTITLE TO NEW PATH: "<<subPath;
m_subtitleModel->jsontoSubtitle(m_subtitleModel->toJson(), subPath);
}
}
......
......@@ -30,6 +30,7 @@
#include "dialogs/kdenlivesettingsdialog.h"
#include "dialogs/renderwidget.h"
#include "dialogs/wizard.h"
#include "dialogs/subtitleedit.h"
#include "doc/docundostack.hpp"
#include "doc/kdenlivedoc.h"
#include "dockareaorientationmanager.h"
......@@ -261,6 +262,7 @@ void MainWindow::init()
LayoutManagement *layoutManager = new LayoutManagement(this);
QDockWidget *libraryDock = addDock(i18n("Library"), QStringLiteral("library"), pCore->library());
QDockWidget *subtitlesDock = addDock(i18n("Subtitles"), QStringLiteral("Subtitles"), pCore->subtitleWidget());
m_clipMonitor = new Monitor(Kdenlive::ClipMonitor, pCore->monitorManager(), this);
pCore->bin()->setMonitor(m_clipMonitor);
......@@ -340,6 +342,7 @@ void MainWindow::init()
// Close library and audiospectrum on first run
screenGrabDock->close();
libraryDock->close();
subtitlesDock->close();
spectrumDock->close();
m_projectBinDock = addDock(i18n("Project Bin"), QStringLiteral("project_bin"), pCore->bin());
......@@ -362,6 +365,14 @@ void MainWindow::init()
m_effectStackDock->raise();
});
connect(m_timelineTabs, &TimelineTabs::showSubtitle, this, [&, subtitlesDock] (int id) {
if (id > -1) {
subtitlesDock->show();
subtitlesDock->raise();
}
pCore->subtitleWidget()->setActiveSubtitle(id);
});
connect(m_timelineTabs, &TimelineTabs::updateZoom, this, &MainWindow::updateZoomSlider);
connect(pCore->bin(), &Bin::requestShowEffectStack, m_assetPanel, &AssetPanel::showEffectStack);
connect(pCore->bin(), &Bin::requestShowEffectStack, [&] () {
......@@ -4191,6 +4202,7 @@ void MainWindow::slotEditSubtitle(const QString subPath)
subtitleModel.reset(new SubtitleModel(getMainTimeline()->controller()->tractor(), getMainTimeline()->controller()->getModel(), this));
getMainTimeline()->controller()->getModel()->setSubModel(subtitleModel);
pCore->currentDoc()->initializeSubtitles(subtitleModel, subPath);
pCore->subtitleWidget()->setModel(subtitleModel);
}
getMainTimeline()->connectSubtitleModel();
}
......
......@@ -2937,12 +2937,18 @@ void TimelineController::updateClipActions()
emit timelineClipSelected(false);
// nothing selected
emit showItemEffectStack(QString(), nullptr, QSize(), false);
emit showSubtitle(-1);
return;
}
std::shared_ptr<ClipModel> clip(nullptr);
int item = *m_model->getCurrentSelection().begin();
if (m_model->getCurrentSelection().size() == 1 && (m_model->isClip(item) || m_model->isComposition(item))) {
showAsset(item);
if (m_model->getCurrentSelection().size() == 1) {
if (m_model->isClip(item) || m_model->isComposition(item)) {
showAsset(item);
emit showSubtitle(-1);
} else if (m_model->isSubTitle(item)) {
emit showSubtitle(item);
}
}
if (m_model->isClip(item)) {
clip = m_model->getClipPtr(item);
......@@ -3740,9 +3746,11 @@ void TimelineController::temporaryUnplug(QList<int> clipIds, bool hide)
void TimelineController::editSubtitle(int startFrame, int endFrame, QString newText, QString oldText)
{
qDebug()<<"Editing existing subtitle in controller at:"<<startFrame<<"\n\n=====================";
qDebug()<<"Editing existing subtitle in controller at:"<<startFrame;
if (oldText == newText) {
return;
}
auto subtitleModel = pCore->projectManager()->current()->getSubtitleModel();
Fun local_redo = [subtitleModel, startFrame, endFrame, newText]() {
subtitleModel->editSubtitle(GenTime(startFrame, pCore->getCurrentFps()), newText, GenTime(endFrame, pCore->getCurrentFps()));
pCore->refreshProjectRange({startFrame, endFrame});
......
......@@ -681,6 +681,7 @@ signals:
/* @brief Requests that a given mix is displayed in the asset panel */
void showMixModel(int cid, const std::shared_ptr<AssetParameterModel> &asset);
void showItemEffectStack(const QString &clipName, std::shared_ptr<EffectStackModel>, QSize frameSize, bool showKeyframes);
void showSubtitle(int id);
/* @brief notify of chunks change
*/
void dirtyChunksChanged();
......
......@@ -86,6 +86,7 @@ void TimelineTabs::connectTimeline(TimelineWidget *timeline)
connect(timeline->controller(), &TimelineController::showMixModel, this, &TimelineTabs::showMixModel);
connect(timeline->controller(), &TimelineController::updateZoom, this, [&](double value) { emit updateZoom(getCurrentTimeline()->zoomForScale(value)); });
connect(timeline->controller(), &TimelineController::showItemEffectStack, this, &TimelineTabs::showItemEffectStack);
connect(timeline->controller(), &TimelineController::showSubtitle, this, &TimelineTabs::showSubtitle);
}
void TimelineTabs::disconnectTimeline(TimelineWidget *timeline)
......@@ -99,5 +100,6 @@ void TimelineTabs::disconnectTimeline(TimelineWidget *timeline)
disconnect(timeline->controller(), &TimelineController::showTransitionModel, this, &TimelineTabs::showTransitionModel);
disconnect(timeline->controller(), &TimelineController::showMixModel, this, &TimelineTabs::showMixModel);
disconnect(timeline->controller(), &TimelineController::showItemEffectStack, this, &TimelineTabs::showItemEffectStack);
disconnect(timeline->controller(), &TimelineController::showSubtitle, this, &TimelineTabs::showSubtitle);
delete timeline;
}
......@@ -88,6 +88,7 @@ signals:
void showMixModel(int cid, std::shared_ptr<AssetParameterModel>);
/* @brief Requests that a given effectstack model is displayed in the asset panel */
void showItemEffectStack(const QString &clipName, std::shared_ptr<EffectStackModel>, QSize, bool);
void showSubtitle(int itemId);
/** @brief Zoom level changed in timeline, update slider
*/
void updateZoom(int);
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SubEdit_UI</class>