Example #1
0
SubsController::SubsController(agi::Context *context)
: context(context)
, undo_connection(context->ass->AddUndoManager(&SubsController::OnCommit, this))
, commit_id(0)
, saved_commit_id(0)
, autosaved_commit_id(0)
{
	autosave_timer_changed(&autosave_timer);
	OPT_SUB("App/Auto/Save", autosave_timer_changed, &autosave_timer);
	OPT_SUB("App/Auto/Save Every Seconds", autosave_timer_changed, &autosave_timer);

	autosave_timer.Bind(wxEVT_TIMER, [=](wxTimerEvent&) {
		try {
			auto fn = AutoSave();
			if (!fn.empty())
				StatusTimeout(wxString::Format(_("File backup saved as \"%s\"."), fn.wstring()));
		}
		catch (const agi::Exception& err) {
			StatusTimeout(to_wx("Exception when attempting to autosave file: " + err.GetMessage()));
		}
		catch (...) {
			StatusTimeout("Unhandled exception when attempting to autosave file.");
		}
	});
}
Example #2
0
AudioController::AudioController(agi::Context *context)
: context(context)
, subtitle_save_slot(context->ass->AddFileSaveListener(&AudioController::OnSubtitlesSave, this))
, player(0)
, provider(0)
, playback_mode(PM_NotPlaying)
, playback_timer(this)
{
	Bind(wxEVT_TIMER, &AudioController::OnPlaybackTimer, this, playback_timer.GetId());

#ifdef wxHAS_POWER_EVENTS
	Bind(wxEVT_POWER_SUSPENDED, &AudioController::OnComputerSuspending, this);
	Bind(wxEVT_POWER_RESUME, &AudioController::OnComputerResuming, this);
#endif

	OPT_SUB("Audio/Player", &AudioController::OnAudioPlayerChanged, this);
	OPT_SUB("Audio/Provider", &AudioController::OnAudioProviderChanged, this);
	OPT_SUB("Audio/Cache/Type", &AudioController::OnAudioProviderChanged, this);

#ifdef WITH_FFMS2
	// As with the video ones, it'd be nice to figure out a decent way to move
	// this to the provider itself
	OPT_SUB("Provider/Audio/FFmpegSource/Decode Error Handling", &AudioController::OnAudioProviderChanged, this);
#endif
}
Example #3
0
Project::Project(agi::Context *c) : context(c) {
	OPT_SUB("Audio/Cache/Type", &Project::ReloadAudio, this);
	OPT_SUB("Audio/Provider", &Project::ReloadAudio, this);
	OPT_SUB("Provider/Audio/FFmpegSource/Decode Error Handling", &Project::ReloadAudio, this);
	OPT_SUB("Provider/Avisynth/Allow Ancient", &Project::ReloadVideo, this);
	OPT_SUB("Provider/Avisynth/Memory Max", &Project::ReloadVideo, this);
	OPT_SUB("Provider/Video/FFmpegSource/Decoding Threads", &Project::ReloadVideo, this);
	OPT_SUB("Provider/Video/FFmpegSource/Unsafe Seeking", &Project::ReloadVideo, this);
	OPT_SUB("Subtitle/Provider", &Project::ReloadVideo, this);
	OPT_SUB("Video/Force BT.601", &Project::ReloadVideo, this);
	OPT_SUB("Video/Provider", &Project::ReloadVideo, this);
}
Example #4
0
AudioTimingControllerKaraoke::AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed)
: file_changed_slot(file_changed)
, c(c)
, active_line(c->selectionController->GetActiveLine())
, kara(kara)
, cur_syl(0)
, separator_pen("Colour/Audio Display/Syllable Boundaries", "Audio/Line Boundaries Thickness", wxPENSTYLE_DOT)
, start_pen("Colour/Audio Display/Line boundary Start", "Audio/Line Boundaries Thickness")
, end_pen("Colour/Audio Display/Line boundary End", "Audio/Line Boundaries Thickness")
, start_marker(active_line->Start, &start_pen, AudioMarker::Feet_Right)
, end_marker(active_line->End, &end_pen, AudioMarker::Feet_Left)
, keyframes_provider(c, "Audio/Display/Draw/Keyframes in Karaoke Mode")
, video_position_provider(c)
, auto_commit(OPT_GET("Audio/Auto/Commit")->GetBool())
, commit_id(-1)
{
	slots.push_back(kara->AddSyllablesChangedListener(&AudioTimingControllerKaraoke::Revert, this));
	slots.push_back(OPT_SUB("Audio/Auto/Commit", &AudioTimingControllerKaraoke::OnAutoCommitChange, this));

	keyframes_provider.AddMarkerMovedListener(std::bind(std::ref(AnnounceMarkerMoved)));
	video_position_provider.AddMarkerMovedListener(std::bind(std::ref(AnnounceMarkerMoved)));

	Revert();

}
Example #5
0
VideoPositionMarkerProvider::VideoPositionMarkerProvider(agi::Context *c)
: vc(c->videoController)
, video_seek_slot(vc->AddSeekListener(&VideoPositionMarkerProvider::Update, this))
, enable_opt_changed_slot(OPT_SUB("Audio/Display/Draw/Video Position", &VideoPositionMarkerProvider::OptChanged, this))
{
	OptChanged(*OPT_GET("Audio/Display/Draw/Video Position"));
}
Example #6
0
/// @brief Constructor
///
VideoContext::VideoContext()
: playback(this)
, startMS(0)
, endFrame(0)
, frame_n(0)
, arValue(1.)
, arType(0)
, hasSubtitles(false)
, playAudioOnStep(OPT_GET("Audio/Plays When Stepping Video"))
, VFR_Input(videoFPS)
, VFR_Output(ovrFPS)
{
	Bind(EVT_VIDEO_ERROR, &VideoContext::OnVideoError, this);
	Bind(EVT_SUBTITLES_ERROR, &VideoContext::OnSubtitlesError, this);
	Bind(wxEVT_TIMER, &VideoContext::OnPlayTimer, this);

	OPT_SUB("Subtitle/Provider", &VideoContext::Reload, this);
	OPT_SUB("Video/Provider", &VideoContext::Reload, this);

	// It would be nice to find a way to move these to the individual providers
	OPT_SUB("Provider/Avisynth/Allow Ancient", &VideoContext::Reload, this);
	OPT_SUB("Provider/Avisynth/Memory Max", &VideoContext::Reload, this);

	OPT_SUB("Provider/Video/FFmpegSource/Decoding Threads", &VideoContext::Reload, this);
	OPT_SUB("Provider/Video/FFmpegSource/Unsafe Seeking", &VideoContext::Reload, this);
	OPT_SUB("Video/Force BT.601", &VideoContext::Reload, this);
}
Example #7
0
AudioMarkerProviderKeyframes::AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name)
: vc(c->videoController)
, keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this))
, timecode_slot(vc->AddTimecodesListener(&AudioMarkerProviderKeyframes::Update, this))
, enabled_slot(OPT_SUB(opt_name, &AudioMarkerProviderKeyframes::Update, this))
, enabled_opt(OPT_GET(opt_name))
, style(new Pen("Colour/Audio Display/Keyframe"))
{
	Update();
}
Example #8
0
void AudioDisplay::OnAudioOpen(AudioProvider *provider)
{
	if (!audio_renderer_provider)
		ReloadRenderingSettings();

	audio_renderer->SetAudioProvider(provider);
	audio_renderer->SetCacheMaxSize(OPT_GET("Audio/Renderer/Spectrum/Memory Max")->GetInt() * 1024 * 1024);

	timeline->ChangeAudio(controller->GetDuration());

	ms_per_pixel = 0;
	SetZoomLevel(zoom_level);

	Refresh();

	if (provider)
	{
		if (connections.empty())
		{
			connections.push_back(controller->AddAudioCloseListener(&AudioDisplay::OnAudioOpen, this, nullptr));
			connections.push_back(controller->AddPlaybackPositionListener(&AudioDisplay::OnPlaybackPosition, this));
			connections.push_back(controller->AddPlaybackStopListener(&AudioDisplay::RemoveTrackCursor, this));
			connections.push_back(controller->AddTimingControllerListener(&AudioDisplay::OnTimingController, this));
			connections.push_back(OPT_SUB("Audio/Spectrum", &AudioDisplay::ReloadRenderingSettings, this));
			connections.push_back(OPT_SUB("Audio/Display/Waveform Style", &AudioDisplay::ReloadRenderingSettings, this));
			connections.push_back(OPT_SUB("Colour/Audio Display/Spectrum", &AudioDisplay::ReloadRenderingSettings, this));
			connections.push_back(OPT_SUB("Colour/Audio Display/Waveform", &AudioDisplay::ReloadRenderingSettings, this));
			connections.push_back(OPT_SUB("Audio/Renderer/Spectrum/Quality", &AudioDisplay::ReloadRenderingSettings, this));

			OnTimingController();
		}
	}
	else
	{
		connections.clear();
	}
}
Example #9
0
VideoSlider::VideoSlider (wxWindow* parent, agi::Context *c)
: wxWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE)
, c(c)
, val(0)
, max(1)
{
	SetClientSize(20,25);
	SetMinSize(wxSize(20, 25));
	slots.push_back(OPT_SUB("Video/Slider/Show Keyframes", &wxWindow::Refresh, this, false, (wxRect*)NULL));
	slots.push_back(c->videoController->AddSeekListener(&VideoSlider::SetValue, this));
	slots.push_back(c->videoController->AddVideoOpenListener(&VideoSlider::VideoOpened, this));
	slots.push_back(c->videoController->AddKeyframesListener(&VideoSlider::KeyframesChanged, this));

	if (c->videoController->IsLoaded()) {
		VideoOpened();
	}
}
Example #10
0
TimeEdit::TimeEdit(wxWindow* parent, wxWindowID id, agi::Context *c, const std::string& value, const wxSize& size, bool asEnd)
    : wxTextCtrl(parent, id, to_wx(value), wxDefaultPosition, size, wxTE_CENTRE | wxTE_PROCESS_ENTER)
    , c(c)
    , isEnd(asEnd)
    , insert(!OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool())
    , insert_opt(OPT_SUB("Subtitle/Time Edit/Insert Mode", &TimeEdit::OnInsertChanged, this))
{
    // Set validator
    wxTextValidator val(wxFILTER_INCLUDE_CHAR_LIST);
    wxString includes[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", ":", ","};
    val.SetIncludes(wxArrayString(countof(includes), includes));
    SetValidator(val);

    // Other stuff
    if (value.empty()) SetValue(to_wx(time.GetAssFormated()));

    Bind(wxEVT_MENU, std::bind(&TimeEdit::CopyTime, this), Time_Edit_Copy);
    Bind(wxEVT_MENU, std::bind(&TimeEdit::PasteTime, this), Time_Edit_Paste);
    Bind(wxEVT_TEXT, &TimeEdit::OnModified, this);
    Bind(wxEVT_CONTEXT_MENU, &TimeEdit::OnContextMenu, this);
    Bind(wxEVT_CHAR_HOOK, &TimeEdit::OnKeyDown, this);
    Bind(wxEVT_CHAR, &TimeEdit::OnChar, this);
    Bind(wxEVT_KILL_FOCUS, &TimeEdit::OnFocusLost, this);
}
Example #11
0
TimeEdit::TimeEdit(wxWindow* parent, wxWindowID id, agi::Context *c, const wxString& value, const wxSize& size, bool asEnd)
: wxTextCtrl(parent, id, value, wxDefaultPosition, size, wxTE_CENTRE | wxTE_PROCESS_ENTER)
, c(c)
, byFrame(false)
, isEnd(asEnd)
, insert(!OPT_GET("Subtitle/Time Edit/Insert Mode")->GetBool())
, insert_opt(OPT_SUB("Subtitle/Time Edit/Insert Mode", &TimeEdit::OnInsertChanged, this))
{
	// Set validator
	wxTextValidator val(wxFILTER_INCLUDE_CHAR_LIST);
	wxArrayString includes;
	includes.Add("0");
	includes.Add("1");
	includes.Add("2");
	includes.Add("3");
	includes.Add("4");
	includes.Add("5");
	includes.Add("6");
	includes.Add("7");
	includes.Add("8");
	includes.Add("9");
	includes.Add(".");
	includes.Add(":");
	val.SetIncludes(includes);
	SetValidator(val);

	// Other stuff
	if (!value) SetValue(time.GetASSFormated());

	Bind(wxEVT_COMMAND_MENU_SELECTED, std::tr1::bind(&TimeEdit::CopyTime, this), Time_Edit_Copy);
	Bind(wxEVT_COMMAND_MENU_SELECTED, std::tr1::bind(&TimeEdit::PasteTime, this), Time_Edit_Paste);
	Bind(wxEVT_COMMAND_TEXT_UPDATED, &TimeEdit::OnModified, this);
	Bind(wxEVT_CONTEXT_MENU, &TimeEdit::OnContextMenu, this);
	Bind(wxEVT_KEY_DOWN, &TimeEdit::OnKeyDown, this);
	Bind(wxEVT_KILL_FOCUS, &TimeEdit::OnFocusLost, this);
}
Example #12
0
SecondsMarkerProvider::SecondsMarkerProvider()
: pen(new Pen("Colour/Audio Display/Seconds Line", 1, wxPENSTYLE_DOT))
, enabled(OPT_GET("Audio/Display/Draw/Seconds"))
, enabled_opt_changed(OPT_SUB("Audio/Display/Draw/Seconds", &SecondsMarkerProvider::EnabledOptChanged, this))
{
}
Example #13
0
FrameMain::FrameMain()
: wxFrame(nullptr, -1, "", wxDefaultPosition, wxSize(920,700), wxDEFAULT_FRAME_STYLE | wxCLIP_CHILDREN)
, context(agi::util::make_unique<agi::Context>())
{
	StartupLog("Entering FrameMain constructor");

#ifdef __WXGTK__
	// XXX HACK XXX
	// We need to set LC_ALL to "" here for input methods to work reliably.
	setlocale(LC_ALL, "");

	// However LC_NUMERIC must be "C", otherwise some parsing fails.
	setlocale(LC_NUMERIC, "C");
#endif
#ifdef __APPLE__
	// When run from an app bundle, LC_CTYPE defaults to "C", which breaks on
	// anything involving unicode and in some cases number formatting.
	// The right thing to do here would be to query CoreFoundation for the user's
	// locale and add .UTF-8 to that, but :effort:
	LOG_D("locale") << setlocale(LC_ALL, nullptr);
	setlocale(LC_CTYPE, "en_US.UTF-8");
	LOG_D("locale") << setlocale(LC_ALL, nullptr);
#endif

	StartupLog("Initializing context models");
	memset(context.get(), 0, sizeof(*context));
	context->ass = new AssFile;

	StartupLog("Initializing context controls");
	context->subsController = new SubsController(context.get());
	context->ass->AddCommitListener(&FrameMain::UpdateTitle, this);
	context->subsController->AddFileOpenListener(&FrameMain::OnSubtitlesOpen, this);
	context->subsController->AddFileSaveListener(&FrameMain::UpdateTitle, this);

	context->audioController = new AudioController(context.get());
	context->audioController->AddAudioOpenListener(&FrameMain::OnAudioOpen, this);
	context->audioController->AddAudioCloseListener(&FrameMain::OnAudioClose, this);

	context->local_scripts = new Automation4::LocalScriptManager(context.get());

	// Initialized later due to that the selection controller is currently the subtitles grid
	context->selectionController = nullptr;

	context->videoController = VideoContext::Get(); // derp
	context->videoController->AddVideoOpenListener(&FrameMain::OnVideoOpen, this);

	StartupLog("Initializing context frames");
	context->parent = this;
	context->previousFocus = nullptr;

	StartupLog("Install PNG handler");
	wxImage::AddHandler(new wxPNGHandler);
#ifndef __APPLE__
	wxSafeYield();
#endif

	StartupLog("Apply saved Maximized state");
	if (OPT_GET("App/Maximized")->GetBool()) Maximize(true);

	StartupLog("Initialize toolbar");
	InitToolbar();

	StartupLog("Initialize menu bar");
	menu::GetMenuBar("main", this, context.get());

	StartupLog("Create status bar");
	CreateStatusBar(2);

	StartupLog("Set icon");
#ifdef _WIN32
	SetIcon(wxICON(wxicon));
#else
	wxIcon icon;
	icon.CopyFromBitmap(GETIMAGE(wxicon));
	SetIcon(icon);
#endif

	StartupLog("Create views and inner main window controls");
	context->dialog = new DialogManager;
	InitContents();
	OPT_SUB("Video/Detached/Enabled", &FrameMain::OnVideoDetach, this, agi::signal::_1);

	StartupLog("Complete context initialization");
	context->videoController->SetContext(context.get());

	StartupLog("Set up drag/drop target");
	SetDropTarget(new AegisubFileDropTarget(this));

	StartupLog("Load default file");
	context->subsController->Close();

	StartupLog("Display main window");
	AddFullScreenButton(this);
	Show();
	SetDisplayMode(1, 1);

	// Version checker
	StartupLog("Possibly perform automatic updates check");
	if (OPT_GET("App/First Start")->GetBool()) {
		OPT_SET("App/First Start")->SetBool(false);
#ifdef WITH_UPDATE_CHECKER
		int result = wxMessageBox(_("Do you want Aegisub to check for updates whenever it starts? You can still do it manually via the Help menu."),_("Check for updates?"), wxYES_NO | wxCENTER);
		OPT_SET("App/Auto/Check For Updates")->SetBool(result == wxYES);
		config::opt->Flush();
#endif
	}

#ifdef WITH_UPDATE_CHECKER
	PerformVersionCheck(false);
#endif

	Bind(FILE_LIST_DROPPED, &FrameMain::OnFilesDropped, this);

	StartupLog("Leaving FrameMain constructor");
}
Example #14
0
Thesaurus::Thesaurus()
: lang_listener(OPT_SUB("Tool/Thesaurus/Language", &Thesaurus::OnLanguageChanged, this))
, dict_path_listener(OPT_SUB("Path/Dictionary", &Thesaurus::OnPathChanged, this))
{
	OnLanguageChanged();
}
Example #15
0
AudioBox::AudioBox(wxWindow *parent, agi::Context *context)
: wxSashWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxSW_3D | wxCLIP_CHILDREN)
, controller(context->audioController.get())
, context(context)
, audio_open_connection(context->audioController->AddAudioPlayerOpenListener(&AudioBox::OnAudioOpen, this))
, panel(new wxPanel(this, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxBORDER_RAISED))
, audioDisplay(new AudioDisplay(panel, context->audioController.get(), context))
, HorizontalZoom(new wxSlider(panel, Audio_Horizontal_Zoom, -OPT_GET("Audio/Zoom/Horizontal")->GetInt(), -50, 30, wxDefaultPosition, wxSize(-1, 20), wxSL_VERTICAL|wxSL_BOTH))
, VerticalZoom(new wxSlider(panel, Audio_Vertical_Zoom, OPT_GET("Audio/Zoom/Vertical")->GetInt(), 0, 100, wxDefaultPosition, wxSize(-1, 20), wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE))
, VolumeBar(new wxSlider(panel, Audio_Volume, OPT_GET("Audio/Volume")->GetInt(), 0, 100, wxDefaultPosition, wxSize(-1, 20), wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE))
{
	SetSashVisible(wxSASH_BOTTOM, true);
	Bind(wxEVT_SASH_DRAGGED, &AudioBox::OnSashDrag, this);

	HorizontalZoom->SetToolTip(_("Horizontal zoom"));
	VerticalZoom->SetToolTip(_("Vertical zoom"));
	VolumeBar->SetToolTip(_("Audio Volume"));

	bool link = OPT_GET("Audio/Link")->GetBool();
	if (link) {
		VolumeBar->SetValue(VerticalZoom->GetValue());
		VolumeBar->Enable(false);
	}

	// VertVol sider
	wxSizer *VertVol = new wxBoxSizer(wxHORIZONTAL);
	VertVol->Add(VerticalZoom,1,wxEXPAND,0);
	VertVol->Add(VolumeBar,1,wxEXPAND,0);
	wxSizer *VertVolArea = new wxBoxSizer(wxVERTICAL);
	VertVolArea->Add(VertVol,1,wxEXPAND,0);

	auto link_btn = new ToggleBitmap(panel, context, "audio/opt/vertical_link", 16, "Audio", wxSize(20, -1));
	link_btn->SetMaxSize(wxDefaultSize);
	VertVolArea->Add(link_btn, 0, wxRIGHT | wxALIGN_CENTER | wxEXPAND, 0);
	OPT_SUB("Audio/Link", &AudioBox::OnVerticalLink, this);

	// Top sizer
	wxSizer *TopSizer = new wxBoxSizer(wxHORIZONTAL);
	TopSizer->Add(audioDisplay,1,wxEXPAND,0);
	TopSizer->Add(HorizontalZoom,0,wxEXPAND,0);
	TopSizer->Add(VertVolArea,0,wxEXPAND,0);

	context->karaoke = new AudioKaraoke(panel, context);

	// Main sizer
	auto MainSizer = new wxBoxSizer(wxVERTICAL);
	MainSizer->Add(TopSizer,1,wxEXPAND|wxALL,3);
	MainSizer->Add(toolbar::GetToolbar(panel, "audio", context, "Audio"),0,wxEXPAND|wxLEFT|wxRIGHT,3);
	MainSizer->Add(context->karaoke,0,wxEXPAND|wxALL,3);
	MainSizer->Show(context->karaoke, false);
	panel->SetSizer(MainSizer);

	wxSizer *audioSashSizer = new wxBoxSizer(wxHORIZONTAL);
	audioSashSizer->Add(panel, 1, wxEXPAND);
	SetSizerAndFit(audioSashSizer);
	SetMinSize(wxSize(-1, OPT_GET("Audio/Display Height")->GetInt()));
	SetMinimumSizeY(panel->GetSize().GetHeight());

	audioDisplay->Bind(wxEVT_MOUSEWHEEL, &AudioBox::OnMouseWheel, this);

	audioDisplay->SetZoomLevel(-HorizontalZoom->GetValue());
	audioDisplay->SetAmplitudeScale(pow(mid(1, VerticalZoom->GetValue(), 100) / 50.0, 3));
}
Example #16
0
void FrameMain::InitToolbar() {
	wxSystemOptions::SetOption("msw.remap", 0);
	OPT_SUB("App/Show Toolbar", &FrameMain::EnableToolBar, this);
	EnableToolBar(*OPT_GET("App/Show Toolbar"));
}
Example #17
0
Pen::Pen(const char *colour_opt, int width, wxPenStyle style)
: impl(to_wx(OPT_GET(colour_opt)->GetColor()), width, style)
, colour_con(OPT_SUB(colour_opt, &Pen::OnColourChanged, this))
{
}
Example #18
0
Pen::Pen(const char *colour_opt, const char *width_opt, wxPenStyle style)
: impl(to_wx(OPT_GET(colour_opt)->GetColor()), OPT_GET(width_opt)->GetInt(), style)
, colour_con(OPT_SUB(colour_opt, &Pen::OnColourChanged, this))
, width_con(OPT_SUB(width_opt, &Pen::OnWidthChanged, this))
{
}
Example #19
0
BaseGrid::BaseGrid(wxWindow* parent, agi::Context *context, const wxSize& size, long style, const wxString& name)
: wxWindow(parent, -1, wxDefaultPosition, size, style, name)
, lineHeight(1) // non-zero to avoid div by 0
, holding(false)
, scrollBar(new wxScrollBar(this, GRID_SCROLLBAR, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL))
, byFrame(false)
, extendRow(-1)
, active_line(0)
, batch_level(0)
, batch_active_line_changed(false)
, seek_listener(context->videoController->AddSeekListener(std::bind(&BaseGrid::Refresh, this, false, nullptr)))
, context_menu(0)
, yPos(0)
, context(context)
{
	scrollBar->SetScrollbar(0,10,100,10);

	wxBoxSizer *scrollbarpositioner = new wxBoxSizer(wxHORIZONTAL);
	scrollbarpositioner->AddStretchSpacer();
	scrollbarpositioner->Add(scrollBar, 0, wxEXPAND, 0);

	SetSizerAndFit(scrollbarpositioner);

	SetBackgroundStyle(wxBG_STYLE_PAINT);

	UpdateStyle();
	OnHighlightVisibleChange(*OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame"));

	OPT_SUB("Subtitle/Grid/Font Face", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Subtitle/Grid/Font Size", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Subtitle/Grid/Highlight Subtitles in Frame", &BaseGrid::OnHighlightVisibleChange, this);
	context->ass->AddCommitListener(&BaseGrid::OnSubtitlesCommit, this);
	context->ass->AddFileOpenListener(&BaseGrid::OnSubtitlesOpen, this);
	context->ass->AddFileSaveListener(&BaseGrid::OnSubtitlesSave, this);

	OPT_SUB("Colour/Subtitle Grid/Active Border", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Background/Background", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Background/Comment", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Background/Inframe", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Background/Selected Comment", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Background/Selection", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Collision", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Header", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Left Column", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Lines", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Selection", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Colour/Subtitle Grid/Standard", &BaseGrid::UpdateStyle, this);
	OPT_SUB("Subtitle/Grid/Hide Overrides", std::bind(&BaseGrid::Refresh, this, false, nullptr));

	Bind(wxEVT_CONTEXT_MENU, &BaseGrid::OnContextMenu, this);
}