Move AssTime to libaegisub and add tests

This commit is contained in:
Thomas Goyne 2014-07-06 07:28:58 -07:00
parent ba0e544d70
commit 3b34ed9a77
44 changed files with 251 additions and 157 deletions

View File

@ -117,7 +117,6 @@
<ClInclude Include="$(SrcDir)ass_parser.h" />
<ClInclude Include="$(SrcDir)ass_style.h" />
<ClInclude Include="$(SrcDir)ass_style_storage.h" />
<ClInclude Include="$(SrcDir)ass_time.h" />
<ClInclude Include="$(SrcDir)audio_box.h" />
<ClInclude Include="$(SrcDir)audio_colorscheme.h" />
<ClInclude Include="$(SrcDir)audio_controller.h" />
@ -257,7 +256,6 @@
<ClCompile Include="$(SrcDir)ass_parser.cpp" />
<ClCompile Include="$(SrcDir)ass_style.cpp" />
<ClCompile Include="$(SrcDir)ass_style_storage.cpp" />
<ClCompile Include="$(SrcDir)ass_time.cpp" />
<ClCompile Include="$(SrcDir)async_video_provider.cpp" />
<ClCompile Include="$(SrcDir)audio_box.cpp" />
<ClCompile Include="$(SrcDir)audio_colorscheme.cpp" />

View File

@ -150,9 +150,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(SrcDir)ass_time.h">
<Filter>ASS</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)ass_dialogue.h">
<Filter>ASS</Filter>
</ClInclude>
@ -578,9 +575,6 @@
<ClCompile Include="$(SrcDir)ass_style_storage.cpp">
<Filter>ASS</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)ass_time.cpp">
<Filter>ASS</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)audio_provider_ram.cpp">
<Filter>Audio\Providers</Filter>
</ClCompile>

View File

@ -61,6 +61,8 @@
<ClInclude Include="$(SrcDir)include\libaegisub\access.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\address_of_adaptor.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\ass\dialogue_parser.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\ass\smpte.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\ass\time.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\ass\uuencode.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\background_runner.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\cajun\elements.h" />
@ -118,6 +120,7 @@
<PrecompiledHeaderFile>lagi_pre.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="$(SrcDir)ass\dialogue_parser.cpp" />
<ClCompile Include="$(SrcDir)ass\time.cpp" />
<ClCompile Include="$(SrcDir)common\cajun\elements.cpp" />
<ClCompile Include="$(SrcDir)common\cajun\reader.cpp" />
<ClCompile Include="$(SrcDir)common\cajun\writer.cpp" />

View File

@ -125,6 +125,12 @@
<ClInclude Include="$(SrcDir)include\libaegisub\ass\dialogue_parser.h">
<Filter>ASS</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\ass\smpte.h">
<Filter>ASS</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\ass\time.h">
<Filter>ASS</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)common\parser.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -265,6 +271,9 @@
<ClCompile Include="$(SrcDir)ass\dialogue_parser.cpp">
<Filter>ASS</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)ass\time.cpp">
<Filter>ASS</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)common\color.cpp">
<Filter>Source Files\Common</Filter>
</ClCompile>

View File

@ -57,6 +57,7 @@
<ClCompile Include="$(SrcDir)tests\signals.cpp" />
<ClCompile Include="$(SrcDir)tests\syntax_highlight.cpp" />
<ClCompile Include="$(SrcDir)tests\thesaurus.cpp" />
<ClCompile Include="$(SrcDir)tests\time.cpp" />
<ClCompile Include="$(SrcDir)tests\util.cpp" />
<ClCompile Include="$(SrcDir)tests\uuencode.cpp" />
<ClCompile Include="$(SrcDir)tests\vfr.cpp" />

View File

@ -65,6 +65,9 @@
<ClCompile Include="$(SrcDir)tests\syntax_highlight.cpp">
<Filter>Tests</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)tests\time.cpp">
<Filter>Tests</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)tests\thesaurus.cpp">
<Filter>Tests</Filter>
</ClCompile>

View File

