mirror of https://github.com/odrling/Aegisub
Split AssFile into separate lists for each section
This commit is contained in:
parent
222b6ee099
commit
805481315e
|
@ -42,78 +42,55 @@
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include <libaegisub/dispatch.h>
|
|
||||||
#include <libaegisub/of_type_adaptor.h>
|
#include <libaegisub/of_type_adaptor.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<>
|
|
||||||
void swap(AssFile &lft, AssFile &rgt) {
|
|
||||||
lft.swap(rgt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AssFile::~AssFile() {
|
AssFile::~AssFile() {
|
||||||
auto copy = new EntryList;
|
Info.clear_and_dispose([](AssEntry *e) { delete e; });
|
||||||
copy->swap(Line);
|
Styles.clear_and_dispose([](AssEntry *e) { delete e; });
|
||||||
agi::dispatch::Background().Async([=]{
|
Events.clear_and_dispose([](AssEntry *e) { delete e; });
|
||||||
copy->clear_and_dispose([](AssEntry *e) { delete e; });
|
Attachments.clear_and_dispose([](AssEntry *e) { delete e; });
|
||||||
delete copy;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssFile::LoadDefault(bool defline) {
|
void AssFile::LoadDefault(bool defline) {
|
||||||
Line.push_back(*new AssInfo("Title", "Default Aegisub file"));
|
Info.push_back(*new AssInfo("Title", "Default Aegisub file"));
|
||||||
Line.push_back(*new AssInfo("ScriptType", "v4.00+"));
|
Info.push_back(*new AssInfo("ScriptType", "v4.00+"));
|
||||||
Line.push_back(*new AssInfo("WrapStyle", "0"));
|
Info.push_back(*new AssInfo("WrapStyle", "0"));
|
||||||
Line.push_back(*new AssInfo("ScaledBorderAndShadow", "yes"));
|
Info.push_back(*new AssInfo("ScaledBorderAndShadow", "yes"));
|
||||||
if (!OPT_GET("Subtitle/Default Resolution/Auto")->GetBool()) {
|
if (!OPT_GET("Subtitle/Default Resolution/Auto")->GetBool()) {
|
||||||
Line.push_back(*new AssInfo("PlayResX", std::to_string(OPT_GET("Subtitle/Default Resolution/Width")->GetInt())));
|
Info.push_back(*new AssInfo("PlayResX", std::to_string(OPT_GET("Subtitle/Default Resolution/Width")->GetInt())));
|
||||||
Line.push_back(*new AssInfo("PlayResY", std::to_string(OPT_GET("Subtitle/Default Resolution/Height")->GetInt())));
|
Info.push_back(*new AssInfo("PlayResY", std::to_string(OPT_GET("Subtitle/Default Resolution/Height")->GetInt())));
|
||||||
}
|
}
|
||||||
Line.push_back(*new AssInfo("YCbCr Matrix", "None"));
|
Info.push_back(*new AssInfo("YCbCr Matrix", "None"));
|
||||||
|
|
||||||
Line.push_back(*new AssStyle);
|
Styles.push_back(*new AssStyle);
|
||||||
|
|
||||||
if (defline)
|
if (defline)
|
||||||
Line.push_back(*new AssDialogue);
|
Events.push_back(*new AssDialogue);
|
||||||
}
|
|
||||||
|
|
||||||
void AssFile::swap(AssFile &that) throw() {
|
|
||||||
Line.swap(that.Line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssFile::AssFile(const AssFile &from) {
|
AssFile::AssFile(const AssFile &from) {
|
||||||
Line.clone_from(from.Line, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
|
Info.clone_from(from.Info, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
|
||||||
|
Styles.clone_from(from.Styles, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
|
||||||
|
Events.clone_from(from.Events, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
|
||||||
|
Attachments.clone_from(from.Attachments, std::mem_fun_ref(&AssEntry::Clone), [](AssEntry *e) { delete e; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssFile::swap(AssFile& from) throw() {
|
||||||
|
Info.swap(from.Info);
|
||||||
|
Styles.swap(from.Styles);
|
||||||
|
Events.swap(from.Events);
|
||||||
|
Attachments.swap(from.Attachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssFile& AssFile::operator=(AssFile from) {
|
AssFile& AssFile::operator=(AssFile from) {
|
||||||
std::swap(*this, from);
|
swap(from);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssFile::InsertLine(AssEntry *entry) {
|
|
||||||
if (Line.empty()) {
|
|
||||||
Line.push_back(*entry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for insertion point
|
|
||||||
entryIter it = Line.end();
|
|
||||||
do {
|
|
||||||
--it;
|
|
||||||
if (it->Group() <= entry->Group()) {
|
|
||||||
Line.insert(++it, *entry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} while (it != Line.begin());
|
|
||||||
|
|
||||||
Line.push_front(*entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssFile::InsertAttachment(agi::fs::path const& filename) {
|
void AssFile::InsertAttachment(agi::fs::path const& filename) {
|
||||||
AssEntryGroup group = AssEntryGroup::GRAPHIC;
|
AssEntryGroup group = AssEntryGroup::GRAPHIC;
|
||||||
|
|
||||||
|
@ -121,11 +98,11 @@ void AssFile::InsertAttachment(agi::fs::path const& filename) {
|
||||||
if (ext == ".ttf" || ext == ".ttc" || ext == ".pfb")
|
if (ext == ".ttf" || ext == ".ttc" || ext == ".pfb")
|
||||||
group = AssEntryGroup::FONT;
|
group = AssEntryGroup::FONT;
|
||||||
|
|
||||||
InsertLine(new AssAttachment(filename, group));
|
Attachments.push_back(*new AssAttachment(filename, group));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AssFile::GetScriptInfo(std::string const& key) const {
|
std::string AssFile::GetScriptInfo(std::string const& key) const {
|
||||||
for (const auto info : Line | agi::of_type<AssInfo>()) {
|
for (const auto info : Info | agi::of_type<AssInfo>()) {
|
||||||
if (boost::iequals(key, info->Key()))
|
if (boost::iequals(key, info->Key()))
|
||||||
return info->Value();
|
return info->Value();
|
||||||
}
|
}
|
||||||
|
@ -154,7 +131,7 @@ void AssFile::SaveUIState(std::string const& key, std::string const& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssFile::SetScriptInfo(std::string const& key, std::string const& value) {
|
void AssFile::SetScriptInfo(std::string const& key, std::string const& value) {
|
||||||
for (auto info : Line | agi::of_type<AssInfo>()) {
|
for (auto info : Info | agi::of_type<AssInfo>()) {
|
||||||
if (boost::iequals(key, info->Key())) {
|
if (boost::iequals(key, info->Key())) {
|
||||||
if (value.empty())
|
if (value.empty())
|
||||||
delete info;
|
delete info;
|
||||||
|
@ -165,7 +142,7 @@ void AssFile::SetScriptInfo(std::string const& key, std::string const& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value.empty())
|
if (!value.empty())
|
||||||
InsertLine(new AssInfo(key, value));
|
Info.push_back(*new AssInfo(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssFile::GetResolution(int &sw,int &sh) const {
|
void AssFile::GetResolution(int &sw,int &sh) const {
|
||||||
|
@ -192,13 +169,13 @@ void AssFile::GetResolution(int &sw,int &sh) const {
|
||||||
|
|
||||||
std::vector<std::string> AssFile::GetStyles() const {
|
std::vector<std::string> AssFile::GetStyles() const {
|
||||||
std::vector<std::string> styles;
|
std::vector<std::string> styles;
|
||||||
for (auto style : Line | agi::of_type<AssStyle>())
|
for (auto style : Styles | agi::of_type<AssStyle>())
|
||||||
styles.push_back(style->name);
|
styles.push_back(style->name);
|
||||||
return styles;
|
return styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssStyle *AssFile::GetStyle(std::string const& name) {
|
AssStyle *AssFile::GetStyle(std::string const& name) {
|
||||||
for (auto style : Line | agi::of_type<AssStyle>()) {
|
for (auto style : Styles | agi::of_type<AssStyle>()) {
|
||||||
if (boost::iequals(style->name, name))
|
if (boost::iequals(style->name, name))
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +214,7 @@ bool AssFile::CompLayer(const AssDialogue* lft, const AssDialogue* rgt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssFile::Sort(CompFunc comp, std::set<AssDialogue*> const& limit) {
|
void AssFile::Sort(CompFunc comp, std::set<AssDialogue*> const& limit) {
|
||||||
Sort(Line, comp, limit);
|
Sort(Events, comp, limit);
|
||||||
}
|
}
|
||||||
namespace {
|
namespace {
|
||||||
inline bool is_dialogue(AssEntry *e, std::set<AssDialogue*> const& limit) {
|
inline bool is_dialogue(AssEntry *e, std::set<AssDialogue*> const& limit) {
|
||||||
|
|
|
@ -62,7 +62,10 @@ class AssFile {
|
||||||
agi::signal::Signal<AssFileCommit> PushState;
|
agi::signal::Signal<AssFileCommit> PushState;
|
||||||
public:
|
public:
|
||||||
/// The lines in the file
|
/// The lines in the file
|
||||||
EntryList Line;
|
EntryList Info;
|
||||||
|
EntryList Styles;
|
||||||
|
EntryList Events;
|
||||||
|
EntryList Attachments;
|
||||||
|
|
||||||
AssFile() { }
|
AssFile() { }
|
||||||
AssFile(const AssFile &from);
|
AssFile(const AssFile &from);
|
||||||
|
@ -72,8 +75,6 @@ public:
|
||||||
/// @brief Load default file
|
/// @brief Load default file
|
||||||
/// @param defline Add a blank line to the file
|
/// @param defline Add a blank line to the file
|
||||||
void LoadDefault(bool defline=true);
|
void LoadDefault(bool defline=true);
|
||||||
/// Add a line to the file at the end of the appropriate section
|
|
||||||
void InsertLine(AssEntry *line);
|
|
||||||
/// Attach a file to the ass file
|
/// Attach a file to the ass file
|
||||||
void InsertAttachment(agi::fs::path const& filename);
|
void InsertAttachment(agi::fs::path const& filename);
|
||||||
/// Get the names of all of the styles available
|
/// Get the names of all of the styles available
|
||||||
|
|
|
@ -280,7 +280,7 @@ void AssKaraoke::SplitLines(std::set<AssDialogue*> const& lines, agi::Context *c
|
||||||
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
||||||
|
|
||||||
bool did_split = false;
|
bool did_split = false;
|
||||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) {
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
|
||||||
if (!diag || !lines.count(diag)) continue;
|
if (!diag || !lines.count(diag)) continue;
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ void AssKaraoke::SplitLines(std::set<AssDialogue*> const& lines, agi::Context *c
|
||||||
new_line->End = syl.start_time + syl.duration;
|
new_line->End = syl.start_time + syl.duration;
|
||||||
new_line->Text = syl.GetText(false);
|
new_line->Text = syl.GetText(false);
|
||||||
|
|
||||||
c->ass->Line.insert(it, *new_line);
|
c->ass->Events.insert(it, *new_line);
|
||||||
|
|
||||||
if (in_sel)
|
if (in_sel)
|
||||||
sel.insert(new_line);
|
sel.insert(new_line);
|
||||||
|
|
|
@ -33,7 +33,6 @@ AssParser::AssParser(AssFile *target, int version)
|
||||||
, version(version)
|
, version(version)
|
||||||
, state(&AssParser::ParseScriptInfoLine)
|
, state(&AssParser::ParseScriptInfoLine)
|
||||||
{
|
{
|
||||||
std::fill(begin(insertion_positions), end(insertion_positions), nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssParser::~AssParser() {
|
AssParser::~AssParser() {
|
||||||
|
@ -52,7 +51,7 @@ void AssParser::ParseAttachmentLine(std::string const& data) {
|
||||||
|
|
||||||
// Data is over, add attachment to the file
|
// Data is over, add attachment to the file
|
||||||
if (!valid_data || is_filename) {
|
if (!valid_data || is_filename) {
|
||||||
InsertLine(attach.release());
|
target->Attachments.push_back(*attach.release());
|
||||||
AddLine(data);
|
AddLine(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -60,7 +59,7 @@ void AssParser::ParseAttachmentLine(std::string const& data) {
|
||||||
|
|
||||||
// Done building
|
// Done building
|
||||||
if (data.size() < 80)
|
if (data.size() < 80)
|
||||||
InsertLine(attach.release());
|
target->Attachments.push_back(*attach.release());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,17 +90,17 @@ void AssParser::ParseScriptInfoLine(std::string const& data) {
|
||||||
size_t pos = data.find(':');
|
size_t pos = data.find(':');
|
||||||
if (pos == data.npos) return;
|
if (pos == data.npos) return;
|
||||||
|
|
||||||
InsertLine(new AssInfo(data.substr(0, pos), boost::trim_left_copy(data.substr(pos + 1))));
|
target->Info.push_back(*new AssInfo(data.substr(0, pos), boost::trim_left_copy(data.substr(pos + 1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssParser::ParseEventLine(std::string const& data) {
|
void AssParser::ParseEventLine(std::string const& data) {
|
||||||
if (boost::starts_with(data, "Dialogue:") || boost::starts_with(data, "Comment:"))
|
if (boost::starts_with(data, "Dialogue:") || boost::starts_with(data, "Comment:"))
|
||||||
InsertLine(new AssDialogue(data));
|
target->Events.push_back(*new AssDialogue(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssParser::ParseStyleLine(std::string const& data) {
|
void AssParser::ParseStyleLine(std::string const& data) {
|
||||||
if (boost::starts_with(data, "Style:"))
|
if (boost::starts_with(data, "Style:"))
|
||||||
InsertLine(new AssStyle(data, version));
|
target->Styles.push_back(*new AssStyle(data, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssParser::ParseFontLine(std::string const& data) {
|
void AssParser::ParseFontLine(std::string const& data) {
|
||||||
|
@ -152,12 +151,3 @@ void AssParser::AddLine(std::string const& data) {
|
||||||
|
|
||||||
(this->*state)(data);
|
(this->*state)(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssParser::InsertLine(AssEntry *entry) {
|
|
||||||
AssEntry *position = insertion_positions[(size_t)entry->Group()];
|
|
||||||
if (position)
|
|
||||||
target->Line.insert(++target->Line.iterator_to(*position), *entry);
|
|
||||||
else
|
|
||||||
target->Line.push_back(*entry);
|
|
||||||
insertion_positions[(size_t)entry->Group()] = entry;
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "ass_entry.h"
|
|
||||||
|
|
||||||
class AssAttachment;
|
class AssAttachment;
|
||||||
class AssFile;
|
class AssFile;
|
||||||
|
|
||||||
|
@ -26,9 +24,6 @@ class AssParser {
|
||||||
int version;
|
int version;
|
||||||
std::unique_ptr<AssAttachment> attach;
|
std::unique_ptr<AssAttachment> attach;
|
||||||
void (AssParser::*state)(std::string const&);
|
void (AssParser::*state)(std::string const&);
|
||||||
std::array<AssEntry*, (size_t)AssEntryGroup::GROUP_MAX> insertion_positions;
|
|
||||||
|
|
||||||
void InsertLine(AssEntry *entry);
|
|
||||||
|
|
||||||
void ParseAttachmentLine(std::string const& data);
|
void ParseAttachmentLine(std::string const& data);
|
||||||
void ParseEventLine(std::string const& data);
|
void ParseEventLine(std::string const& data);
|
||||||
|
|
|
@ -742,20 +742,20 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
|
||||||
case 2: // Previous and next lines
|
case 2: // Previous and next lines
|
||||||
if (AssDialogue *line = context->selectionController->GetActiveLine())
|
if (AssDialogue *line = context->selectionController->GetActiveLine())
|
||||||
{
|
{
|
||||||
entryIter current_line = context->ass->Line.iterator_to(*line);
|
entryIter current_line = context->ass->Events.iterator_to(*line);
|
||||||
if (current_line == context->ass->Line.end())
|
if (current_line == context->ass->Events.end())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
entryIter prev = current_line;
|
entryIter prev = current_line;
|
||||||
while (--prev != context->ass->Line.begin() && !predicate(*prev)) ;
|
while (--prev != context->ass->Events.begin() && !predicate(*prev)) ;
|
||||||
if (prev != context->ass->Line.begin())
|
if (prev != context->ass->Events.begin())
|
||||||
AddInactiveLine(sel, static_cast<AssDialogue*>(&*prev));
|
AddInactiveLine(sel, static_cast<AssDialogue*>(&*prev));
|
||||||
|
|
||||||
if (mode == 2)
|
if (mode == 2)
|
||||||
{
|
{
|
||||||
entryIter next =
|
entryIter next =
|
||||||
find_if(++current_line, context->ass->Line.end(), predicate);
|
find_if(++current_line, context->ass->Events.end(), predicate);
|
||||||
if (next != context->ass->Line.end())
|
if (next != context->ass->Events.end())
|
||||||
AddInactiveLine(sel, static_cast<AssDialogue*>(&*next));
|
AddInactiveLine(sel, static_cast<AssDialogue*>(&*next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -763,7 +763,7 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
|
||||||
case 3: // All inactive lines
|
case 3: // All inactive lines
|
||||||
{
|
{
|
||||||
AssDialogue *active_line = context->selectionController->GetActiveLine();
|
AssDialogue *active_line = context->selectionController->GetActiveLine();
|
||||||
for (auto& line : context->ass->Line)
|
for (auto& line : context->ass->Events)
|
||||||
{
|
{
|
||||||
if (&line != active_line && predicate(line))
|
if (&line != active_line && predicate(line))
|
||||||
AddInactiveLine(sel, static_cast<AssDialogue*>(&line));
|
AddInactiveLine(sel, static_cast<AssDialogue*>(&line));
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "auto4_lua.h"
|
#include "auto4_lua.h"
|
||||||
|
|
||||||
#include "auto4_lua_utils.h"
|
#include "auto4_lua_utils.h"
|
||||||
|
#include "ass_attachment.h"
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
|
@ -838,13 +839,11 @@ namespace Automation4 {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
int active_idx = -1;
|
int active_idx = -1;
|
||||||
|
|
||||||
int row = 0;
|
int row = c->ass->Info.size() + c->ass->Styles.size();
|
||||||
int idx = 1;
|
int idx = 1;
|
||||||
for (auto& line : c->ass->Line) {
|
for (auto& line : c->ass->Events) {
|
||||||
++row;
|
++row;
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&line);
|
auto diag = static_cast<AssDialogue*>(&line);
|
||||||
if (!diag) continue;
|
|
||||||
|
|
||||||
if (diag == active_line) active_idx = row;
|
if (diag == active_line) active_idx = row;
|
||||||
if (sel.count(diag)) {
|
if (sel.count(diag)) {
|
||||||
push_value(L, row);
|
push_value(L, row);
|
||||||
|
@ -901,7 +900,7 @@ namespace Automation4 {
|
||||||
try {
|
try {
|
||||||
LuaThreadedCall(L, 3, 2, from_wx(StrDisplay(c)), c->parent, true);
|
LuaThreadedCall(L, 3, 2, from_wx(StrDisplay(c)), c->parent, true);
|
||||||
|
|
||||||
subsobj->ProcessingComplete(StrDisplay(c));
|
auto lines = subsobj->ProcessingComplete(StrDisplay(c));
|
||||||
|
|
||||||
AssDialogue *active_line = nullptr;
|
AssDialogue *active_line = nullptr;
|
||||||
int active_idx = 0;
|
int active_idx = 0;
|
||||||
|
@ -909,8 +908,8 @@ namespace Automation4 {
|
||||||
// Check for a new active row
|
// Check for a new active row
|
||||||
if (lua_isnumber(L, -1)) {
|
if (lua_isnumber(L, -1)) {
|
||||||
active_idx = lua_tointeger(L, -1);
|
active_idx = lua_tointeger(L, -1);
|
||||||
if (active_idx < 1 || active_idx > (int)c->ass->Line.size()) {
|
if (active_idx < 1 || active_idx > (int)lines.size()) {
|
||||||
wxLogError("Active row %d is out of bounds (must be 1-%u)", active_idx, c->ass->Line.size());
|
wxLogError("Active row %d is out of bounds (must be 1-%u)", active_idx, lines.size());
|
||||||
active_idx = 0;
|
active_idx = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -921,26 +920,21 @@ namespace Automation4 {
|
||||||
// top of stack will be selected lines array, if any was returned
|
// top of stack will be selected lines array, if any was returned
|
||||||
if (lua_istable(L, -1)) {
|
if (lua_istable(L, -1)) {
|
||||||
std::set<AssDialogue*> sel;
|
std::set<AssDialogue*> sel;
|
||||||
entryIter it = c->ass->Line.begin();
|
|
||||||
int last_idx = 1;
|
|
||||||
lua_for_each(L, [&] {
|
lua_for_each(L, [&] {
|
||||||
if (lua_isnumber(L, -1)) {
|
if (lua_isnumber(L, -1)) {
|
||||||
int cur = lua_tointeger(L, -1);
|
int cur = lua_tointeger(L, -1);
|
||||||
if (cur < 1 || cur > (int)c->ass->Line.size()) {
|
if (cur < 1 || cur > (int)lines.size()) {
|
||||||
wxLogError("Selected row %d is out of bounds (must be 1-%u)", cur, c->ass->Line.size());
|
wxLogError("Selected row %d is out of bounds (must be 1-%u)", cur, lines.size());
|
||||||
throw LuaForEachBreak();
|
throw LuaForEachBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
advance(it, cur - last_idx);
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(lines[cur - 1]);
|
||||||
|
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
|
|
||||||
if (!diag) {
|
if (!diag) {
|
||||||
wxLogError("Selected row %d is not a dialogue line", cur);
|
wxLogError("Selected row %d is not a dialogue line", cur);
|
||||||
throw LuaForEachBreak();
|
throw LuaForEachBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
sel.insert(diag);
|
sel.insert(diag);
|
||||||
last_idx = cur;
|
|
||||||
if (!active_line || active_idx == cur)
|
if (!active_line || active_idx == cur)
|
||||||
active_line = diag;
|
active_line = diag;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace Automation4 {
|
||||||
/// @param set_undo If there's any uncommitted changes to the file,
|
/// @param set_undo If there's any uncommitted changes to the file,
|
||||||
/// they will be automatically committed with this
|
/// they will be automatically committed with this
|
||||||
/// description
|
/// description
|
||||||
void ProcessingComplete(wxString const& undo_description = wxString());
|
std::vector<AssEntry *> ProcessingComplete(wxString const& undo_description = wxString());
|
||||||
|
|
||||||
/// End processing without applying any changes made
|
/// End processing without applying any changes made
|
||||||
void Cancel();
|
void Cancel();
|
||||||
|
|
|
@ -121,9 +121,7 @@ namespace {
|
||||||
{
|
{
|
||||||
case AssEntryGroup::DIALOGUE: return AssFile::COMMIT_DIAG_ADDREM;
|
case AssEntryGroup::DIALOGUE: return AssFile::COMMIT_DIAG_ADDREM;
|
||||||
case AssEntryGroup::STYLE: return AssFile::COMMIT_STYLES;
|
case AssEntryGroup::STYLE: return AssFile::COMMIT_STYLES;
|
||||||
case AssEntryGroup::FONT: return AssFile::COMMIT_ATTACHMENT;
|
default: return AssFile::COMMIT_SCRIPTINFO;
|
||||||
case AssEntryGroup::GRAPHIC: return AssFile::COMMIT_ATTACHMENT;
|
|
||||||
default: return AssFile::COMMIT_SCRIPTINFO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,8 +215,7 @@ namespace Automation4 {
|
||||||
set_field(L, "class", "style");
|
set_field(L, "class", "style");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Attachments
|
assert(false);
|
||||||
set_field(L, "class", "unknown");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,27 +590,40 @@ namespace Automation4 {
|
||||||
return *((LuaAssFile**)ud);
|
return *((LuaAssFile**)ud);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaAssFile::ProcessingComplete(wxString const& undo_description)
|
std::vector<AssEntry *> LuaAssFile::ProcessingComplete(wxString const& undo_description)
|
||||||
{
|
{
|
||||||
|
auto apply_lines = [&](std::vector<AssEntry *> const& lines) {
|
||||||
|
ass->Info.clear();
|
||||||
|
ass->Styles.clear();
|
||||||
|
ass->Events.clear();
|
||||||
|
|
||||||
|
for (auto line : lines) {
|
||||||
|
switch (line->Group()) {
|
||||||
|
case AssEntryGroup::INFO: ass->Info.push_back(*static_cast<AssInfo *>(line)); break;
|
||||||
|
case AssEntryGroup::STYLE: ass->Styles.push_back(*static_cast<AssStyle *>(line)); break;
|
||||||
|
case AssEntryGroup::DIALOGUE: ass->Events.push_back(*static_cast<AssDialogue *>(line)); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
// Apply any pending commits
|
// Apply any pending commits
|
||||||
for (auto const& pc : pending_commits) {
|
for (auto const& pc : pending_commits) {
|
||||||
ass->Line.clear();
|
apply_lines(pc.lines);
|
||||||
boost::push_back(ass->Line, pc.lines | boost::adaptors::indirected);
|
|
||||||
ass->Commit(pc.mesage, pc.modification_type);
|
ass->Commit(pc.mesage, pc.modification_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit any changes after the last undo point was set
|
// Commit any changes after the last undo point was set
|
||||||
if (modification_type) {
|
if (modification_type)
|
||||||
ass->Line.clear();
|
apply_lines(lines);
|
||||||
boost::push_back(ass->Line, lines | boost::adaptors::indirected);
|
|
||||||
}
|
|
||||||
if (modification_type && can_set_undo && !undo_description.empty())
|
if (modification_type && can_set_undo && !undo_description.empty())
|
||||||
ass->Commit(undo_description, modification_type);
|
ass->Commit(undo_description, modification_type);
|
||||||
|
|
||||||
lines_to_delete.clear();
|
lines_to_delete.clear();
|
||||||
|
|
||||||
|
auto ret = std::move(lines);
|
||||||
references--;
|
references--;
|
||||||
if (!references) delete this;
|
if (!references) delete this;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaAssFile::Cancel()
|
void LuaAssFile::Cancel()
|
||||||
|
@ -631,7 +641,11 @@ namespace Automation4 {
|
||||||
, modification_type(0)
|
, modification_type(0)
|
||||||
, references(2)
|
, references(2)
|
||||||
{
|
{
|
||||||
for (auto& line : ass->Line)
|
for (auto& line : ass->Info)
|
||||||
|
lines.push_back(&line);
|
||||||
|
for (auto& line : ass->Styles)
|
||||||
|
lines.push_back(&line);
|
||||||
|
for (auto& line : ass->Events)
|
||||||
lines.push_back(&line);
|
lines.push_back(&line);
|
||||||
|
|
||||||
// prepare userdata object
|
// prepare userdata object
|
||||||
|
|
|
@ -265,7 +265,7 @@ void BaseGrid::UpdateMaps() {
|
||||||
index_line_map.clear();
|
index_line_map.clear();
|
||||||
line_index_map.clear();
|
line_index_map.clear();
|
||||||
|
|
||||||
for (auto curdiag : context->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto curdiag : context->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
line_index_map[curdiag] = (int)index_line_map.size();
|
line_index_map[curdiag] = (int)index_line_map.size();
|
||||||
index_line_map.push_back(curdiag);
|
index_line_map.push_back(curdiag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,7 +488,7 @@ struct edit_find_replace : public Command {
|
||||||
static std::string get_entry_data(AssDialogue *d) { return d->GetEntryData(); }
|
static std::string get_entry_data(AssDialogue *d) { return d->GetEntryData(); }
|
||||||
static void copy_lines(agi::Context *c) {
|
static void copy_lines(agi::Context *c) {
|
||||||
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
||||||
SetClipboard(join(c->ass->Line
|
SetClipboard(join(c->ass->Events
|
||||||
| agi::of_type<AssDialogue>()
|
| agi::of_type<AssDialogue>()
|
||||||
| filtered([&](AssDialogue *d) { return sel.count(d); })
|
| filtered([&](AssDialogue *d) { return sel.count(d); })
|
||||||
| transformed(get_entry_data),
|
| transformed(get_entry_data),
|
||||||
|
@ -503,7 +503,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
|
||||||
AssDialogue *post_sel = nullptr;
|
AssDialogue *post_sel = nullptr;
|
||||||
bool hit_selection = false;
|
bool hit_selection = false;
|
||||||
|
|
||||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (sel.count(diag))
|
if (sel.count(diag))
|
||||||
hit_selection = true;
|
hit_selection = true;
|
||||||
else if (hit_selection && !post_sel) {
|
else if (hit_selection && !post_sel) {
|
||||||
|
@ -519,7 +519,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
|
||||||
// need to create a new dialogue line for it, and we can't select dialogue
|
// need to create a new dialogue line for it, and we can't select dialogue
|
||||||
// lines until after they're committed.
|
// lines until after they're committed.
|
||||||
std::vector<std::unique_ptr<AssEntry>> to_delete;
|
std::vector<std::unique_ptr<AssEntry>> to_delete;
|
||||||
c->ass->Line.remove_and_dispose_if([&sel](AssEntry const& e) {
|
c->ass->Events.remove_and_dispose_if([&sel](AssEntry const& e) {
|
||||||
return sel.count(const_cast<AssDialogue *>(static_cast<const AssDialogue*>(&e)));
|
return sel.count(const_cast<AssDialogue *>(static_cast<const AssDialogue*>(&e)));
|
||||||
}, [&](AssEntry *e) {
|
}, [&](AssEntry *e) {
|
||||||
to_delete.emplace_back(e);
|
to_delete.emplace_back(e);
|
||||||
|
@ -532,7 +532,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
|
||||||
// lines, so make a new one
|
// lines, so make a new one
|
||||||
if (!new_active) {
|
if (!new_active) {
|
||||||
new_active = new AssDialogue;
|
new_active = new AssDialogue;
|
||||||
c->ass->InsertLine(new_active);
|
c->ass->Events.push_back(*new_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->ass->Commit(commit_message, AssFile::COMMIT_DIAG_ADDREM);
|
c->ass->Commit(commit_message, AssFile::COMMIT_DIAG_ADDREM);
|
||||||
|
@ -605,8 +605,8 @@ static void duplicate_lines(agi::Context *c, int shift) {
|
||||||
SubtitleSelectionController::Selection new_sel;
|
SubtitleSelectionController::Selection new_sel;
|
||||||
AssDialogue *new_active = nullptr;
|
AssDialogue *new_active = nullptr;
|
||||||
|
|
||||||
entryIter start = c->ass->Line.begin();
|
entryIter start = c->ass->Events.begin();
|
||||||
entryIter end = c->ass->Line.end();
|
entryIter end = c->ass->Events.end();
|
||||||
while (start != end) {
|
while (start != end) {
|
||||||
// Find the first line in the selection
|
// Find the first line in the selection
|
||||||
start = find_if(start, end, sel);
|
start = find_if(start, end, sel);
|
||||||
|
@ -622,7 +622,7 @@ static void duplicate_lines(agi::Context *c, int shift) {
|
||||||
auto old_diag = static_cast<AssDialogue*>(&*start);
|
auto old_diag = static_cast<AssDialogue*>(&*start);
|
||||||
auto new_diag = new AssDialogue(*old_diag);
|
auto new_diag = new AssDialogue(*old_diag);
|
||||||
|
|
||||||
c->ass->Line.insert(insert_pos, *new_diag);
|
c->ass->Events.insert(insert_pos, *new_diag);
|
||||||
new_sel.insert(new_diag);
|
new_sel.insert(new_diag);
|
||||||
if (!new_active)
|
if (!new_active)
|
||||||
new_active = new_diag;
|
new_active = new_diag;
|
||||||
|
@ -703,7 +703,7 @@ static void combine_lines(agi::Context *c, void (*combiner)(AssDialogue *, AssDi
|
||||||
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
||||||
|
|
||||||
AssDialogue *first = nullptr;
|
AssDialogue *first = nullptr;
|
||||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ) {
|
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ) {
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it++);
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it++);
|
||||||
if (!diag || !sel.count(diag))
|
if (!diag || !sel.count(diag))
|
||||||
continue;
|
continue;
|
||||||
|
@ -790,8 +790,8 @@ static bool try_paste_lines(agi::Context *c) {
|
||||||
for (auto& line : parsed)
|
for (auto& line : parsed)
|
||||||
new_selection.insert(static_cast<AssDialogue *>(&line));
|
new_selection.insert(static_cast<AssDialogue *>(&line));
|
||||||
|
|
||||||
auto pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
|
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
|
||||||
c->ass->Line.splice(pos, parsed, parsed.begin(), parsed.end());
|
c->ass->Events.splice(pos, parsed, parsed.begin(), parsed.end());
|
||||||
c->ass->Commit(_("paste"), AssFile::COMMIT_DIAG_ADDREM);
|
c->ass->Commit(_("paste"), AssFile::COMMIT_DIAG_ADDREM);
|
||||||
c->selectionController->SetSelectionAndActive(new_selection, new_active);
|
c->selectionController->SetSelectionAndActive(new_selection, new_active);
|
||||||
|
|
||||||
|
@ -821,9 +821,9 @@ struct edit_line_paste : public Command {
|
||||||
ctrl->Paste();
|
ctrl->Paste();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
|
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
|
||||||
paste_lines(c, false, [=](AssDialogue *new_line) -> AssDialogue * {
|
paste_lines(c, false, [=](AssDialogue *new_line) -> AssDialogue * {
|
||||||
c->ass->Line.insert(pos, *new_line);
|
c->ass->Events.insert(pos, *new_line);
|
||||||
return new_line;
|
return new_line;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -852,15 +852,15 @@ struct edit_line_paste_over : public Command {
|
||||||
|
|
||||||
// Only one line selected, so paste over downwards from the active line
|
// Only one line selected, so paste over downwards from the active line
|
||||||
if (sel.size() < 2) {
|
if (sel.size() < 2) {
|
||||||
auto pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
|
auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
|
||||||
|
|
||||||
paste_lines(c, true, [&](AssDialogue *new_line) -> AssDialogue * {
|
paste_lines(c, true, [&](AssDialogue *new_line) -> AssDialogue * {
|
||||||
std::unique_ptr<AssDialogue> deleter(new_line);
|
std::unique_ptr<AssDialogue> deleter(new_line);
|
||||||
if (pos == c->ass->Line.end()) return nullptr;
|
if (pos == c->ass->Events.end()) return nullptr;
|
||||||
|
|
||||||
AssDialogue *ret = paste_over(c->parent, pasteOverOptions, new_line, static_cast<AssDialogue*>(&*pos));
|
AssDialogue *ret = paste_over(c->parent, pasteOverOptions, new_line, static_cast<AssDialogue*>(&*pos));
|
||||||
if (ret)
|
if (ret)
|
||||||
pos = find_if(next(pos), c->ass->Line.end(), cast<AssDialogue*>());
|
pos = find_if(next(pos), c->ass->Events.end(), cast<AssDialogue*>());
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -870,7 +870,7 @@ struct edit_line_paste_over : public Command {
|
||||||
// Sort the selection by grid order
|
// Sort the selection by grid order
|
||||||
std::vector<AssDialogue*> sorted_selection;
|
std::vector<AssDialogue*> sorted_selection;
|
||||||
sorted_selection.reserve(sel.size());
|
sorted_selection.reserve(sel.size());
|
||||||
for (auto& line : c->ass->Line) {
|
for (auto& line : c->ass->Events) {
|
||||||
if (sel.count(static_cast<AssDialogue*>(&line)))
|
if (sel.count(static_cast<AssDialogue*>(&line)))
|
||||||
sorted_selection.push_back(static_cast<AssDialogue*>(&line));
|
sorted_selection.push_back(static_cast<AssDialogue*>(&line));
|
||||||
}
|
}
|
||||||
|
@ -983,7 +983,7 @@ struct edit_line_recombine : public validate_sel_multiple {
|
||||||
|
|
||||||
// Remove now non-existent lines from the selection
|
// Remove now non-existent lines from the selection
|
||||||
SubtitleSelection lines, new_sel;
|
SubtitleSelection lines, new_sel;
|
||||||
boost::copy(c->ass->Line | agi::of_type<AssDialogue>(), inserter(lines, lines.begin()));
|
boost::copy(c->ass->Events | agi::of_type<AssDialogue>(), inserter(lines, lines.begin()));
|
||||||
boost::set_intersection(lines, sel_set, inserter(new_sel, new_sel.begin()));
|
boost::set_intersection(lines, sel_set, inserter(new_sel, new_sel.begin()));
|
||||||
|
|
||||||
if (new_sel.empty())
|
if (new_sel.empty())
|
||||||
|
@ -1015,7 +1015,7 @@ void split_lines(agi::Context *c, Func&& set_time) {
|
||||||
|
|
||||||
AssDialogue *n1 = c->selectionController->GetActiveLine();
|
AssDialogue *n1 = c->selectionController->GetActiveLine();
|
||||||
auto n2 = new AssDialogue(*n1);
|
auto n2 = new AssDialogue(*n1);
|
||||||
c->ass->Line.insert(++c->ass->Line.iterator_to(*n1), *n2);
|
c->ass->Events.insert(++c->ass->Events.iterator_to(*n1), *n2);
|
||||||
|
|
||||||
std::string orig = n1->Text;
|
std::string orig = n1->Text;
|
||||||
n1->Text = boost::trim_right_copy(orig.substr(0, pos));
|
n1->Text = boost::trim_right_copy(orig.substr(0, pos));
|
||||||
|
|
|
@ -79,8 +79,8 @@ struct grid_line_next_create : public Command {
|
||||||
newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt();
|
newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt();
|
||||||
newline->Style = cur->Style;
|
newline->Style = cur->Style;
|
||||||
|
|
||||||
entryIter pos = c->ass->Line.iterator_to(*cur);
|
entryIter pos = c->ass->Events.iterator_to(*cur);
|
||||||
c->ass->Line.insert(++pos, *newline);
|
c->ass->Events.insert(++pos, *newline);
|
||||||
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
|
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
|
||||||
c->selectionController->NextLine();
|
c->selectionController->NextLine();
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ struct grid_move_up : public Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(agi::Context *c) override {
|
void operator()(agi::Context *c) override {
|
||||||
if (move_one(c->ass->Line.begin(), c->ass->Line.end(), c->selectionController->GetSelectedSet(), 1))
|
if (move_one(c->ass->Events.begin(), c->ass->Events.end(), c->selectionController->GetSelectedSet(), 1))
|
||||||
c->ass->Commit(_("move lines"), AssFile::COMMIT_ORDER);
|
c->ass->Commit(_("move lines"), AssFile::COMMIT_ORDER);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -373,7 +373,7 @@ struct grid_move_down : public Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(agi::Context *c) override {
|
void operator()(agi::Context *c) override {
|
||||||
if (move_one(--c->ass->Line.end(), c->ass->Line.begin(), c->selectionController->GetSelectedSet(), -1))
|
if (move_one(--c->ass->Events.end(), c->ass->Events.begin(), c->selectionController->GetSelectedSet(), -1))
|
||||||
c->ass->Commit(_("move lines"), AssFile::COMMIT_ORDER);
|
c->ass->Commit(_("move lines"), AssFile::COMMIT_ORDER);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "../video_context.h"
|
#include "../video_context.h"
|
||||||
|
|
||||||
#include <libaegisub/charset_conv.h>
|
#include <libaegisub/charset_conv.h>
|
||||||
|
#include <libaegisub/of_type_adaptor.h>
|
||||||
#include <libaegisub/util.h>
|
#include <libaegisub/util.h>
|
||||||
|
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
@ -123,10 +124,10 @@ static void insert_subtitle_at_video(agi::Context *c, bool after) {
|
||||||
def->End = video_ms + OPT_GET("Timing/Default Duration")->GetInt();
|
def->End = video_ms + OPT_GET("Timing/Default Duration")->GetInt();
|
||||||
def->Style = c->selectionController->GetActiveLine()->Style;
|
def->Style = c->selectionController->GetActiveLine()->Style;
|
||||||
|
|
||||||
entryIter pos = c->ass->Line.iterator_to(*c->selectionController->GetActiveLine());
|
entryIter pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine());
|
||||||
if (after) ++pos;
|
if (after) ++pos;
|
||||||
|
|
||||||
c->ass->Line.insert(pos, *def);
|
c->ass->Events.insert(pos, *def);
|
||||||
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
|
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
|
||||||
|
|
||||||
c->selectionController->SetSelectionAndActive({ def }, def);
|
c->selectionController->SetSelectionAndActive({ def }, def);
|
||||||
|
@ -146,17 +147,17 @@ struct subtitle_insert_after : public validate_nonempty_selection {
|
||||||
new_line->Start = active_line->End;
|
new_line->Start = active_line->End;
|
||||||
new_line->End = new_line->Start + OPT_GET("Timing/Default Duration")->GetInt();
|
new_line->End = new_line->Start + OPT_GET("Timing/Default Duration")->GetInt();
|
||||||
|
|
||||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) {
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
|
AssDialogue *diag = static_cast<AssDialogue*>(&*it);
|
||||||
|
|
||||||
// Limit the line to the available time
|
// Limit the line to the available time
|
||||||
if (diag && diag->Start >= new_line->Start)
|
if (diag->Start >= new_line->Start)
|
||||||
new_line->End = std::min(new_line->End, diag->Start);
|
new_line->End = std::min(new_line->End, diag->Start);
|
||||||
|
|
||||||
// If we just hit the active line, insert the new line after it
|
// If we just hit the active line, insert the new line after it
|
||||||
if (diag == active_line) {
|
if (diag == active_line) {
|
||||||
++it;
|
++it;
|
||||||
c->ass->Line.insert(it, *new_line);
|
c->ass->Events.insert(it, *new_line);
|
||||||
--it;
|
--it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,16 +192,16 @@ struct subtitle_insert_before : public validate_nonempty_selection {
|
||||||
new_line->End = active_line->Start;
|
new_line->End = active_line->Start;
|
||||||
new_line->Start = new_line->End - OPT_GET("Timing/Default Duration")->GetInt();
|
new_line->Start = new_line->End - OPT_GET("Timing/Default Duration")->GetInt();
|
||||||
|
|
||||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) {
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
|
auto diag = static_cast<AssDialogue*>(&*it);
|
||||||
|
|
||||||
// Limit the line to the available time
|
// Limit the line to the available time
|
||||||
if (diag && diag->End <= new_line->End)
|
if (diag->End <= new_line->End)
|
||||||
new_line->Start = std::max(new_line->Start, diag->End);
|
new_line->Start = std::max(new_line->Start, diag->End);
|
||||||
|
|
||||||
// If we just hit the active line, insert the new line before it
|
// If we just hit the active line, insert the new line before it
|
||||||
if (diag == active_line)
|
if (diag == active_line)
|
||||||
c->ass->Line.insert(it, *new_line);
|
c->ass->Events.insert(it, *new_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
|
c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM);
|
||||||
|
@ -371,7 +372,7 @@ struct subtitle_select_all : public Command {
|
||||||
|
|
||||||
void operator()(agi::Context *c) override {
|
void operator()(agi::Context *c) override {
|
||||||
SubtitleSelection sel;
|
SubtitleSelection sel;
|
||||||
transform(c->ass->Line.begin(), c->ass->Line.end(),
|
transform(c->ass->Events.begin(), c->ass->Events.end(),
|
||||||
inserter(sel, sel.begin()), cast<AssDialogue*>());
|
inserter(sel, sel.begin()), cast<AssDialogue*>());
|
||||||
sel.erase(nullptr);
|
sel.erase(nullptr);
|
||||||
c->selectionController->SetSelectedSet(sel);
|
c->selectionController->SetSelectedSet(sel);
|
||||||
|
@ -393,10 +394,8 @@ struct subtitle_select_visible : public Command {
|
||||||
SubtitleSelectionController::Selection new_selection;
|
SubtitleSelectionController::Selection new_selection;
|
||||||
int frame = c->videoController->GetFrameN();
|
int frame = c->videoController->GetFrameN();
|
||||||
|
|
||||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&*it);
|
if (c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame &&
|
||||||
if (diag &&
|
|
||||||
c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame &&
|
|
||||||
c->videoController->FrameAtTime(diag->End, agi::vfr::END) >= frame)
|
c->videoController->FrameAtTime(diag->End, agi::vfr::END) >= frame)
|
||||||
{
|
{
|
||||||
if (new_selection.empty())
|
if (new_selection.empty())
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace {
|
||||||
if (sel.size() < 2) return !sel.empty();
|
if (sel.size() < 2) return !sel.empty();
|
||||||
|
|
||||||
size_t found = 0;
|
size_t found = 0;
|
||||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (sel.count(diag)) {
|
if (sel.count(diag)) {
|
||||||
if (++found == sel.size())
|
if (++found == sel.size())
|
||||||
return true;
|
return true;
|
||||||
|
@ -84,7 +84,7 @@ static void adjoin_lines(agi::Context *c, bool set_start) {
|
||||||
AssDialogue *prev = nullptr;
|
AssDialogue *prev = nullptr;
|
||||||
size_t seen = 0;
|
size_t seen = 0;
|
||||||
bool prev_sel = false;
|
bool prev_sel = false;
|
||||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
bool cur_sel = !!sel.count(diag);
|
bool cur_sel = !!sel.count(diag);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
// One row selections act as if the previous or next line was selected
|
// One row selections act as if the previous or next line was selected
|
||||||
|
|
|
@ -99,7 +99,7 @@ void DialogAttachments::UpdateList() {
|
||||||
listView->InsertColumn(1, _("Size"), wxLIST_FORMAT_LEFT, 100);
|
listView->InsertColumn(1, _("Size"), wxLIST_FORMAT_LEFT, 100);
|
||||||
listView->InsertColumn(2, _("Group"), wxLIST_FORMAT_LEFT, 100);
|
listView->InsertColumn(2, _("Group"), wxLIST_FORMAT_LEFT, 100);
|
||||||
|
|
||||||
for (auto attach : ass->Line | agi::of_type<AssAttachment>()) {
|
for (auto attach : ass->Attachments | agi::of_type<AssAttachment>()) {
|
||||||
int row = listView->GetItemCount();
|
int row = listView->GetItemCount();
|
||||||
listView->InsertItem(row, to_wx(attach->GetFileName(true)));
|
listView->InsertItem(row, to_wx(attach->GetFileName(true)));
|
||||||
listView->SetItem(row, 1, PrettySize(attach->GetSize()));
|
listView->SetItem(row, 1, PrettySize(attach->GetSize()));
|
||||||
|
|
|
@ -557,8 +557,8 @@ void DialogKanjiTimer::OnStart(wxCommandEvent &) {
|
||||||
else if (SourceStyle->GetValue() == DestStyle->GetValue())
|
else if (SourceStyle->GetValue() == DestStyle->GetValue())
|
||||||
wxMessageBox(_("The source and destination styles must be different."),_("Error"),wxICON_EXCLAMATION | wxOK);
|
wxMessageBox(_("The source and destination styles must be different."),_("Error"),wxICON_EXCLAMATION | wxOK);
|
||||||
else {
|
else {
|
||||||
currentSourceLine = FindNextStyleMatch(&*subs->Line.begin(), from_wx(SourceStyle->GetValue()));
|
currentSourceLine = FindNextStyleMatch(&*subs->Events.begin(), from_wx(SourceStyle->GetValue()));
|
||||||
currentDestinationLine = FindNextStyleMatch(&*subs->Line.begin(), from_wx(DestStyle->GetValue()));
|
currentDestinationLine = FindNextStyleMatch(&*subs->Events.begin(), from_wx(DestStyle->GetValue()));
|
||||||
ResetForNewLine();
|
ResetForNewLine();
|
||||||
}
|
}
|
||||||
LinesToChange.clear();
|
LinesToChange.clear();
|
||||||
|
@ -686,11 +686,11 @@ static AssEntry *find_next(Iterator from, Iterator to, std::string const& style_
|
||||||
AssEntry *DialogKanjiTimer::FindNextStyleMatch(AssEntry *search_from, const std::string &search_style)
|
AssEntry *DialogKanjiTimer::FindNextStyleMatch(AssEntry *search_from, const std::string &search_style)
|
||||||
{
|
{
|
||||||
if (!search_from) return search_from;
|
if (!search_from) return search_from;
|
||||||
return find_next(++subs->Line.iterator_to(*search_from), subs->Line.end(), search_style);
|
return find_next(++subs->Events.iterator_to(*search_from), subs->Events.end(), search_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssEntry *DialogKanjiTimer::FindPrevStyleMatch(AssEntry *search_from, const std::string &search_style)
|
AssEntry *DialogKanjiTimer::FindPrevStyleMatch(AssEntry *search_from, const std::string &search_style)
|
||||||
{
|
{
|
||||||
if (!search_from) return search_from;
|
if (!search_from) return search_from;
|
||||||
return find_next(EntryList::reverse_iterator(subs->Line.iterator_to(*search_from)), subs->Line.rend(), search_style);
|
return find_next(EntryList::reverse_iterator(subs->Events.iterator_to(*search_from)), subs->Events.rend(), search_style);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ static std::set<AssDialogue*> process(std::string const& match_text, bool match_
|
||||||
auto predicate = SearchReplaceEngine::GetMatcher(settings);
|
auto predicate = SearchReplaceEngine::GetMatcher(settings);
|
||||||
|
|
||||||
std::set<AssDialogue*> matches;
|
std::set<AssDialogue*> matches;
|
||||||
for (auto diag : ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (diag->Comment && !comments) continue;
|
if (diag->Comment && !comments) continue;
|
||||||
if (!diag->Comment && !dialogue) continue;
|
if (!diag->Comment && !dialogue) continue;
|
||||||
|
|
||||||
|
|
|
@ -354,7 +354,7 @@ void DialogShiftTimes::Process(wxCommandEvent &) {
|
||||||
int block_start = 0;
|
int block_start = 0;
|
||||||
json::Array shifted_blocks;
|
json::Array shifted_blocks;
|
||||||
|
|
||||||
for (auto line : context->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto line : context->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
++row_number;
|
++row_number;
|
||||||
|
|
||||||
if (!sel.count(line)) {
|
if (!sel.count(line)) {
|
||||||
|
|
|
@ -212,7 +212,7 @@ bool DialogSpellChecker::FindNext() {
|
||||||
if (CheckLine(active_line, start_pos, &commit_id))
|
if (CheckLine(active_line, start_pos, &commit_id))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
entryIter it = context->ass->Line.iterator_to(*active_line);
|
entryIter it = context->ass->Events.iterator_to(*active_line);
|
||||||
|
|
||||||
// Note that it is deliberate that the start line is checked twice, as if
|
// Note that it is deliberate that the start line is checked twice, as if
|
||||||
// the cursor is past the first misspelled word in the current line, that
|
// the cursor is past the first misspelled word in the current line, that
|
||||||
|
@ -220,8 +220,8 @@ bool DialogSpellChecker::FindNext() {
|
||||||
while(!has_looped || active_line != start_line) {
|
while(!has_looped || active_line != start_line) {
|
||||||
do {
|
do {
|
||||||
// Wrap around to the beginning if we hit the end
|
// Wrap around to the beginning if we hit the end
|
||||||
if (++it == context->ass->Line.end()) {
|
if (++it == context->ass->Events.end()) {
|
||||||
it = context->ass->Line.begin();
|
it = context->ass->Events.begin();
|
||||||
has_looped = true;
|
has_looped = true;
|
||||||
}
|
}
|
||||||
} while (!(active_line = dynamic_cast<AssDialogue*>(&*it)));
|
} while (!(active_line = dynamic_cast<AssDialogue*>(&*it)));
|
||||||
|
|
|
@ -86,7 +86,7 @@ class StyleRenamer {
|
||||||
found_any = false;
|
found_any = false;
|
||||||
do_replace = replace;
|
do_replace = replace;
|
||||||
|
|
||||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (diag->Style == source_name) {
|
if (diag->Style == source_name) {
|
||||||
if (replace)
|
if (replace)
|
||||||
diag->Style = new_name;
|
diag->Style = new_name;
|
||||||
|
@ -437,7 +437,7 @@ void DialogStyleEditor::Apply(bool apply, bool close) {
|
||||||
if (store)
|
if (store)
|
||||||
store->push_back(std::unique_ptr<AssStyle>(style));
|
store->push_back(std::unique_ptr<AssStyle>(style));
|
||||||
else
|
else
|
||||||
c->ass->InsertLine(style);
|
c->ass->Styles.push_back(*style);
|
||||||
is_new = false;
|
is_new = false;
|
||||||
}
|
}
|
||||||
if (!store)
|
if (!store)
|
||||||
|
|
|
@ -288,7 +288,7 @@ void DialogStyleManager::LoadCurrentStyles(int commit_type) {
|
||||||
CurrentList->Clear();
|
CurrentList->Clear();
|
||||||
styleMap.clear();
|
styleMap.clear();
|
||||||
|
|
||||||
for (auto style : c->ass->Line | agi::of_type<AssStyle>()) {
|
for (auto style : c->ass->Styles | agi::of_type<AssStyle>()) {
|
||||||
CurrentList->Append(to_wx(style->name));
|
CurrentList->Append(to_wx(style->name));
|
||||||
styleMap.push_back(style);
|
styleMap.push_back(style);
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ void DialogStyleManager::OnCopyToCurrent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
c->ass->InsertLine(new AssStyle(*Store[selections[i]]));
|
c->ass->Styles.push_back(*new AssStyle(*Store[selections[i]]));
|
||||||
copied.push_back(styleName);
|
copied.push_back(styleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,7 +480,7 @@ void DialogStyleManager::CopyToClipboard(wxListBox *list, T const& v) {
|
||||||
void DialogStyleManager::PasteToCurrent() {
|
void DialogStyleManager::PasteToCurrent() {
|
||||||
add_styles(
|
add_styles(
|
||||||
std::bind(&AssFile::GetStyle, c->ass, _1),
|
std::bind(&AssFile::GetStyle, c->ass, _1),
|
||||||
std::bind(&AssFile::InsertLine, c->ass, _1));
|
[=](AssStyle *s) { c->ass->Styles.push_back(*s); });
|
||||||
|
|
||||||
c->ass->Commit(_("style paste"), AssFile::COMMIT_STYLES);
|
c->ass->Commit(_("style paste"), AssFile::COMMIT_STYLES);
|
||||||
}
|
}
|
||||||
|
@ -630,7 +630,7 @@ void DialogStyleManager::OnCurrentImport() {
|
||||||
|
|
||||||
// Copy
|
// Copy
|
||||||
modified = true;
|
modified = true;
|
||||||
c->ass->InsertLine(temp.GetStyle(styles[sel])->Clone());
|
c->ass->Styles.push_back(*temp.GetStyle(styles[sel])->Clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
|
@ -779,10 +779,10 @@ void DialogStyleManager::MoveStyles(bool storage, int type) {
|
||||||
|
|
||||||
// Replace styles
|
// Replace styles
|
||||||
size_t curn = 0;
|
size_t curn = 0;
|
||||||
for (auto it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
for (auto it = c->ass->Styles.begin(); it != c->ass->Styles.end(); ++it) {
|
||||||
if (!dynamic_cast<AssStyle*>(&*it)) continue;
|
if (!dynamic_cast<AssStyle*>(&*it)) continue;
|
||||||
|
|
||||||
auto new_style_at_pos = c->ass->Line.iterator_to(*styleMap[curn]);
|
auto new_style_at_pos = c->ass->Styles.iterator_to(*styleMap[curn]);
|
||||||
EntryList::node_algorithms::swap_nodes(it.pointed_node(), new_style_at_pos.pointed_node());
|
EntryList::node_algorithms::swap_nodes(it.pointed_node(), new_style_at_pos.pointed_node());
|
||||||
if (++curn == styleMap.size()) break;
|
if (++curn == styleMap.size()) break;
|
||||||
it = new_style_at_pos;
|
it = new_style_at_pos;
|
||||||
|
|
|
@ -307,14 +307,14 @@ std::vector<AssDialogue*> DialogTimingProcessor::SortDialogues() {
|
||||||
[&](AssDialogue *d) { return !d->Comment && styles.count(d->Style); });
|
[&](AssDialogue *d) { return !d->Comment && styles.count(d->Style); });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
transform(c->ass->Line.begin(), c->ass->Line.end(), back_inserter(sorted), cast<AssDialogue*>());
|
transform(c->ass->Events.begin(), c->ass->Events.end(), back_inserter(sorted), cast<AssDialogue*>());
|
||||||
sorted.erase(boost::remove_if(sorted, bind(bad_line, &styles, _1)), sorted.end());
|
sorted.erase(boost::remove_if(sorted, bind(bad_line, &styles, _1)), sorted.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if rows are valid
|
// Check if rows are valid
|
||||||
for (auto diag : sorted) {
|
for (auto diag : sorted) {
|
||||||
if (diag->Start > diag->End) {
|
if (diag->Start > diag->End) {
|
||||||
int line = count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*diag), cast<const AssDialogue*>());
|
int line = distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*diag));
|
||||||
wxMessageBox(
|
wxMessageBox(
|
||||||
wxString::Format(_("One of the lines in the file (%i) has negative duration. Aborting."), line),
|
wxString::Format(_("One of the lines in the file (%i) has negative duration. Aborting."), line),
|
||||||
_("Invalid script"),
|
_("Invalid script"),
|
||||||
|
|
|
@ -66,8 +66,8 @@ DialogTranslation::DialogTranslation(agi::Context *c)
|
||||||
, file_change_connection(c->ass->AddCommitListener(&DialogTranslation::OnExternalCommit, this))
|
, file_change_connection(c->ass->AddCommitListener(&DialogTranslation::OnExternalCommit, this))
|
||||||
, active_line_connection(c->selectionController->AddActiveLineListener(&DialogTranslation::OnActiveLineChanged, this))
|
, active_line_connection(c->selectionController->AddActiveLineListener(&DialogTranslation::OnActiveLineChanged, this))
|
||||||
, active_line(c->selectionController->GetActiveLine())
|
, active_line(c->selectionController->GetActiveLine())
|
||||||
, line_count(count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>()))
|
, line_count(c->ass->Events.size())
|
||||||
, line_number(count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*active_line), cast<AssDialogue*>()) + 1)
|
, line_number(distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*active_line)) + 1)
|
||||||
{
|
{
|
||||||
SetIcon(GETICON(translation_toolbutton_16));
|
SetIcon(GETICON(translation_toolbutton_16));
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ void DialogTranslation::OnActiveLineChanged(AssDialogue *new_line) {
|
||||||
active_line = new_line;
|
active_line = new_line;
|
||||||
blocks = active_line->ParseTags();
|
blocks = active_line->ParseTags();
|
||||||
cur_block = 0;
|
cur_block = 0;
|
||||||
line_number = count_if(c->ass->Line.begin(), c->ass->Line.iterator_to(*new_line), cast<AssDialogue*>()) + 1;
|
line_number = distance(c->ass->Events.begin(), c->ass->Events.iterator_to(*new_line)) + 1;
|
||||||
|
|
||||||
if (bad_block(blocks[cur_block]) && !NextBlock()) {
|
if (bad_block(blocks[cur_block]) && !NextBlock()) {
|
||||||
wxMessageBox(_("No more lines to translate."));
|
wxMessageBox(_("No more lines to translate."));
|
||||||
|
@ -185,7 +185,7 @@ void DialogTranslation::OnActiveLineChanged(AssDialogue *new_line) {
|
||||||
|
|
||||||
void DialogTranslation::OnExternalCommit(int commit_type) {
|
void DialogTranslation::OnExternalCommit(int commit_type) {
|
||||||
if (commit_type == AssFile::COMMIT_NEW || commit_type & AssFile::COMMIT_DIAG_ADDREM) {
|
if (commit_type == AssFile::COMMIT_NEW || commit_type & AssFile::COMMIT_DIAG_ADDREM) {
|
||||||
line_count = count_if(c->ass->Line.begin(), c->ass->Line.end(), cast<AssDialogue*>());
|
line_count = c->ass->Events.size();
|
||||||
line_number_display->SetLabel(wxString::Format(_("Current line: %d/%d"), (int)line_number, (int)line_count));
|
line_number_display->SetLabel(wxString::Format(_("Current line: %d/%d"), (int)line_number, (int)line_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *) {
|
||||||
for_each(begin(styles), end(styles), [](std::string& str) { boost::to_lower(str); });
|
for_each(begin(styles), end(styles), [](std::string& str) { boost::to_lower(str); });
|
||||||
sort(begin(styles), end(styles));
|
sort(begin(styles), end(styles));
|
||||||
|
|
||||||
for (auto diag : subs->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : subs->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (!binary_search(begin(styles), end(styles), boost::to_lower_copy(diag->Style.get())))
|
if (!binary_search(begin(styles), end(styles), boost::to_lower_copy(diag->Style.get())))
|
||||||
diag->Style = "Default";
|
diag->Style = "Default";
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ void AssTransformFramerateFilter::TransformTimeTags(std::string const& name, Ass
|
||||||
|
|
||||||
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
|
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
|
||||||
if (!Input->IsLoaded() || !Output->IsLoaded()) return;
|
if (!Input->IsLoaded() || !Output->IsLoaded()) return;
|
||||||
for (auto curDialogue : subs->Line | agi::of_type<AssDialogue>()) {
|
for (auto curDialogue : subs->Events | agi::of_type<AssDialogue>()) {
|
||||||
line = curDialogue;
|
line = curDialogue;
|
||||||
newK = 0;
|
newK = 0;
|
||||||
oldK = 0;
|
oldK = 0;
|
||||||
|
|
|
@ -182,7 +182,7 @@ std::vector<agi::fs::path> FontCollector::GetFontPaths(const AssFile *file) {
|
||||||
|
|
||||||
status_callback(_("Parsing file\n"), 0);
|
status_callback(_("Parsing file\n"), 0);
|
||||||
|
|
||||||
for (auto style : file->Line | agi::of_type<const AssStyle>()) {
|
for (auto style : file->Styles | agi::of_type<const AssStyle>()) {
|
||||||
StyleInfo &info = styles[style->name];
|
StyleInfo &info = styles[style->name];
|
||||||
info.facename = style->font;
|
info.facename = style->font;
|
||||||
info.bold = style->bold;
|
info.bold = style->bold;
|
||||||
|
@ -191,7 +191,7 @@ std::vector<agi::fs::path> FontCollector::GetFontPaths(const AssFile *file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (auto diag : file->Line | agi::of_type<const AssDialogue>())
|
for (auto diag : file->Events | agi::of_type<const AssDialogue>())
|
||||||
ProcessDialogueLine(diag, ++index);
|
ProcessDialogueLine(diag, ++index);
|
||||||
|
|
||||||
status_callback(_("Searching for font files\n"), 0);
|
status_callback(_("Searching for font files\n"), 0);
|
||||||
|
|
|
@ -172,7 +172,9 @@ void ResampleResolution(AssFile *ass, ResampleSettings const& settings) {
|
||||||
if (settings.change_ar)
|
if (settings.change_ar)
|
||||||
state.ar = state.rx / state.ry;
|
state.ar = state.rx / state.ry;
|
||||||
|
|
||||||
for (auto& line : ass->Line)
|
for (auto& line : ass->Styles)
|
||||||
|
resample_line(&state, line);
|
||||||
|
for (auto& line : ass->Events)
|
||||||
resample_line(&state, line);
|
resample_line(&state, line);
|
||||||
|
|
||||||
ass->SetScriptInfo("PlayResX", std::to_string(settings.script_x));
|
ass->SetScriptInfo("PlayResX", std::to_string(settings.script_x));
|
||||||
|
|
|
@ -230,7 +230,7 @@ bool SearchReplaceEngine::FindReplace(bool replace) {
|
||||||
auto matches = GetMatcher(settings);
|
auto matches = GetMatcher(settings);
|
||||||
|
|
||||||
AssDialogue *line = context->selectionController->GetActiveLine();
|
AssDialogue *line = context->selectionController->GetActiveLine();
|
||||||
auto it = context->ass->Line.iterator_to(*line);
|
auto it = context->ass->Events.iterator_to(*line);
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
|
||||||
MatchState replace_ms;
|
MatchState replace_ms;
|
||||||
|
@ -263,7 +263,7 @@ bool SearchReplaceEngine::FindReplace(bool replace) {
|
||||||
// For non-text fields we just look for matching lines rather than each
|
// For non-text fields we just look for matching lines rather than each
|
||||||
// match within the line, so move to the next line
|
// match within the line, so move to the next line
|
||||||
else if (settings.field != SearchReplaceSettings::Field::TEXT)
|
else if (settings.field != SearchReplaceSettings::Field::TEXT)
|
||||||
it = circular_next(it, context->ass->Line);
|
it = circular_next(it, context->ass->Events);
|
||||||
|
|
||||||
auto const& sel = context->selectionController->GetSelectedSet();
|
auto const& sel = context->selectionController->GetSelectedSet();
|
||||||
bool selection_only = sel.size() > 1 && settings.limit_to == SearchReplaceSettings::Limit::SELECTED;
|
bool selection_only = sel.size() > 1 && settings.limit_to == SearchReplaceSettings::Limit::SELECTED;
|
||||||
|
@ -286,7 +286,7 @@ bool SearchReplaceEngine::FindReplace(bool replace) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} while (pos = 0, &*(it = circular_next(it, context->ass->Line)) != line);
|
} while (pos = 0, &*(it = circular_next(it, context->ass->Events)) != line);
|
||||||
|
|
||||||
// Replaced something and didn't find another match, so select the newly
|
// Replaced something and didn't find another match, so select the newly
|
||||||
// inserted text
|
// inserted text
|
||||||
|
@ -307,7 +307,7 @@ bool SearchReplaceEngine::ReplaceAll() {
|
||||||
SubtitleSelection const& sel = context->selectionController->GetSelectedSet();
|
SubtitleSelection const& sel = context->selectionController->GetSelectedSet();
|
||||||
bool selection_only = settings.limit_to == SearchReplaceSettings::Limit::SELECTED;
|
bool selection_only = settings.limit_to == SearchReplaceSettings::Limit::SELECTED;
|
||||||
|
|
||||||
for (auto diag : context->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : context->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (selection_only && !sel.count(diag)) continue;
|
if (selection_only && !sel.count(diag)) continue;
|
||||||
if (settings.ignore_comments && diag->Comment) continue;
|
if (settings.ignore_comments && diag->Comment) continue;
|
||||||
|
|
||||||
|
|
|
@ -69,35 +69,22 @@ struct SubsController::UndoInfo {
|
||||||
UndoInfo(const agi::Context *c, wxString const& d, int commit_id)
|
UndoInfo(const agi::Context *c, wxString const& d, int commit_id)
|
||||||
: undo_description(d), commit_id(commit_id)
|
: undo_description(d), commit_id(commit_id)
|
||||||
{
|
{
|
||||||
size_t info_count = 0, style_count = 0, event_count = 0, font_count = 0, graphics_count = 0;
|
script_info.reserve(c->ass->Info.size());
|
||||||
for (auto const& line : c->ass->Line) {
|
for (auto const& line : c->ass->Info) {
|
||||||
switch (line.Group()) {
|
auto info = static_cast<const AssInfo *>(&line);
|
||||||
case AssEntryGroup::DIALOGUE: ++event_count; break;
|
script_info.emplace_back(info->Key(), info->Value());
|
||||||
case AssEntryGroup::INFO: ++info_count; break;
|
|
||||||
case AssEntryGroup::STYLE: ++style_count; break;
|
|
||||||
case AssEntryGroup::FONT: ++font_count; break;
|
|
||||||
case AssEntryGroup::GRAPHIC: ++graphics_count; break;
|
|
||||||
default: assert(false); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
script_info.reserve(info_count);
|
styles.reserve(c->ass->Styles.size());
|
||||||
styles.reserve(style_count);
|
for (auto const& line : c->ass->Styles)
|
||||||
events.reserve(event_count);
|
styles.push_back(static_cast<AssStyle const&>(line));
|
||||||
|
|
||||||
for (auto const& line : c->ass->Line) {
|
events.reserve(c->ass->Events.size());
|
||||||
|
for (auto const& line : c->ass->Events)
|
||||||
|
events.push_back(static_cast<AssDialogue const&>(line));
|
||||||
|
|
||||||
|
for (auto const& line : c->ass->Attachments) {
|
||||||
switch (line.Group()) {
|
switch (line.Group()) {
|
||||||
case AssEntryGroup::DIALOGUE:
|
|
||||||
events.push_back(static_cast<AssDialogue const&>(line));
|
|
||||||
break;
|
|
||||||
case AssEntryGroup::INFO: {
|
|
||||||
auto info = static_cast<const AssInfo *>(&line);
|
|
||||||
script_info.emplace_back(info->Key(), info->Value());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssEntryGroup::STYLE:
|
|
||||||
styles.push_back(static_cast<AssStyle const&>(line));
|
|
||||||
break;
|
|
||||||
case AssEntryGroup::FONT:
|
case AssEntryGroup::FONT:
|
||||||
fonts.push_back(static_cast<AssAttachment const&>(line));
|
fonts.push_back(static_cast<AssAttachment const&>(line));
|
||||||
break;
|
break;
|
||||||
|
@ -125,16 +112,16 @@ struct SubsController::UndoInfo {
|
||||||
SubtitleSelection new_sel;
|
SubtitleSelection new_sel;
|
||||||
|
|
||||||
for (auto const& info : script_info)
|
for (auto const& info : script_info)
|
||||||
c->ass->Line.push_back(*new AssInfo(info.first, info.second));
|
c->ass->Info.push_back(*new AssInfo(info.first, info.second));
|
||||||
for (auto const& style : styles)
|
for (auto const& style : styles)
|
||||||
c->ass->Line.push_back(*new AssStyle(style));
|
c->ass->Styles.push_back(*new AssStyle(style));
|
||||||
for (auto const& attachment : fonts)
|
for (auto const& attachment : fonts)
|
||||||
c->ass->Line.push_back(*new AssAttachment(attachment));
|
c->ass->Attachments.push_back(*new AssAttachment(attachment));
|
||||||
for (auto const& attachment : graphics)
|
for (auto const& attachment : graphics)
|
||||||
c->ass->Line.push_back(*new AssAttachment(attachment));
|
c->ass->Attachments.push_back(*new AssAttachment(attachment));
|
||||||
for (auto const& event : events) {
|
for (auto const& event : events) {
|
||||||
auto copy = new AssDialogue(event);
|
auto copy = new AssDialogue(event);
|
||||||
c->ass->Line.push_back(*copy);
|
c->ass->Events.push_back(*copy);
|
||||||
if (copy->Id == active_line_id)
|
if (copy->Id == active_line_id)
|
||||||
active_line = copy;
|
active_line = copy;
|
||||||
if (binary_search(begin(selection), end(selection), copy->Id))
|
if (binary_search(begin(selection), end(selection), copy->Id))
|
||||||
|
@ -142,7 +129,7 @@ struct SubsController::UndoInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
c->subsGrid->BeginBatch();
|
c->subsGrid->BeginBatch();
|
||||||
c->selectionController->SetSelectedSet({ });
|
c->selectionController->SetSelectedSet(std::set<AssDialogue *>{});
|
||||||
c->ass->Commit("", AssFile::COMMIT_NEW);
|
c->ass->Commit("", AssFile::COMMIT_NEW);
|
||||||
c->selectionController->SetSelectionAndActive(new_sel, active_line);
|
c->selectionController->SetSelectionAndActive(new_sel, active_line);
|
||||||
c->subsGrid->EndBatch();
|
c->subsGrid->EndBatch();
|
||||||
|
@ -222,22 +209,11 @@ void SubsController::Load(agi::fs::path const& filename, std::string charset) {
|
||||||
AssFile temp;
|
AssFile temp;
|
||||||
reader->ReadFile(&temp, filename, charset);
|
reader->ReadFile(&temp, filename, charset);
|
||||||
|
|
||||||
bool found_style = false;
|
// Make sure the file has at least one style and one dialogue line
|
||||||
bool found_dialogue = false;
|
if (temp.Styles.empty())
|
||||||
|
temp.Styles.push_back(*new AssStyle);
|
||||||
// Check if the file has at least one style and at least one dialogue line
|
if (temp.Events.empty())
|
||||||
for (auto const& line : temp.Line) {
|
temp.Events.push_back(*new AssDialogue);
|
||||||
AssEntryGroup type = line.Group();
|
|
||||||
if (type == AssEntryGroup::STYLE) found_style = true;
|
|
||||||
if (type == AssEntryGroup::DIALOGUE) found_dialogue = true;
|
|
||||||
if (found_style && found_dialogue) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// And if it doesn't add defaults for each
|
|
||||||
if (!found_style)
|
|
||||||
temp.InsertLine(new AssStyle);
|
|
||||||
if (!found_dialogue)
|
|
||||||
temp.InsertLine(new AssDialogue);
|
|
||||||
|
|
||||||
context->ass->swap(temp);
|
context->ass->swap(temp);
|
||||||
}
|
}
|
||||||
|
@ -318,7 +294,7 @@ void SubsController::Close() {
|
||||||
autosaved_commit_id = saved_commit_id = commit_id + 1;
|
autosaved_commit_id = saved_commit_id = commit_id + 1;
|
||||||
filename.clear();
|
filename.clear();
|
||||||
AssFile blank;
|
AssFile blank;
|
||||||
swap(blank.Line, context->ass->Line);
|
blank.swap(*context->ass);
|
||||||
context->ass->LoadDefault();
|
context->ass->LoadDefault();
|
||||||
context->ass->Commit("", AssFile::COMMIT_NEW);
|
context->ass->Commit("", AssFile::COMMIT_NEW);
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,8 +343,7 @@ void SubsEditBox::PopulateList(wxComboBox *combo, boost::flyweight<std::string>
|
||||||
wxEventBlocker blocker(this);
|
wxEventBlocker blocker(this);
|
||||||
|
|
||||||
std::unordered_set<std::string> values;
|
std::unordered_set<std::string> values;
|
||||||
for (auto const& line : c->ass->Line) {
|
for (auto const& line : c->ass->Events) {
|
||||||
if (line.Group() != AssEntryGroup::DIALOGUE) continue;
|
|
||||||
auto const& value = static_cast<const AssDialogue *>(&line)->*field;
|
auto const& value = static_cast<const AssDialogue *>(&line)->*field;
|
||||||
if (!value.get().empty())
|
if (!value.get().empty())
|
||||||
values.insert(value);
|
values.insert(value);
|
||||||
|
@ -435,12 +434,12 @@ void SubsEditBox::SetSelectedRows(setter set, wxString const& desc, int type, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void SubsEditBox::SetSelectedRows(T AssDialogue::*field, T value, wxString const& desc, int type, bool amend) {
|
void SubsEditBox::SetSelectedRows(T AssDialogueBase::*field, T value, wxString const& desc, int type, bool amend) {
|
||||||
SetSelectedRows([&](AssDialogue *d) { d->*field = value; }, desc, type, amend);
|
SetSelectedRows([&](AssDialogue *d) { d->*field = value; }, desc, type, amend);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void SubsEditBox::SetSelectedRows(T AssDialogue::*field, wxString const& value, wxString const& desc, int type, bool amend) {
|
void SubsEditBox::SetSelectedRows(T AssDialogueBase::*field, wxString const& value, wxString const& desc, int type, bool amend) {
|
||||||
boost::flyweight<std::string> conv_value(from_wx(value));
|
boost::flyweight<std::string> conv_value(from_wx(value));
|
||||||
SetSelectedRows([&](AssDialogue *d) { d->*field = conv_value; }, desc, type, amend);
|
SetSelectedRows([&](AssDialogue *d) { d->*field = conv_value; }, desc, type, amend);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ class wxSpinCtrl;
|
||||||
class wxStyledTextCtrl;
|
class wxStyledTextCtrl;
|
||||||
class wxStyledTextEvent;
|
class wxStyledTextEvent;
|
||||||
class wxTextCtrl;
|
class wxTextCtrl;
|
||||||
|
struct AssDialogueBase;
|
||||||
|
|
||||||
template<class Base> class Placeholder;
|
template<class Base> class Placeholder;
|
||||||
|
|
||||||
|
@ -177,10 +178,10 @@ class SubsEditBox : public wxPanel {
|
||||||
/// @param type Commit type to use
|
/// @param type Commit type to use
|
||||||
/// @param amend Coalesce sequences of commits of the same type
|
/// @param amend Coalesce sequences of commits of the same type
|
||||||
template<class T>
|
template<class T>
|
||||||
void SetSelectedRows(T AssDialogue::*field, T value, wxString const& desc, int type, bool amend = false);
|
void SetSelectedRows(T AssDialogueBase::*field, T value, wxString const& desc, int type, bool amend = false);
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void SetSelectedRows(T AssDialogue::*field, wxString const& value, wxString const& desc, int type, bool amend = false);
|
void SetSelectedRows(T AssDialogueBase::*field, wxString const& value, wxString const& desc, int type, bool amend = false);
|
||||||
|
|
||||||
/// @brief Reload the current line from the file
|
/// @brief Reload the current line from the file
|
||||||
/// @param type AssFile::COMMITType
|
/// @param type AssFile::COMMITType
|
||||||
|
|
|
@ -60,8 +60,8 @@ SubtitlesPreview::SubtitlesPreview(wxWindow *parent, wxSize size, int winStyle,
|
||||||
SetStyle(*style);
|
SetStyle(*style);
|
||||||
|
|
||||||
sub_file->LoadDefault();
|
sub_file->LoadDefault();
|
||||||
sub_file->InsertLine(style);
|
sub_file->Styles.push_back(*style);
|
||||||
sub_file->Line.push_back(*line);
|
sub_file->Events.push_back(*line);
|
||||||
|
|
||||||
SetSizeHints(size.GetWidth(), size.GetHeight(), -1, -1);
|
SetSizeHints(size.GetWidth(), size.GetHeight(), -1, -1);
|
||||||
wxSizeEvent evt(size);
|
wxSizeEvent evt(size);
|
||||||
|
|
|
@ -89,22 +89,19 @@ bool SubtitleFormat::CanWriteFile(agi::fs::path const& filename) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubtitleFormat::CanSave(const AssFile *subs) const {
|
bool SubtitleFormat::CanSave(const AssFile *subs) const {
|
||||||
AssStyle defstyle;
|
if (!subs->Attachments.empty())
|
||||||
for (auto const& line : subs->Line) {
|
return false;
|
||||||
// Check style, if anything non-default is found, return false
|
|
||||||
if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(&line)) {
|
|
||||||
if (curstyle->GetEntryData() != defstyle.GetEntryData())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for attachments, if any is found, return false
|
std::string defstyle = AssStyle().GetEntryData();
|
||||||
if (dynamic_cast<const AssAttachment*>(&line)) return false;
|
for (auto const& line : subs->Styles) {
|
||||||
|
if (static_cast<const AssStyle *>(&line)->GetEntryData() != defstyle)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check dialog
|
for (auto const& line : subs->Events) {
|
||||||
if (const AssDialogue *curdiag = dynamic_cast<const AssDialogue*>(&line)) {
|
auto diag = static_cast<const AssDialogue *>(&line);
|
||||||
if (curdiag->GetStrippedText() != curdiag->Text)
|
if (diag->GetStrippedText() != diag->Text)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -176,12 +173,12 @@ agi::vfr::Framerate SubtitleFormat::AskForFPS(bool allow_vfr, bool show_smpte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubtitleFormat::StripTags(AssFile &file) {
|
void SubtitleFormat::StripTags(AssFile &file) {
|
||||||
for (auto current : file.Line | agi::of_type<AssDialogue>())
|
for (auto current : file.Events | agi::of_type<AssDialogue>())
|
||||||
current->StripTags();
|
current->StripTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubtitleFormat::ConvertNewlines(AssFile &file, std::string const& newline, bool mergeLineBreaks) {
|
void SubtitleFormat::ConvertNewlines(AssFile &file, std::string const& newline, bool mergeLineBreaks) {
|
||||||
for (auto current : file.Line | agi::of_type<AssDialogue>()) {
|
for (auto current : file.Events | agi::of_type<AssDialogue>()) {
|
||||||
std::string repl = current->Text;
|
std::string repl = current->Text;
|
||||||
boost::replace_all(repl, "\\h", " ");
|
boost::replace_all(repl, "\\h", " ");
|
||||||
boost::ireplace_all(repl, "\\n", newline);
|
boost::ireplace_all(repl, "\\n", newline);
|
||||||
|
@ -196,18 +193,12 @@ void SubtitleFormat::ConvertNewlines(AssFile &file, std::string const& newline,
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubtitleFormat::StripComments(AssFile &file) {
|
void SubtitleFormat::StripComments(AssFile &file) {
|
||||||
file.Line.remove_and_dispose_if([](AssEntry const& e) {
|
file.Events.remove_and_dispose_if([](AssEntry const& e) {
|
||||||
const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&e);
|
const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&e);
|
||||||
return diag && (diag->Comment || diag->Text.get().empty());
|
return diag && (diag->Comment || diag->Text.get().empty());
|
||||||
}, [](AssEntry *e) { delete e; });
|
}, [](AssEntry *e) { delete e; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubtitleFormat::StripNonDialogue(AssFile &file) {
|
|
||||||
file.Line.remove_and_dispose_if([](AssEntry const& e) {
|
|
||||||
return e.Group() != AssEntryGroup::DIALOGUE;
|
|
||||||
}, [](AssEntry *e) { delete e; });
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dialog_start_lt(AssEntry &pos, AssDialogue *to_insert) {
|
static bool dialog_start_lt(AssEntry &pos, AssDialogue *to_insert) {
|
||||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(&pos);
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(&pos);
|
||||||
return diag && diag->Start > to_insert->Start;
|
return diag && diag->Start > to_insert->Start;
|
||||||
|
@ -217,10 +208,10 @@ static bool dialog_start_lt(AssEntry &pos, AssDialogue *to_insert) {
|
||||||
///
|
///
|
||||||
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
|
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
|
||||||
void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
entryIter cur, next = file.Line.begin();
|
entryIter cur, next = file.Events.begin();
|
||||||
cur = next++;
|
cur = next++;
|
||||||
|
|
||||||
for (; next != file.Line.end(); cur = next++) {
|
for (; next != file.Events.end(); cur = next++) {
|
||||||
AssDialogue *prevdlg = dynamic_cast<AssDialogue*>(&*cur);
|
AssDialogue *prevdlg = dynamic_cast<AssDialogue*>(&*cur);
|
||||||
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(&*next);
|
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(&*next);
|
||||||
|
|
||||||
|
@ -236,8 +227,8 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
// std::list::insert() inserts items before the given iterator, so
|
// std::list::insert() inserts items before the given iterator, so
|
||||||
// we need 'next' for inserting. 'prev' and 'cur' can safely be erased
|
// we need 'next' for inserting. 'prev' and 'cur' can safely be erased
|
||||||
// from the list now.
|
// from the list now.
|
||||||
file.Line.erase(prev);
|
file.Events.erase(prev);
|
||||||
file.Line.erase(cur);
|
file.Events.erase(cur);
|
||||||
|
|
||||||
//Is there an A part before the overlap?
|
//Is there an A part before the overlap?
|
||||||
if (curdlg->Start > prevdlg->Start) {
|
if (curdlg->Start > prevdlg->Start) {
|
||||||
|
@ -247,7 +238,7 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
newdlg->End = curdlg->Start;
|
newdlg->End = curdlg->Start;
|
||||||
newdlg->Text = prevdlg->Text;
|
newdlg->Text = prevdlg->Text;
|
||||||
|
|
||||||
file.Line.insert(find_if(next, file.Line.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
file.Events.insert(find_if(next, file.Events.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overlapping A+B part
|
// Overlapping A+B part
|
||||||
|
@ -258,7 +249,7 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
// Put an ASS format hard linewrap between lines
|
// Put an ASS format hard linewrap between lines
|
||||||
newdlg->Text = curdlg->Text.get() + "\\N" + prevdlg->Text.get();
|
newdlg->Text = curdlg->Text.get() + "\\N" + prevdlg->Text.get();
|
||||||
|
|
||||||
file.Line.insert(find_if(next, file.Line.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
file.Events.insert(find_if(next, file.Events.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there an A part after the overlap?
|
// Is there an A part after the overlap?
|
||||||
|
@ -269,7 +260,7 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
newdlg->End = prevdlg->End;
|
newdlg->End = prevdlg->End;
|
||||||
newdlg->Text = prevdlg->Text;
|
newdlg->Text = prevdlg->Text;
|
||||||
|
|
||||||
file.Line.insert(find_if(next, file.Line.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
file.Events.insert(find_if(next, file.Events.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there a B part after the overlap?
|
// Is there a B part after the overlap?
|
||||||
|
@ -280,7 +271,7 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
newdlg->End = curdlg->End;
|
newdlg->End = curdlg->End;
|
||||||
newdlg->Text = curdlg->Text;
|
newdlg->Text = curdlg->Text;
|
||||||
|
|
||||||
file.Line.insert(find_if(next, file.Line.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
file.Events.insert(find_if(next, file.Events.end(), std::bind(dialog_start_lt, _1, newdlg)), *newdlg);
|
||||||
}
|
}
|
||||||
|
|
||||||
next--;
|
next--;
|
||||||
|
@ -289,10 +280,10 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) {
|
||||||
|
|
||||||
/// @brief Merge identical lines that follow each other
|
/// @brief Merge identical lines that follow each other
|
||||||
void SubtitleFormat::MergeIdentical(AssFile &file) {
|
void SubtitleFormat::MergeIdentical(AssFile &file) {
|
||||||
entryIter cur, next = file.Line.begin();
|
entryIter cur, next = file.Events.begin();
|
||||||
cur = next++;
|
cur = next++;
|
||||||
|
|
||||||
for (; next != file.Line.end(); cur = next++) {
|
for (; next != file.Events.end(); cur = next++) {
|
||||||
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(&*cur);
|
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(&*cur);
|
||||||
AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(&*next);
|
AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(&*next);
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,6 @@ public:
|
||||||
static void ConvertNewlines(AssFile &file, std::string const& newline, bool mergeLineBreaks = true);
|
static void ConvertNewlines(AssFile &file, std::string const& newline, bool mergeLineBreaks = true);
|
||||||
/// Remove All commented and empty lines
|
/// Remove All commented and empty lines
|
||||||
static void StripComments(AssFile &file);
|
static void StripComments(AssFile &file);
|
||||||
/// Remove everything but the dialogue lines
|
|
||||||
static void StripNonDialogue(AssFile &file);
|
|
||||||
/// @brief Split and merge lines so there are no overlapping lines
|
/// @brief Split and merge lines so there are no overlapping lines
|
||||||
///
|
///
|
||||||
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
|
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
|
||||||
|
|
|
@ -115,17 +115,24 @@ void AssSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen
|
||||||
bool ssa = agi::fs::HasExtension(filename, "ssa");
|
bool ssa = agi::fs::HasExtension(filename, "ssa");
|
||||||
AssEntryGroup group = AssEntryGroup::INFO;
|
AssEntryGroup group = AssEntryGroup::INFO;
|
||||||
|
|
||||||
for (auto const& line : src->Line) {
|
auto write = [&](EntryList const& list) {
|
||||||
if (line.Group() != group) {
|
for (auto const& line : list) {
|
||||||
// Add a blank line between each group
|
if (line.Group() != group) {
|
||||||
file.WriteLineToFile("");
|
// Add a blank line between each group
|
||||||
|
file.WriteLineToFile("");
|
||||||
|
|
||||||
file.WriteLineToFile(line.GroupHeader(ssa));
|
file.WriteLineToFile(line.GroupHeader(ssa));
|
||||||
file.WriteLineToFile(format(line.Group(), ssa), false);
|
file.WriteLineToFile(format(line.Group(), ssa), false);
|
||||||
|
|
||||||
group = line.Group();
|
group = line.Group();
|
||||||
|
}
|
||||||
|
|
||||||
|
file.WriteLineToFile(ssa ? line.GetSSAText() : line.GetEntryData());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
file.WriteLineToFile(ssa ? line.GetSSAText() : line.GetEntryData());
|
write(src->Info);
|
||||||
}
|
write(src->Styles);
|
||||||
|
write(src->Attachments);
|
||||||
|
write(src->Events);
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,10 +370,10 @@ namespace
|
||||||
|
|
||||||
AssStyle default_style;
|
AssStyle default_style;
|
||||||
std::vector<EbuSubtitle> subs_list;
|
std::vector<EbuSubtitle> subs_list;
|
||||||
subs_list.reserve(copy.Line.size());
|
subs_list.reserve(copy.Events.size());
|
||||||
|
|
||||||
// convert to intermediate format
|
// convert to intermediate format
|
||||||
for (auto line : copy.Line | agi::of_type<AssDialogue>())
|
for (auto line : copy.Events | agi::of_type<AssDialogue>())
|
||||||
{
|
{
|
||||||
// add a new subtitle and work on it
|
// add a new subtitle and work on it
|
||||||
subs_list.emplace_back();
|
subs_list.emplace_back();
|
||||||
|
|
|
@ -77,6 +77,6 @@ void EncoreSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& fi
|
||||||
// Write lines
|
// Write lines
|
||||||
int i = 0;
|
int i = 0;
|
||||||
TextFileWriter file(filename, "UTF-8");
|
TextFileWriter file(filename, "UTF-8");
|
||||||
for (auto current : copy.Line | agi::of_type<AssDialogue>())
|
for (auto current : copy.Events | agi::of_type<AssDialogue>())
|
||||||
file.WriteLineToFile(str(boost::format("%i %s %s %s") % ++i % ft.ToSMPTE(current->Start) % ft.ToSMPTE(current->End) % current->Text));
|
file.WriteLineToFile(str(boost::format("%i %s %s %s") % ++i % ft.ToSMPTE(current->Start) % ft.ToSMPTE(current->End) % current->Text));
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ void MicroDVDSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& file
|
||||||
diag->Start = fps.TimeAtFrame(f1, agi::vfr::START);
|
diag->Start = fps.TimeAtFrame(f1, agi::vfr::START);
|
||||||
diag->End = fps.TimeAtFrame(f2, agi::vfr::END);
|
diag->End = fps.TimeAtFrame(f2, agi::vfr::END);
|
||||||
diag->Text = text;
|
diag->Text = text;
|
||||||
target->Line.push_back(*diag);
|
target->Events.push_back(*diag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ void MicroDVDSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const&
|
||||||
file.WriteLineToFile(str(boost::format("{1}{1}%.6f") % fps.FPS()));
|
file.WriteLineToFile(str(boost::format("{1}{1}%.6f") % fps.FPS()));
|
||||||
|
|
||||||
// Write lines
|
// Write lines
|
||||||
for (auto current : copy.Line | agi::of_type<AssDialogue>()) {
|
for (auto current : copy.Events | agi::of_type<AssDialogue>()) {
|
||||||
int start = fps.FrameAtTime(current->Start, agi::vfr::START);
|
int start = fps.FrameAtTime(current->Start, agi::vfr::START);
|
||||||
int end = fps.FrameAtTime(current->End, agi::vfr::END);
|
int end = fps.FrameAtTime(current->End, agi::vfr::END);
|
||||||
|
|
||||||
|
|
|
@ -404,7 +404,7 @@ found_timestamps:
|
||||||
line->Start = ReadSRTTime(timestamp_match.str(1));
|
line->Start = ReadSRTTime(timestamp_match.str(1));
|
||||||
line->End = ReadSRTTime(timestamp_match.str(2));
|
line->End = ReadSRTTime(timestamp_match.str(2));
|
||||||
// store pointer to subtitle, we'll continue working on it
|
// store pointer to subtitle, we'll continue working on it
|
||||||
target->Line.push_back(*line);
|
target->Events.push_back(*line);
|
||||||
// next we're reading the text
|
// next we're reading the text
|
||||||
state = STATE_FIRST_LINE_OF_BODY;
|
state = STATE_FIRST_LINE_OF_BODY;
|
||||||
break;
|
break;
|
||||||
|
@ -480,7 +480,7 @@ void SRTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen
|
||||||
|
|
||||||
// Write lines
|
// Write lines
|
||||||
int i=0;
|
int i=0;
|
||||||
for (auto current : copy.Line | agi::of_type<AssDialogue>()) {
|
for (auto current : copy.Events | agi::of_type<AssDialogue>()) {
|
||||||
file.WriteLineToFile(std::to_string(++i));
|
file.WriteLineToFile(std::to_string(++i));
|
||||||
file.WriteLineToFile(WriteSRTTime(current->Start) + " --> " + WriteSRTTime(current->End));
|
file.WriteLineToFile(WriteSRTTime(current->Start) + " --> " + WriteSRTTime(current->End));
|
||||||
file.WriteLineToFile(ConvertTags(current));
|
file.WriteLineToFile(ConvertTags(current));
|
||||||
|
@ -491,26 +491,23 @@ void SRTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen
|
||||||
bool SRTSubtitleFormat::CanSave(const AssFile *file) const {
|
bool SRTSubtitleFormat::CanSave(const AssFile *file) const {
|
||||||
std::string supported_tags[] = { "\\b", "\\i", "\\s", "\\u" };
|
std::string supported_tags[] = { "\\b", "\\i", "\\s", "\\u" };
|
||||||
|
|
||||||
AssStyle defstyle;
|
if (!file->Attachments.empty())
|
||||||
for (auto const& line : file->Line) {
|
return false;
|
||||||
// Check style, if anything non-default is found, return false
|
|
||||||
if (const AssStyle *curstyle = dynamic_cast<const AssStyle*>(&line)) {
|
|
||||||
if (curstyle->GetEntryData() != defstyle.GetEntryData())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for attachments, if any is found, return false
|
std::string defstyle = AssStyle().GetEntryData();
|
||||||
if (dynamic_cast<const AssAttachment*>(&line)) return false;
|
for (auto const& line : file->Styles) {
|
||||||
|
if (static_cast<const AssStyle *>(&line)->GetEntryData() != defstyle)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check dialogue
|
for (auto const& line : file->Events) {
|
||||||
if (const AssDialogue *curdiag = dynamic_cast<const AssDialogue*>(&line)) {
|
auto diag = static_cast<const AssDialogue *>(&line);
|
||||||
boost::ptr_vector<AssDialogueBlock> blocks(curdiag->ParseTags());
|
boost::ptr_vector<AssDialogueBlock> blocks(diag->ParseTags());
|
||||||
for (auto ovr : blocks | agi::of_type<AssDialogueBlockOverride>()) {
|
for (auto ovr : blocks | agi::of_type<AssDialogueBlockOverride>()) {
|
||||||
// Verify that all overrides used are supported
|
// Verify that all overrides used are supported
|
||||||
for (auto const& tag : ovr->Tags) {
|
for (auto const& tag : ovr->Tags) {
|
||||||
if (!std::binary_search(supported_tags, std::end(supported_tags), tag.Name))
|
if (!std::binary_search(supported_tags, std::end(supported_tags), tag.Name))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ void TranStationSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path cons
|
||||||
SmpteFormatter ft(fps);
|
SmpteFormatter ft(fps);
|
||||||
TextFileWriter file(filename, encoding);
|
TextFileWriter file(filename, encoding);
|
||||||
AssDialogue *prev = nullptr;
|
AssDialogue *prev = nullptr;
|
||||||
for (auto cur : copy.Line | agi::of_type<AssDialogue>()) {
|
for (auto cur : copy.Events | agi::of_type<AssDialogue>()) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
file.WriteLineToFile(ConvertLine(©, prev, fps, ft, cur->Start));
|
file.WriteLineToFile(ConvertLine(©, prev, fps, ft, cur->Start));
|
||||||
file.WriteLineToFile("");
|
file.WriteLineToFile("");
|
||||||
|
|
|
@ -92,7 +92,7 @@ void TTXTSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename
|
||||||
if (child->GetName() == "TextSample") {
|
if (child->GetName() == "TextSample") {
|
||||||
if ((diag = ProcessLine(child, diag, version))) {
|
if ((diag = ProcessLine(child, diag, version))) {
|
||||||
lines++;
|
lines++;
|
||||||
target->Line.push_back(*diag);
|
target->Events.push_back(*diag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Header
|
// Header
|
||||||
|
@ -103,7 +103,7 @@ void TTXTSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename
|
||||||
|
|
||||||
// No lines?
|
// No lines?
|
||||||
if (lines == 0)
|
if (lines == 0)
|
||||||
target->Line.push_back(*new AssDialogue);
|
target->Events.push_back(*new AssDialogue);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssDialogue *TTXTSubtitleFormat::ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const {
|
AssDialogue *TTXTSubtitleFormat::ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const {
|
||||||
|
@ -177,7 +177,7 @@ void TTXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& file
|
||||||
|
|
||||||
// Create lines
|
// Create lines
|
||||||
const AssDialogue *prev = nullptr;
|
const AssDialogue *prev = nullptr;
|
||||||
for (auto current : copy.Line | agi::of_type<AssDialogue>()) {
|
for (auto current : copy.Events | agi::of_type<AssDialogue>()) {
|
||||||
WriteLine(root, prev, current);
|
WriteLine(root, prev, current);
|
||||||
prev = current;
|
prev = current;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
|
||||||
|
|
||||||
// Find last line
|
// Find last line
|
||||||
AssTime lastTime;
|
AssTime lastTime;
|
||||||
for (auto line : file.Line | boost::adaptors::reversed | agi::of_type<AssDialogue>()) {
|
for (auto line : file.Events | boost::adaptors::reversed | agi::of_type<AssDialogue>()) {
|
||||||
lastTime = line->End;
|
lastTime = line->End;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -273,5 +273,5 @@ void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
|
||||||
auto diag = new AssDialogue;
|
auto diag = new AssDialogue;
|
||||||
diag->Start = lastTime;
|
diag->Start = lastTime;
|
||||||
diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt();
|
diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt();
|
||||||
file.Line.push_back(*diag);
|
file.Events.push_back(*diag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ void TXTSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename,
|
||||||
line->Text = value;
|
line->Text = value;
|
||||||
line->End = 0;
|
line->End = 0;
|
||||||
|
|
||||||
target->Line.push_back(*line);
|
target->Events.push_back(*line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ void TXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen
|
||||||
size_t num_actor_names = 0, num_dialogue_lines = 0;
|
size_t num_actor_names = 0, num_dialogue_lines = 0;
|
||||||
|
|
||||||
// Detect number of lines with Actor field filled out
|
// Detect number of lines with Actor field filled out
|
||||||
for (auto dia : src->Line | agi::of_type<AssDialogue>()) {
|
for (auto dia : src->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (!dia->Comment) {
|
if (!dia->Comment) {
|
||||||
num_dialogue_lines++;
|
num_dialogue_lines++;
|
||||||
if (!dia->Actor.get().empty())
|
if (!dia->Actor.get().empty())
|
||||||
|
@ -147,7 +147,7 @@ void TXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen
|
||||||
file.WriteLineToFile(std::string("# Exported by Aegisub ") + GetAegisubShortVersionString());
|
file.WriteLineToFile(std::string("# Exported by Aegisub ") + GetAegisubShortVersionString());
|
||||||
|
|
||||||
// Write the file
|
// Write the file
|
||||||
for (auto dia : src->Line | agi::of_type<AssDialogue>()) {
|
for (auto dia : src->Events | agi::of_type<AssDialogue>()) {
|
||||||
std::string out_line;
|
std::string out_line;
|
||||||
|
|
||||||
if (dia->Comment)
|
if (dia->Comment)
|
||||||
|
|
|
@ -118,13 +118,19 @@ void LibassSubtitlesProvider::LoadSubtitles(AssFile *subs) {
|
||||||
data.reserve(0x4000);
|
data.reserve(0x4000);
|
||||||
|
|
||||||
AssEntryGroup group = AssEntryGroup::GROUP_MAX;
|
AssEntryGroup group = AssEntryGroup::GROUP_MAX;
|
||||||
for (auto const& line : subs->Line) {
|
auto write_group = [&](EntryList const& list) {
|
||||||
if (group != line.Group()) {
|
for (auto const& line : list) {
|
||||||
group = line.Group();
|
if (group != line.Group()) {
|
||||||
boost::push_back(data, line.GroupHeader() + "\r\n");
|
group = line.Group();
|
||||||
|
boost::push_back(data, line.GroupHeader() + "\r\n");
|
||||||
|
}
|
||||||
|
boost::push_back(data, line.GetEntryData() + "\r\n");
|
||||||
}
|
}
|
||||||
boost::push_back(data, line.GetEntryData() + "\r\n");
|
};
|
||||||
}
|
|
||||||
|
write_group(subs->Info);
|
||||||
|
write_group(subs->Styles);
|
||||||
|
write_group(subs->Events);
|
||||||
|
|
||||||
if (ass_track) ass_free_track(ass_track);
|
if (ass_track) ass_free_track(ass_track);
|
||||||
ass_track = ass_read_memory(library, &data[0], data.size(), nullptr);
|
ass_track = ass_read_memory(library, &data[0], data.size(), nullptr);
|
||||||
|
|
|
@ -71,9 +71,9 @@ std::shared_ptr<VideoFrame> ThreadedFrameSource::ProcFrame(int frame_number, dou
|
||||||
// instead muck around with its innards to just temporarily
|
// instead muck around with its innards to just temporarily
|
||||||
// remove the non-visible lines without deleting them
|
// remove the non-visible lines without deleting them
|
||||||
std::deque<AssEntry*> full;
|
std::deque<AssEntry*> full;
|
||||||
for (auto& line : subs->Line)
|
for (auto& line : subs->Events)
|
||||||
full.push_back(&line);
|
full.push_back(&line);
|
||||||
subs->Line.remove_if([=](AssEntry const& e) -> bool {
|
subs->Events.remove_if([=](AssEntry const& e) -> bool {
|
||||||
const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&e);
|
const AssDialogue *diag = dynamic_cast<const AssDialogue*>(&e);
|
||||||
return diag && (diag->Start > time || diag->End <= time);
|
return diag && (diag->Start > time || diag->End <= time);
|
||||||
});
|
});
|
||||||
|
@ -81,12 +81,12 @@ std::shared_ptr<VideoFrame> ThreadedFrameSource::ProcFrame(int frame_number, dou
|
||||||
try {
|
try {
|
||||||
subs_provider->LoadSubtitles(subs.get());
|
subs_provider->LoadSubtitles(subs.get());
|
||||||
|
|
||||||
subs->Line.clear();
|
subs->Events.clear();
|
||||||
boost::push_back(subs->Line, full | boost::adaptors::indirected);
|
boost::push_back(subs->Events, full | boost::adaptors::indirected);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
subs->Line.clear();
|
subs->Events.clear();
|
||||||
boost::push_back(subs->Line, full | boost::adaptors::indirected);
|
boost::push_back(subs->Events, full | boost::adaptors::indirected);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ void ThreadedFrameSource::UpdateSubtitles(const AssFile *new_subs, std::set<cons
|
||||||
// same indices in the worker's copy of the file with the new entries
|
// same indices in the worker's copy of the file with the new entries
|
||||||
std::deque<std::pair<size_t, AssEntry*>> changed;
|
std::deque<std::pair<size_t, AssEntry*>> changed;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (auto const& e : new_subs->Line) {
|
for (auto const& e : new_subs->Events) {
|
||||||
if (changes.count(&e))
|
if (changes.count(&e))
|
||||||
changed.emplace_back(i, e.Clone());
|
changed.emplace_back(i, e.Clone());
|
||||||
++i;
|
++i;
|
||||||
|
@ -148,11 +148,11 @@ void ThreadedFrameSource::UpdateSubtitles(const AssFile *new_subs, std::set<cons
|
||||||
|
|
||||||
worker->Async([=]{
|
worker->Async([=]{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
auto it = subs->Line.begin();
|
auto it = subs->Events.begin();
|
||||||
for (auto& update : changed) {
|
for (auto& update : changed) {
|
||||||
advance(it, update.first - i);
|
advance(it, update.first - i);
|
||||||
i = update.first;
|
i = update.first;
|
||||||
subs->Line.insert(it, *update.second);
|
subs->Events.insert(it, *update.second);
|
||||||
delete &*it--;
|
delete &*it--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ void VisualToolDrag::OnFileChanged() {
|
||||||
primary = nullptr;
|
primary = nullptr;
|
||||||
active_feature = nullptr;
|
active_feature = nullptr;
|
||||||
|
|
||||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (IsDisplayed(diag))
|
if (IsDisplayed(diag))
|
||||||
MakeFeatures(diag);
|
MakeFeatures(diag);
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ void VisualToolDrag::OnFrameChanged() {
|
||||||
auto feat = features.begin();
|
auto feat = features.begin();
|
||||||
auto end = features.end();
|
auto end = features.end();
|
||||||
|
|
||||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
for (auto diag : c->ass->Events | agi::of_type<AssDialogue>()) {
|
||||||
if (IsDisplayed(diag)) {
|
if (IsDisplayed(diag)) {
|
||||||
// Features don't exist and should
|
// Features don't exist and should
|
||||||
if (feat == end || feat->line != diag)
|
if (feat == end || feat->line != diag)
|
||||||
|
|
Loading…
Reference in New Issue