Skip to content
Open
5 changes: 4 additions & 1 deletion libaegisub/common/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ std::string Color::GetHexFormatted(bool rgba) const {
}

std::string Color::GetRgbFormatted() const {
return agi::format("rgb(%d, %d, %d)", r, g, b);
if (a)
return agi::format("rgba(%d, %d, %d, %d)", r, g, b, a);
else
return agi::format("rgb(%d, %d, %d)", r, g, b);
}

}
1 change: 1 addition & 0 deletions libaegisub/common/option.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class ConfigVisitor final : public json::ConstVisitor {
if ((size == 4 && string[0] == '#') ||
(size == 7 && string[0] == '#') ||
(size >= 10 && string.starts_with("rgb(")) ||
(size >= 13 && string.starts_with("rgba(")) ||
((size == 9 || size == 10) && string.starts_with("&H")))
{
values.push_back(std::make_unique<OptionValueColor>(name, agi::Color(string)));
Expand Down
1 change: 1 addition & 0 deletions libaegisub/common/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct color_grammar : qi::grammar<Iterator, agi::Color()> {

css_color
= "rgb(" >> blank >> rgb_component >> comma >> rgb_component >> comma >> rgb_component >> blank >> ')'
| "rgba(" >> blank >> rgb_component >> comma >> rgb_component >> comma >> rgb_component >> comma >> rgb_component >> blank >> ')'
| '#' >> hex_byte >> hex_byte >> hex_byte
| '#' >> hex_char >> hex_char >> hex_char
;
Expand Down
13 changes: 11 additions & 2 deletions src/audio_display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,17 @@ void AudioDisplay::PaintMarkers(wxDC &dc, TimeRange updtime)
{
int marker_x = RelativeXFromTime(marker->GetPosition());

dc.SetPen(marker->GetStyle());
dc.DrawLine(marker_x, audio_top, marker_x, audio_top+audio_height);
if (marker->GetWidth() == 0) {
dc.SetPen(marker->GetStyle());
dc.DrawLine(marker_x, audio_top, marker_x, audio_top+audio_height);
} else {
int w = RelativeXFromTime((marker->GetPosition() + marker->GetWidth() - 1) + (ms_per_pixel - 1)) - marker_x - 1; // Add (ms_per_pixel - 1) to get "rounding up" behavior

dc.SetBrush(wxBrush(marker->GetStyle().GetColour()));
dc.SetPen(*wxTRANSPARENT_PEN);

dc.DrawRectangle(marker_x, audio_top, w, audio_height);
}

if (marker->GetFeet() == AudioMarker::Feet_None) continue;

Expand Down
65 changes: 60 additions & 5 deletions src/audio_marker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,36 @@ void AudioMarkerProviderKeyframes::GetMarkers(TimeRange const& range, AudioMarke
out.push_back(&*a);
}

class VideoPositionSnapPoint final : public AudioMarker {
int position = -1;

public:
void SetPosition(int new_pos) { position = new_pos; }

int GetPosition() const override { return position; }
FeetStyle GetFeet() const override { return Feet_None; }
wxPen GetStyle() const override { return wxPen{}; }
};

class VideoPositionRange final : public AudioMarker {
Pen style;
int position = -1;
int width = 0;

public:
VideoPositionRange(bool previous) : style{previous ? "Colour/Audio Display/Previous Frame Range" : "Colour/Audio Display/Current Frame Range"} { }

void SetPosition(int frame, int nextframe) {
position = frame + 1;
width = nextframe - frame - 1;
}

int GetPosition() const override { return position; }
int GetWidth() const override { return width; }
FeetStyle GetFeet() const override { return Feet_None; }
wxPen GetStyle() const override { return style; }
};

class VideoPositionMarker final : public AudioMarker {
Pen style{"Colour/Audio Display/Play Cursor"};
int position = -1;
Expand All @@ -92,7 +122,6 @@ class VideoPositionMarker final : public AudioMarker {
int GetPosition() const override { return position; }
FeetStyle GetFeet() const override { return Feet_None; }
wxPen GetStyle() const override { return style; }
operator int() const { return position; }
};

VideoPositionMarkerProvider::VideoPositionMarkerProvider(agi::Context *c)
Expand All @@ -105,26 +134,52 @@ VideoPositionMarkerProvider::VideoPositionMarkerProvider(agi::Context *c)

VideoPositionMarkerProvider::~VideoPositionMarkerProvider() { }

void VideoPositionMarkerProvider::Update(int frame_number) {
void VideoPositionMarkerProvider::SetPositions(int frame_number) {
marker->SetPosition(vc->TimeAtFrame(frame_number));
range1->SetPosition(vc->TimeAtFrame(frame_number - 1), vc->TimeAtFrame(frame_number));
range2->SetPosition(vc->TimeAtFrame(frame_number), vc->TimeAtFrame(frame_number + 1));
snap1->SetPosition(vc->TimeAtFrame(frame_number, agi::vfr::START));
snap2->SetPosition(vc->TimeAtFrame(frame_number, agi::vfr::END));
}

void VideoPositionMarkerProvider::Update(int frame_number) {
SetPositions(frame_number);
AnnounceMarkerMoved();
}

void VideoPositionMarkerProvider::OptChanged(agi::OptionValue const& opt) {
if (opt.GetBool()) {
video_seek_slot.Unblock();
marker = std::make_unique<VideoPositionMarker>();
marker->SetPosition(vc->GetFrameN());
range1 = std::make_unique<VideoPositionRange>(true);
range2 = std::make_unique<VideoPositionRange>(false);
snap1 = std::make_unique<VideoPositionSnapPoint>();
snap2 = std::make_unique<VideoPositionSnapPoint>();
SetPositions(vc->GetFrameN());
}
else {
video_seek_slot.Block();
marker.reset();
range1.reset();
range2.reset();
snap1.reset();
snap2.reset();
}
}

void VideoPositionMarkerProvider::GetMarkers(const TimeRange &range, AudioMarkerVector &out) const {
if (marker && range.contains(*marker))
void VideoPositionMarkerProvider::GetMarkers(const TimeRange &timerange, AudioMarkerVector &out) const {
if (marker && timerange.contains(marker->GetPosition()))
out.push_back(marker.get());

for (auto range : {range1.get(), range2.get()})
if (range && timerange.overlaps({range->GetPosition(), range->GetPosition() + range->GetWidth() - 1}))
out.push_back(range);
}

void VideoPositionMarkerProvider::GetSnapMarkers(const TimeRange &timerange, AudioMarkerVector &out) const {
for (auto snap : {snap1.get(), snap2.get()})
if (snap && timerange.contains(snap->GetPosition()))
out.push_back(snap);
}

SecondsMarkerProvider::SecondsMarkerProvider()
Expand Down
17 changes: 16 additions & 1 deletion src/audio_marker.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class Pen;
class Project;
class VideoController;
class VideoPositionMarker;
class VideoPositionRange;
class VideoPositionSnapPoint;
class wxPen;

namespace agi {
Expand All @@ -54,6 +56,10 @@ class AudioMarker {
/// @return The marker's position in milliseconds
virtual int GetPosition() const = 0;

/// @brief Get the marker's width
/// @return The marker's width if the marker should be a rectangle, or 0 if the marker should be drawn as a line (with the thickness specified by the style)
virtual int GetWidth() const { return 0; }

/// @brief Get the marker's drawing style
/// @return A pen object describing the marker's drawing style
virtual wxPen GetStyle() const = 0;
Expand All @@ -73,9 +79,12 @@ class AudioMarkerProvider {

~AudioMarkerProvider() = default;
public:
/// @brief Return markers in a time range
/// @brief Return markers in a time range to render in audio display
virtual void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const = 0;

/// @brief Return markers in a time range to snap timed lines to
virtual void GetSnapMarkers(const TimeRange &range, AudioMarkerVector &out) const { GetMarkers(range, out); };

DEFINE_SIGNAL_ADDERS(AnnounceMarkerMoved, AddMarkerMovedListener)
};

Expand Down Expand Up @@ -143,10 +152,15 @@ class VideoPositionMarkerProvider final : public AudioMarkerProvider {
VideoController *vc;

std::unique_ptr<VideoPositionMarker> marker;
std::unique_ptr<VideoPositionRange> range1;
std::unique_ptr<VideoPositionRange> range2;
std::unique_ptr<VideoPositionSnapPoint> snap1;
std::unique_ptr<VideoPositionSnapPoint> snap2;

agi::signal::Connection video_seek_slot;
agi::signal::Connection enable_opt_changed_slot;

void SetPositions(int frame_number);
void Update(int frame_number);
void OptChanged(agi::OptionValue const& opt);

Expand All @@ -155,6 +169,7 @@ class VideoPositionMarkerProvider final : public AudioMarkerProvider {
~VideoPositionMarkerProvider();

void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const override;
void GetSnapMarkers(const TimeRange &range, AudioMarkerVector &out) const override;
};

/// Marker provider for lines every second
Expand Down
6 changes: 3 additions & 3 deletions src/audio_timing_dialogue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ void AudioTimingControllerDialogue::GetMarkers(const TimeRange &range, AudioMark
boost::upper_bound(markers, range.end(), marker_ptr_cmp()),
back_inserter(out_markers));

keyframes_provider.GetMarkers(range, out_markers);
video_position_provider.GetMarkers(range, out_markers);
keyframes_provider.GetMarkers(range, out_markers);
}

void AudioTimingControllerDialogue::OnSelectedSetChanged()
Expand Down Expand Up @@ -897,8 +897,8 @@ int AudioTimingControllerDialogue::SnapMarkers(int snap_range, std::vector<Audio

snap_markers.clear();
TimeRange range(pos - snap_range, pos + snap_range);
keyframes_provider.GetMarkers(range, snap_markers);
video_position_provider.GetMarkers(range, snap_markers);
keyframes_provider.GetSnapMarkers(range, snap_markers);
video_position_provider.GetSnapMarkers(range, snap_markers);

for (const auto marker : snap_markers)
{
Expand Down
2 changes: 2 additions & 0 deletions src/libresrc/default_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
"Line boundary End" : "rgb(0, 0, 216)",
"Line boundary Start" : "rgb(216, 0, 0)",
"Play Cursor" : "rgb(255,255,255)",
"Current Frame Range" : "rgba(255,255,255,170)",
"Previous Frame Range" : "rgba(255,255,255,210)",
"Seconds Line" : "rgb(0,100,255)",
"Spectrum" : "Icy Blue",
"Syllable Boundaries" : "rgb(255,255,0)",
Expand Down
36 changes: 19 additions & 17 deletions src/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ void General(wxTreebook *book, Preferences *parent) {
wxString autoload_modes[] = { _("Never"), _("Always"), _("Ask") };
wxArrayString autoload_modes_arr(3, autoload_modes);
p->OptionChoice(general, _("Automatically load linked files"), autoload_modes_arr, "App/Auto/Load Linked Files");
p->OptionAdd(general, _("Undo Levels"), "Limits/Undo Levels", 2, 10000);
p->OptionAdd(general, _("Undo Levels"), "Limits/Undo Levels", {.min = 2, .max = 10000});

auto recent = p->PageSizer(_("Recently Used Lists"));
p->OptionAdd(recent, _("Files"), "Limits/MRU", 0, 16);
p->OptionAdd(recent, _("Files"), "Limits/MRU", {.min = 0, .max = 16});
p->OptionAdd(recent, _("Find/Replace"), "Limits/Find Replace");

p->SetSizerAndFit(p->sizer);
Expand Down Expand Up @@ -136,13 +136,13 @@ void Audio(wxTreebook *book, Preferences *parent) {
p->OptionAdd(general, _("Auto-focus on mouse over"), "Audio/Auto/Focus");
p->OptionAdd(general, _("Play audio when stepping in video"), "Audio/Plays When Stepping Video");
p->OptionAdd(general, _("Left-click-drag moves end marker"), "Audio/Drag Timing");
p->OptionAdd(general, _("Default timing length (ms)"), "Timing/Default Duration", 0, 36000);
p->OptionAdd(general, _("Default lead-in length (ms)"), "Audio/Lead/IN", 0, 36000);
p->OptionAdd(general, _("Default lead-out length (ms)"), "Audio/Lead/OUT", 0, 36000);
p->OptionAdd(general, _("Default timing length (ms)"), "Timing/Default Duration", {.min = 0, .max = 36000});
p->OptionAdd(general, _("Default lead-in length (ms)"), "Audio/Lead/IN", {.min = 0, .max = 36000});
p->OptionAdd(general, _("Default lead-out length (ms)"), "Audio/Lead/OUT", {.min = 0, .max = 36000});

p->OptionAdd(general, _("Marker drag-start sensitivity (px)"), "Audio/Start Drag Sensitivity", 1, 15);
p->OptionAdd(general, _("Line boundary thickness (px)"), "Audio/Line Boundaries Thickness", 1, 5);
p->OptionAdd(general, _("Maximum snap distance (px)"), "Audio/Snap/Distance", 0, 25);
p->OptionAdd(general, _("Marker drag-start sensitivity (px)"), "Audio/Start Drag Sensitivity", {.min = 1, .max = 15});
p->OptionAdd(general, _("Line boundary thickness (px)"), "Audio/Line Boundaries Thickness", {.min = 1, .max = 5});
p->OptionAdd(general, _("Maximum snap distance (px)"), "Audio/Snap/Distance", {.min = 0, .max = 25});

const wxString dtl_arr[] = { _("Don't show"), _("Show previous"), _("Show previous and next"), _("Show all") };
wxArrayString choice_dtl(4, dtl_arr);
Expand Down Expand Up @@ -223,9 +223,9 @@ void Interface(wxTreebook *book, Preferences *parent) {
p->OptionFont(edit_box, "Subtitle/Edit Box/");

auto character_count = p->PageSizer(_("Character Counter"));
p->OptionAdd(character_count, _("Maximum characters per line"), "Subtitle/Character Limit", 0, 1000);
p->OptionAdd(character_count, _("Characters Per Second Warning Threshold"), "Subtitle/Character Counter/CPS Warning Threshold", 0, 1000);
p->OptionAdd(character_count, _("Characters Per Second Error Threshold"), "Subtitle/Character Counter/CPS Error Threshold", 0, 1000);
p->OptionAdd(character_count, _("Maximum characters per line"), "Subtitle/Character Limit", {.min = 0, .max = 1000});
p->OptionAdd(character_count, _("Characters Per Second Warning Threshold"), "Subtitle/Character Counter/CPS Warning Threshold", {.min = 0, .max = 1000});
p->OptionAdd(character_count, _("Characters Per Second Error Threshold"), "Subtitle/Character Counter/CPS Error Threshold", {.min = 0, .max = 1000});
p->OptionAdd(character_count, _("Ignore whitespace"), "Subtitle/Character Counter/Ignore Whitespace");
p->OptionAdd(character_count, _("Ignore punctuation"), "Subtitle/Character Counter/Ignore Punctuation");

Expand Down Expand Up @@ -253,6 +253,8 @@ void Interface_Colours(wxTreebook *book, Preferences *parent) {

auto audio = p->PageSizer(_("Audio Display"));
p->OptionAdd(audio, _("Play cursor"), "Colour/Audio Display/Play Cursor");
p->OptionAdd(audio, _("Current frame range"), "Colour/Audio Display/Current Frame Range", {.alpha = true});
p->OptionAdd(audio, _("Previous frame range"), "Colour/Audio Display/Previous Frame Range", {.alpha = true});
p->OptionAdd(audio, _("Line boundary start"), "Colour/Audio Display/Line boundary Start");
p->OptionAdd(audio, _("Line boundary end"), "Colour/Audio Display/Line boundary End");
p->OptionAdd(audio, _("Line boundary inactive line"), "Colour/Audio Display/Line Boundary Inactive Line");
Expand Down Expand Up @@ -310,7 +312,7 @@ void Interface_Colours(wxTreebook *book, Preferences *parent) {

// Separate sizer to prevent the colors in the visual tools section from getting resized
auto visual_tools_alpha = p->PageSizer(_("Visual Typesetting Tools Alpha"));
p->OptionAdd(visual_tools_alpha, _("Shaded Area"), "Colour/Visual Tools/Shaded Area Alpha", 0, 1, 0.1);
p->OptionAdd(visual_tools_alpha, _("Shaded Area"), "Colour/Visual Tools/Shaded Area Alpha", {.min = 0, .max = 1, .inc = 0.1});

p->sizer = main_sizer;

Expand All @@ -325,7 +327,7 @@ void Backup(wxTreebook *book, Preferences *parent) {
wxControl *cb = p->OptionAdd(save, _("Enable"), "App/Auto/Save");
p->CellSkip(save);
p->EnableIfChecked(cb,
p->OptionAdd(save, _("Interval in seconds"), "App/Auto/Save Every Seconds", 1));
p->OptionAdd(save, _("Interval in seconds"), "App/Auto/Save Every Seconds", {.min = 1}));
p->OptionBrowse(save, _("Path"), "Path/Auto/Save", cb, true);
p->OptionAdd(save, _("Autosave after every change"), "App/Auto/Save on Every Change");

Expand Down Expand Up @@ -403,7 +405,7 @@ void Advanced_Audio(wxTreebook *book, Preferences *parent) {
wxArrayString sc_choice(5, sc_arr);
p->OptionChoice(spectrum, _("Frequency mapping"), sc_choice, "Audio/Renderer/Spectrum/FreqCurve");

p->OptionAdd(spectrum, _("Cache memory max (MB)"), "Audio/Renderer/Spectrum/Memory Max", 2, 1024);
p->OptionAdd(spectrum, _("Cache memory max (MB)"), "Audio/Renderer/Spectrum/Memory Max", {.min = 2, .max = 1024});

#ifdef WITH_AVISYNTH
auto avisynth = p->PageSizer("Avisynth");
Expand Down Expand Up @@ -435,8 +437,8 @@ void Advanced_Audio(wxTreebook *book, Preferences *parent) {

#ifdef WITH_DIRECTSOUND
auto dsound = p->PageSizer("DirectSound");
p->OptionAdd(dsound, _("Buffer latency"), "Player/Audio/DirectSound/Buffer Latency", 1, 1000);
p->OptionAdd(dsound, _("Buffer length"), "Player/Audio/DirectSound/Buffer Length", 1, 100);
p->OptionAdd(dsound, _("Buffer latency"), "Player/Audio/DirectSound/Buffer Latency", {.min = 1, .max = 1000});
p->OptionAdd(dsound, _("Buffer length"), "Player/Audio/DirectSound/Buffer Length", {.min = 1, .max = 100});
#endif

p->SetSizerAndFit(p->sizer);
Expand Down Expand Up @@ -468,7 +470,7 @@ void Advanced_Video(wxTreebook *book, Preferences *parent) {
wxArrayString log_levels_choice(8, log_levels);
p->OptionChoice(ffms, _("Debug log verbosity"), log_levels_choice, "Provider/FFmpegSource/Log Level", true);

p->OptionAdd(ffms, _("Decoding threads"), "Provider/Video/FFmpegSource/Decoding Threads", -1);
p->OptionAdd(ffms, _("Decoding threads"), "Provider/Video/FFmpegSource/Decoding Threads", {.min = -1});
p->OptionAdd(ffms, _("Enable unsafe seeking"), "Provider/Video/FFmpegSource/Unsafe Seeking");
#endif

Expand Down
8 changes: 4 additions & 4 deletions src/preferences_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void OptionPage::CellSkip(PageSection section) {
section.sizer->AddStretchSpacer();
}

wxControl *OptionPage::OptionAdd(PageSection section, const wxString &name, const char *opt_name, double min, double max, double inc) {
wxControl *OptionPage::OptionAdd(PageSection section, const wxString &name, const char *opt_name, OptionAddArgs kwargs) {
parent->AddChangeableOption(opt_name);
const auto opt = OPT_GET(opt_name);

Expand All @@ -140,14 +140,14 @@ wxControl *OptionPage::OptionAdd(PageSection section, const wxString &name, cons
}

case agi::OptionType::Int: {
auto sc = new wxSpinCtrl(section.box, -1, std::to_wstring((int)opt->GetInt()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, opt->GetInt());
auto sc = new wxSpinCtrl(section.box, -1, std::to_wstring((int)opt->GetInt()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, kwargs.min, kwargs.max, opt->GetInt());
sc->Bind(wxEVT_SPINCTRL, IntUpdater(opt_name, parent));
Add(section, name, sc);
return sc;
}

case agi::OptionType::Double: {
auto scd = new wxSpinCtrlDouble(section.box, -1, std::to_wstring(opt->GetDouble()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, opt->GetDouble(), inc);
auto scd = new wxSpinCtrlDouble(section.box, -1, std::to_wstring(opt->GetDouble()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, kwargs.min, kwargs.max, opt->GetDouble(), kwargs.inc);
scd->Bind(wxEVT_SPINCTRLDOUBLE, DoubleUpdater(opt_name, parent));
Add(section, name, scd);
return scd;
Expand All @@ -161,7 +161,7 @@ wxControl *OptionPage::OptionAdd(PageSection section, const wxString &name, cons
}

case agi::OptionType::Color: {
auto cb = new ColourButton(section.box, wxSize(40,10), false, opt->GetColor());
auto cb = new ColourButton(section.box, wxSize(40,10), kwargs.alpha, opt->GetColor());
cb->Bind(EVT_COLOR, ColourUpdater(opt_name, parent));
Add(section, name, cb);
return cb;
Expand Down
10 changes: 9 additions & 1 deletion src/preferences_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ struct PageSection {
wxWindow *box;
};

struct OptionAddArgs {
double min = 0;
double max = INT_MAX;
double inc = 1;
bool alpha = false;
};

class OptionPage : public wxScrolled<wxPanel> {
template<class T>
void Add(PageSection section, wxString const& label, T *control);
Expand All @@ -48,7 +55,8 @@ class OptionPage : public wxScrolled<wxPanel> {
PageSection PageSizer(wxString name);

void CellSkip(PageSection section);
wxControl *OptionAdd(PageSection section, const wxString &name, const char *opt_name, double min=0, double max=INT_MAX, double inc=1);

wxControl *OptionAdd(PageSection section, const wxString &name, const char *opt_name, OptionAddArgs kwargs = {});
void OptionChoice(PageSection section, const wxString &name, const wxArrayString &choices, const char *opt_name, bool translate = false);
void OptionBrowse(PageSection section, const wxString &name, const char *opt_name, wxControl *enabler = nullptr, bool do_enable = false);
void OptionFont(PageSection section, std::string opt_prefix);
Expand Down
Loading
Loading