Add selection-preserving logic to BaseGrid::UpdateMaps and eliminate some unnecessary updates and clears of the maps. Fixes a pile of cases where operations would result in incorrect or no selections, or scrolling to the top of the file.
Originally committed to SVN as r4677.
This commit is contained in:
parent
4a8abae3a3
commit
a32bbab0b6
9 changed files with 105 additions and 109 deletions
|
@ -161,6 +161,85 @@ void BaseGrid::ClearMaps() {
|
||||||
AnnounceSelectedSetChanged(Selection(), old_selection);
|
AnnounceSelectedSetChanged(Selection(), old_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Update maps
|
||||||
|
///
|
||||||
|
void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
|
||||||
|
BeginBatch();
|
||||||
|
int active_row = line_index_map[active_line];
|
||||||
|
|
||||||
|
std::vector<int> sel_rows;
|
||||||
|
if (preserve_selected_rows) {
|
||||||
|
sel_rows.reserve(selection.size());
|
||||||
|
std::transform(selection.begin(), selection.end(), std::back_inserter(sel_rows),
|
||||||
|
std::bind1st(std::mem_fun(&BaseGrid::GetDialogueIndex), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
index_line_map.clear();
|
||||||
|
line_index_map.clear();
|
||||||
|
|
||||||
|
for (entryIter cur=AssFile::top->Line.begin();cur != AssFile::top->Line.end();cur++) {
|
||||||
|
AssDialogue *curdiag = dynamic_cast<AssDialogue*>(*cur);
|
||||||
|
if (curdiag) {
|
||||||
|
line_index_map[curdiag] = (int)index_line_map.size();
|
||||||
|
index_line_map.push_back(curdiag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preserve_selected_rows) {
|
||||||
|
Selection sel;
|
||||||
|
|
||||||
|
// If the file shrank enough that no selected rows are left, select the
|
||||||
|
// last row
|
||||||
|
if (sel_rows.empty()) {
|
||||||
|
sel_rows.push_back(index_line_map.size() - 1);
|
||||||
|
}
|
||||||
|
else if (sel_rows[0] >= (int)index_line_map.size()) {
|
||||||
|
sel_rows[0] = index_line_map.size() - 1;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < sel_rows.size(); i++) {
|
||||||
|
if (sel_rows[i] >= (int)index_line_map.size()) break;
|
||||||
|
sel.insert(index_line_map[sel_rows[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSelectedSet(sel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Selection lines;
|
||||||
|
std::copy(index_line_map.begin(), index_line_map.end(), std::inserter(lines, lines.begin()));
|
||||||
|
Selection new_sel;
|
||||||
|
// Remove lines which no longer exist from the selection
|
||||||
|
set_intersection(selection.begin(), selection.end(),
|
||||||
|
lines.begin(), lines.end(),
|
||||||
|
std::inserter(new_sel, new_sel.begin()));
|
||||||
|
|
||||||
|
SetSelectedSet(new_sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The active line may have ceased to exist; pick a new one if so
|
||||||
|
if (line_index_map.find(active_line) == line_index_map.end()) {
|
||||||
|
if (active_row < (int)index_line_map.size()) {
|
||||||
|
SetActiveLine(index_line_map[active_row]);
|
||||||
|
}
|
||||||
|
else if (preserve_selected_rows && !selection.empty()) {
|
||||||
|
SetActiveLine(index_line_map[sel_rows[0]]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SetActiveLine(index_line_map.back());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selection.empty() && active_line) {
|
||||||
|
Selection sel;
|
||||||
|
sel.insert(active_line);
|
||||||
|
SetSelectedSet(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndBatch();
|
||||||
|
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Begin batch
|
/// @brief Begin batch
|
||||||
|
@ -858,7 +937,6 @@ void BaseGrid::ScrollTo(int y) {
|
||||||
/// @brief Adjust scrollbar
|
/// @brief Adjust scrollbar
|
||||||
///
|
///
|
||||||
void BaseGrid::AdjustScrollbar() {
|
void BaseGrid::AdjustScrollbar() {
|
||||||
// Variables
|
|
||||||
int w,h,sw,sh;
|
int w,h,sw,sh;
|
||||||
GetClientSize(&w,&h);
|
GetClientSize(&w,&h);
|
||||||
int drawPerScreen = h/lineHeight;
|
int drawPerScreen = h/lineHeight;
|
||||||
|
@ -866,15 +944,12 @@ void BaseGrid::AdjustScrollbar() {
|
||||||
bool barToEnable = drawPerScreen < rows+2;
|
bool barToEnable = drawPerScreen < rows+2;
|
||||||
bool barEnabled = scrollBar->IsEnabled();
|
bool barEnabled = scrollBar->IsEnabled();
|
||||||
|
|
||||||
// Set yPos
|
|
||||||
yPos = MID(0,yPos,rows - drawPerScreen);
|
yPos = MID(0,yPos,rows - drawPerScreen);
|
||||||
|
|
||||||
// Set size
|
|
||||||
scrollBar->Freeze();
|
scrollBar->Freeze();
|
||||||
scrollBar->GetSize(&sw,&sh);
|
scrollBar->GetSize(&sw,&sh);
|
||||||
scrollBar->SetSize(w-sw,0,sw,h);
|
scrollBar->SetSize(w-sw,0,sw,h);
|
||||||
|
|
||||||
// Set parameters
|
|
||||||
if (barEnabled) {
|
if (barEnabled) {
|
||||||
scrollBar->SetScrollbar(yPos,drawPerScreen,rows+2,drawPerScreen-2,true);
|
scrollBar->SetScrollbar(yPos,drawPerScreen,rows+2,drawPerScreen-2,true);
|
||||||
}
|
}
|
||||||
|
@ -1043,32 +1118,6 @@ bool BaseGrid::IsDisplayed(AssDialogue *line) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Update maps
|
|
||||||
///
|
|
||||||
void BaseGrid::UpdateMaps() {
|
|
||||||
index_line_map.clear();
|
|
||||||
line_index_map.clear();
|
|
||||||
|
|
||||||
for (entryIter cur=AssFile::top->Line.begin();cur != AssFile::top->Line.end();cur++) {
|
|
||||||
AssDialogue *curdiag = dynamic_cast<AssDialogue*>(*cur);
|
|
||||||
if (curdiag) {
|
|
||||||
line_index_map[curdiag] = (int)index_line_map.size();
|
|
||||||
index_line_map.push_back(curdiag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line_index_map.find(active_line) == line_index_map.end()) {
|
|
||||||
// this isn't supposed to happen
|
|
||||||
SetActiveLine(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Key press
|
/// @brief Key press
|
||||||
/// @param event
|
/// @param event
|
||||||
/// @return
|
/// @return
|
||||||
|
|
|
@ -169,7 +169,10 @@ public:
|
||||||
wxArrayInt GetSelection(bool *continuous=NULL) const;
|
wxArrayInt GetSelection(bool *continuous=NULL) const;
|
||||||
|
|
||||||
void ClearMaps();
|
void ClearMaps();
|
||||||
void UpdateMaps();
|
/// @brief Update the row <-> AssDialogue mappings
|
||||||
|
/// @param preserve_selected_rows Try to keep the same rows selected rather
|
||||||
|
/// rather than the same lines
|
||||||
|
void UpdateMaps(bool preserve_selected_rows = false);
|
||||||
void UpdateStyle();
|
void UpdateStyle();
|
||||||
|
|
||||||
int GetRows() const;
|
int GetRows() const;
|
||||||
|
|
|
@ -312,7 +312,6 @@ void DialogShiftTimes::OnOK(wxCommandEvent &event) {
|
||||||
// End dialog
|
// End dialog
|
||||||
grid->ass->Commit(_("shifting"));
|
grid->ass->Commit(_("shifting"));
|
||||||
grid->CommitChanges();
|
grid->CommitChanges();
|
||||||
grid->UpdateMaps();
|
|
||||||
grid->editBox->Update();
|
grid->editBox->Update();
|
||||||
EndModal(0);
|
EndModal(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,8 +273,6 @@ void DialogStyling::OnActivate(wxActivateEvent &event) {
|
||||||
// Enable/disable play video/audio buttons
|
// Enable/disable play video/audio buttons
|
||||||
PlayVideoButton->Enable(video->IsLoaded());
|
PlayVideoButton->Enable(video->IsLoaded());
|
||||||
PlayAudioButton->Enable(audio->loaded);
|
PlayAudioButton->Enable(audio->loaded);
|
||||||
// Update grid
|
|
||||||
grid->UpdateMaps();
|
|
||||||
// Fix style list
|
// Fix style list
|
||||||
Styles->Set(grid->ass->GetStyles());
|
Styles->Set(grid->ass->GetStyles());
|
||||||
// Fix line selection
|
// Fix line selection
|
||||||
|
|
|
@ -1049,19 +1049,14 @@ void FrameMain::OnAutomationMacro (wxCommandEvent &event) {
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
SubsGrid->BeginBatch();
|
SubsGrid->BeginBatch();
|
||||||
// First get selection data
|
// First get selection data
|
||||||
// This much be done before clearing the maps, since selection data are lost during that
|
|
||||||
std::vector<int> selected_lines = SubsGrid->GetAbsoluteSelection();
|
std::vector<int> selected_lines = SubsGrid->GetAbsoluteSelection();
|
||||||
int first_sel = SubsGrid->GetFirstSelRow();
|
int first_sel = SubsGrid->GetFirstSelRow();
|
||||||
// Clear all maps from the subs grid before running the macro
|
|
||||||
// The stuff done by the macro might invalidate some of the iterators held by the grid, which will cause great crashing
|
|
||||||
SubsGrid->ClearMaps();
|
|
||||||
// Run the macro...
|
// Run the macro...
|
||||||
activeMacroItems[event.GetId()-Menu_Automation_Macro]->Process(SubsGrid->ass, selected_lines, first_sel, this);
|
activeMacroItems[event.GetId()-Menu_Automation_Macro]->Process(SubsGrid->ass, selected_lines, first_sel, this);
|
||||||
// Have the grid update its maps, this properly refreshes it to reflect the changed subs
|
// Have the grid update its maps, this properly refreshes it to reflect the changed subs
|
||||||
SubsGrid->UpdateMaps();
|
SubsGrid->UpdateMaps();
|
||||||
SubsGrid->SetSelectionFromAbsolute(selected_lines);
|
SubsGrid->SetSelectionFromAbsolute(selected_lines);
|
||||||
SubsGrid->CommitChanges(true, false);
|
SubsGrid->CommitChanges(true, false);
|
||||||
SubsGrid->AdjustScrollbar();
|
|
||||||
SubsGrid->EndBatch();
|
SubsGrid->EndBatch();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1167,25 +1162,17 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &) {
|
||||||
/// @brief Undo
|
/// @brief Undo
|
||||||
void FrameMain::OnUndo(wxCommandEvent&) {
|
void FrameMain::OnUndo(wxCommandEvent&) {
|
||||||
VideoContext::Get()->Stop();
|
VideoContext::Get()->Stop();
|
||||||
std::vector<int> selected_lines = SubsGrid->GetAbsoluteSelection();
|
|
||||||
int active_line = SubsGrid->GetDialogueIndex(SubsGrid->GetActiveLine());
|
|
||||||
ass->Undo();
|
ass->Undo();
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
SubsGrid->UpdateMaps();
|
SubsGrid->UpdateMaps(true);
|
||||||
SubsGrid->SetSelectionFromAbsolute(selected_lines);
|
|
||||||
SubsGrid->SetActiveLine(SubsGrid->GetDialogue(active_line));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Redo
|
/// @brief Redo
|
||||||
void FrameMain::OnRedo(wxCommandEvent&) {
|
void FrameMain::OnRedo(wxCommandEvent&) {
|
||||||
VideoContext::Get()->Stop();
|
VideoContext::Get()->Stop();
|
||||||
std::vector<int> selected_lines = SubsGrid->GetAbsoluteSelection();
|
|
||||||
int active_line = SubsGrid->GetDialogueIndex(SubsGrid->GetActiveLine());
|
|
||||||
ass->Redo();
|
ass->Redo();
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
SubsGrid->UpdateMaps();
|
SubsGrid->UpdateMaps(true);
|
||||||
SubsGrid->SetSelectionFromAbsolute(selected_lines);
|
|
||||||
SubsGrid->SetActiveLine(SubsGrid->GetDialogue(active_line));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Find
|
/// @brief Find
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "hilimod_textctrl.h"
|
#include "hilimod_textctrl.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "options.h"
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
|
|
|
@ -333,8 +333,8 @@ void SubsEditBox::UpdateGlobals () {
|
||||||
ActorBox->Thaw();
|
ActorBox->Thaw();
|
||||||
|
|
||||||
// Set subs update
|
// Set subs update
|
||||||
|
OnActiveLineChanged(grid->GetActiveLine());
|
||||||
TextEdit->SetSelection(0,0);
|
TextEdit->SetSelection(0,0);
|
||||||
grid->SetActiveLine(grid->GetDialogue(grid->GetFirstSelRow()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -701,7 +701,6 @@ void SubtitlesGrid::OnRecombine(wxCommandEvent &) {
|
||||||
ass->Commit(_("combining"));
|
ass->Commit(_("combining"));
|
||||||
UpdateMaps();
|
UpdateMaps();
|
||||||
CommitChanges();
|
CommitChanges();
|
||||||
AdjustScrollbar();
|
|
||||||
|
|
||||||
// Remove now non-existent lines from the selection
|
// Remove now non-existent lines from the selection
|
||||||
Selection lines;
|
Selection lines;
|
||||||
|
@ -809,44 +808,20 @@ void SubtitlesGrid::OnAudioClip(wxCommandEvent &event) {
|
||||||
///
|
///
|
||||||
void SubtitlesGrid::LoadDefault () {
|
void SubtitlesGrid::LoadDefault () {
|
||||||
ass->LoadDefault();
|
ass->LoadDefault();
|
||||||
|
ClearMaps();
|
||||||
UpdateMaps();
|
UpdateMaps();
|
||||||
|
|
||||||
assert(!line_iter_map.empty());
|
|
||||||
SetActiveLine(GetDialogue(0));
|
SetActiveLine(GetDialogue(0));
|
||||||
SelectRow(0);
|
SelectRow(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Clear internal data structures
|
|
||||||
void SubtitlesGrid::ClearMaps() {
|
|
||||||
line_iter_map.clear();
|
|
||||||
BaseGrid::ClearMaps();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Update internal data structures
|
/// @brief Update internal data structures
|
||||||
void SubtitlesGrid::UpdateMaps() {
|
void SubtitlesGrid::UpdateMaps(bool preserve_selected_rows) {
|
||||||
BeginBatch();
|
BaseGrid::UpdateMaps(preserve_selected_rows);
|
||||||
|
|
||||||
line_iter_map.clear();
|
|
||||||
BaseGrid::ClearMaps();
|
|
||||||
|
|
||||||
BaseGrid::UpdateMaps();
|
|
||||||
|
|
||||||
for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ++it) {
|
|
||||||
AssDialogue *dlg = dynamic_cast<AssDialogue*>(*it);
|
|
||||||
if (dlg) line_iter_map.insert(std::pair<AssDialogue*,entryIter>(dlg, it));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editBox) {
|
if (editBox) {
|
||||||
editBox->UpdateGlobals();
|
editBox->UpdateGlobals();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish setting layout
|
|
||||||
AdjustScrollbar();
|
|
||||||
EndBatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -862,7 +837,6 @@ void SubtitlesGrid::SwapLines(int n1,int n2) {
|
||||||
if (n1 == 0 || n2 == 0) return;
|
if (n1 == 0 || n2 == 0) return;
|
||||||
|
|
||||||
std::swap(*dlg1, *dlg2);
|
std::swap(*dlg1, *dlg2);
|
||||||
UpdateMaps();
|
|
||||||
|
|
||||||
ass->Commit(_("swap lines"));
|
ass->Commit(_("swap lines"));
|
||||||
CommitChanges();
|
CommitChanges();
|
||||||
|
@ -878,19 +852,15 @@ void SubtitlesGrid::SwapLines(int n1,int n2) {
|
||||||
///
|
///
|
||||||
void SubtitlesGrid::InsertLine(AssDialogue *line,int n,bool after,bool update) {
|
void SubtitlesGrid::InsertLine(AssDialogue *line,int n,bool after,bool update) {
|
||||||
AssDialogue *rel_line = GetDialogue(n + (after?1:0));
|
AssDialogue *rel_line = GetDialogue(n + (after?1:0));
|
||||||
entryIter pos;
|
entryIter pos = std::find(ass->Line.begin(), ass->Line.end(), rel_line);
|
||||||
if (rel_line) pos = line_iter_map[rel_line];
|
|
||||||
else pos = ass->Line.end();
|
|
||||||
|
|
||||||
entryIter newIter = ass->Line.insert(pos,line);
|
entryIter newIter = ass->Line.insert(pos,line);
|
||||||
line_iter_map[line] = newIter;
|
|
||||||
BaseGrid::UpdateMaps();
|
BaseGrid::UpdateMaps();
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
if (update) {
|
if (update) {
|
||||||
ass->Commit(_("line insertion"));
|
ass->Commit(_("line insertion"));
|
||||||
CommitChanges();
|
CommitChanges();
|
||||||
AdjustScrollbar();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1020,7 +990,6 @@ void SubtitlesGrid::PasteLines(int n,bool pasteOver) {
|
||||||
if (inserted > 0) {
|
if (inserted > 0) {
|
||||||
// Commit
|
// Commit
|
||||||
UpdateMaps();
|
UpdateMaps();
|
||||||
AdjustScrollbar();
|
|
||||||
ass->Commit(_("paste"));
|
ass->Commit(_("paste"));
|
||||||
CommitChanges();
|
CommitChanges();
|
||||||
|
|
||||||
|
@ -1047,16 +1016,20 @@ void SubtitlesGrid::PasteLines(int n,bool pasteOver) {
|
||||||
/// @param flagModified
|
/// @param flagModified
|
||||||
///
|
///
|
||||||
void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
|
void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
|
||||||
// Check if it's wiping file
|
entryIter before_first = std::find_if(ass->Line.begin(), ass->Line.end(), cast<AssDialogue*>()); --before_first;
|
||||||
int deleted = 0;
|
|
||||||
entryIter before_first = line_iter_map[GetDialogue(0)]; --before_first;
|
|
||||||
int old_active_line_index = GetDialogueIndex(GetActiveLine());
|
int old_active_line_index = GetDialogueIndex(GetActiveLine());
|
||||||
|
|
||||||
// Delete lines
|
int row = -1;
|
||||||
int size = target.Count();
|
int deleted = 0;
|
||||||
for (int i=0;i<size;i++) {
|
for (entryIter cur = ass->Line.begin(); cur != ass->Line.end();) {
|
||||||
ass->Line.erase(line_iter_map[GetDialogue(target[i])]);
|
if (dynamic_cast<AssDialogue*>(*cur) && ++row == target[deleted]) {
|
||||||
deleted++;
|
cur = ass->Line.erase(cur);
|
||||||
|
++deleted;
|
||||||
|
if (deleted == target.size()) break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++cur;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add default line if file was wiped
|
// Add default line if file was wiped
|
||||||
|
@ -1067,21 +1040,12 @@ void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
|
||||||
old_active_line_index = 0;
|
old_active_line_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update
|
|
||||||
UpdateMaps();
|
UpdateMaps();
|
||||||
AdjustScrollbar();
|
|
||||||
if (flagModified) {
|
if (flagModified) {
|
||||||
ass->Commit(_("delete"));
|
ass->Commit(_("delete"));
|
||||||
CommitChanges();
|
CommitChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_active_line_index >= GetRows()) {
|
|
||||||
old_active_line_index = GetRows() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update selected line
|
|
||||||
SelectRow(old_active_line_index);
|
|
||||||
SetActiveLine(GetDialogue(old_active_line_index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -94,8 +94,6 @@ private:
|
||||||
void OnAudioClip(wxCommandEvent &event);
|
void OnAudioClip(wxCommandEvent &event);
|
||||||
void OnShowColMenu(wxCommandEvent &event);
|
void OnShowColMenu(wxCommandEvent &event);
|
||||||
|
|
||||||
std::map<AssDialogue*,entryIter> line_iter_map;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
@ -107,8 +105,7 @@ public:
|
||||||
void LoadDefault();
|
void LoadDefault();
|
||||||
void CommitChanges(bool force=false,bool videoOnly=false);
|
void CommitChanges(bool force=false,bool videoOnly=false);
|
||||||
|
|
||||||
void ClearMaps();
|
void UpdateMaps(bool preserve_selected_rows = false);
|
||||||
void UpdateMaps();
|
|
||||||
|
|
||||||
void SetVideoToSubs(bool start);
|
void SetVideoToSubs(bool start);
|
||||||
void SetSubsToVideo(bool start);
|
void SetSubsToVideo(bool start);
|
||||||
|
|
Loading…
Reference in a new issue