@ -3,6 +3,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../header.mk
aegisub_OBJ := \
$(d)common/parser.o \
$(d)ass/dialogue_parser.o \
$(d)ass/time.o \
$(subst .cpp,.o,$(wildcard $(d)common/cajun/*.cpp)) \
$(subst .cpp,.o,$(wildcard $(d)lua/modules/*.cpp)) \
$(subst .c,.o,$(wildcard $(d)lua/modules/*.c)) \

View File

@ -1,4 +1,4 @@
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@ -14,14 +14,8 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file ass_time.cpp
/// @brief Class for managing timestamps in subtitles
/// @ingroup subs_storage
///
#include "ass_time.h"
#include "utils.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/ass/smpte.h>
#include <libaegisub/format.h>
#include <libaegisub/util.h>
@ -31,9 +25,10 @@
#include <boost/algorithm/string/split.hpp>
#include <boost/range/adaptor/filtered.hpp>
AssTime::AssTime(int time) : time(mid(0, time, 10 * 60 * 60 * 1000 - 1)) { }
namespace agi {
Time::Time(int time) : time(util::mid(0, time, 10 * 60 * 60 * 1000 - 1)) { }
AssTime::AssTime(std::string const& text) {
Time::Time(std::string const& text) {
int after_decimal = -1;
int current = 0;
for (char c : text | boost::adaptors::filtered(boost::is_any_of(",.0123456789:"))) {
@ -61,10 +56,10 @@ AssTime::AssTime(std::string const& text) {
time = (time * 60 + current) * 1000;
// Limit to the valid range
time = mid(0, time, 10 * 60 * 60 * 1000 - 1);
time = util::mid(0, time, 10 * 60 * 60 * 1000 - 1);
}
std::string AssTime::GetAssFormated(bool msPrecision) const {
std::string Time::GetAssFormatted(bool msPrecision) const {
std::string ret(10 + msPrecision, ':');
ret[0] = '0' + GetTimeHours();
ret[2] = '0' + (time % (60 * 60 * 1000)) / (60 * 1000 * 10);
@ -79,33 +74,34 @@ std::string AssTime::GetAssFormated(bool msPrecision) const {
return ret;
}
int AssTime::GetTimeHours() const { return time / 3600000; }
int AssTime::GetTimeMinutes() const { return (time % 3600000) / 60000; }
int AssTime::GetTimeSeconds() const { return (time % 60000) / 1000; }
int AssTime::GetTimeMiliseconds() const { return (time % 1000); }
int AssTime::GetTimeCentiseconds() const { return (time % 1000) / 10; }
int Time::GetTimeHours() const { return time / 3600000; }
int Time::GetTimeMinutes() const { return (time % 3600000) / 60000; }
int Time::GetTimeSeconds() const { return (time % 60000) / 1000; }
int Time::GetTimeMiliseconds() const { return (time % 1000); }
int Time::GetTimeCentiseconds() const { return (time % 1000) / 10; }
SmpteFormatter::SmpteFormatter(agi::vfr::Framerate fps, std::string sep)
SmpteFormatter::SmpteFormatter(vfr::Framerate fps, std::string sep)
: fps(std::move(fps))
, sep(std::move(sep))
{
}
std::string SmpteFormatter::ToSMPTE(AssTime time) const {
std::string SmpteFormatter::ToSMPTE(Time time) const {
int h=0, m=0, s=0, f=0;
fps.SmpteAtTime(time, &h, &m, &s, &f);
return agi::format("%02d%s%02d%s%02d%c%02d", h, sep, m, sep, s, sep, f);
return format("%02d%s%02d%s%02d%s%02d", h, sep, m, sep, s, sep, f);
}
AssTime SmpteFormatter::FromSMPTE(std::string const& str) const {
Time SmpteFormatter::FromSMPTE(std::string const& str) const {
std::vector<std::string> toks;
boost::split(toks, str, boost::is_any_of(sep));
if (toks.size() != 4) return 0;
int h, m, s, f;
agi::util::try_parse(toks[0], &h);
agi::util::try_parse(toks[1], &m);
agi::util::try_parse(toks[2], &s);
agi::util::try_parse(toks[3], &f);
util::try_parse(toks[0], &h);
util::try_parse(toks[1], &m);
util::try_parse(toks[2], &s);
util::try_parse(toks[3], &f);
return fps.TimeAtSmpte(h, m, s, f);
}
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <libaegisub/vfr.h>
#include <string>
namespace agi {
class Time;
/// @class SmpteFormatter
/// @brief Convert times to and from SMPTE timecodes
class SmpteFormatter {
/// Frame rate to use
vfr::Framerate fps;
/// Separator character
std::string sep;
public:
SmpteFormatter(vfr::Framerate fps, std::string sep=":");
/// Convert an Time to a SMPTE timecode
std::string ToSMPTE(Time time) const;
/// Convert a SMPTE timecode to an Time
Time FromSMPTE(std::string const& str) const;
};
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@ -14,24 +14,18 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file ass_time.h
/// @see ass_time.cpp
/// @ingroup subs_storage
///
#pragma once
#include <string>
#include <libaegisub/vfr.h>
class AssTime {
namespace agi {
class Time {
/// Time in milliseconds
int time = 0;
public:
AssTime(int ms = 0);
AssTime(std::string const& text);
Time(int ms = 0);
Time(std::string const& text);
/// Get millisecond, rounded to centisecond precision
operator int() const { return time / 10 * 10; }
@ -44,22 +38,6 @@ public:
/// Return the time as a string
/// @param ms Use milliseconds precision, for non-ASS formats
std::string GetAssFormated(bool ms=false) const;
};
/// @class SmpteFormatter
/// @brief Convert times to and from SMPTE timecodes
class SmpteFormatter {
/// Frame rate to use
agi::vfr::Framerate fps;
/// Separator character
std::string sep;
public:
SmpteFormatter(agi::vfr::Framerate fps, std::string sep=":");
/// Convert an AssTime to a SMPTE timecode
std::string ToSMPTE(AssTime time) const;
/// Convert a SMPTE timecode to an AssTime
AssTime FromSMPTE(std::string const& str) const;
std::string GetAssFormatted(bool ms=false) const;
};
}

View File

@ -28,7 +28,6 @@ src_OBJ := \
$(d)ass_parser.o \
$(d)ass_style.o \
$(d)ass_style_storage.o \
$(d)ass_time.o \
$(d)async_video_provider.o \
$(d)audio_box.o \
$(d)audio_colorscheme.o \

View File

@ -168,8 +168,8 @@ std::string AssDialogue::GetEntryData() const {
str.reserve(51 + Style.get().size() + Actor.get().size() + Effect.get().size() + Text.get().size());
append_int(str, Layer);
append_str(str, Start.GetAssFormated());
append_str(str, End.GetAssFormated());
append_str(str, Start.GetAssFormatted());
append_str(str, End.GetAssFormatted());
append_unsafe_str(str, Style);
append_unsafe_str(str, Actor);
for (auto margin : Margin)

View File

@ -27,14 +27,10 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file ass_dialogue.h
/// @see ass_dialogue.cpp
/// @ingroup subs_storage
///
#include "ass_entry.h"
#include "ass_override.h"
#include "ass_time.h"
#include <libaegisub/ass/time.h>
#include <array>
#include <boost/flyweight.hpp>
@ -135,9 +131,9 @@ struct AssDialogueBase {
/// Margins: 0 = Left, 1 = Right, 2 = Top (Vertical)
std::array<int, 3> Margin = {{0, 0, 0}};
/// Starting time
AssTime Start = 0;
agi::Time Start = 0;
/// Ending time
AssTime End = 5000;
agi::Time End = 5000;
/// Style name
boost::flyweight<std::string> Style{ "Default" };
/// Actor name

View File

@ -28,16 +28,12 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file ass_override.cpp
/// @brief Parse and modify ASSA style overrides
/// @ingroup subs_storage
///
#include "ass_dialogue.h"
#include "utils.h"
#include <libaegisub/color.h>
#include <libaegisub/exception.h>
#include <libaegisub/format.h>
#include <libaegisub/make_unique.h>

View File

@ -30,7 +30,6 @@
#include "audio_display.h"
#include "ass_time.h"
#include "audio_controller.h"
#include "audio_renderer.h"
#include "audio_renderer_spectrum.h"
@ -46,6 +45,7 @@
#include "utils.h"
#include "video_controller.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/make_unique.h>
#include <algorithm>
@ -977,8 +977,8 @@ void AudioDisplay::SetTrackCursor(int new_pos, bool show_time)
if (show_time)
{
AssTime new_label_time = TimeFromAbsoluteX(track_cursor_pos);
track_cursor_label = to_wx(new_label_time.GetAssFormated());
agi::Time new_label_time = TimeFromAbsoluteX(track_cursor_pos);
track_cursor_label = to_wx(new_label_time.GetAssFormatted());
track_cursor_label_rect.x += new_pos - old_pos;
RefreshRect(track_cursor_label_rect, false);
}

View File

@ -29,7 +29,6 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_time.h"
#include "audio_marker.h"
#include "audio_rendering_style.h"
#include "audio_timing.h"
@ -40,6 +39,7 @@
#include "selection_controller.h"
#include "utils.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/make_unique.h>
#include <boost/range/algorithm.hpp>

View File

@ -200,7 +200,7 @@ struct audio_save_clip final : public Command {
auto filename = SaveFileSelector(_("Save audio clip"), "", "", "wav", "", c->parent);
if (filename.empty()) return;
AssTime start = INT_MAX, end = 0;
agi::Time start = INT_MAX, end = 0;
for (auto line : sel) {
start = std::min(start, line->Start);
end = std::max(end, line->End);

View File

@ -32,7 +32,6 @@
#include "command.h"
#include "../ass_dialogue.h"
#include "../ass_time.h"
#include "../async_video_provider.h"
#include "../compat.h"
#include "../dialog_detached_video.h"
@ -51,6 +50,7 @@
#include "../video_display.h"
#include "../video_frame.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/fs.h>
#include <libaegisub/path.h>
#include <libaegisub/make_unique.h>

View File

@ -14,7 +14,6 @@
//
// Aegisub Project http://www.aegisub.org/
#include "ass_time.h"
#include "colour_button.h"
#include "format.h"
#include "help_button.h"
@ -23,6 +22,7 @@
#include "validators.h"
#include "video_provider_dummy.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/color.h>
#include <wx/checkbox.h>
@ -161,7 +161,7 @@ void DialogDummyVideo::OnResolutionShortcut(wxCommandEvent &e) {
}
void DialogDummyVideo::UpdateLengthDisplay() {
length_display->SetLabel(fmt_tl("Resulting duration: %s", AssTime(length / fps * 1000).GetAssFormated(true)));
length_display->SetLabel(fmt_tl("Resulting duration: %s", agi::Time(length / fps * 1000).GetAssFormatted(true)));
}
}

View File

@ -27,7 +27,6 @@
//
// Aegisub Project http://www.aegisub.org/
#include "ass_time.h"
#include "async_video_provider.h"
#include "format.h"
#include "include/aegisub/context.h"
@ -37,6 +36,8 @@
#include "validators.h"
#include "video_controller.h"
#include <libaegisub/ass/time.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -74,7 +75,7 @@ DialogJumpTo::DialogJumpTo(agi::Context *c)
JumpFrame = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxSize(-1,-1),wxTE_PROCESS_ENTER, IntValidator((int)jumpframe));
JumpFrame->SetMaxLength(std::to_string(c->project->VideoProvider()->GetFrameCount() - 1).size());
JumpTime = new TimeEdit(&d, -1, c, AssTime(c->videoController->TimeAtFrame(jumpframe)).GetAssFormated(), wxSize(-1,-1));
JumpTime = new TimeEdit(&d, -1, c, agi::Time(c->videoController->TimeAtFrame(jumpframe)).GetAssFormatted(), wxSize(-1,-1));
auto TimesSizer = new wxGridSizer(2, 5, 5);

View File

@ -16,7 +16,6 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_time.h"
#include "compat.h"
#include "dialog_manager.h"
#include "format.h"
@ -29,6 +28,7 @@
#include "subs_controller.h"
#include "timeedit_ctrl.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/fs.h>
#include <libaegisub/io.h>
#include <libaegisub/log.h>
@ -286,7 +286,7 @@ void DialogShiftTimes::OnHistoryClick(wxCommandEvent &evt) {
json::Object& obj = history[entry];
if (obj["is by time"]) {
shift_time->SetTime(AssTime((std::string)obj["amount"]));
shift_time->SetTime(agi::Time((std::string)obj["amount"]));
shift_by_time->SetValue(true);
OnByTime(evt);
}

View File

@ -46,10 +46,11 @@
#include "subtitle_format.h"
#include <libaegisub/fs.h>
#include <libaegisub/make_unique.h>
#include <libaegisub/path.h>
#include <libaegisub/signal.h>
#include <libaegisub/split.h>
#include <libaegisub/make_unique.h>
#include <libaegisub/vfr.h>
#include <algorithm>
#include <boost/algorithm/string/trim.hpp>

View File

@ -29,7 +29,6 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_time.h"
#include "async_video_provider.h"
#include "compat.h"
#include "format.h"
@ -42,6 +41,7 @@
#include "utils.h"
#include <libaegisub/address_of_adaptor.h>
#include <libaegisub/ass/time.h>
#include <algorithm>
#include <boost/range/adaptor/filtered.hpp>

View File

@ -27,13 +27,14 @@
//
// Aegisub Project http://www.aegisub.org/
#include "ass_time.h"
#include "async_video_provider.h"
#include "compat.h"
#include "format.h"
#include "include/aegisub/context.h"
#include "project.h"
#include <libaegisub/ass/time.h>
#include <boost/rational.hpp>
#include <wx/dialog.h>
#include <wx/sizer.h>
@ -59,7 +60,7 @@ void ShowVideoDetailsDialog(agi::Context *c) {
make_field(_("FPS:"), fmt_wx("%.3f", fps.FPS()));
make_field(_("Resolution:"), fmt_wx("%dx%d (%d:%d)", width, height, ar.numerator(), ar.denominator()));
make_field(_("Length:"), fmt_plural(framecount, "1 frame", "%d frames (%s)",
framecount, AssTime(fps.TimeAtFrame(framecount - 1)).GetAssFormated(true)));
framecount, agi::Time(fps.TimeAtFrame(framecount - 1)).GetAssFormatted(true)));
make_field(_("Decoder:"), to_wx(provider->GetDecoderName()));
auto video_sizer = new wxStaticBoxSizer(wxVERTICAL, &d, _("Video"));

View File

@ -131,7 +131,7 @@ struct GridColumnStartTime final : GridColumnTime {
wxString Value(const AssDialogue *d, const agi::Context *c) const override {
if (by_frame)
return std::to_wstring(c->videoController->FrameAtTime(d->Start, agi::vfr::START));
return to_wx(d->Start.GetAssFormated());
return to_wx(d->Start.GetAssFormatted());
}
int Width(const agi::Context *c, WidthHelper &helper) const override {
@ -149,7 +149,7 @@ struct GridColumnEndTime final : GridColumnTime {
wxString Value(const AssDialogue *d, const agi::Context *c) const override {
if (by_frame)
return std::to_wstring(c->videoController->FrameAtTime(d->End, agi::vfr::END));
return to_wx(d->End.GetAssFormated());
return to_wx(d->End.GetAssFormatted());
}
int Width(const agi::Context *c, WidthHelper &helper) const override {

View File

@ -36,12 +36,12 @@
#include "ass_file.h"
#include "ass_parser.h"
#include "ass_time.h"
#include "compat.h"
#include "dialog_progress.h"
#include "MatroskaParser.h"
#include "options.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/file_mapping.h>
#include <libaegisub/format.h>
#include <libaegisub/scoped_ptr.h>
@ -130,8 +130,8 @@ static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *
// Get start and end times
int64_t timecodeScaleLow = 1000000;
AssTime subStart = startTime / timecodeScaleLow;
AssTime subEnd = endTime / timecodeScaleLow;
agi::Time subStart = startTime / timecodeScaleLow;
agi::Time subEnd = endTime / timecodeScaleLow;
using str_range = boost::iterator_range<const char *>;
@ -146,15 +146,15 @@ static void read_subtitles(agi::ProgressSink *ps, MatroskaFile *file, MkvStdIO *
boost::lexical_cast<int>(str_range(readBuf, first)),
agi::format("Dialogue: %d,%s,%s,%s"
, boost::lexical_cast<int>(str_range(first + 1, second))
, subStart.GetAssFormated()
, subEnd.GetAssFormated()
, subStart.GetAssFormatted()
, subEnd.GetAssFormatted()
, str_range(second + 1, readBufEnd)));
}
// Process SRT
else {
auto line = agi::format("Dialogue: 0,%s,%s,Default,,0,0,0,,%s"
, subStart.GetAssFormated()
, subEnd.GetAssFormated()
, subStart.GetAssFormatted()
, subEnd.GetAssFormatted()
, str_range(readBuf, readBufEnd));
boost::replace_all(line, "\r\n", "\\N");
boost::replace_all(line, "\r", "\\N");

View File

@ -21,6 +21,7 @@
#include "ass_style.h"
#include "utils.h"
#include <libaegisub/exception.h>
#include <libaegisub/of_type_adaptor.h>
#include <libaegisub/split.h>
#include <libaegisub/util.h>

View File

@ -23,6 +23,7 @@
#include "selection_controller.h"
#include "text_selection_controller.h"
#include <libaegisub/exception.h>
#include <libaegisub/util.h>
#include <boost/locale/conversion.hpp>

View File

@ -40,9 +40,9 @@
namespace agi { namespace vfr { class Framerate; } }
namespace agi { struct Context; }
namespace agi { class Time; }
class AssDialogue;
class AssStyle;
class AssTime;
class SubsTextEditCtrl;
class TimeEdit;
class wxButton;
@ -126,7 +126,7 @@ class SubsEditBox final : public wxPanel {
/// The start and end times of the selected lines without changes made to
/// avoid negative durations, so that they can be restored if future changes
/// eliminate the negative durations
boost::container::map<AssDialogue *, std::pair<AssTime, AssTime>> initial_times;
boost::container::map<AssDialogue *, std::pair<agi::Time, agi::Time>> initial_times;
// Constructor helpers
wxTextCtrl *MakeMarginCtrl(wxString const& tooltip, int margin, wxString const& commit_msg);

View File

@ -50,6 +50,7 @@
#include <libaegisub/fs.h>
#include <libaegisub/make_unique.h>
#include <libaegisub/vfr.h>
#include <algorithm>
#include <boost/algorithm/string/join.hpp>

View File

@ -38,6 +38,7 @@
#include "ass_file.h"
#include "text_file_writer.h"
#include <libaegisub/ass/smpte.h>
#include <libaegisub/format.h>
EncoreSubtitleFormat::EncoreSubtitleFormat()
@ -64,7 +65,7 @@ void EncoreSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& fi
// Encore wants ; for NTSC and : for PAL
// The manual suggests no other frame rates are supported
SmpteFormatter ft(fps, fps.NeedsDropFrames() ? ";" : ":");
agi::SmpteFormatter ft(fps, fps.NeedsDropFrames() ? ";" : ":");
// Write lines
int i = 0;

View File

@ -36,14 +36,15 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_time.h"
#include "options.h"
#include "text_file_reader.h"
#include "text_file_writer.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/format.h>
#include <libaegisub/fs.h>
#include <libaegisub/util.h>
#include <libaegisub/vfr.h>
#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>

View File

@ -277,7 +277,7 @@ public:
}
};
std::string WriteSRTTime(AssTime const& ts)
std::string WriteSRTTime(agi::Time const& ts)
{
return agi::format("%02d:%02d:%02d,%03d", ts.GetTimeHours(), ts.GetTimeMinutes(), ts.GetTimeSeconds(), ts.GetTimeMiliseconds());
}

View File

@ -84,7 +84,7 @@ void SsaSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filen
for (auto const& line : src->Events)
file.WriteLineToFile(agi::format("%s: Marked=0,%s,%s,%s,%s,%d,%d,%d,%s,%s"
, (line.Comment ? "Comment" : "Dialogue")
, line.Start.GetAssFormated(), line.End.GetAssFormated()
, line.Start.GetAssFormatted(), line.End.GetAssFormatted()
, replace_commas(line.Style), replace_commas(line.Actor)
, line.Margin[0], line.Margin[1], line.Margin[2]
, replace_commas(line.Effect)

View File

@ -27,19 +27,15 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file subtitle_format_transtation.cpp
/// @brief Reading/writing Transtation-compatible subtitles
/// @ingroup subtitle_io
///
#include "subtitle_format_transtation.h"
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_style.h"
#include "ass_time.h"
#include "text_file_writer.h"
#include <libaegisub/ass/smpte.h>
#include <libaegisub/ass/time.h>
#include <libaegisub/format.h>
TranStationSubtitleFormat::TranStationSubtitleFormat()
@ -52,7 +48,7 @@ std::vector<std::string> TranStationSubtitleFormat::GetWriteWildcards() const {
}
void TranStationSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filename, agi::vfr::Framerate const& vfps, std::string const& encoding) const {
agi::vfr::Framerate fps = AskForFPS(false, true, vfps);
auto fps = AskForFPS(false, true, vfps);
if (!fps.IsLoaded()) return;
// Convert to TranStation
@ -64,7 +60,7 @@ void TranStationSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path cons
StripTags(copy);
ConvertNewlines(copy, "\r\n");
SmpteFormatter ft(fps);
agi::SmpteFormatter ft(fps);
TextFileWriter file(filename, encoding);
const AssDialogue *prev = nullptr;
for (auto const& cur : copy.Events) {
@ -84,7 +80,7 @@ void TranStationSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path cons
file.WriteLineToFile("SUB[");
}
std::string TranStationSubtitleFormat::ConvertLine(AssFile *file, const 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, agi::SmpteFormatter const& ft, int nextl_start) const {
int valign = 0;
const char *halign = " "; // default is centered
const char *type = "N"; // no special style
@ -101,7 +97,7 @@ std::string TranStationSubtitleFormat::ConvertLine(AssFile *file, const AssDialo
if (current->Text.get().find("\\i1") != std::string::npos) type = "I";
// Write header
AssTime end = current->End;
agi::Time end = current->End;
// Subtract one frame if the end time of the current line is equal to the
// start of next one, since the end timestamp is inclusive and the lines

View File

@ -27,18 +27,13 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file subtitle_format_transtation.h
/// @see subtitle_format_transtation.cpp
/// @ingroup subtitle_io
///
#include "subtitle_format.h"
class AssDialogue;
class SmpteFormatter;
namespace agi { class SmpteFormatter; }
class TranStationSubtitleFormat final : public SubtitleFormat {
std::string ConvertLine(AssFile *file, const 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, agi::SmpteFormatter const& ft, int nextl_start) const;
public:
TranStationSubtitleFormat();

View File

@ -36,10 +36,11 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_time.h"
#include "compat.h"
#include "options.h"
#include <libaegisub/ass/time.h>
#include <wx/xml/xml.h>
DEFINE_EXCEPTION(TTXTParseError, SubtitleFormatParseError);
@ -102,7 +103,7 @@ void TTXTSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename
AssDialogue *TTXTSubtitleFormat::ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const {
// Get time
wxString sampleTime = node->GetAttribute("sampleTime", "00:00:00.000");
AssTime time(from_wx(sampleTime));
agi::Time time(from_wx(sampleTime));
// Set end time of last line
if (prev)
@ -233,7 +234,7 @@ void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, const AssDialogue *prev, con
// If it doesn't start at the end of previous, add blank
if (prev && prev->End != line->Start) {
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample");
node->AddAttribute("sampleTime", to_wx("0" + prev->End.GetAssFormated(true)));
node->AddAttribute("sampleTime", to_wx("0" + prev->End.GetAssFormatted(true)));
node->AddAttribute("xml:space", "preserve");
root->AddChild(node);
node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, "", ""));
@ -241,7 +242,7 @@ void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, const AssDialogue *prev, con
// Generate and insert node
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample");
node->AddAttribute("sampleTime", to_wx("0" + line->Start.GetAssFormated(true)));
node->AddAttribute("sampleTime", to_wx("0" + line->Start.GetAssFormatted(true)));
node->AddAttribute("xml:space", "preserve");
root->AddChild(node);
node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, "", to_wx(line->Text)));
@ -256,7 +257,7 @@ void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
ConvertNewlines(file, "\r\n");
// Find last line
AssTime lastTime;
agi::Time lastTime;
if (!file.Events.empty())
lastTime = file.Events.back().End;

View File

@ -44,6 +44,7 @@
#include <libaegisub/background_runner.h>
#include <libaegisub/dispatch.h>
#include <libaegisub/exception.h>
#include <libaegisub/log.h>
#include <libaegisub/make_unique.h>
#include <libaegisub/util.h>

View File

@ -34,15 +34,15 @@
#include "timeedit_ctrl.h"
#include <functional>
#include "ass_time.h"
#include "compat.h"
#include "include/aegisub/context.h"
#include "options.h"
#include "project.h"
#include "utils.h"
#include <libaegisub/ass/time.h>
#include <functional>
#include <wx/menu.h>
#include <wx/valtext.h>
@ -67,7 +67,7 @@ TimeEdit::TimeEdit(wxWindow* parent, wxWindowID id, agi::Context *c, const std::
SetValidator(val);
// Other stuff
if (value.empty()) SetValue(to_wx(time.GetAssFormated()));
if (value.empty()) SetValue(to_wx(time.GetAssFormatted()));
Bind(wxEVT_MENU, std::bind(&TimeEdit::CopyTime, this), Time_Edit_Copy);
Bind(wxEVT_MENU, std::bind(&TimeEdit::PasteTime, this), Time_Edit_Paste);
@ -78,7 +78,7 @@ TimeEdit::TimeEdit(wxWindow* parent, wxWindowID id, agi::Context *c, const std::
Bind(wxEVT_KILL_FOCUS, &TimeEdit::OnFocusLost, this);
}
void TimeEdit::SetTime(AssTime new_time) {
void TimeEdit::SetTime(agi::Time new_time) {
if (time != new_time) {
time = new_time;
UpdateText();
@ -115,7 +115,7 @@ void TimeEdit::UpdateText() {
if (byFrame)
ChangeValue(std::to_wstring(c->project->Timecodes().FrameAtTime(time, isEnd ? agi::vfr::END : agi::vfr::START)));
else
ChangeValue(to_wx(time.GetAssFormated()));
ChangeValue(to_wx(time.GetAssFormatted()));
}
void TimeEdit::OnKeyDown(wxKeyEvent &event) {
@ -190,7 +190,7 @@ void TimeEdit::OnChar(wxKeyEvent &event) {
// Overwrite the digit
text[start] = (char)key;
time = text;
SetValue(to_wx(time.GetAssFormated()));
SetValue(to_wx(time.GetAssFormatted()));
SetInsertionPoint(start + 1);
}
@ -229,8 +229,8 @@ void TimeEdit::PasteTime() {
std::string text(GetClipboard());
if (text.empty()) return;
AssTime tempTime(text);
if (tempTime.GetAssFormated() == text) {
agi::Time tempTime(text);
if (tempTime.GetAssFormatted() == text) {
SetTime(tempTime);
SetSelection(0, GetValue().size());

View File

@ -27,23 +27,17 @@
//
// Aegisub Project http://www.aegisub.org/
/// @file timeedit_ctrl.h
/// @see timeedit_ctrl.cpp
/// @ingroup custom_control
///
#include <libaegisub/ass/time.h>
#include <libaegisub/signal.h>
#include <wx/textctrl.h>
#include "ass_time.h"
#include <libaegisub/signal.h>
namespace agi {
class OptionValue;
struct Context;
}
/// @brief A text edit control for editing AssTime objects
/// @brief A text edit control for editing agi::Time objects
///
/// This control constrains values to valid times, and can display the time
/// being edited as either a h:mm:ss.cc formatted time, or a frame number
@ -51,7 +45,7 @@ class TimeEdit final : public wxTextCtrl {
bool byFrame = false; ///< Is the time displayed as a frame number?
agi::Context *c; ///< Project context
bool isEnd; ///< Should the time be treated as an end time for time <-> frame conversions?
AssTime time; ///< The time, which may be displayed as either a frame number or time
agi::Time time; ///< The time, which may be displayed as either a frame number or time
bool insert; ///< If true, disable overwriting behavior in time mode
agi::signal::Connection insert_opt;
@ -78,10 +72,10 @@ class TimeEdit final : public wxTextCtrl {
#endif
public:
/// Get the current time as an AssTime object
AssTime GetTime() const { return time; }
/// Get the current time as an agi::Time object
agi::Time GetTime() const { return time; }
/// Set the time
void SetTime(AssTime time);
void SetTime(agi::Time time);
/// Get the current time as a frame number, or 0 if timecodes are unavailable
int GetFrame() const;

View File

@ -115,7 +115,7 @@ void VideoBox::UpdateTimeBoxes() {
int time = context->videoController->TimeAtFrame(frame, agi::vfr::EXACT);
// Set the text box for frame number and time
VideoPosition->SetValue(fmt_wx("%s - %d", AssTime(time).GetAssFormated(true), frame));
VideoPosition->SetValue(fmt_wx("%s - %d", agi::Time(time).GetAssFormatted(true), frame));
if (boost::binary_search(context->project->Keyframes(), frame)) {
// Set the background color to indicate this is a keyframe
VideoPosition->SetBackgroundColour(to_wx(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColor()));

View File

@ -31,7 +31,6 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_time.h"
#include "audio_controller.h"
#include "compat.h"
#include "include/aegisub/context.h"
@ -42,6 +41,8 @@
#include "async_video_provider.h"
#include "utils.h"
#include <libaegisub/ass/time.h>
#include <wx/log.h>
VideoController::VideoController(agi::Context *c)

View File

@ -23,7 +23,6 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_style.h"
#include "ass_time.h"
#include "include/aegisub/context.h"
#include "selection_controller.h"
#include "video_controller.h"
@ -32,6 +31,7 @@
#include "visual_tool_drag.h"
#include "visual_tool_vector_clip.h"
#include <libaegisub/ass/time.h>
#include <libaegisub/format.h>
#include <libaegisub/of_type_adaptor.h>

84
tests/tests/time.cpp Normal file
View File

@ -0,0 +1,84 @@
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <main.h>
#include <libaegisub/ass/smpte.h>
#include <libaegisub/ass/time.h>
using agi::Time;
TEST(lagi_time, out_of_range_times) {
EXPECT_EQ(0, (int)Time(-1));
EXPECT_EQ(10 * 60 * 60 * 1000 - 10, (int)Time(10 * 60 * 60 * 1000));
}
TEST(lagi_time, rounds_to_cs) {
EXPECT_EQ(10, (int)Time(14));
}
TEST(lagi_time, cs_formatting) {
EXPECT_STREQ("1:23:45.67", Time((((1 * 60) + 23) * 60 + 45) * 1000 + 670).GetAssFormatted().c_str());
}
TEST(lagi_time, ms_formatting) {
EXPECT_STREQ("1:23:45.678", Time((((1 * 60) + 23) * 60 + 45) * 1000 + 678).GetAssFormatted(true).c_str());
}
TEST(lagi_time, well_formed_ass_time_parse) {
EXPECT_STREQ("1:23:45.67", Time("1:23:45.67").GetAssFormatted().c_str());
}
TEST(lagi_time, missing_components) {
EXPECT_STREQ("0:23:45.67", Time("23:45.67").GetAssFormatted().c_str());
EXPECT_STREQ("0:00:45.67", Time("45.67").GetAssFormatted().c_str());
EXPECT_STREQ("0:00:45.60", Time("45.6").GetAssFormatted().c_str());
EXPECT_STREQ("0:00:45.00", Time("45").GetAssFormatted().c_str());
}
TEST(lagi_time, out_of_range_compontents) {
EXPECT_STREQ("1:23:45.67", Time("0:83:45.67").GetAssFormatted().c_str());
EXPECT_STREQ("0:01:40.00", Time("100").GetAssFormatted().c_str());
}
TEST(lagi_time, comma_decimal) {
EXPECT_STREQ("1:23:45.67", Time("1:23:45,67").GetAssFormatted().c_str());
}
TEST(lagi_time, component_getters) {
Time t("1:23:45.67");
EXPECT_EQ(1, t.GetTimeHours());
EXPECT_EQ(23, t.GetTimeMinutes());
EXPECT_EQ(45, t.GetTimeSeconds());
EXPECT_EQ(67, t.GetTimeCentiseconds());
EXPECT_EQ(670, t.GetTimeMiliseconds());
}
TEST(lagi_time, srt_time) {
EXPECT_STREQ("1:23:45.678", Time("1:23:45,678").GetAssFormatted(true).c_str());
}
TEST(lagi_time, smpte_parse_valid) {
EXPECT_STREQ("1:23:45.44", agi::SmpteFormatter(25).FromSMPTE("1:23:45:11").GetAssFormatted().c_str());
}
TEST(lagi_time, smpte_parse_invalid) {
EXPECT_EQ(0, (int)agi::SmpteFormatter(25).FromSMPTE("1:23:45.11"));
}
TEST(lagi_time, to_smpte) {
EXPECT_STREQ("01:23:45:11", agi::SmpteFormatter(25).ToSMPTE(Time("1:23:45.44")).c_str());
}