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."); } }); }
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 }
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); }
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(); }
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")); }
/// @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); }
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(); }
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(); } }
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(); } }
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); }
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); }
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)) { }
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"); }
Thesaurus::Thesaurus() : lang_listener(OPT_SUB("Tool/Thesaurus/Language", &Thesaurus::OnLanguageChanged, this)) , dict_path_listener(OPT_SUB("Path/Dictionary", &Thesaurus::OnPathChanged, this)) { OnLanguageChanged(); }
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)); }
void FrameMain::InitToolbar() { wxSystemOptions::SetOption("msw.remap", 0); OPT_SUB("App/Show Toolbar", &FrameMain::EnableToolBar, this); EnableToolBar(*OPT_GET("App/Show Toolbar")); }
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)) { }
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)) { }
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); }