From b1639c6162879555323504561fc03cbd31c7e0ed Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Fri, 7 Mar 2014 10:58:51 -0800 Subject: [PATCH] Make the entry lists be of the appropriate type rather than just AssEntry Eliminates a bajillion dynamic casts. --- aegisub/build/libaegisub/libaegisub.vcxproj | 1 + .../libaegisub/libaegisub.vcxproj.filters | 3 + .../include/libaegisub/address_of_adaptor.h | 52 ++++++ aegisub/src/ass_attachment.cpp | 8 - aegisub/src/ass_attachment.h | 4 +- aegisub/src/ass_dialogue.cpp | 2 +- aegisub/src/ass_dialogue.h | 2 +- aegisub/src/ass_file.cpp | 167 ++++++++---------- aegisub/src/ass_file.h | 45 ++--- aegisub/src/ass_info.h | 2 +- aegisub/src/ass_karaoke.cpp | 15 +- aegisub/src/ass_style.cpp | 4 - aegisub/src/ass_style.h | 2 +- aegisub/src/audio_karaoke.cpp | 2 +- aegisub/src/audio_karaoke.h | 3 +- aegisub/src/audio_timing_dialogue.cpp | 25 ++- aegisub/src/auto4_lua.cpp | 9 +- aegisub/src/auto4_lua_assfile.cpp | 3 +- aegisub/src/base_grid.cpp | 50 +++--- aegisub/src/command/edit.cpp | 77 ++++---- aegisub/src/command/grid.cpp | 6 +- aegisub/src/command/subtitle.cpp | 27 ++- aegisub/src/command/time.cpp | 15 +- aegisub/src/dialog_attachments.cpp | 12 +- aegisub/src/dialog_kara_timing_copy.cpp | 31 ++-- aegisub/src/dialog_kara_timing_copy.h | 9 +- aegisub/src/dialog_selection.cpp | 12 +- aegisub/src/dialog_shift_times.cpp | 9 +- aegisub/src/dialog_spellchecker.cpp | 14 +- aegisub/src/dialog_style_editor.cpp | 10 +- aegisub/src/dialog_style_manager.cpp | 11 +- aegisub/src/dialog_timing_processor.cpp | 27 +-- aegisub/src/export_fixstyle.cpp | 13 +- aegisub/src/export_framerate.cpp | 14 +- aegisub/src/font_file_lister.cpp | 18 +- aegisub/src/resolution_resampler.cpp | 47 ++--- aegisub/src/search_replace_engine.cpp | 27 ++- aegisub/src/subs_controller.cpp | 21 +-- aegisub/src/subs_controller.h | 1 - aegisub/src/subs_edit_box.cpp | 3 +- aegisub/src/subtitle_format.cpp | 55 +++--- aegisub/src/subtitle_format.h | 1 - aegisub/src/subtitle_format_ass.cpp | 97 +++++----- aegisub/src/subtitle_format_ebu3264.cpp | 13 +- aegisub/src/subtitle_format_encore.cpp | 6 +- aegisub/src/subtitle_format_microdvd.cpp | 9 +- aegisub/src/subtitle_format_srt.cpp | 11 +- aegisub/src/subtitle_format_transtation.cpp | 12 +- aegisub/src/subtitle_format_transtation.h | 2 +- aegisub/src/subtitle_format_ttxt.cpp | 11 +- aegisub/src/subtitle_format_txt.cpp | 16 +- aegisub/src/subtitles_provider_libass.cpp | 40 +++-- aegisub/src/threaded_frame_source.cpp | 15 +- aegisub/src/threaded_frame_source.h | 4 +- aegisub/src/utils.h | 13 -- aegisub/src/video_context.cpp | 6 +- aegisub/src/video_context.h | 8 +- aegisub/src/visual_tool_drag.cpp | 19 +- 58 files changed, 538 insertions(+), 603 deletions(-) create mode 100644 aegisub/libaegisub/include/libaegisub/address_of_adaptor.h diff --git a/aegisub/build/libaegisub/libaegisub.vcxproj b/aegisub/build/libaegisub/libaegisub.vcxproj index a73a35119..a8126c3f9 100644 --- a/aegisub/build/libaegisub/libaegisub.vcxproj +++ b/aegisub/build/libaegisub/libaegisub.vcxproj @@ -38,6 +38,7 @@ + diff --git a/aegisub/build/libaegisub/libaegisub.vcxproj.filters b/aegisub/build/libaegisub/libaegisub.vcxproj.filters index a73b5aaf7..ff2bba3f6 100644 --- a/aegisub/build/libaegisub/libaegisub.vcxproj.filters +++ b/aegisub/build/libaegisub/libaegisub.vcxproj.filters @@ -164,6 +164,9 @@ Header Files + + Header Files + diff --git a/aegisub/libaegisub/include/libaegisub/address_of_adaptor.h b/aegisub/libaegisub/include/libaegisub/address_of_adaptor.h new file mode 100644 index 000000000..1ca2c33f9 --- /dev/null +++ b/aegisub/libaegisub/include/libaegisub/address_of_adaptor.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#include + +namespace agi { +namespace address_of_detail { + using namespace boost::adaptors; + + // Tag type to select the operator| overload + struct address_of_tag_type { }; + + template + struct take_address_of { + using result_type = typename std::iterator_traits::pointer; + using input_type = typename std::iterator_traits::reference; + + result_type operator()(input_type v) const { return &v; } + }; + + template + auto operator|(Rng&& r, address_of_tag_type) + -> boost::transformed_range, Rng> + { + return r | transformed(take_address_of()); + } + + template + auto operator|(Rng& r, address_of_tag_type) + -> boost::transformed_range, Rng> + { + return r | transformed(take_address_of()); + } +} + +namespace { + const auto address_of = address_of_detail::address_of_tag_type{}; +} +} diff --git a/aegisub/src/ass_attachment.cpp b/aegisub/src/ass_attachment.cpp index a5b06dfb7..e0c482c84 100644 --- a/aegisub/src/ass_attachment.cpp +++ b/aegisub/src/ass_attachment.cpp @@ -59,14 +59,6 @@ AssAttachment::AssAttachment(agi::fs::path const& name, AssEntryGroup group) entry_data = entry_data.get() + agi::ass::UUEncode(data); } -AssEntry *AssAttachment::Clone() const { - return new AssAttachment(*this); -} - -const std::string AssAttachment::GetEntryData() const { - return entry_data; -} - size_t AssAttachment::GetSize() const { auto header_end = entry_data.get().find('\n'); return entry_data.get().size() - header_end - 1; diff --git a/aegisub/src/ass_attachment.h b/aegisub/src/ass_attachment.h index 142b01441..ebbad86a6 100644 --- a/aegisub/src/ass_attachment.h +++ b/aegisub/src/ass_attachment.h @@ -46,9 +46,9 @@ public: /// @param raw If false, remove the SSA filename mangling std::string GetFileName(bool raw=false) const; - const std::string GetEntryData() const override; + const std::string GetEntryData() const override { return entry_data; } AssEntryGroup Group() const override { return group; } - AssEntry *Clone() const override; + AssAttachment *Clone() const override { return new AssAttachment(*this); } AssAttachment(AssAttachment const& rgt); AssAttachment(std::string const& header, AssEntryGroup group); diff --git a/aegisub/src/ass_dialogue.cpp b/aegisub/src/ass_dialogue.cpp index 6954fb974..f75298d04 100644 --- a/aegisub/src/ass_dialogue.cpp +++ b/aegisub/src/ass_dialogue.cpp @@ -256,7 +256,7 @@ std::string AssDialogue::GetStrippedText() const { return join(blocks | agi::of_type() | transformed(get_text_p), ""); } -AssEntry *AssDialogue::Clone() const { +AssDialogue *AssDialogue::Clone() const { auto clone = new AssDialogue(*this); clone->Id = Id; return clone; diff --git a/aegisub/src/ass_dialogue.h b/aegisub/src/ass_dialogue.h index 56af7cacc..780553ba8 100644 --- a/aegisub/src/ass_dialogue.h +++ b/aegisub/src/ass_dialogue.h @@ -177,7 +177,7 @@ public: /// Does this line collide with the passed line? bool CollidesWith(const AssDialogue *target) const; - AssEntry *Clone() const override; + AssDialogue *Clone() const override; AssDialogue(); AssDialogue(AssDialogue const&); diff --git a/aegisub/src/ass_file.cpp b/aegisub/src/ass_file.cpp index 90671e469..0e76725b1 100644 --- a/aegisub/src/ass_file.cpp +++ b/aegisub/src/ass_file.cpp @@ -1,36 +1,19 @@ -// Copyright (c) 2005, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2014, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ -/// @file ass_file.cpp -/// @brief Overall storage of subtitle files, undo management and more -/// @ingroup subs_storage - #include "config.h" #include "ass_file.h" @@ -42,20 +25,20 @@ #include "options.h" #include "utils.h" -#include - #include #include #include +AssFile::AssFile() { } + AssFile::~AssFile() { - Info.clear_and_dispose([](AssEntry *e) { delete e; }); - Styles.clear_and_dispose([](AssEntry *e) { delete e; }); - Events.clear_and_dispose([](AssEntry *e) { delete e; }); - Attachments.clear_and_dispose([](AssEntry *e) { delete e; }); + Info.clear_and_dispose([](AssInfo *e) { delete e; }); + Styles.clear_and_dispose([](AssStyle *e) { delete e; }); + Events.clear_and_dispose([](AssDialogue *e) { delete e; }); + Attachments.clear_and_dispose([](AssAttachment *e) { delete e; }); } -void AssFile::LoadDefault(bool defline) { +void AssFile::LoadDefault(bool include_dialogue_line) { Info.push_back(*new AssInfo("Title", "Default Aegisub file")); Info.push_back(*new AssInfo("ScriptType", "v4.00+")); Info.push_back(*new AssInfo("WrapStyle", "0")); @@ -68,15 +51,15 @@ void AssFile::LoadDefault(bool defline) { Styles.push_back(*new AssStyle); - if (defline) + if (include_dialogue_line) Events.push_back(*new AssDialogue); } AssFile::AssFile(const AssFile &from) { - 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; }); + Info.clone_from(from.Info, std::mem_fun_ref(&AssInfo::Clone), [](AssInfo *e) { delete e; }); + Styles.clone_from(from.Styles, std::mem_fun_ref(&AssStyle::Clone), [](AssStyle *e) { delete e; }); + Events.clone_from(from.Events, std::mem_fun_ref(&AssDialogue::Clone), [](AssDialogue *e) { delete e; }); + Attachments.clone_from(from.Attachments, std::mem_fun_ref(&AssAttachment::Clone), [](AssAttachment *e) { delete e; }); } void AssFile::swap(AssFile& from) throw() { @@ -102,9 +85,9 @@ void AssFile::InsertAttachment(agi::fs::path const& filename) { } std::string AssFile::GetScriptInfo(std::string const& key) const { - for (const auto info : Info | agi::of_type()) { - if (boost::iequals(key, info->Key())) - return info->Value(); + for (auto const& info : Info) { + if (boost::iequals(key, info.Key())) + return info.Value(); } return ""; @@ -131,12 +114,12 @@ void AssFile::SaveUIState(std::string const& key, std::string const& value) { } void AssFile::SetScriptInfo(std::string const& key, std::string const& value) { - for (auto info : Info | agi::of_type()) { - if (boost::iequals(key, info->Key())) { + for (auto& info : Info) { + if (boost::iequals(key, info.Key())) { if (value.empty()) - delete info; + delete &info; else - info->SetValue(value); + info.SetValue(value); return; } } @@ -145,47 +128,42 @@ void AssFile::SetScriptInfo(std::string const& key, std::string const& value) { Info.push_back(*new AssInfo(key, value)); } -void AssFile::GetResolution(int &sw,int &sh) const { +void AssFile::GetResolution(int &sw, int &sh) const { sw = GetScriptInfoAsInt("PlayResX"); sh = GetScriptInfoAsInt("PlayResY"); - // Gabest logic? + // Gabest logic: default is 384x288, assume 1280x1024 if either height or + // width are that, otherwise assume 4:3 if only heigh or width are set. + // Why 1280x1024? Who the fuck knows. Clearly just Gabest trolling everyone. if (sw == 0 && sh == 0) { sw = 384; sh = 288; - } else if (sw == 0) { - if (sh == 1024) - sw = 1280; - else - sw = sh * 4 / 3; - } else if (sh == 0) { - // you are not crazy; this doesn't make any sense - if (sw == 1280) - sh = 1024; - else - sh = sw * 3 / 4; } + else if (sw == 0) + sw = sh == 1024 ? 1280 : sh * 4 / 3; + else if (sh == 0) + sh = sw == 1280 ? 1024 : sw * 3 / 4; } std::vector AssFile::GetStyles() const { std::vector styles; - for (auto style : Styles | agi::of_type()) - styles.push_back(style->name); + for (auto& style : Styles) + styles.push_back(style.name); return styles; } AssStyle *AssFile::GetStyle(std::string const& name) { - for (auto style : Styles | agi::of_type()) { - if (boost::iequals(style->name, name)) - return style; + for (auto& style : Styles) { + if (boost::iequals(style.name, name)) + return &style; } return nullptr; } -int AssFile::Commit(wxString const& desc, int type, int amend_id, AssEntry *single_line) { +int AssFile::Commit(wxString const& desc, int type, int amend_id, AssDialogue *single_line) { PushState({desc, &amend_id, single_line}); - std::set changed_lines; + std::set changed_lines; if (single_line) changed_lines.insert(single_line); @@ -194,50 +172,45 @@ int AssFile::Commit(wxString const& desc, int type, int amend_id, AssEntry *sing return amend_id; } -bool AssFile::CompStart(const AssDialogue* lft, const AssDialogue* rgt) { - return lft->Start < rgt->Start; +bool AssFile::CompStart(AssDialogue const& lft, AssDialogue const& rgt) { + return lft.Start < rgt.Start; } -bool AssFile::CompEnd(const AssDialogue* lft, const AssDialogue* rgt) { - return lft->End < rgt->End; +bool AssFile::CompEnd(AssDialogue const& lft, AssDialogue const& rgt) { + return lft.End < rgt.End; } -bool AssFile::CompStyle(const AssDialogue* lft, const AssDialogue* rgt) { - return lft->Style < rgt->Style; +bool AssFile::CompStyle(AssDialogue const& lft, AssDialogue const& rgt) { + return lft.Style < rgt.Style; } -bool AssFile::CompActor(const AssDialogue* lft, const AssDialogue* rgt) { - return lft->Actor < rgt->Actor; +bool AssFile::CompActor(AssDialogue const& lft, AssDialogue const& rgt) { + return lft.Actor < rgt.Actor; } -bool AssFile::CompEffect(const AssDialogue* lft, const AssDialogue* rgt) { - return lft->Effect < rgt->Effect; +bool AssFile::CompEffect(AssDialogue const& lft, AssDialogue const& rgt) { + return lft.Effect < rgt.Effect; } -bool AssFile::CompLayer(const AssDialogue* lft, const AssDialogue* rgt) { - return lft->Layer < rgt->Layer; +bool AssFile::CompLayer(AssDialogue const& lft, AssDialogue const& rgt) { + return lft.Layer < rgt.Layer; } void AssFile::Sort(CompFunc comp, std::set const& limit) { Sort(Events, comp, limit); } -namespace { - inline bool is_dialogue(AssEntry *e, std::set const& limit) { - AssDialogue *d = dynamic_cast(e); - return d && (limit.empty() || limit.count(d)); + +void AssFile::Sort(EntryList &lst, CompFunc comp, std::set const& limit) { + if (limit.empty()) { + lst.sort(comp); + return; } -} -void AssFile::Sort(EntryList &lst, CompFunc comp, std::set const& limit) { - auto compE = [&](AssEntry const& a, AssEntry const& b) { - return comp(static_cast(&a), static_cast(&b)); - }; + // Sort each selected block separately, leaving everything else untouched + for (auto begin = lst.begin(); begin != lst.end(); ++begin) { + if (!limit.count(&*begin)) continue; + auto end = begin; + while (end != lst.end() && limit.count(&*end)) ++end; - // Sort each block of AssDialogues separately, leaving everything else untouched - for (entryIter begin = lst.begin(); begin != lst.end(); ++begin) { - if (!is_dialogue(&*begin, limit)) continue; - entryIter end = begin; - while (end != lst.end() && is_dialogue(&*end, limit)) ++end; - - // used instead of std::list::sort for partial list sorting - EntryList tmp; + // sort doesn't support only sorting a sublist, so move them to a temp list + EntryList tmp; tmp.splice(tmp.begin(), lst, begin, end); - tmp.sort(compE); + tmp.sort(comp); lst.splice(end, tmp); begin = --end; diff --git a/aegisub/src/ass_file.h b/aegisub/src/ass_file.h index dd36272e5..207d4a271 100644 --- a/aegisub/src/ass_file.h +++ b/aegisub/src/ass_file.h @@ -41,33 +41,36 @@ #include #include -class AssDialogue; -class AssStyle; class AssAttachment; +class AssDialogue; +class AssInfo; +class AssStyle; class wxString; -typedef boost::intrusive::make_list>::type EntryList; -typedef EntryList::iterator entryIter; -typedef EntryList::const_iterator constEntryIter; +template +using EntryList = typename boost::intrusive::make_list, boost::intrusive::base_hook>::type; + +template +using EntryIter = typename EntryList::iterator; struct AssFileCommit { wxString const& message; int *commit_id; - AssEntry *single_line; + AssDialogue *single_line; }; class AssFile { /// A set of changes has been committed to the file (AssFile::COMMITType) - agi::signal::Signal const&> AnnounceCommit; + agi::signal::Signal const&> AnnounceCommit; agi::signal::Signal PushState; public: /// The lines in the file - EntryList Info; - EntryList Styles; - EntryList Events; - EntryList Attachments; + EntryList Info; + EntryList Styles; + EntryList Events; + EntryList Attachments; - AssFile() { } + AssFile(); AssFile(const AssFile &from); AssFile& operator=(AssFile from); ~AssFile(); @@ -139,23 +142,23 @@ public: /// @param commitId Commit to amend rather than pushing a new commit /// @param single_line Line which was changed, if only one line was /// @return Unique identifier for the new undo group - int Commit(wxString const& desc, int type, int commitId = -1, AssEntry *single_line = nullptr); + int Commit(wxString const& desc, int type, int commitId = -1, AssDialogue *single_line = nullptr); /// Comparison function for use when sorting - typedef bool (*CompFunc)(const AssDialogue* lft, const AssDialogue* rgt); + typedef bool (*CompFunc)(AssDialogue const& lft, AssDialogue const& rgt); /// Compare based on start time - static bool CompStart(const AssDialogue* lft, const AssDialogue* rgt); + static bool CompStart(AssDialogue const& lft, AssDialogue const& rgt); /// Compare based on end time - static bool CompEnd(const AssDialogue* lft, const AssDialogue* rgt); + static bool CompEnd(AssDialogue const& lft, AssDialogue const& rgt); /// Compare based on style name - static bool CompStyle(const AssDialogue* lft, const AssDialogue* rgt); + static bool CompStyle(AssDialogue const& lft, AssDialogue const& rgt); /// Compare based on actor name - static bool CompActor(const AssDialogue* lft, const AssDialogue* rgt); + static bool CompActor(AssDialogue const& lft, AssDialogue const& rgt); /// Compare based on effect - static bool CompEffect(const AssDialogue* lft, const AssDialogue* rgt); + static bool CompEffect(AssDialogue const& lft, AssDialogue const& rgt); /// Compare based on layer - static bool CompLayer(const AssDialogue* lft, const AssDialogue* rgt); + static bool CompLayer(AssDialogue const& lft, AssDialogue const& rgt); /// @brief Sort the dialogue lines in this file /// @param comp Comparison function to use. Defaults to sorting by start time. @@ -164,5 +167,5 @@ public: /// @brief Sort the dialogue lines in the given list /// @param comp Comparison function to use. Defaults to sorting by start time. /// @param limit If non-empty, only lines in this set are sorted - static void Sort(EntryList& lst, CompFunc comp = CompStart, std::set const& limit = std::set()); + static void Sort(EntryList& lst, CompFunc comp = CompStart, std::set const& limit = std::set()); }; diff --git a/aegisub/src/ass_info.h b/aegisub/src/ass_info.h index acededc66..07d3998df 100644 --- a/aegisub/src/ass_info.h +++ b/aegisub/src/ass_info.h @@ -26,7 +26,7 @@ public: AssInfo(AssInfo const& o) = default; AssInfo(std::string key, std::string value) : key(std::move(key)), value(std::move(value)) { } - AssEntry *Clone() const override { return new AssInfo(*this); } + AssInfo *Clone() const override { return new AssInfo(*this); } AssEntryGroup Group() const override { return AssEntryGroup::INFO; } const std::string GetEntryData() const override { return key + ": " + value; } std::string GetSSAText() const override { return boost::iequals(key, "scripttype: v4.00+") ? "ScriptType: v4.00" : GetEntryData(); } diff --git a/aegisub/src/ass_karaoke.cpp b/aegisub/src/ass_karaoke.cpp index 9181d78e0..f9303395c 100644 --- a/aegisub/src/ass_karaoke.cpp +++ b/aegisub/src/ass_karaoke.cpp @@ -280,19 +280,18 @@ void AssKaraoke::SplitLines(std::set const& lines, agi::Context *c SubtitleSelection sel = c->selectionController->GetSelectedSet(); bool did_split = false; - for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) { - AssDialogue *diag = dynamic_cast(&*it); - if (!diag || !lines.count(diag)) continue; + for (auto it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) { + if (!lines.count(&*it)) continue; - kara.SetLine(diag); + kara.SetLine(&*it); // If there aren't at least two tags there's nothing to split if (kara.size() < 2) continue; - bool in_sel = sel.count(diag) > 0; + bool in_sel = sel.count(&*it) > 0; for (auto const& syl : kara) { - auto new_line = new AssDialogue(*diag); + auto new_line = new AssDialogue(*it); new_line->Start = syl.start_time; new_line->End = syl.start_time + syl.duration; @@ -305,8 +304,8 @@ void AssKaraoke::SplitLines(std::set const& lines, agi::Context *c } --it; // Move `it` to the last of the new lines - sel.erase(diag); - delete diag; + sel.erase(&*it); + delete &*it; did_split = true; } diff --git a/aegisub/src/ass_style.cpp b/aegisub/src/ass_style.cpp index 88f551929..0b9216a9d 100644 --- a/aegisub/src/ass_style.cpp +++ b/aegisub/src/ass_style.cpp @@ -204,10 +204,6 @@ std::string AssStyle::GetSSAText() const { % Margin[0] % Margin[1] % Margin[2] % encoding); } -AssEntry *AssStyle::Clone() const { - return new AssStyle(*this); -} - void AssStyle::GetEncodings(wxArrayString &encodingStrings) { encodingStrings.Clear(); encodingStrings.Add(wxString("0 - ") + _("ANSI")); diff --git a/aegisub/src/ass_style.h b/aegisub/src/ass_style.h index 149fd3d13..aaf2b15a5 100644 --- a/aegisub/src/ass_style.h +++ b/aegisub/src/ass_style.h @@ -80,7 +80,7 @@ public: const std::string GetEntryData() const override { return data; } std::string GetSSAText() const override; AssEntryGroup Group() const override { return AssEntryGroup::STYLE; } - AssEntry *Clone() const override; + AssStyle *Clone() const override { return new AssStyle(*this); } /// Convert an ASS alignment to the equivalent SSA alignment static int AssToSsa(int ass_align); diff --git a/aegisub/src/audio_karaoke.cpp b/aegisub/src/audio_karaoke.cpp index f2e9270b3..500d9bb46 100644 --- a/aegisub/src/audio_karaoke.cpp +++ b/aegisub/src/audio_karaoke.cpp @@ -117,7 +117,7 @@ void AudioKaraoke::OnActiveLineChanged(AssDialogue *new_line) { } } -void AudioKaraoke::OnFileChanged(int type, std::set const& changed) { +void AudioKaraoke::OnFileChanged(int type, std::set const& changed) { if (enabled && (type & AssFile::COMMIT_DIAG_FULL) && (changed.empty() || changed.count(active_line))) { LoadFromLine(); split_area->Refresh(false); diff --git a/aegisub/src/audio_karaoke.h b/aegisub/src/audio_karaoke.h index cf4a293a6..e026cb282 100644 --- a/aegisub/src/audio_karaoke.h +++ b/aegisub/src/audio_karaoke.h @@ -31,7 +31,6 @@ #include class AssDialogue; -class AssEntry; class AssKaraoke; class wxButton; @@ -144,7 +143,7 @@ class AudioKaraoke : public wxWindow { void OnActiveLineChanged(AssDialogue *new_line); void OnContextMenu(wxContextMenuEvent&); void OnEnableButton(wxCommandEvent &evt); - void OnFileChanged(int type, std::set const& changed); + void OnFileChanged(int type, std::set const& changed); void OnMouse(wxMouseEvent &event); void OnPaint(wxPaintEvent &event); void OnSize(wxSizeEvent &event); diff --git a/aegisub/src/audio_timing_dialogue.cpp b/aegisub/src/audio_timing_dialogue.cpp index f29ea64d1..748d1ac3b 100644 --- a/aegisub/src/audio_timing_dialogue.cpp +++ b/aegisub/src/audio_timing_dialogue.cpp @@ -715,21 +715,19 @@ void AudioTimingControllerDialogue::SetMarkers(std::vector const& AnnounceMarkerMoved(); } -static bool noncomment_dialogue(AssEntry const& e) +static bool noncomment_dialogue(AssDialogue const& diag) { - if (const AssDialogue *diag = dynamic_cast(&e)) - return !diag->Comment; - return false; + return !diag.Comment; } -static bool dialogue(AssEntry const& e) +static bool dialogue(AssDialogue const&) { - return !!dynamic_cast(&e); + return true; } void AudioTimingControllerDialogue::RegenerateInactiveLines() { - bool (*predicate)(AssEntry const&) = inactive_line_comments->GetBool() ? dialogue : noncomment_dialogue; + auto predicate = inactive_line_comments->GetBool() ? dialogue : noncomment_dialogue; bool was_empty = inactive_lines.empty(); inactive_lines.clear(); @@ -742,21 +740,20 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines() case 2: // Previous and next lines if (AssDialogue *line = context->selectionController->GetActiveLine()) { - entryIter current_line = context->ass->Events.iterator_to(*line); + auto current_line = context->ass->Events.iterator_to(*line); if (current_line == context->ass->Events.end()) break; - entryIter prev = current_line; + auto prev = current_line; while (--prev != context->ass->Events.begin() && !predicate(*prev)) ; if (prev != context->ass->Events.begin()) - AddInactiveLine(sel, static_cast(&*prev)); + AddInactiveLine(sel, &*prev); if (mode == 2) { - entryIter next = - find_if(++current_line, context->ass->Events.end(), predicate); + auto next = find_if(++current_line, context->ass->Events.end(), predicate); if (next != context->ass->Events.end()) - AddInactiveLine(sel, static_cast(&*next)); + AddInactiveLine(sel, &*next); } } break; @@ -766,7 +763,7 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines() for (auto& line : context->ass->Events) { if (&line != active_line && predicate(line)) - AddInactiveLine(sel, static_cast(&line)); + AddInactiveLine(sel, &line); } break; } diff --git a/aegisub/src/auto4_lua.cpp b/aegisub/src/auto4_lua.cpp index 6ba8f4123..51b3a6c0a 100644 --- a/aegisub/src/auto4_lua.cpp +++ b/aegisub/src/auto4_lua.cpp @@ -277,7 +277,7 @@ namespace { lua_pushvalue(L, 1); std::unique_ptr et(Automation4::LuaAssFile::LuaToAssEntry(L)); - AssStyle *st = dynamic_cast(et.get()); + auto st = dynamic_cast(et.get()); lua_pop(L, 1); if (!st) return luaL_error(L, "Not a style entry"); @@ -843,9 +843,8 @@ namespace Automation4 { int idx = 1; for (auto& line : c->ass->Events) { ++row; - auto diag = static_cast(&line); - if (diag == active_line) active_idx = row; - if (sel.count(diag)) { + if (&line == active_line) active_idx = row; + if (sel.count(&line)) { push_value(L, row); lua_rawseti(L, -2, idx++); } @@ -928,7 +927,7 @@ namespace Automation4 { throw LuaForEachBreak(); } - AssDialogue *diag = dynamic_cast(lines[cur - 1]); + auto diag = dynamic_cast(lines[cur - 1]); if (!diag) { wxLogError("Selected row %d is not a dialogue line", cur); throw LuaForEachBreak(); diff --git a/aegisub/src/auto4_lua_assfile.cpp b/aegisub/src/auto4_lua_assfile.cpp index 87350f3e3..ecb77e661 100644 --- a/aegisub/src/auto4_lua_assfile.cpp +++ b/aegisub/src/auto4_lua_assfile.cpp @@ -37,6 +37,7 @@ #include "auto4_lua.h" #include "auto4_lua_utils.h" +#include "ass_attachment.h" #include "ass_dialogue.h" #include "ass_info.h" #include "ass_file.h" @@ -535,7 +536,7 @@ namespace Automation4 { int LuaAssFile::LuaParseKaraokeData(lua_State *L) { auto e = LuaToAssEntry(L); - AssDialogue *dia = dynamic_cast(e.get()); + auto dia = dynamic_cast(e.get()); luaL_argcheck(L, dia, 1, "Subtitle line must be a dialogue line"); int idx = 0; diff --git a/aegisub/src/base_grid.cpp b/aegisub/src/base_grid.cpp index 0e00ff47a..9ac3f3edf 100644 --- a/aegisub/src/base_grid.cpp +++ b/aegisub/src/base_grid.cpp @@ -52,8 +52,6 @@ #include "video_context.h" #include "video_slider.h" -#include - #include #include #include @@ -82,13 +80,6 @@ enum RowColor { COLOR_LEFT_COL }; -template -static inline void set_difference(const S1 &src1, const S2 &src2, D &dst) { - std::set_difference( - src1.begin(), src1.end(), src2.begin(), src2.end(), - std::inserter(dst, dst.begin())); -} - namespace std { template struct hash> { @@ -265,9 +256,9 @@ void BaseGrid::UpdateMaps() { index_line_map.clear(); line_index_map.clear(); - for (auto curdiag : context->ass->Events | agi::of_type()) { - line_index_map[curdiag] = (int)index_line_map.size(); - index_line_map.push_back(curdiag); + for (auto& curdiag : context->ass->Events) { + line_index_map[&curdiag] = (int)index_line_map.size(); + index_line_map.push_back(&curdiag); } auto sorted = index_line_map; @@ -751,6 +742,7 @@ void BaseGrid::SetColumnWidths() { std::unordered_map, int> widths; auto get_width = [&](boost::flyweight const& str) -> int { + if (str.get().empty()) return 0; auto it = widths.find(str); if (it != end(widths)) return it->second; int width = dc.GetTextExtent(to_wx(str)).GetWidth(); @@ -766,24 +758,22 @@ void BaseGrid::SetColumnWidths() { int maxLayer = 0; int maxStart = 0; int maxEnd = 0; - for (int i = 0; i < GetRows(); i++) { - AssDialogue *curDiag = GetDialogue(i); - - maxLayer = std::max(maxLayer, curDiag->Layer); - actorLen = std::max(actorLen, get_width(curDiag->Actor)); - styleLen = std::max(styleLen, get_width(curDiag->Style)); - effectLen = std::max(effectLen, get_width(curDiag->Effect)); + for (auto const& diag : context->ass->Events) { + maxLayer = std::max(maxLayer, diag.Layer); + actorLen = std::max(actorLen, get_width(diag.Actor)); + styleLen = std::max(styleLen, get_width(diag.Style)); + effectLen = std::max(effectLen, get_width(diag.Effect)); // Margins for (int j = 0; j < 3; j++) { - if (curDiag->Margin[j]) + if (diag.Margin[j]) showMargin[j] = true; } // Times if (byFrame) { - maxStart = std::max(maxStart, context->videoController->FrameAtTime(curDiag->Start, agi::vfr::START)); - maxEnd = std::max(maxEnd, context->videoController->FrameAtTime(curDiag->End, agi::vfr::END)); + maxStart = std::max(maxStart, context->videoController->FrameAtTime(diag.Start, agi::vfr::START)); + maxEnd = std::max(maxEnd, context->videoController->FrameAtTime(diag.End, agi::vfr::END)); } } @@ -991,15 +981,19 @@ void BaseGrid::SetSelectionAndActive(Selection const& new_selection, AssDialogue } void BaseGrid::PrevLine() { - int cur_line_i = GetDialogueIndex(GetActiveLine()); - if (AssDialogue *prev_line = GetDialogue(cur_line_i-1)) - SetSelectionAndActive({ prev_line }, prev_line); + if (!active_line) return; + auto it = context->ass->Events.iterator_to(*active_line); + if (it != context->ass->Events.begin()) { + --it; + SetSelectionAndActive({&*it}, &*it); + } } void BaseGrid::NextLine() { - int cur_line_i = GetDialogueIndex(GetActiveLine()); - if (AssDialogue *next_line = GetDialogue(cur_line_i+1)) - SetSelectionAndActive({ next_line }, next_line); + if (!active_line) return; + auto it = context->ass->Events.iterator_to(*active_line); + if (++it != context->ass->Events.end()) + SetSelectionAndActive({&*it}, &*it); } void BaseGrid::AnnounceActiveLineChanged(AssDialogue *new_line) { diff --git a/aegisub/src/command/edit.cpp b/aegisub/src/command/edit.cpp index a85e4e96c..ffb6663f5 100644 --- a/aegisub/src/command/edit.cpp +++ b/aegisub/src/command/edit.cpp @@ -53,6 +53,7 @@ #include "../utils.h" #include "../video_context.h" +#include #include #include @@ -485,12 +486,11 @@ 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) { SubtitleSelection sel = c->selectionController->GetSelectedSet(); SetClipboard(join(c->ass->Events - | agi::of_type() - | filtered([&](AssDialogue *d) { return sel.count(d); }) + | filtered([&](AssDialogue &d) { return sel.count(&d); }) | transformed(get_entry_data), "\r\n")); } @@ -503,25 +503,25 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) { AssDialogue *post_sel = nullptr; bool hit_selection = false; - for (auto diag : c->ass->Events | agi::of_type()) { - if (sel.count(diag)) + for (auto& diag : c->ass->Events) { + if (sel.count(&diag)) hit_selection = true; else if (hit_selection && !post_sel) { - post_sel = diag; + post_sel = &diag; break; } else - pre_sel = diag; + pre_sel = &diag; } // Remove the selected lines, but defer the deletion until after we select // different lines. We can't just change the selection first because we may // need to create a new dialogue line for it, and we can't select dialogue // lines until after they're committed. - std::vector> to_delete; - c->ass->Events.remove_and_dispose_if([&sel](AssEntry const& e) { - return sel.count(const_cast(static_cast(&e))); - }, [&](AssEntry *e) { + std::vector> to_delete; + c->ass->Events.remove_and_dispose_if([&sel](AssDialogue const& e) { + return sel.count(const_cast(&e)); + }, [&](AssDialogue *e) { to_delete.emplace_back(e); }); @@ -591,35 +591,28 @@ struct edit_line_delete : public validate_sel_nonempty { } }; -struct in_selection : public std::unary_function { - SubtitleSelectionController::Selection const& sel; - in_selection(SubtitleSelectionController::Selection const& sel) : sel(sel) { } - bool operator()(AssEntry const& e) const { - const AssDialogue *d = dynamic_cast(&e); - return d && sel.count(const_cast(d)); - } -}; - static void duplicate_lines(agi::Context *c, int shift) { - in_selection sel(c->selectionController->GetSelectedSet()); + auto const& sel = c->selectionController->GetSelectedSet(); + auto in_selection = [&](AssDialogue const& d) { return sel.count(const_cast(&d)); }; + SubtitleSelectionController::Selection new_sel; AssDialogue *new_active = nullptr; - entryIter start = c->ass->Events.begin(); - entryIter end = c->ass->Events.end(); + auto start = c->ass->Events.begin(); + auto end = c->ass->Events.end(); while (start != end) { // Find the first line in the selection - start = find_if(start, end, sel); + start = find_if(start, end, in_selection); if (start == end) break; // And the last line in this contiguous selection - entryIter insert_pos = find_if_not(start, end, sel); - entryIter last = std::prev(insert_pos); + auto insert_pos = find_if_not(start, end, in_selection); + auto last = std::prev(insert_pos); // Duplicate each of the selected lines, inserting them in a block // after the selected block do { - auto old_diag = static_cast(&*start); + auto old_diag = &*start; auto new_diag = new AssDialogue(*old_diag); c->ass->Events.insert(insert_pos, *new_diag); @@ -703,10 +696,9 @@ static void combine_lines(agi::Context *c, void (*combiner)(AssDialogue *, AssDi SubtitleSelection sel = c->selectionController->GetSelectedSet(); AssDialogue *first = nullptr; - for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ) { - AssDialogue *diag = dynamic_cast(&*it++); - if (!diag || !sel.count(diag)) - continue; + for (auto it = c->ass->Events.begin(); it != c->ass->Events.end(); ) { + AssDialogue *diag = &*it++; + if (!sel.count(diag)) continue; if (!first) { first = diag; continue; @@ -772,7 +764,7 @@ static bool try_paste_lines(agi::Context *c) { boost::trim_left(data); if (!boost::starts_with(data, "Dialogue:")) return false; - EntryList parsed; + EntryList parsed; boost::char_separator sep("\r\n"); for (auto curdata : boost::tokenizer>(data, sep)) { boost::trim(curdata); @@ -780,15 +772,15 @@ static bool try_paste_lines(agi::Context *c) { parsed.push_back(*new AssDialogue(curdata)); } catch (...) { - parsed.clear_and_dispose([](AssEntry *e) { delete e; }); + parsed.clear_and_dispose([](AssDialogue *e) { delete e; }); return false; } } - AssDialogue *new_active = static_cast(&*parsed.begin()); + AssDialogue *new_active = &*parsed.begin(); SubtitleSelection new_selection; for (auto& line : parsed) - new_selection.insert(static_cast(&line)); + new_selection.insert(&line); auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine()); c->ass->Events.splice(pos, parsed, parsed.begin(), parsed.end()); @@ -858,9 +850,9 @@ struct edit_line_paste_over : public Command { std::unique_ptr deleter(new_line); if (pos == c->ass->Events.end()) return nullptr; - AssDialogue *ret = paste_over(c->parent, pasteOverOptions, new_line, static_cast(&*pos)); + AssDialogue *ret = paste_over(c->parent, pasteOverOptions, new_line, &*pos); if (ret) - pos = find_if(next(pos), c->ass->Events.end(), cast()); + ++pos; return ret; }); } @@ -871,8 +863,8 @@ struct edit_line_paste_over : public Command { std::vector sorted_selection; sorted_selection.reserve(sel.size()); for (auto& line : c->ass->Events) { - if (sel.count(static_cast(&line))) - sorted_selection.push_back(static_cast(&line)); + if (sel.count(&line)) + sorted_selection.push_back(&line); } auto pos = begin(sorted_selection); @@ -936,7 +928,10 @@ struct edit_line_recombine : public validate_sel_multiple { auto active_line = c->selectionController->GetActiveLine(); std::vector sel(sel_set.begin(), sel_set.end()); - boost::sort(sel, &AssFile::CompStart); + boost::sort(sel, [](const AssDialogue *a, const AssDialogue *b) { + return a->Start < b->Start; + }); + for (auto &diag : sel) diag->Text = trim_text(diag->Text); @@ -983,7 +978,7 @@ struct edit_line_recombine : public validate_sel_multiple { // Remove now non-existent lines from the selection SubtitleSelection lines, new_sel; - boost::copy(c->ass->Events | agi::of_type(), inserter(lines, lines.begin())); + boost::copy(c->ass->Events | agi::address_of, inserter(lines, lines.begin())); boost::set_intersection(lines, sel_set, inserter(new_sel, new_sel.begin())); if (new_sel.empty()) diff --git a/aegisub/src/command/grid.cpp b/aegisub/src/command/grid.cpp index b51043c63..e63a70d22 100644 --- a/aegisub/src/command/grid.cpp +++ b/aegisub/src/command/grid.cpp @@ -79,7 +79,7 @@ struct grid_line_next_create : public Command { newline->End = cur->End + OPT_GET("Timing/Default Duration")->GetInt(); newline->Style = cur->Style; - entryIter pos = c->ass->Events.iterator_to(*cur); + auto pos = c->ass->Events.iterator_to(*cur); c->ass->Events.insert(++pos, *newline); c->ass->Commit(_("line insertion"), AssFile::COMMIT_DIAG_ADDREM); c->selectionController->NextLine(); @@ -328,9 +328,7 @@ static bool move_one(T begin, T end, U const& to_move, int step) { size_t move_count = 0; auto prev = end; for (auto it = begin; it != end; std::advance(it, step)) { - auto cur = dynamic_cast(&*it); - if (!cur) continue; - + auto cur = &*it; if (!to_move.count(cur)) prev = it; else if (prev != end) { diff --git a/aegisub/src/command/subtitle.cpp b/aegisub/src/command/subtitle.cpp index 89ee24ef6..80bfe9544 100644 --- a/aegisub/src/command/subtitle.cpp +++ b/aegisub/src/command/subtitle.cpp @@ -53,10 +53,11 @@ #include "../utils.h" #include "../video_context.h" +#include #include -#include #include +#include #include #include @@ -124,7 +125,7 @@ static void insert_subtitle_at_video(agi::Context *c, bool after) { def->End = video_ms + OPT_GET("Timing/Default Duration")->GetInt(); def->Style = c->selectionController->GetActiveLine()->Style; - entryIter pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine()); + auto pos = c->ass->Events.iterator_to(*c->selectionController->GetActiveLine()); if (after) ++pos; c->ass->Events.insert(pos, *def); @@ -147,8 +148,8 @@ struct subtitle_insert_after : public validate_nonempty_selection { new_line->Start = active_line->End; new_line->End = new_line->Start + OPT_GET("Timing/Default Duration")->GetInt(); - for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) { - AssDialogue *diag = static_cast(&*it); + for (auto it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) { + AssDialogue *diag = &*it; // Limit the line to the available time if (diag->Start >= new_line->Start) @@ -192,8 +193,8 @@ struct subtitle_insert_before : public validate_nonempty_selection { new_line->End = active_line->Start; new_line->Start = new_line->End - OPT_GET("Timing/Default Duration")->GetInt(); - for (entryIter it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) { - auto diag = static_cast(&*it); + for (auto it = c->ass->Events.begin(); it != c->ass->Events.end(); ++it) { + auto diag = &*it; // Limit the line to the available time if (diag->End <= new_line->End) @@ -372,9 +373,7 @@ struct subtitle_select_all : public Command { void operator()(agi::Context *c) override { SubtitleSelection sel; - transform(c->ass->Events.begin(), c->ass->Events.end(), - inserter(sel, sel.begin()), cast()); - sel.erase(nullptr); + boost::copy(c->ass->Events | agi::address_of, inserter(sel, sel.end())); c->selectionController->SetSelectedSet(sel); } }; @@ -394,13 +393,13 @@ struct subtitle_select_visible : public Command { SubtitleSelectionController::Selection new_selection; int frame = c->videoController->GetFrameN(); - for (auto diag : c->ass->Events | agi::of_type()) { - if (c->videoController->FrameAtTime(diag->Start, agi::vfr::START) <= frame && - c->videoController->FrameAtTime(diag->End, agi::vfr::END) >= frame) + for (auto& diag : c->ass->Events) { + if (c->videoController->FrameAtTime(diag.Start, agi::vfr::START) <= frame && + c->videoController->FrameAtTime(diag.End, agi::vfr::END) >= frame) { if (new_selection.empty()) - c->selectionController->SetActiveLine(diag); - new_selection.insert(diag); + c->selectionController->SetActiveLine(&diag); + new_selection.insert(&diag); } } diff --git a/aegisub/src/command/time.cpp b/aegisub/src/command/time.cpp index 5bceb7155..eeb73017e 100644 --- a/aegisub/src/command/time.cpp +++ b/aegisub/src/command/time.cpp @@ -45,7 +45,6 @@ #include "../selection_controller.h" #include "../video_context.h" -#include #include #include @@ -67,8 +66,8 @@ namespace { if (sel.size() < 2) return !sel.empty(); size_t found = 0; - for (auto diag : c->ass->Events | agi::of_type()) { - if (sel.count(diag)) { + for (auto& diag : c->ass->Events) { + if (sel.count(&diag)) { if (++found == sel.size()) return true; } @@ -84,14 +83,14 @@ static void adjoin_lines(agi::Context *c, bool set_start) { AssDialogue *prev = nullptr; size_t seen = 0; bool prev_sel = false; - for (auto diag : c->ass->Events | agi::of_type()) { - bool cur_sel = !!sel.count(diag); + for (auto diag : c->ass->Events) { + bool cur_sel = !!sel.count(&diag); if (prev) { // One row selections act as if the previous or next line was selected if (set_start && cur_sel && (sel.size() == 1 || prev_sel)) - diag->Start = prev->End; + diag.Start = prev->End; else if (!set_start && prev_sel && (cur_sel || sel.size() == 1)) - prev->End = diag->Start; + prev->End = diag.Start; } if (seen == sel.size()) @@ -100,7 +99,7 @@ static void adjoin_lines(agi::Context *c, bool set_start) { if (cur_sel) ++seen; - prev = diag; + prev = &diag; prev_sel = cur_sel; } diff --git a/aegisub/src/dialog_attachments.cpp b/aegisub/src/dialog_attachments.cpp index dc4de6e18..50434ed72 100644 --- a/aegisub/src/dialog_attachments.cpp +++ b/aegisub/src/dialog_attachments.cpp @@ -50,8 +50,6 @@ #include "options.h" #include "utils.h" -#include - DialogAttachments::DialogAttachments(wxWindow *parent, AssFile *ass) : wxDialog(parent, -1, _("Attachment List"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) , ass(ass) @@ -99,12 +97,12 @@ void DialogAttachments::UpdateList() { listView->InsertColumn(1, _("Size"), wxLIST_FORMAT_LEFT, 100); listView->InsertColumn(2, _("Group"), wxLIST_FORMAT_LEFT, 100); - for (auto attach : ass->Attachments | agi::of_type()) { + for (auto& attach : ass->Attachments) { int row = listView->GetItemCount(); - listView->InsertItem(row, to_wx(attach->GetFileName(true))); - listView->SetItem(row, 1, PrettySize(attach->GetSize())); - listView->SetItem(row, 2, to_wx(attach->GroupHeader())); - listView->SetItemPtrData(row, wxPtrToUInt(attach)); + listView->InsertItem(row, to_wx(attach.GetFileName(true))); + listView->SetItem(row, 1, PrettySize(attach.GetSize())); + listView->SetItem(row, 2, to_wx(attach.GroupHeader())); + listView->SetItemPtrData(row, wxPtrToUInt(&attach)); } } diff --git a/aegisub/src/dialog_kara_timing_copy.cpp b/aegisub/src/dialog_kara_timing_copy.cpp index 135cca6ee..030bff8e3 100644 --- a/aegisub/src/dialog_kara_timing_copy.cpp +++ b/aegisub/src/dialog_kara_timing_copy.cpp @@ -601,8 +601,8 @@ void DialogKanjiTimer::OnAccept(wxCommandEvent &) { if (display->GetRemainingSource() > 0) wxMessageBox(_("Group all of the source text."),_("Error"),wxICON_EXCLAMATION | wxOK); - else if (AssDialogue *destLine = dynamic_cast(currentDestinationLine)) { - LinesToChange.push_back(std::make_pair(destLine, display->GetOutputLine())); + else { + LinesToChange.push_back(std::make_pair(currentDestinationLine, display->GetOutputLine())); currentSourceLine = FindNextStyleMatch(currentSourceLine, from_wx(SourceStyle->GetValue())); currentDestinationLine = FindNextStyleMatch(currentDestinationLine, from_wx(DestStyle->GetValue())); @@ -644,21 +644,13 @@ void DialogKanjiTimer::OnKeyDown(wxKeyEvent &event) { void DialogKanjiTimer::ResetForNewLine() { - AssDialogue *src = nullptr; - AssDialogue *dst = nullptr; - - if (currentSourceLine) - src = dynamic_cast(currentSourceLine); - if (currentDestinationLine) - dst = dynamic_cast(currentDestinationLine); - - if (!src || !dst) + if (!currentSourceLine || !currentDestinationLine) { - src = dst = nullptr; + currentSourceLine = currentDestinationLine = nullptr; wxBell(); } - display->SetInputData(src, dst); + display->SetInputData(currentSourceLine, currentDestinationLine); TryAutoMatch(); @@ -672,25 +664,24 @@ void DialogKanjiTimer::TryAutoMatch() } template -static AssEntry *find_next(Iterator from, Iterator to, std::string const& style_name) { +static AssDialogue *find_next(Iterator from, Iterator to, std::string const& style_name) { for (; from != to; ++from) { - AssDialogue *dlg = dynamic_cast(&*from); - if (dlg && dlg->Style == style_name && !dlg->Text.get().empty()) - return dlg; + if (from->Style == style_name && !from->Text.get().empty()) + return &*from; } return nullptr; } -AssEntry *DialogKanjiTimer::FindNextStyleMatch(AssEntry *search_from, const std::string &search_style) +AssDialogue *DialogKanjiTimer::FindNextStyleMatch(AssDialogue *search_from, const std::string &search_style) { if (!search_from) return search_from; 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) +AssDialogue *DialogKanjiTimer::FindPrevStyleMatch(AssDialogue *search_from, const std::string &search_style) { if (!search_from) return search_from; - return find_next(EntryList::reverse_iterator(subs->Events.iterator_to(*search_from)), subs->Events.rend(), search_style); + return find_next(EntryList::reverse_iterator(subs->Events.iterator_to(*search_from)), subs->Events.rend(), search_style); } diff --git a/aegisub/src/dialog_kara_timing_copy.h b/aegisub/src/dialog_kara_timing_copy.h index c74f0ba1a..ab61b3ba8 100644 --- a/aegisub/src/dialog_kara_timing_copy.h +++ b/aegisub/src/dialog_kara_timing_copy.h @@ -39,7 +39,6 @@ namespace agi { struct Context; } class AssDialogue; -class AssEntry; class AssFile; class KaraokeLineMatchDisplay; class wxComboBox; @@ -55,8 +54,8 @@ class DialogKanjiTimer : public wxDialog { std::vector> LinesToChange; - AssEntry *currentSourceLine = nullptr; - AssEntry *currentDestinationLine = nullptr; + AssDialogue *currentSourceLine = nullptr; + AssDialogue *currentDestinationLine = nullptr; void OnClose(wxCommandEvent &event); void OnStart(wxCommandEvent &event); @@ -71,8 +70,8 @@ class DialogKanjiTimer : public wxDialog { void ResetForNewLine(); void TryAutoMatch(); - AssEntry *FindNextStyleMatch(AssEntry *search_from, const std::string &search_style); - AssEntry *FindPrevStyleMatch(AssEntry *search_from, const std::string &search_style); + AssDialogue *FindNextStyleMatch(AssDialogue *search_from, const std::string &search_style); + AssDialogue *FindPrevStyleMatch(AssDialogue *search_from, const std::string &search_style); public: DialogKanjiTimer(agi::Context *context); diff --git a/aegisub/src/dialog_selection.cpp b/aegisub/src/dialog_selection.cpp index fdc29027e..d09384c06 100644 --- a/aegisub/src/dialog_selection.cpp +++ b/aegisub/src/dialog_selection.cpp @@ -34,8 +34,6 @@ #include "selection_controller.h" #include "utils.h" -#include - #include #include #include @@ -77,12 +75,12 @@ static std::set process(std::string const& match_text, bool match_ auto predicate = SearchReplaceEngine::GetMatcher(settings); std::set matches; - for (auto diag : ass->Events | agi::of_type()) { - if (diag->Comment && !comments) continue; - if (!diag->Comment && !dialogue) continue; + for (auto& diag : ass->Events) { + if (diag.Comment && !comments) continue; + if (!diag.Comment && !dialogue) continue; - if (invert != predicate(diag, 0)) - matches.insert(diag); + if (invert != predicate(&diag, 0)) + matches.insert(&diag); } return matches; diff --git a/aegisub/src/dialog_shift_times.cpp b/aegisub/src/dialog_shift_times.cpp index 42f3cea2b..772ee15ec 100644 --- a/aegisub/src/dialog_shift_times.cpp +++ b/aegisub/src/dialog_shift_times.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -354,10 +353,10 @@ void DialogShiftTimes::Process(wxCommandEvent &) { int block_start = 0; json::Array shifted_blocks; - for (auto line : context->ass->Events | agi::of_type()) { + for (auto& line : context->ass->Events) { ++row_number; - if (!sel.count(line)) { + if (!sel.count(&line)) { if (block_start) { json::Object block; block["start"] = block_start; @@ -372,9 +371,9 @@ void DialogShiftTimes::Process(wxCommandEvent &) { block_start = row_number; if (start) - line->Start = Shift(line->Start, shift, by_time, agi::vfr::START); + line.Start = Shift(line.Start, shift, by_time, agi::vfr::START); if (end) - line->End = Shift(line->End, shift, by_time, agi::vfr::END); + line.End = Shift(line.End, shift, by_time, agi::vfr::END); } context->ass->Commit(_("shifting"), AssFile::COMMIT_DIAG_TIME); diff --git a/aegisub/src/dialog_spellchecker.cpp b/aegisub/src/dialog_spellchecker.cpp index 541e5d2f9..10d4ee464 100644 --- a/aegisub/src/dialog_spellchecker.cpp +++ b/aegisub/src/dialog_spellchecker.cpp @@ -212,19 +212,17 @@ bool DialogSpellChecker::FindNext() { if (CheckLine(active_line, start_pos, &commit_id)) return true; - entryIter it = context->ass->Events.iterator_to(*active_line); + auto it = context->ass->Events.iterator_to(*active_line); // 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 // word should be hit last while(!has_looped || active_line != start_line) { - do { - // Wrap around to the beginning if we hit the end - if (++it == context->ass->Events.end()) { - it = context->ass->Events.begin(); - has_looped = true; - } - } while (!(active_line = dynamic_cast(&*it))); + // Wrap around to the beginning if we hit the end + if (++it == context->ass->Events.end()) { + it = context->ass->Events.begin(); + has_looped = true; + } if (CheckLine(active_line, 0, &commit_id)) return true; diff --git a/aegisub/src/dialog_style_editor.cpp b/aegisub/src/dialog_style_editor.cpp index bc5bdfefd..bf730b373 100644 --- a/aegisub/src/dialog_style_editor.cpp +++ b/aegisub/src/dialog_style_editor.cpp @@ -86,19 +86,19 @@ class StyleRenamer { found_any = false; do_replace = replace; - for (auto diag : c->ass->Events | agi::of_type()) { - if (diag->Style == source_name) { + for (auto& diag : c->ass->Events) { + if (diag.Style == source_name) { if (replace) - diag->Style = new_name; + diag.Style = new_name; else found_any = true; } - boost::ptr_vector blocks(diag->ParseTags()); + boost::ptr_vector blocks(diag.ParseTags()); for (auto block : blocks | agi::of_type()) block->ProcessParameters(&StyleRenamer::ProcessTag, this); if (replace) - diag->UpdateText(blocks); + diag.UpdateText(blocks); if (found_any) return; } diff --git a/aegisub/src/dialog_style_manager.cpp b/aegisub/src/dialog_style_manager.cpp index 8737a6a1b..1783a72f2 100644 --- a/aegisub/src/dialog_style_manager.cpp +++ b/aegisub/src/dialog_style_manager.cpp @@ -54,7 +54,6 @@ #include #include -#include #include #include @@ -288,9 +287,9 @@ void DialogStyleManager::LoadCurrentStyles(int commit_type) { CurrentList->Clear(); styleMap.clear(); - for (auto style : c->ass->Styles | agi::of_type()) { - CurrentList->Append(to_wx(style->name)); - styleMap.push_back(style); + for (auto& style : c->ass->Styles) { + CurrentList->Append(to_wx(style.name)); + styleMap.push_back(&style); } } @@ -780,10 +779,8 @@ void DialogStyleManager::MoveStyles(bool storage, int type) { // Replace styles size_t curn = 0; for (auto it = c->ass->Styles.begin(); it != c->ass->Styles.end(); ++it) { - if (!dynamic_cast(&*it)) continue; - 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; it = new_style_at_pos; } diff --git a/aegisub/src/dialog_timing_processor.cpp b/aegisub/src/dialog_timing_processor.cpp index 2c83d9046..be888e136 100644 --- a/aegisub/src/dialog_timing_processor.cpp +++ b/aegisub/src/dialog_timing_processor.cpp @@ -48,8 +48,12 @@ #include "utils.h" #include "video_context.h" +#include + #include +#include #include +#include #include #include @@ -63,6 +67,8 @@ #include #include +using namespace boost::adaptors; + namespace { using std::placeholders::_1; @@ -288,10 +294,6 @@ void DialogTimingProcessor::OnApply(wxCommandEvent &) { EndModal(0); } -static bool bad_line(std::set *styles, AssDialogue *d) { - return !d || d->Comment || styles->find(d->Style) == styles->end(); -} - std::vector DialogTimingProcessor::SortDialogues() { std::set styles; for (size_t i = 0; i < StyleList->GetCount(); ++i) { @@ -301,14 +303,13 @@ std::vector DialogTimingProcessor::SortDialogues() { std::vector sorted; - if (onlySelection->IsChecked()) { - SubtitleSelection sel = c->selectionController->GetSelectedSet(); - copy_if(sel.begin(), sel.end(), back_inserter(sorted), - [&](AssDialogue *d) { return !d->Comment && styles.count(d->Style); }); - } + auto valid_line = [&](const AssDialogue *d) { return !d->Comment && styles.count(d->Style); }; + if (onlySelection->IsChecked()) + boost::copy(c->selectionController->GetSelectedSet() | filtered(valid_line), + back_inserter(sorted)); else { - transform(c->ass->Events.begin(), c->ass->Events.end(), back_inserter(sorted), cast()); - sorted.erase(boost::remove_if(sorted, bind(bad_line, &styles, _1)), sorted.end()); + sorted.reserve(c->ass->Events.size()); + boost::push_back(sorted, c->ass->Events | agi::address_of | filtered(valid_line)); } // Check if rows are valid @@ -324,7 +325,9 @@ std::vector DialogTimingProcessor::SortDialogues() { } } - boost::sort(sorted, AssFile::CompStart); + boost::sort(sorted, [](const AssDialogue *a, const AssDialogue *b) { + return a->Start < b->Start; + }); return sorted; } diff --git a/aegisub/src/export_fixstyle.cpp b/aegisub/src/export_fixstyle.cpp index 04a71c672..54de56bdd 100644 --- a/aegisub/src/export_fixstyle.cpp +++ b/aegisub/src/export_fixstyle.cpp @@ -40,11 +40,8 @@ #include "ass_dialogue.h" #include "compat.h" -#include - #include #include -#include #include AssFixStylesFilter::AssFixStylesFilter() @@ -53,12 +50,12 @@ AssFixStylesFilter::AssFixStylesFilter() } void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *) { - std::vector styles = subs->GetStyles(); - for_each(begin(styles), end(styles), [](std::string& str) { boost::to_lower(str); }); + auto styles = subs->GetStyles(); + for (auto& str : styles) boost::to_lower(str); sort(begin(styles), end(styles)); - for (auto diag : subs->Events | agi::of_type()) { - if (!binary_search(begin(styles), end(styles), boost::to_lower_copy(diag->Style.get()))) - diag->Style = "Default"; + for (auto& diag : subs->Events) { + if (!binary_search(begin(styles), end(styles), boost::to_lower_copy(diag.Style.get()))) + diag.Style = "Default"; } } diff --git a/aegisub/src/export_framerate.cpp b/aegisub/src/export_framerate.cpp index a827479fd..b7d4f1edd 100644 --- a/aegisub/src/export_framerate.cpp +++ b/aegisub/src/export_framerate.cpp @@ -201,20 +201,20 @@ void AssTransformFramerateFilter::TransformTimeTags(std::string const& name, Ass void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) { if (!Input->IsLoaded() || !Output->IsLoaded()) return; - for (auto curDialogue : subs->Events | agi::of_type()) { - line = curDialogue; + for (auto& curDialogue : subs->Events) { + line = &curDialogue; newK = 0; oldK = 0; - newStart = trunc_cs(ConvertTime(curDialogue->Start)); - newEnd = trunc_cs(ConvertTime(curDialogue->End) + 9); + newStart = trunc_cs(ConvertTime(curDialogue.Start)); + newEnd = trunc_cs(ConvertTime(curDialogue.End) + 9); // Process stuff boost::ptr_vector blocks; for (auto block : blocks | agi::of_type()) block->ProcessParameters(TransformTimeTags, this); - curDialogue->Start = newStart; - curDialogue->End = newEnd; - curDialogue->UpdateText(blocks); + curDialogue.Start = newStart; + curDialogue.End = newEnd; + curDialogue.UpdateText(blocks); } } diff --git a/aegisub/src/font_file_lister.cpp b/aegisub/src/font_file_lister.cpp index f6d57d932..5bbfbb1e0 100644 --- a/aegisub/src/font_file_lister.cpp +++ b/aegisub/src/font_file_lister.cpp @@ -29,8 +29,6 @@ #include "compat.h" #include "utils.h" -#include - #include #include #include @@ -182,17 +180,17 @@ std::vector FontCollector::GetFontPaths(const AssFile *file) { status_callback(_("Parsing file\n"), 0); - for (auto style : file->Styles | agi::of_type()) { - StyleInfo &info = styles[style->name]; - info.facename = style->font; - info.bold = style->bold; - info.italic = style->italic; - used_styles[info].styles.insert(style->name); + for (auto const& style : file->Styles) { + StyleInfo &info = styles[style.name]; + info.facename = style.font; + info.bold = style.bold; + info.italic = style.italic; + used_styles[info].styles.insert(style.name); } int index = 0; - for (auto diag : file->Events | agi::of_type()) - ProcessDialogueLine(diag, ++index); + for (auto const& diag : file->Events) + ProcessDialogueLine(&diag, ++index); status_callback(_("Searching for font files\n"), 0); for_each(used_styles.begin(), used_styles.end(), bind(&FontCollector::ProcessChunk, this, _1)); diff --git a/aegisub/src/resolution_resampler.cpp b/aegisub/src/resolution_resampler.cpp index 069e0f7be..c1179fe11 100644 --- a/aegisub/src/resolution_resampler.cpp +++ b/aegisub/src/resolution_resampler.cpp @@ -125,32 +125,33 @@ namespace { cur->Set((cur->Get() + shift) * resizer + 0.5); } - void resample_line(resample_state *state, AssEntry &line) { - AssDialogue *diag = dynamic_cast(&line); - if (diag && !(diag->Comment && (boost::starts_with(diag->Effect.get(), "template") || boost::starts_with(diag->Effect.get(), "code")))) { - boost::ptr_vector blocks(diag->ParseTags()); + void resample_line(resample_state *state, AssDialogue &diag) { + if (diag.Comment && (boost::starts_with(diag.Effect.get(), "template") || boost::starts_with(diag.Effect.get(), "code"))) + return; - for (auto block : blocks | agi::of_type()) - block->ProcessParameters(resample_tags, state); + boost::ptr_vector blocks(diag.ParseTags()); - for (auto drawing : blocks | agi::of_type()) - drawing->text = transform_drawing(drawing->text, state->margin[LEFT], state->margin[TOP], state->rx, state->ry); + for (auto block : blocks | agi::of_type()) + block->ProcessParameters(resample_tags, state); - for (size_t i = 0; i < 3; ++i) - diag->Margin[i] = int((diag->Margin[i] + state->margin[i]) * (i < 2 ? state->rx : state->ry) + 0.5); + for (auto drawing : blocks | agi::of_type()) + drawing->text = transform_drawing(drawing->text, state->margin[LEFT], state->margin[TOP], state->rx, state->ry); - diag->UpdateText(blocks); - } - else if (AssStyle *style = dynamic_cast(&line)) { - style->fontsize = int(style->fontsize * state->ry + 0.5); - style->outline_w *= state->ry; - style->shadow_w *= state->ry; - style->spacing *= state->rx; - style->scalex *= state->ar; - for (int i = 0; i < 3; i++) - style->Margin[i] = int((style->Margin[i] + state->margin[i]) * (i < 2 ? state->rx : state->ry) + 0.5); - style->UpdateData(); - } + for (size_t i = 0; i < 3; ++i) + diag.Margin[i] = int((diag.Margin[i] + state->margin[i]) * (i < 2 ? state->rx : state->ry) + 0.5); + + diag.UpdateText(blocks); + } + + void resample_style(resample_state *state, AssStyle &style) { + style.fontsize = int(style.fontsize * state->ry + 0.5); + style.outline_w *= state->ry; + style.shadow_w *= state->ry; + style.spacing *= state->rx; + style.scalex *= state->ar; + for (int i = 0; i < 3; i++) + style.Margin[i] = int((style.Margin[i] + state->margin[i]) * (i < 2 ? state->rx : state->ry) + 0.5); + style.UpdateData(); } } @@ -173,7 +174,7 @@ void ResampleResolution(AssFile *ass, ResampleSettings const& settings) { state.ar = state.rx / state.ry; for (auto& line : ass->Styles) - resample_line(&state, line); + resample_style(&state, line); for (auto& line : ass->Events) resample_line(&state, line); diff --git a/aegisub/src/search_replace_engine.cpp b/aegisub/src/search_replace_engine.cpp index b821e08dd..e28598a71 100644 --- a/aegisub/src/search_replace_engine.cpp +++ b/aegisub/src/search_replace_engine.cpp @@ -24,7 +24,6 @@ #include "selection_controller.h" #include "text_selection_controller.h" -#include #include #include @@ -269,17 +268,15 @@ bool SearchReplaceEngine::FindReplace(bool replace) { bool selection_only = sel.size() > 1 && settings.limit_to == SearchReplaceSettings::Limit::SELECTED; do { - AssDialogue *diag = dynamic_cast(&*it); - if (!diag) continue; - if (selection_only && !sel.count(diag)) continue; - if (settings.ignore_comments && diag->Comment) continue; + if (selection_only && !sel.count(&*it)) continue; + if (settings.ignore_comments && it->Comment) continue; - if (MatchState ms = matches(diag, pos)) { + if (MatchState ms = matches(&*it, pos)) { if (selection_only) // We're cycling through the selection, so don't muck with it - context->selectionController->SetActiveLine(diag); + context->selectionController->SetActiveLine(&*it); else - context->selectionController->SetSelectionAndActive({ diag }, diag); + context->selectionController->SetSelectionAndActive({ &*it }, &*it); if (settings.field == SearchReplaceSettings::Field::TEXT) context->textSelectionController->SetSelection(ms.start, ms.end); @@ -307,13 +304,13 @@ bool SearchReplaceEngine::ReplaceAll() { SubtitleSelection const& sel = context->selectionController->GetSelectedSet(); bool selection_only = settings.limit_to == SearchReplaceSettings::Limit::SELECTED; - for (auto diag : context->ass->Events | agi::of_type()) { - if (selection_only && !sel.count(diag)) continue; - if (settings.ignore_comments && diag->Comment) continue; + for (auto& diag : context->ass->Events) { + if (selection_only && !sel.count(&diag)) continue; + if (settings.ignore_comments && diag.Comment) continue; if (settings.use_regex) { - if (MatchState ms = matches(diag, 0)) { - auto& diag_field = diag->*get_dialogue_field(settings.field); + if (MatchState ms = matches(&diag, 0)) { + auto& diag_field = diag.*get_dialogue_field(settings.field); std::string const& text = diag_field.get(); count += distance( boost::u32regex_iterator(begin(text), end(text), *ms.re), @@ -324,9 +321,9 @@ bool SearchReplaceEngine::ReplaceAll() { } size_t pos = 0; - while (MatchState ms = matches(diag, pos)) { + while (MatchState ms = matches(&diag, pos)) { ++count; - Replace(diag, ms); + Replace(&diag, ms); pos = ms.end; } } diff --git a/aegisub/src/subs_controller.cpp b/aegisub/src/subs_controller.cpp index d1835f9b6..a82846362 100644 --- a/aegisub/src/subs_controller.cpp +++ b/aegisub/src/subs_controller.cpp @@ -70,26 +70,22 @@ struct SubsController::UndoInfo { : undo_description(d), commit_id(commit_id) { script_info.reserve(c->ass->Info.size()); - for (auto const& line : c->ass->Info) { - auto info = static_cast(&line); - script_info.emplace_back(info->Key(), info->Value()); - } + for (auto const& info : c->ass->Info) + script_info.emplace_back(info.Key(), info.Value()); styles.reserve(c->ass->Styles.size()); - for (auto const& line : c->ass->Styles) - styles.push_back(static_cast(line)); + styles.assign(c->ass->Styles.begin(), c->ass->Styles.end()); events.reserve(c->ass->Events.size()); - for (auto const& line : c->ass->Events) - events.push_back(static_cast(line)); + events.assign(c->ass->Events.begin(), c->ass->Events.end()); for (auto const& line : c->ass->Attachments) { switch (line.Group()) { case AssEntryGroup::FONT: - fonts.push_back(static_cast(line)); + fonts.push_back(line); break; case AssEntryGroup::GRAPHIC: - graphics.push_back(static_cast(line)); + graphics.push_back(line); break; default: assert(false); @@ -364,10 +360,9 @@ void SubsController::OnCommit(AssFileCommit c) { if (commit_id == *c.commit_id+1 && redo_stack.empty() && saved_commit_id+1 != commit_id && autosaved_commit_id+1 != commit_id) { // If only one line changed just modify it instead of copying the file if (c.single_line && c.single_line->Group() == AssEntryGroup::DIALOGUE) { - auto src_diag = static_cast(c.single_line); for (auto& diag : undo_stack.back().events) { - if (diag.Id == src_diag->Id) { - diag = *src_diag; + if (diag.Id == c.single_line->Id) { + diag = *c.single_line; break; } } diff --git a/aegisub/src/subs_controller.h b/aegisub/src/subs_controller.h index f0c5fbd99..f85571603 100644 --- a/aegisub/src/subs_controller.h +++ b/aegisub/src/subs_controller.h @@ -23,7 +23,6 @@ #include class AssDialogue; -class AssEntry; class AssFile; struct AssFileCommit; template class SelectionController; diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp index e365b7a20..012d55a4c 100644 --- a/aegisub/src/subs_edit_box.cpp +++ b/aegisub/src/subs_edit_box.cpp @@ -56,7 +56,6 @@ #include "video_context.h" #include -#include #include #include @@ -344,7 +343,7 @@ void SubsEditBox::PopulateList(wxComboBox *combo, boost::flyweight std::unordered_set values; for (auto const& line : c->ass->Events) { - auto const& value = static_cast(&line)->*field; + auto const& value = line.*field; if (!value.get().empty()) values.insert(value); } diff --git a/aegisub/src/subtitle_format.cpp b/aegisub/src/subtitle_format.cpp index ec599d648..36355dc69 100644 --- a/aegisub/src/subtitle_format.cpp +++ b/aegisub/src/subtitle_format.cpp @@ -57,7 +57,6 @@ #include "video_context.h" #include -#include #include #include @@ -94,13 +93,12 @@ bool SubtitleFormat::CanSave(const AssFile *subs) const { std::string defstyle = AssStyle().GetEntryData(); for (auto const& line : subs->Styles) { - if (static_cast(&line)->GetEntryData() != defstyle) + if (line.GetEntryData() != defstyle) return false; } for (auto const& line : subs->Events) { - auto diag = static_cast(&line); - if (diag->GetStrippedText() != diag->Text) + if (line.GetStrippedText() != line.Text) return false; } @@ -173,13 +171,13 @@ agi::vfr::Framerate SubtitleFormat::AskForFPS(bool allow_vfr, bool show_smpte) { } void SubtitleFormat::StripTags(AssFile &file) { - for (auto current : file.Events | agi::of_type()) - current->StripTags(); + for (auto& current : file.Events) + current.StripTags(); } void SubtitleFormat::ConvertNewlines(AssFile &file, std::string const& newline, bool mergeLineBreaks) { - for (auto current : file.Events | agi::of_type()) { - std::string repl = current->Text; + for (auto& current : file.Events) { + std::string repl = current.Text; boost::replace_all(repl, "\\h", " "); boost::ireplace_all(repl, "\\n", newline); if (mergeLineBreaks) { @@ -188,39 +186,35 @@ void SubtitleFormat::ConvertNewlines(AssFile &file, std::string const& newline, while ((pos = repl.find(dbl, pos)) != std::string::npos) boost::replace_all(repl, dbl, newline); } - current->Text = repl; + current.Text = repl; } } void SubtitleFormat::StripComments(AssFile &file) { - file.Events.remove_and_dispose_if([](AssEntry const& e) { - const AssDialogue *diag = dynamic_cast(&e); - return diag && (diag->Comment || diag->Text.get().empty()); - }, [](AssEntry *e) { delete e; }); + file.Events.remove_and_dispose_if([](AssDialogue const& diag) { + return diag.Comment || diag.Text.get().empty(); + }, [](AssDialogue *e) { delete e; }); } -static bool dialog_start_lt(AssEntry &pos, AssDialogue *to_insert) { - AssDialogue *diag = dynamic_cast(&pos); - return diag && diag->Start > to_insert->Start; +static bool dialog_start_lt(AssDialogue &pos, AssDialogue *to_insert) { + return pos.Start > to_insert->Start; } /// @brief Split and merge lines so there are no overlapping lines /// /// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge void SubtitleFormat::RecombineOverlaps(AssFile &file) { - entryIter cur, next = file.Events.begin(); - cur = next++; + auto next = file.Events.begin(); + auto cur = next++; for (; next != file.Events.end(); cur = next++) { - AssDialogue *prevdlg = dynamic_cast(&*cur); - AssDialogue *curdlg = dynamic_cast(&*next); - - if (!curdlg || !prevdlg) continue; + AssDialogue *prevdlg = &*cur; + AssDialogue *curdlg = &*next; if (prevdlg->End <= curdlg->Start) continue; // Use names like in the algorithm description and prepare for erasing // old dialogues from the list - entryIter prev = cur; + auto prev = cur; cur = next; next++; @@ -280,20 +274,17 @@ void SubtitleFormat::RecombineOverlaps(AssFile &file) { /// @brief Merge identical lines that follow each other void SubtitleFormat::MergeIdentical(AssFile &file) { - entryIter cur, next = file.Events.begin(); - cur = next++; + auto next = file.Events.begin(); + auto cur = next++; for (; next != file.Events.end(); cur = next++) { - AssDialogue *curdlg = dynamic_cast(&*cur); - AssDialogue *nextdlg = dynamic_cast(&*next); - - if (curdlg && nextdlg && curdlg->End == nextdlg->Start && curdlg->Text == nextdlg->Text) { + if (cur->End == next->Start && cur->Text == next->Text) { // Merge timing - nextdlg->Start = std::min(nextdlg->Start, curdlg->Start); - nextdlg->End = std::max(nextdlg->End, curdlg->End); + next->Start = std::min(next->Start, cur->Start); + next->End = std::max(next->End, cur->End); // Remove duplicate line - delete curdlg; + delete &*cur; } } } diff --git a/aegisub/src/subtitle_format.h b/aegisub/src/subtitle_format.h index 3a66f93a8..5d4f847ad 100644 --- a/aegisub/src/subtitle_format.h +++ b/aegisub/src/subtitle_format.h @@ -40,7 +40,6 @@ #include #include -class AssEntry; class AssFile; namespace agi { namespace vfr { class Framerate; } } diff --git a/aegisub/src/subtitle_format_ass.cpp b/aegisub/src/subtitle_format_ass.cpp index 898573037..cda8c761b 100644 --- a/aegisub/src/subtitle_format_ass.cpp +++ b/aegisub/src/subtitle_format_ass.cpp @@ -1,42 +1,28 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. +// Copyright (c) 2014, Thomas Goyne // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. // -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ -/// @file subtitle_format_ass.cpp -/// @brief Reading/writing of SSA-lineage subtitles -/// @ingroup subtitle_io -/// - #include "config.h" #include "subtitle_format_ass.h" +#include "ass_attachment.h" +#include "ass_dialogue.h" +#include "ass_info.h" #include "ass_file.h" +#include "ass_style.h" #include "ass_parser.h" #include "text_file_reader.h" #include "text_file_writer.h" @@ -52,17 +38,11 @@ AssSubtitleFormat::AssSubtitleFormat() } std::vector AssSubtitleFormat::GetReadWildcards() const { - std::vector formats; - formats.push_back("ass"); - formats.push_back("ssa"); - return formats; + return {"ass", "ssa"}; } std::vector AssSubtitleFormat::GetWriteWildcards() const { - std::vector formats; - formats.push_back("ass"); - formats.push_back("ssa"); - return formats; + return {"ass", "ssa"}; } void AssSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename, std::string const& encoding) const { @@ -87,7 +67,8 @@ void AssSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename, #define LINEBREAK "\n" #endif -static inline std::string format(AssEntryGroup group, bool ssa) { +namespace { +std::string format(AssEntryGroup group, bool ssa) { if (group == AssEntryGroup::DIALOGUE) { if (ssa) return "Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" LINEBREAK; @@ -105,17 +86,22 @@ static inline std::string format(AssEntryGroup group, bool ssa) { return ""; } -void AssSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filename, std::string const& encoding) const { - TextFileWriter file(filename, encoding); - - file.WriteLineToFile("[Script Info]"); - file.WriteLineToFile(std::string("; Script generated by Aegisub ") + GetAegisubLongVersionString()); - file.WriteLineToFile("; http://www.aegisub.org/"); - - bool ssa = agi::fs::HasExtension(filename, "ssa"); +struct Writer { + TextFileWriter file; + bool ssa; AssEntryGroup group = AssEntryGroup::INFO; - auto write = [&](EntryList const& list) { + Writer(agi::fs::path const& filename, std::string const& encoding) + : file(filename, encoding) + , ssa(agi::fs::HasExtension(filename, "ssa")) + { + file.WriteLineToFile("[Script Info]"); + file.WriteLineToFile(std::string("; Script generated by Aegisub ") + GetAegisubLongVersionString()); + file.WriteLineToFile("; http://www.aegisub.org/"); + } + + template + void Write(T const& list) { for (auto const& line : list) { if (line.Group() != group) { // Add a blank line between each group @@ -129,10 +115,15 @@ void AssSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen file.WriteLineToFile(ssa ? line.GetSSAText() : line.GetEntryData()); } - }; - - write(src->Info); - write(src->Styles); - write(src->Attachments); - write(src->Events); + } +}; +} + +void AssSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filename, std::string const& encoding) const { + Writer writer(filename, encoding); + + writer.Write(src->Info); + writer.Write(src->Styles); + writer.Write(src->Attachments); + writer.Write(src->Events); } diff --git a/aegisub/src/subtitle_format_ebu3264.cpp b/aegisub/src/subtitle_format_ebu3264.cpp index 79411960f..8e73df9e7 100644 --- a/aegisub/src/subtitle_format_ebu3264.cpp +++ b/aegisub/src/subtitle_format_ebu3264.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -373,7 +372,7 @@ namespace subs_list.reserve(copy.Events.size()); // convert to intermediate format - for (auto line : copy.Events | agi::of_type()) + for (auto& line : copy.Events) { // add a new subtitle and work on it subs_list.emplace_back(); @@ -385,19 +384,19 @@ namespace imline.cumulative_status = EbuSubtitle::NotCumulative; // convert times - imline.time_in = fps.FrameAtTime(line->Start) + timecode_bias; - imline.time_out = fps.FrameAtTime(line->End) + timecode_bias; + imline.time_in = fps.FrameAtTime(line.Start) + timecode_bias; + imline.time_out = fps.FrameAtTime(line.End) + timecode_bias; if (export_settings.inclusive_end_times) // cheap and possibly wrong way to ensure exclusive times, subtract one frame from end time imline.time_out -= 1; // convert alignment from style - AssStyle *style = copy.GetStyle(line->Style); + AssStyle *style = copy.GetStyle(line.Style); if (!style) style = &default_style; // add text, translate formatting - imline.SetTextFromAss(line, style->underline, style->italic, style->alignment, line_wrap_type); + imline.SetTextFromAss(&line, style->underline, style->italic, style->alignment, line_wrap_type); // line breaking handling if (export_settings.line_wrapping_mode == EbuExportSettings::AutoWrap) @@ -407,7 +406,7 @@ namespace else if (!imline.CheckLineLengths(export_settings.max_line_length)) { if (export_settings.line_wrapping_mode == EbuExportSettings::AbortOverLength) - throw Ebu3264SubtitleFormat::ConversionFailed(from_wx(wxString::Format(_("Line over maximum length: %s"), line->Text.get())), nullptr); + throw Ebu3264SubtitleFormat::ConversionFailed(from_wx(wxString::Format(_("Line over maximum length: %s"), line.Text.get())), nullptr); else // skip over-long lines subs_list.pop_back(); } diff --git a/aegisub/src/subtitle_format_encore.cpp b/aegisub/src/subtitle_format_encore.cpp index d710345bc..aa2dc1f2f 100644 --- a/aegisub/src/subtitle_format_encore.cpp +++ b/aegisub/src/subtitle_format_encore.cpp @@ -40,8 +40,6 @@ #include "ass_file.h" #include "text_file_writer.h" -#include - #include #include #include @@ -77,6 +75,6 @@ void EncoreSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& fi // Write lines int i = 0; TextFileWriter file(filename, "UTF-8"); - for (auto current : copy.Events | agi::of_type()) - file.WriteLineToFile(str(boost::format("%i %s %s %s") % ++i % ft.ToSMPTE(current->Start) % ft.ToSMPTE(current->End) % current->Text)); + for (auto const& current : copy.Events) + file.WriteLineToFile(str(boost::format("%i %s %s %s") % ++i % ft.ToSMPTE(current.Start) % ft.ToSMPTE(current.End) % current.Text)); } diff --git a/aegisub/src/subtitle_format_microdvd.cpp b/aegisub/src/subtitle_format_microdvd.cpp index c14553da0..a579658b4 100644 --- a/aegisub/src/subtitle_format_microdvd.cpp +++ b/aegisub/src/subtitle_format_microdvd.cpp @@ -44,7 +44,6 @@ #include "video_context.h" #include -#include #include #include @@ -143,10 +142,10 @@ void MicroDVDSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& file.WriteLineToFile(str(boost::format("{1}{1}%.6f") % fps.FPS())); // Write lines - for (auto current : copy.Events | agi::of_type()) { - int start = fps.FrameAtTime(current->Start, agi::vfr::START); - int end = fps.FrameAtTime(current->End, agi::vfr::END); + for (auto const& current : copy.Events) { + int start = fps.FrameAtTime(current.Start, agi::vfr::START); + int end = fps.FrameAtTime(current.End, agi::vfr::END); - file.WriteLineToFile(str(boost::format("{%i}{%i}%s") % start % end % boost::replace_all_copy(current->Text.get(), "\\N", "|"))); + file.WriteLineToFile(str(boost::format("{%i}{%i}%s") % start % end % boost::replace_all_copy(current.Text.get(), "\\N", "|"))); } } diff --git a/aegisub/src/subtitle_format_srt.cpp b/aegisub/src/subtitle_format_srt.cpp index c5078b4eb..1d8f0341e 100644 --- a/aegisub/src/subtitle_format_srt.cpp +++ b/aegisub/src/subtitle_format_srt.cpp @@ -480,10 +480,10 @@ void SRTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen // Write lines int i=0; - for (auto current : copy.Events | agi::of_type()) { + for (auto const& current : copy.Events) { file.WriteLineToFile(std::to_string(++i)); - file.WriteLineToFile(WriteSRTTime(current->Start) + " --> " + WriteSRTTime(current->End)); - file.WriteLineToFile(ConvertTags(current)); + file.WriteLineToFile(WriteSRTTime(current.Start) + " --> " + WriteSRTTime(current.End)); + file.WriteLineToFile(ConvertTags(¤t)); file.WriteLineToFile(""); } } @@ -496,13 +496,12 @@ bool SRTSubtitleFormat::CanSave(const AssFile *file) const { std::string defstyle = AssStyle().GetEntryData(); for (auto const& line : file->Styles) { - if (static_cast(&line)->GetEntryData() != defstyle) + if (line.GetEntryData() != defstyle) return false; } for (auto const& line : file->Events) { - auto diag = static_cast(&line); - boost::ptr_vector blocks(diag->ParseTags()); + boost::ptr_vector blocks(line.ParseTags()); for (auto ovr : blocks | agi::of_type()) { // Verify that all overrides used are supported for (auto const& tag : ovr->Tags) { diff --git a/aegisub/src/subtitle_format_transtation.cpp b/aegisub/src/subtitle_format_transtation.cpp index 4cb3d58aa..285551536 100644 --- a/aegisub/src/subtitle_format_transtation.cpp +++ b/aegisub/src/subtitle_format_transtation.cpp @@ -44,8 +44,6 @@ #include "ass_time.h" #include "text_file_writer.h" -#include - #include #include #include @@ -76,14 +74,14 @@ void TranStationSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path cons SmpteFormatter ft(fps); TextFileWriter file(filename, encoding); - AssDialogue *prev = nullptr; - for (auto cur : copy.Events | agi::of_type()) { + const AssDialogue *prev = nullptr; + for (auto const& cur : copy.Events) { if (prev) { - file.WriteLineToFile(ConvertLine(©, prev, fps, ft, cur->Start)); + file.WriteLineToFile(ConvertLine(©, prev, fps, ft, cur.Start)); file.WriteLineToFile(""); } - prev = cur; + prev = &cur; } // flush last line @@ -94,7 +92,7 @@ void TranStationSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path cons file.WriteLineToFile("SUB["); } -std::string TranStationSubtitleFormat::ConvertLine(AssFile *file, AssDialogue *current, agi::vfr::Framerate const& fps, SmpteFormatter const& ft, int nextl_start) const { +std::string TranStationSubtitleFormat::ConvertLine(AssFile *file, const AssDialogue *current, agi::vfr::Framerate const& fps, SmpteFormatter const& ft, int nextl_start) const { int valign = 0; const char *halign = " "; // default is centered const char *type = "N"; // no special style diff --git a/aegisub/src/subtitle_format_transtation.h b/aegisub/src/subtitle_format_transtation.h index 174e2e197..5740ce405 100644 --- a/aegisub/src/subtitle_format_transtation.h +++ b/aegisub/src/subtitle_format_transtation.h @@ -38,7 +38,7 @@ class AssDialogue; class SmpteFormatter; class TranStationSubtitleFormat : public SubtitleFormat { - std::string ConvertLine(AssFile *file, AssDialogue *line, agi::vfr::Framerate const& fps, SmpteFormatter const& ft, int nextl_start) const; + std::string ConvertLine(AssFile *file, const AssDialogue *line, agi::vfr::Framerate const& fps, SmpteFormatter const& ft, int nextl_start) const; public: TranStationSubtitleFormat(); diff --git a/aegisub/src/subtitle_format_ttxt.cpp b/aegisub/src/subtitle_format_ttxt.cpp index 28a293d98..0532adc57 100644 --- a/aegisub/src/subtitle_format_ttxt.cpp +++ b/aegisub/src/subtitle_format_ttxt.cpp @@ -44,7 +44,6 @@ #include "compat.h" #include "options.h" -#include #include DEFINE_SIMPLE_EXCEPTION(TTXTParseError, SubtitleFormatParseError, "subtitle_io/parse/ttxt") @@ -177,9 +176,9 @@ void TTXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& file // Create lines const AssDialogue *prev = nullptr; - for (auto current : copy.Events | agi::of_type()) { - WriteLine(root, prev, current); - prev = current; + for (auto const& current : copy.Events) { + WriteLine(root, prev, ¤t); + prev = ¤t; } // Save XML @@ -264,8 +263,8 @@ void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const { // Find last line AssTime lastTime; - for (auto line : file.Events | boost::adaptors::reversed | agi::of_type()) { - lastTime = line->End; + for (auto const& line : file.Events | boost::adaptors::reversed) { + lastTime = line.End; break; } diff --git a/aegisub/src/subtitle_format_txt.cpp b/aegisub/src/subtitle_format_txt.cpp index 3ced45aec..9e4d7c326 100644 --- a/aegisub/src/subtitle_format_txt.cpp +++ b/aegisub/src/subtitle_format_txt.cpp @@ -45,8 +45,6 @@ #include "utils.h" #include "version.h" -#include - #include #include @@ -131,10 +129,10 @@ void TXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen size_t num_actor_names = 0, num_dialogue_lines = 0; // Detect number of lines with Actor field filled out - for (auto dia : src->Events | agi::of_type()) { - if (!dia->Comment) { + for (auto const& dia : src->Events) { + if (!dia.Comment) { num_dialogue_lines++; - if (!dia->Actor.get().empty()) + if (!dia.Actor.get().empty()) num_actor_names++; } } @@ -147,16 +145,16 @@ void TXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen file.WriteLineToFile(std::string("# Exported by Aegisub ") + GetAegisubShortVersionString()); // Write the file - for (auto dia : src->Events | agi::of_type()) { + for (auto const& dia : src->Events) { std::string out_line; - if (dia->Comment) + if (dia.Comment) out_line = "# "; if (write_actors) - out_line += dia->Actor.get() + ": "; + out_line += dia.Actor.get() + ": "; - std::string out_text = strip_formatting ? dia->GetStrippedText() : dia->Text; + std::string out_text = strip_formatting ? dia.GetStrippedText() : dia.Text; out_line += out_text; if (!out_text.empty()) diff --git a/aegisub/src/subtitles_provider_libass.cpp b/aegisub/src/subtitles_provider_libass.cpp index 2e4e66008..1557800c9 100644 --- a/aegisub/src/subtitles_provider_libass.cpp +++ b/aegisub/src/subtitles_provider_libass.cpp @@ -41,7 +41,10 @@ #include #endif +#include "ass_info.h" +#include "ass_dialogue.h" #include "ass_file.h" +#include "ass_style.h" #include "dialog_progress.h" #include "frame_main.h" #include "main.h" @@ -112,28 +115,35 @@ LibassSubtitlesProvider::~LibassSubtitlesProvider() { if (ass_renderer) ass_renderer_done(ass_renderer); } -void LibassSubtitlesProvider::LoadSubtitles(AssFile *subs) { - std::vector data; - data.clear(); - data.reserve(0x4000); +namespace { + struct Writer { + std::vector data; + AssEntryGroup group = AssEntryGroup::GROUP_MAX; - AssEntryGroup group = AssEntryGroup::GROUP_MAX; - auto write_group = [&](EntryList const& list) { - for (auto const& line : list) { - if (group != line.Group()) { - group = line.Group(); - boost::push_back(data, line.GroupHeader() + "\r\n"); + template + void Write(T const& list) { + for (auto const& line : list) { + if (group != line.Group()) { + 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); +void LibassSubtitlesProvider::LoadSubtitles(AssFile *subs) { + Writer writer; + + writer.data.reserve(0x4000); + + writer.Write(subs->Info); + writer.Write(subs->Styles); + writer.Write(subs->Events); 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, &writer.data[0], writer.data.size(), nullptr); if (!ass_track) throw "libass failed to load subtitles."; } diff --git a/aegisub/src/threaded_frame_source.cpp b/aegisub/src/threaded_frame_source.cpp index 87b37a297..52f48366d 100644 --- a/aegisub/src/threaded_frame_source.cpp +++ b/aegisub/src/threaded_frame_source.cpp @@ -28,6 +28,7 @@ #include "video_frame.h" #include "video_provider_manager.h" +#include #include #include @@ -70,12 +71,10 @@ std::shared_ptr ThreadedFrameSource::ProcFrame(int frame_number, dou // Copying a nontrivially sized AssFile is fairly slow, so // instead muck around with its innards to just temporarily // remove the non-visible lines without deleting them - std::deque full; - for (auto& line : subs->Events) - full.push_back(&line); - subs->Events.remove_if([=](AssEntry const& e) -> bool { - const AssDialogue *diag = dynamic_cast(&e); - return diag && (diag->Start > time || diag->End <= time); + std::deque full; + boost::push_back(full, subs->Events | agi::address_of); + subs->Events.remove_if([=](AssDialogue const& diag) { + return diag.Start > time || diag.End <= time; }); try { @@ -133,12 +132,12 @@ void ThreadedFrameSource::LoadSubtitles(const AssFile *new_subs) throw() { }); } -void ThreadedFrameSource::UpdateSubtitles(const AssFile *new_subs, std::set const& changes) throw() { +void ThreadedFrameSource::UpdateSubtitles(const AssFile *new_subs, std::set const& changes) throw() { uint_fast32_t req_version = ++version; // Copy just the lines which were changed, then replace the lines at the // same indices in the worker's copy of the file with the new entries - std::deque> changed; + std::deque> changed; size_t i = 0; for (auto const& e : new_subs->Events) { if (changes.count(&e)) diff --git a/aegisub/src/threaded_frame_source.h b/aegisub/src/threaded_frame_source.h index fa7223245..fbb08c914 100644 --- a/aegisub/src/threaded_frame_source.h +++ b/aegisub/src/threaded_frame_source.h @@ -29,7 +29,7 @@ #include -class AssEntry; +class AssDialogue; class AssFile; class SubtitlesProvider; class VideoProvider; @@ -84,7 +84,7 @@ public: /// /// This function only supports changes to existing lines, and not /// insertions or deletions. - void UpdateSubtitles(const AssFile *subs, std::set const& changes) throw(); + void UpdateSubtitles(const AssFile *subs, std::set const& changes) throw(); /// @brief Queue a request for a frame /// @brief frame Frame number diff --git a/aegisub/src/utils.h b/aegisub/src/utils.h index dd5a7edb5..2cbfb555f 100644 --- a/aegisub/src/utils.h +++ b/aegisub/src/utils.h @@ -115,19 +115,6 @@ void SetClipboard(wxBitmap const& new_value); #define countof(array) (sizeof(array) / sizeof(array[0])) -template -struct cast { - template - Out operator()(In *in) const { - return dynamic_cast(in); - } - - template - Out operator()(In &in) const { - return dynamic_cast(&in); - } -}; - wxString FontFace(std::string opt_prefix); agi::fs::path OpenFileSelector(wxString const& message, std::string const& option_name, std::string const& default_filename, std::string const& default_extension, wxString const& wildcard, wxWindow *parent); diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp index 4560e61d5..31da0be64 100644 --- a/aegisub/src/video_context.cpp +++ b/aegisub/src/video_context.cpp @@ -232,7 +232,7 @@ void VideoContext::Reload() { } } -void VideoContext::OnSubtitlesCommit(int type, std::set const& changed) { +void VideoContext::OnSubtitlesCommit(int type, std::set const& changed) { if (!IsLoaded()) return; if (changed.empty() || no_amend) @@ -436,7 +436,7 @@ void VideoContext::LoadTimecodes(agi::fs::path const& filename) { ovr_fps = agi::vfr::Framerate(filename); timecodes_filename = filename; config::mru->Add("Timecodes", filename); - OnSubtitlesCommit(0, std::set()); + OnSubtitlesCommit(0, std::set()); TimecodesOpen(ovr_fps); } catch (agi::fs::FileSystemError const& err) { @@ -460,7 +460,7 @@ void VideoContext::SaveTimecodes(agi::fs::path const& filename) { void VideoContext::CloseTimecodes() { ovr_fps = agi::vfr::Framerate(); timecodes_filename.clear(); - OnSubtitlesCommit(0, std::set()); + OnSubtitlesCommit(0, std::set()); TimecodesOpen(video_fps); } diff --git a/aegisub/src/video_context.h b/aegisub/src/video_context.h index ea2c72e45..3c1a8cb07 100644 --- a/aegisub/src/video_context.h +++ b/aegisub/src/video_context.h @@ -45,11 +45,11 @@ #include -class AssEntry; -struct SubtitlesProviderErrorEvent; +class AssDialogue; class ThreadedFrameSource; -struct VideoFrame; class VideoProvider; +struct SubtitlesProviderErrorEvent; +struct VideoFrame; struct VideoProviderErrorEvent; namespace agi { @@ -152,7 +152,7 @@ class VideoContext : public wxEvtHandler { void OnVideoError(VideoProviderErrorEvent const& err); void OnSubtitlesError(SubtitlesProviderErrorEvent const& err); - void OnSubtitlesCommit(int type, std::set const& changed); + void OnSubtitlesCommit(int type, std::set const& changed); void OnSubtitlesSave(); /// Close the video, keyframes and timecodes diff --git a/aegisub/src/visual_tool_drag.cpp b/aegisub/src/visual_tool_drag.cpp index 3dd7b49c4..9997605cd 100644 --- a/aegisub/src/visual_tool_drag.cpp +++ b/aegisub/src/visual_tool_drag.cpp @@ -31,7 +31,6 @@ #include "video_context.h" #include "video_display.h" -#include #include #include @@ -115,9 +114,9 @@ void VisualToolDrag::OnFileChanged() { primary = nullptr; active_feature = nullptr; - for (auto diag : c->ass->Events | agi::of_type()) { - if (IsDisplayed(diag)) - MakeFeatures(diag); + for (auto& diag : c->ass->Events) { + if (IsDisplayed(&diag)) + MakeFeatures(&diag); } UpdateToggleButtons(); @@ -130,18 +129,18 @@ void VisualToolDrag::OnFrameChanged() { auto feat = features.begin(); auto end = features.end(); - for (auto diag : c->ass->Events | agi::of_type()) { - if (IsDisplayed(diag)) { + for (auto& diag : c->ass->Events) { + if (IsDisplayed(&diag)) { // Features don't exist and should - if (feat == end || feat->line != diag) - MakeFeatures(diag, feat); + if (feat == end || feat->line != &diag) + MakeFeatures(&diag, feat); // Move past already existing features for the line else - while (feat != end && feat->line == diag) ++feat; + while (feat != end && feat->line == &diag) ++feat; } else { // Remove all features for this line (if any) - while (feat != end && feat->line == diag) { + while (feat != end && feat->line == &diag) { if (&*feat == active_feature) active_feature = nullptr; feat->line = nullptr; RemoveSelection(&*feat);