Rework how committing changes works

Rather than everything having to separately commit changes to the ass
and then tell the subs grid to notify various parts of Aegisub about the
changes, committing the AssFile now triggers an event which objects
listen for.

AssFile::Commit now also has an argument to indicate what sorts of
changes were made to the file. For now these types are very broad.

Originally committed to SVN as r4901.
This commit is contained in:
Thomas Goyne 2010-12-07 19:09:28 +00:00
parent d9006b0eb4
commit 6d2b941e76
35 changed files with 273 additions and 423 deletions

View file

@ -757,12 +757,15 @@ wxString AssFile::GetWildcardList(int mode) {
else return ""; else return "";
} }
int AssFile::Commit(wxString desc, int amendId) { int AssFile::Commit(wxString desc, CommitType type, int amendId) {
assert(type != COMMIT_UNDO);
++commitId; ++commitId;
// Allow coalescing only if it's the last change and the file has not been // Allow coalescing only if it's the last change and the file has not been
// saved since the last change // saved since the last change
if (commitId == amendId+1 && RedoStack.empty() && savedCommitId != commitId) { if (commitId == amendId+1 && RedoStack.empty() && savedCommitId != commitId) {
UndoStack.back() = *this; UndoStack.back() = *this;
AnnounceCommit(type);
return commitId; return commitId;
} }
@ -778,6 +781,7 @@ int AssFile::Commit(wxString desc, int amendId) {
UndoStack.pop_front(); UndoStack.pop_front();
} }
AnnounceCommit(type);
return commitId; return commitId;
} }
@ -788,6 +792,8 @@ void AssFile::Undo() {
std::swap(RedoStack.back(), *this); std::swap(RedoStack.back(), *this);
UndoStack.pop_back(); UndoStack.pop_back();
*this = UndoStack.back(); *this = UndoStack.back();
AnnounceCommit(COMMIT_UNDO);
} }
void AssFile::Redo() { void AssFile::Redo() {
@ -796,6 +802,8 @@ void AssFile::Redo() {
std::swap(*this, RedoStack.back()); std::swap(*this, RedoStack.back());
UndoStack.push_back(*this); UndoStack.push_back(*this);
RedoStack.pop_back(); RedoStack.pop_back();
AnnounceCommit(COMMIT_UNDO);
} }
wxString AssFile::GetUndoDescription() const { wxString AssFile::GetUndoDescription() const {

View file

@ -45,6 +45,8 @@
#include <wx/arrstr.h> #include <wx/arrstr.h>
#endif #endif
#include <libaegisub/signals.h>
class FrameRate; class FrameRate;
class AssDialogue; class AssDialogue;
class AssStyle; class AssStyle;
@ -70,6 +72,8 @@ class AssFile {
/// Last saved version of this file /// Last saved version of this file
int savedCommitId; int savedCommitId;
agi::signal::Signal<int> AnnounceCommit;
public: public:
/// The lines in the file /// The lines in the file
std::list<AssEntry*> Line; std::list<AssEntry*> Line;
@ -150,11 +154,28 @@ public:
/// @param[out] outGroup Group it was actually added to; attachments do something strange here /// @param[out] outGroup Group it was actually added to; attachments do something strange here
void AddLine(wxString data,wxString group,int &version,wxString *outGroup=NULL); void AddLine(wxString data,wxString group,int &version,wxString *outGroup=NULL);
/// Type of changes made in a commit
enum CommitType {
/// Entire file has been swapped for a different version of the same file
COMMIT_UNDO,
/// Potentially the entire file has been changed; any saved information
/// should be discarded
COMMIT_FULL,
/// The contents of lines have changed, but the number or order of lines
/// has not
COMMIT_TEXT,
/// Only the start and end times of lines has changed
COMMIT_TIMES
};
DEFINE_SIGNAL_ADDERS(AnnounceCommit, AddCommitListener)
/// @brief Flag the file as modified and push a copy onto the undo stack /// @brief Flag the file as modified and push a copy onto the undo stack
/// @param desc Undo description /// @param desc Undo description
/// @param type Type of changes made to the file in this commit
/// @param commitId Commit to amend rather than pushing a new commit /// @param commitId Commit to amend rather than pushing a new commit
/// @return Unique identifier for the new undo group /// @return Unique identifier for the new undo group
int Commit(wxString desc, int commitId = -1); int Commit(wxString desc, CommitType type = COMMIT_FULL, int commitId = -1);
/// @brief Undo the last set of changes to the file /// @brief Undo the last set of changes to the file
void Undo(); void Undo();
/// @brief Redo the last undone changes /// @brief Redo the last undone changes

View file

@ -62,7 +62,7 @@
/// @brief Constructor /// @brief Constructor
/// @param parent /// @param parent
/// ///
AudioBox::AudioBox(wxWindow *parent) : AudioBox::AudioBox(wxWindow *parent, SubtitlesGrid *grid) :
wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISED) wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISED)
{ {
// Setup // Setup
@ -75,7 +75,7 @@ wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISE
audioScroll->SetToolTip(_("Seek bar")); audioScroll->SetToolTip(_("Seek bar"));
Sash = new wxSashWindow(this,Audio_Sash,wxDefaultPosition,wxDefaultSize,wxCLIP_CHILDREN | wxSW_3DBORDER); Sash = new wxSashWindow(this,Audio_Sash,wxDefaultPosition,wxDefaultSize,wxCLIP_CHILDREN | wxSW_3DBORDER);
sashSizer = new wxBoxSizer(wxVERTICAL); sashSizer = new wxBoxSizer(wxVERTICAL);
audioDisplay = new AudioDisplay(Sash); audioDisplay = new AudioDisplay(Sash, grid);
sashSizer->Add(audioDisplay,1,wxEXPAND,0); sashSizer->Add(audioDisplay,1,wxEXPAND,0);
Sash->SetSizer(sashSizer); Sash->SetSizer(sashSizer);
Sash->SetSashVisible(wxSASH_BOTTOM,true); Sash->SetSashVisible(wxSASH_BOTTOM,true);

View file

@ -60,6 +60,7 @@
class AudioDisplay; class AudioDisplay;
class AudioKaraoke; class AudioKaraoke;
class FrameMain; class FrameMain;
class SubtitlesGrid;
class wxToggleButton; class wxToggleButton;
class ToggleBitmap; class ToggleBitmap;
@ -197,7 +198,7 @@ public:
/// DOCME /// DOCME
bool karaokeMode; bool karaokeMode;
AudioBox(wxWindow *parent); AudioBox(wxWindow *parent, SubtitlesGrid *grid);
~AudioBox(); ~AudioBox();
void SetFile(wxString file,bool FromVideo); void SetFile(wxString file,bool FromVideo);

View file

@ -79,9 +79,9 @@
/// @brief Constructor /// @brief Constructor
/// @param parent /// @param parent
AudioDisplay::AudioDisplay(wxWindow *parent) AudioDisplay::AudioDisplay(wxWindow *parent, SubtitlesGrid *grid)
: wxWindow (parent, -1, wxDefaultPosition, wxSize(200,OPT_GET("Audio/Display Height")->GetInt()), AudioDisplayWindowStyle , _T("Audio Display")) : wxWindow (parent, -1, wxDefaultPosition, wxSize(200,OPT_GET("Audio/Display Height")->GetInt()), AudioDisplayWindowStyle , _T("Audio Display"))
, grid(0) , grid(grid)
{ {
// Set variables // Set variables
origImage = NULL; origImage = NULL;
@ -99,7 +99,6 @@ AudioDisplay::AudioDisplay(wxWindow *parent)
loaded = false; loaded = false;
temporary = false; temporary = false;
blockUpdate = false; blockUpdate = false;
dontReadTimes = false;
holding = false; holding = false;
draggingScale = false; draggingScale = false;
Position = 0; Position = 0;
@ -127,6 +126,9 @@ AudioDisplay::AudioDisplay(wxWindow *parent)
if (OPT_GET("Audio/Display/Draw/Video Position")->GetBool()) if (OPT_GET("Audio/Display/Draw/Video Position")->GetBool())
vc->AddSeekListener(&AudioDisplay::UpdateImage, this, false); vc->AddSeekListener(&AudioDisplay::UpdateImage, this, false);
grid->AddSelectionListener(this);
commitListener = grid->ass->AddCommitListener(&AudioDisplay::OnCommit, this);
// Set cursor // Set cursor
//wxCursor cursor(wxCURSOR_BLANK); //wxCursor cursor(wxCURSOR_BLANK);
//SetCursor(cursor); //SetCursor(cursor);
@ -1119,28 +1121,24 @@ void AudioDisplay::SetSelection(int start, int end) {
/// @param diag /// @param diag
/// @param n /// @param n
/// @return /// @return
void AudioDisplay::SetDialogue(SubtitlesGrid *_grid,AssDialogue *diag,int n) { void AudioDisplay::SetDialogue(SubtitlesGrid *,AssDialogue *diag,int n) {
// Actual parameters // Set variables
if (_grid) { line_n = n;
// Set variables dialogue = diag;
grid = _grid;
line_n = n;
dialogue = diag;
// Set flags // Set flags
diagUpdated = false; diagUpdated = false;
NeedCommit = false; NeedCommit = false;
// Set times // Set times
if (dialogue && !dontReadTimes && OPT_GET("Audio/Grab Times on Select")->GetBool()) { if (dialogue && OPT_GET("Audio/Grab Times on Select")->GetBool()) {
int s = dialogue->Start.GetMS(); int s = dialogue->Start.GetMS();
int e = dialogue->End.GetMS(); int e = dialogue->End.GetMS();
// Never do it for 0:00:00.00->0:00:00.00 lines // Never do it for 0:00:00.00->0:00:00.00 lines
if (s != 0 || e != 0) { if (s != 0 || e != 0) {
curStartMS = s; curStartMS = s;
curEndMS = e; curEndMS = e;
}
} }
} }
@ -1163,11 +1161,11 @@ void AudioDisplay::SetDialogue(SubtitlesGrid *_grid,AssDialogue *diag,int n) {
void AudioDisplay::CommitChanges (bool nextLine) { void AudioDisplay::CommitChanges (bool nextLine) {
// Loaded? // Loaded?
if (!loaded) return; if (!loaded) return;
commitListener.Block();
// Check validity // Check validity
bool textNeedsCommit = grid->GetDialogue(line_n)->Text != grid->editBox->TextEdit->GetText();
bool timeNeedsCommit = grid->GetDialogue(line_n)->Start.GetMS() != curStartMS || grid->GetDialogue(line_n)->End.GetMS() != curEndMS; bool timeNeedsCommit = grid->GetDialogue(line_n)->Start.GetMS() != curStartMS || grid->GetDialogue(line_n)->End.GetMS() != curEndMS;
if (timeNeedsCommit || textNeedsCommit) NeedCommit = true; NeedCommit = timeNeedsCommit;
bool wasKaraSplitting = false; bool wasKaraSplitting = false;
bool validCommit = true; bool validCommit = true;
if (!karaoke->enabled && !karaoke->splitting) { if (!karaoke->enabled && !karaoke->splitting) {
@ -1208,7 +1206,7 @@ void AudioDisplay::CommitChanges (bool nextLine) {
curDiag->Start.SetMS(curStartMS); curDiag->Start.SetMS(curStartMS);
curDiag->End.SetMS(curEndMS); curDiag->End.SetMS(curEndMS);
} }
if (!karaoke->enabled && textNeedsCommit) { if (!karaoke->enabled) {
// If user was editing karaoke stuff, that should take precedence of manual changes in the editbox, // If user was editing karaoke stuff, that should take precedence of manual changes in the editbox,
// so only update from editbox when not in kara mode // so only update from editbox when not in kara mode
curDiag->Text = grid->editBox->TextEdit->GetText(); curDiag->Text = grid->editBox->TextEdit->GetText();
@ -1216,15 +1214,7 @@ void AudioDisplay::CommitChanges (bool nextLine) {
if (!grid->IsInSelection(line_n)) break; if (!grid->IsInSelection(line_n)) break;
} }
// Update edit box grid->ass->Commit(_T(""), karaoke->enabled ? AssFile::COMMIT_TEXT : AssFile::COMMIT_TIMES);
grid->editBox->StartTime->Update();
grid->editBox->EndTime->Update();
grid->editBox->Duration->Update();
// Update grid
grid->editBox->Update(!karaoke->enabled);
grid->ass->Commit(_T(""));
grid->CommitChanges();
karaoke->SetSelection(karaSelStart, karaSelEnd); karaoke->SetSelection(karaSelStart, karaSelEnd);
blockUpdate = false; blockUpdate = false;
} }
@ -1240,24 +1230,19 @@ void AudioDisplay::CommitChanges (bool nextLine) {
def->End.SetMS(def->End.GetMS()+OPT_GET("Timing/Default Duration")->GetInt()); def->End.SetMS(def->End.GetMS()+OPT_GET("Timing/Default Duration")->GetInt());
def->Style = grid->GetDialogue(line_n)->Style; def->Style = grid->GetDialogue(line_n)->Style;
grid->InsertLine(def,line_n,true); grid->InsertLine(def,line_n,true);
curStartMS = curEndMS;
curEndMS = curStartMS + OPT_GET("Timing/Default Duration")->GetInt();
} }
else if (grid->GetDialogue(line_n+1)->Start.GetMS() == 0 && grid->GetDialogue(line_n+1)->End.GetMS() == 0) { int endMs = curEndMS;
curStartMS = curEndMS;
curEndMS = curStartMS + OPT_GET("Timing/Default Duration")->GetInt(); grid->NextLine();
curStartMS = grid->GetActiveLine()->Start.GetMS();
curEndMS = grid->GetActiveLine()->End.GetMS();
if (curStartMS == 0 && curEndMS == 0) {
curStartMS = endMs;
curEndMS = endMs + OPT_GET("Timing/Default Duration")->GetInt();
} }
else {
curStartMS = grid->GetDialogue(line_n+1)->Start.GetMS();
curEndMS = grid->GetDialogue(line_n+1)->End.GetMS();
}
// Go to next
dontReadTimes = true;
ChangeLine(1,sel.GetCount() > 1 ? true : false);
dontReadTimes = false;
} }
commitListener.Unblock();
Update(); Update();
} }
@ -1277,7 +1262,6 @@ void AudioDisplay::AddLead(bool in,bool out) {
} }
// Set changes // Set changes
UpdateTimeEditCtrls();
NeedCommit = true; NeedCommit = true;
if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges(); if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges();
Update(); Update();
@ -1674,7 +1658,6 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
diagUpdated = false; diagUpdated = false;
NeedCommit = true; NeedCommit = true;
if (curStartMS <= curEndMS) { if (curStartMS <= curEndMS) {
UpdateTimeEditCtrls();
if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges(); if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges();
} }
@ -2218,10 +2201,12 @@ void AudioDisplay::OnLoseFocus(wxFocusEvent &event) {
Refresh(false); Refresh(false);
} }
} }
void AudioDisplay::OnActiveLineChanged(AssDialogue *new_line) {
/// @brief Update time edit controls SetDialogue(grid,new_line,grid->GetDialogueIndex(new_line));
void AudioDisplay::UpdateTimeEditCtrls() { }
grid->editBox->StartTime->SetTime(curStartMS); void AudioDisplay::OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) {
grid->editBox->EndTime->SetTime(curEndMS); }
grid->editBox->Duration->SetTime(curEndMS-curStartMS); void AudioDisplay::OnCommit(int type) {
AssDialogue *line = grid->GetActiveLine();
SetDialogue(grid,line,grid->GetDialogueIndex(line));
} }

View file

@ -45,7 +45,10 @@
#include <wx/window.h> #include <wx/window.h>
#endif #endif
#include <libaegisub/signals.h>
#include "audio_renderer_spectrum.h" #include "audio_renderer_spectrum.h"
#include "selection_controller.h"
class AudioBox; class AudioBox;
class AudioKaraoke; class AudioKaraoke;
@ -61,7 +64,7 @@ class VideoProvider;
/// @brief DOCME /// @brief DOCME
/// ///
/// DOCME /// DOCME
class AudioDisplay: public wxWindow { class AudioDisplay: public wxWindow, private SelectionListener<AssDialogue> {
friend class FrameMain; friend class FrameMain;
private: private:
@ -201,6 +204,11 @@ private:
int GetBoundarySnap(int x,int range,bool shiftHeld,bool start=true); int GetBoundarySnap(int x,int range,bool shiftHeld,bool start=true);
void DoUpdateImage(); void DoUpdateImage();
void OnActiveLineChanged(AssDialogue *new_line);
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
void OnCommit(int);
agi::signal::Connection commitListener;
public: public:
/// DOCME /// DOCME
@ -235,7 +243,7 @@ public:
/// DOCME /// DOCME
wxTimer UpdateTimer; wxTimer UpdateTimer;
AudioDisplay(wxWindow *parent); AudioDisplay(wxWindow *parent, SubtitlesGrid *grid);
~AudioDisplay(); ~AudioDisplay();
void UpdateImage(bool weak=false); void UpdateImage(bool weak=false);
@ -251,7 +259,6 @@ public:
void Next(bool play=true); void Next(bool play=true);
void Prev(bool play=true); void Prev(bool play=true);
void UpdateTimeEditCtrls();
void CommitChanges(bool nextLine=false); void CommitChanges(bool nextLine=false);
void AddLead(bool in,bool out); void AddLead(bool in,bool out);

View file

@ -196,7 +196,6 @@ void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
std::bind1st(std::mem_fun(&BaseGrid::GetDialogueIndex), this)); std::bind1st(std::mem_fun(&BaseGrid::GetDialogueIndex), this));
} }
active_line = NULL;
index_line_map.clear(); index_line_map.clear();
line_index_map.clear(); line_index_map.clear();
@ -238,8 +237,14 @@ void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
SetSelectedSet(new_sel); SetSelectedSet(new_sel);
} }
// Force a reannounce of the active line if it hasn't changed, as it isn't
// safe to touch the active line while processing a commit event which would
// cause this function to be called
AssDialogue *line = active_line;
active_line = NULL;
// The active line may have ceased to exist; pick a new one if so // The active line may have ceased to exist; pick a new one if so
if (line_index_map.size() && line_index_map.find(active_line) == line_index_map.end()) { if (line_index_map.size() && line_index_map.find(line) == line_index_map.end()) {
if (active_row < (int)index_line_map.size()) { if (active_row < (int)index_line_map.size()) {
SetActiveLine(index_line_map[active_row]); SetActiveLine(index_line_map[active_row]);
} }
@ -250,6 +255,9 @@ void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
SetActiveLine(index_line_map.back()); SetActiveLine(index_line_map.back());
} }
} }
else {
SetActiveLine(line);
}
if (selection.empty() && active_line) { if (selection.empty() && active_line) {
Selection sel; Selection sel;

View file

@ -45,6 +45,7 @@
#include "dialog_detached_video.h" #include "dialog_detached_video.h"
#include "frame_main.h" #include "frame_main.h"
#include "main.h" #include "main.h"
#include "subs_grid.h"
#include "video_box.h" #include "video_box.h"
#include "video_context.h" #include "video_context.h"
#include "video_display.h" #include "video_display.h"
@ -75,7 +76,7 @@ DialogDetachedVideo::DialogDetachedVideo(FrameMain *par, const wxSize &initialDi
wxPanel *panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN); wxPanel *panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN);
// Video area; // Video area;
videoBox = new VideoBox(panel, true, NULL); videoBox = new VideoBox(panel, true, NULL, VideoContext::Get()->grid->ass);
videoBox->videoDisplay->freeSize = true; videoBox->videoDisplay->freeSize = true;
videoBox->videoDisplay->SetClientSize(initialDisplaySize); videoBox->videoDisplay->SetClientSize(initialDisplaySize);
videoBox->videoSlider->grid = par->SubsGrid; videoBox->videoSlider->grid = par->SubsGrid;

View file

@ -54,7 +54,6 @@
#include "compat.h" #include "compat.h"
#include "dialog_fonts_collector.h" #include "dialog_fonts_collector.h"
#include "font_file_lister.h" #include "font_file_lister.h"
#include "frame_main.h"
#include "help_button.h" #include "help_button.h"
#include "libresrc/libresrc.h" #include "libresrc/libresrc.h"
#include "main.h" #include "main.h"
@ -94,9 +93,6 @@ DialogFontsCollector::DialogFontsCollector(wxWindow *parent, AssFile *ass)
// Set icon // Set icon
SetIcon(BitmapToIcon(GETIMAGE(font_collector_button_24))); SetIcon(BitmapToIcon(GETIMAGE(font_collector_button_24)));
// Parent
main = (FrameMain*) parent;
// Destination box // Destination box
wxString dest = lagi_wxString(OPT_GET("Path/Fonts Collector Destination")->GetString()); wxString dest = lagi_wxString(OPT_GET("Path/Fonts Collector Destination")->GetString());
if (dest == _T("?script")) { if (dest == _T("?script")) {
@ -515,7 +511,6 @@ void FontsCollectorThread::Collect() {
if (oper == 3 && someOk) { if (oper == 3 && someOk) {
wxMutexGuiEnter(); wxMutexGuiEnter();
subs->Commit(_("font attachment")); subs->Commit(_("font attachment"));
collector->main->SubsGrid->CommitChanges();
wxMutexGuiLeave(); wxMutexGuiLeave();
} }
} }

View file

@ -46,7 +46,6 @@
class AssFile; class AssFile;
class AssOverrideParameter; class AssOverrideParameter;
class DialogFontsCollector; class DialogFontsCollector;
class FrameMain;
class wxZipOutputStream; class wxZipOutputStream;
class ScintillaTextCtrl; class ScintillaTextCtrl;
@ -133,9 +132,6 @@ class DialogFontsCollector : public wxDialog {
/// DOCME /// DOCME
wxRadioBox *CollectAction; wxRadioBox *CollectAction;
/// DOCME
FrameMain *main;
void OnStart(wxCommandEvent &event); void OnStart(wxCommandEvent &event);
void OnClose(wxCommandEvent &event); void OnClose(wxCommandEvent &event);
void OnBrowse(wxCommandEvent &event); void OnBrowse(wxCommandEvent &event);
@ -161,5 +157,3 @@ struct ColourString {
/// DOCME /// DOCME
int colour; int colour;
}; };

View file

@ -941,8 +941,6 @@ void DialogKanjiTimer::OnClose(wxCommandEvent &event) {
} }
if (modified) { if (modified) {
grid->ass->Commit(_("kanji timing")); grid->ass->Commit(_("kanji timing"));
grid->CommitChanges();
grid->UpdateMaps();
LinesToChange.clear(); LinesToChange.clear();
} }
Close(); Close();

View file

@ -320,8 +320,7 @@ void DialogResample::OnResample (wxCommandEvent &event) {
subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2)); subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2));
// Flag as modified // Flag as modified
subs->Commit(_("resolution resampling")); subs->Commit(_("resolution resampling"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
EndModal(0); EndModal(0);
} }

View file

@ -186,8 +186,6 @@ END_EVENT_TABLE()
/// @param event /// @param event
/// ///
void DialogSearchReplace::OnClose (wxCommandEvent &event) { void DialogSearchReplace::OnClose (wxCommandEvent &event) {
Search.OnDialogClose();
// Just hide
Show(false); Show(false);
} }
@ -435,8 +433,7 @@ void SearchReplaceEngine::ReplaceNext(bool DoReplace) {
} }
// Commit // Commit
grid->ass->Commit(_("replace")); grid->ass->Commit(_("replace"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
} }
else { else {
@ -453,7 +450,6 @@ void SearchReplaceEngine::ReplaceNext(bool DoReplace) {
// Update video // Update video
if (updateVideo) { if (updateVideo) {
grid->CommitChanges();
grid->SetVideoToSubs(true); grid->SetVideoToSubs(true);
} }
else if (DoReplace) Modified = true; else if (DoReplace) Modified = true;
@ -541,8 +537,7 @@ void SearchReplaceEngine::ReplaceAll() {
// Commit // Commit
if (count > 0) { if (count > 0) {
grid->ass->Commit(_("replace")); grid->ass->Commit(_("replace"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
wxMessageBox(wxString::Format(_("%i matches were replaced."),count)); wxMessageBox(wxString::Format(_("%i matches were replaced."),count));
} }
@ -572,16 +567,6 @@ void SearchReplaceEngine::OnDialogOpen() {
replaceLen = 0; replaceLen = 0;
} }
/// @brief Search dialog closed
///
void SearchReplaceEngine::OnDialogClose() {
if (Modified) grid->CommitChanges();
}
/// @brief Open dialog /// @brief Open dialog
/// @param replace /// @param replace
/// @return /// @return

View file

@ -123,7 +123,6 @@ public:
void ReplaceAll(); void ReplaceAll();
void OpenDialog(bool HasReplace); void OpenDialog(bool HasReplace);
void OnDialogOpen(); void OnDialogOpen();
void OnDialogClose();
SearchReplaceEngine(); SearchReplaceEngine();
friend class DialogSearchReplace; friend class DialogSearchReplace;

View file

@ -309,8 +309,7 @@ void DialogShiftTimes::OnOK(wxCommandEvent &event) {
OPT_SET("Tool/Shift Times/Direction")->SetBool(backward); OPT_SET("Tool/Shift Times/Direction")->SetBool(backward);
// End dialog // End dialog
grid->ass->Commit(_("shifting")); grid->ass->Commit(_("shifting"), AssFile::COMMIT_TIMES);
grid->CommitChanges();
EndModal(0); EndModal(0);
} }

View file

@ -390,8 +390,7 @@ void DialogSpellChecker::Replace() {
lastPos = wordStart + replaceWord->GetValue().Length(); lastPos = wordStart + replaceWord->GetValue().Length();
// Commit // Commit
grid->ass->Commit(_("Spell check replace")); grid->ass->Commit(_("Spell check replace"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
} }

View file

@ -580,8 +580,7 @@ void DialogStyleEditor::Apply (bool apply,bool close) {
*style = *work; *style = *work;
style->UpdateData(); style->UpdateData();
if (isLocal) { if (isLocal) {
grid->ass->Commit(_("style change")); grid->ass->Commit(_("style change"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
} }
// Exit // Exit

View file

@ -607,7 +607,6 @@ void DialogStyleManager::OnCopyToCurrent (wxCommandEvent &) {
CurrentList->SetStringSelection(*name, true); CurrentList->SetStringSelection(*name, true);
} }
grid->ass->Commit(_("style copy")); grid->ass->Commit(_("style copy"));
grid->CommitChanges();
wxCommandEvent dummy; wxCommandEvent dummy;
OnCurrentChange(dummy); OnCurrentChange(dummy);
} }
@ -656,7 +655,6 @@ void DialogStyleManager::OnCurrentCopy (wxCommandEvent &) {
else delete temp; else delete temp;
grid->ass->Commit(_("style copy")); grid->ass->Commit(_("style copy"));
grid->CommitChanges();
UpdateMoveButtons(); UpdateMoveButtons();
} }
@ -709,7 +707,6 @@ void DialogStyleManager::PasteToCurrent() {
LoadCurrentStyles(grid->ass); LoadCurrentStyles(grid->ass);
grid->ass->Commit(_("style paste")); grid->ass->Commit(_("style paste"));
grid->CommitChanges();
} }
else else
wxMessageBox(_("Could not parse style"), _("Could not parse style"), wxOK | wxICON_EXCLAMATION , this); wxMessageBox(_("Could not parse style"), _("Could not parse style"), wxOK | wxICON_EXCLAMATION , this);
@ -855,7 +852,6 @@ void DialogStyleManager::OnCurrentDelete (wxCommandEvent &) {
CurrentDelete->Enable(false); CurrentDelete->Enable(false);
grid->ass->Commit(_("style delete")); grid->ass->Commit(_("style delete"));
grid->CommitChanges();
} }
UpdateMoveButtons(); UpdateMoveButtons();
} }
@ -917,7 +913,6 @@ void DialogStyleManager::OnCurrentImport(wxCommandEvent &) {
if (modified) { if (modified) {
LoadCurrentStyles(grid->ass); LoadCurrentStyles(grid->ass);
grid->ass->Commit(_("style import")); grid->ass->Commit(_("style import"));
grid->CommitChanges();
} }
} }
catch (...) { catch (...) {
@ -1114,7 +1109,6 @@ void DialogStyleManager::MoveStyles(bool storage, int type) {
// Flag as modified // Flag as modified
grid->ass->Commit(_("style move")); grid->ass->Commit(_("style move"));
grid->CommitChanges();
} }
// Update // Update

View file

@ -169,8 +169,7 @@ wxDialog (parent, -1, _("Styling assistant"), wxDefaultPosition, wxDefaultSize,
DialogStyling::~DialogStyling () { DialogStyling::~DialogStyling () {
GetPosition(&lastx, &lasty); GetPosition(&lastx, &lasty);
if (needCommit) { if (needCommit) {
grid->ass->Commit(_("style changes")); grid->ass->Commit(_("style changes"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
} }
} }
@ -232,8 +231,7 @@ void DialogStyling::SetStyle (wxString curName, bool jump) {
// Update grid/subs // Update grid/subs
grid->Refresh(false); grid->Refresh(false);
if (PreviewCheck->IsChecked()) { if (PreviewCheck->IsChecked()) {
grid->ass->Commit(_("styling assistant")); grid->ass->Commit(_("styling assistant"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
} }
else needCommit = true; else needCommit = true;
@ -264,8 +262,7 @@ void DialogStyling::OnActivate(wxActivateEvent &event) {
// Dialog lost focus // Dialog lost focus
if (!event.GetActive()) { if (!event.GetActive()) {
if (needCommit) { if (needCommit) {
grid->ass->Commit(_("styling assistant")); grid->ass->Commit(_("styling assistant"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
needCommit = false; needCommit = false;
} }
return; return;

View file

@ -541,6 +541,5 @@ void DialogTimingProcessor::Process() {
} }
// Update grid // Update grid
grid->ass->Commit(_("timing processor")); grid->ass->Commit(_("timing processor"), AssFile::COMMIT_TIMES);
grid->CommitChanges();
} }

View file

@ -357,9 +357,7 @@ void DialogTranslation::OnTransBoxKey(wxKeyEvent &event) {
// Update line // Update line
cur->UpdateText(); cur->UpdateText();
cur->ClearBlocks(); cur->ClearBlocks();
subs->Commit(_("translation assistant")); subs->Commit(_("translation assistant"), AssFile::COMMIT_TEXT);
grid->CommitChanges();
((FrameMain*)main)->UpdateTitle();
UpdatePreview(); UpdatePreview();
// Next // Next

View file

@ -551,6 +551,8 @@ void FrameMain::InitMenu() {
/// @brief Initialize contents /// @brief Initialize contents
void FrameMain::InitContents() { void FrameMain::InitContents() {
AssFile::top = ass = new AssFile; AssFile::top = ass = new AssFile;
ass->AddCommitListener(&FrameMain::OnSubtitlesFileChanged, this);
// Set a background panel // Set a background panel
StartupLog(_T("Create background panel")); StartupLog(_T("Create background panel"));
Panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN); Panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN);
@ -563,7 +565,7 @@ void FrameMain::InitContents() {
// Video area; // Video area;
StartupLog(_T("Create video box")); StartupLog(_T("Create video box"));
videoBox = new VideoBox(Panel, false, ZoomBox); videoBox = new VideoBox(Panel, false, ZoomBox, ass);
TopSizer->Add(videoBox,0,wxEXPAND,0); TopSizer->Add(videoBox,0,wxEXPAND,0);
// Subtitles area // Subtitles area
@ -576,13 +578,13 @@ void FrameMain::InitContents() {
// Audio area // Audio area
StartupLog(_T("Create audio box")); StartupLog(_T("Create audio box"));
audioBox = new AudioBox(Panel); audioBox = new AudioBox(Panel, SubsGrid);
audioBox->frameMain = this; audioBox->frameMain = this;
VideoContext::Get()->audio = audioBox->audioDisplay; VideoContext::Get()->audio = audioBox->audioDisplay;
// Top sizer // Top sizer
StartupLog(_T("Create subtitle editing box")); StartupLog(_T("Create subtitle editing box"));
EditBox = new SubsEditBox(Panel,SubsGrid, audioBox->audioDisplay); EditBox = new SubsEditBox(Panel,SubsGrid);
StartupLog(_T("Arrange controls in sizers")); StartupLog(_T("Arrange controls in sizers"));
ToolSizer = new wxBoxSizer(wxVERTICAL); ToolSizer = new wxBoxSizer(wxVERTICAL);
ToolSizer->Add(audioBox,0,wxEXPAND | wxBOTTOM,5); ToolSizer->Add(audioBox,0,wxEXPAND | wxBOTTOM,5);
@ -682,7 +684,6 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
SubsGrid->ClearMaps(); SubsGrid->ClearMaps();
if (isFile) { if (isFile) {
ass->Load(filename,charset); ass->Load(filename,charset);
SubsGrid->UpdateMaps();
if (SubsGrid->GetRows()) { if (SubsGrid->GetRows()) {
SubsGrid->SetActiveLine(SubsGrid->GetDialogue(0)); SubsGrid->SetActiveLine(SubsGrid->GetDialogue(0));
SubsGrid->SelectRow(0); SubsGrid->SelectRow(0);
@ -737,8 +738,6 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
// Update title bar // Update title bar
UpdateTitle(); UpdateTitle();
VideoContext::Get()->Refresh();
} }
/// @brief Save subtitles /// @brief Save subtitles
@ -1109,7 +1108,6 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
SubsGrid->ass->SetScriptInfo(_T("PlayResX"), wxString::Format(_T("%d"), vidx)); SubsGrid->ass->SetScriptInfo(_T("PlayResX"), wxString::Format(_T("%d"), vidx));
SubsGrid->ass->SetScriptInfo(_T("PlayResY"), wxString::Format(_T("%d"), vidy)); SubsGrid->ass->SetScriptInfo(_T("PlayResY"), wxString::Format(_T("%d"), vidy));
SubsGrid->ass->Commit(_("Change script resolution")); SubsGrid->ass->Commit(_("Change script resolution"));
SubsGrid->CommitChanges();
break; break;
case 0: case 0:
default: default:
@ -1119,7 +1117,6 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
} }
} }
SubsGrid->CommitChanges();
SetDisplayMode(1,-1); SetDisplayMode(1,-1);
EditBox->UpdateFrameTiming(); EditBox->UpdateFrameTiming();
@ -1159,7 +1156,6 @@ void FrameMain::LoadVFR(wxString filename) {
else { else {
VideoContext::Get()->LoadTimecodes(filename); VideoContext::Get()->LoadTimecodes(filename);
} }
SubsGrid->CommitChanges();
EditBox->UpdateFrameTiming(); EditBox->UpdateFrameTiming();
} }

View file

@ -322,6 +322,9 @@ private:
void RebuildRecentList(wxString listName,wxMenu *menu,int startID); void RebuildRecentList(wxString listName,wxMenu *menu,int startID);
void SynchronizeProject(bool FromSubs=false); void SynchronizeProject(bool FromSubs=false);
void OnSubtitlesFileChanged();
public: public:
/// DOCME /// DOCME

View file

@ -914,10 +914,7 @@ void FrameMain::OnShift(wxCommandEvent&) {
void FrameMain::OnOpenProperties (wxCommandEvent &) { void FrameMain::OnOpenProperties (wxCommandEvent &) {
VideoContext::Get()->Stop(); VideoContext::Get()->Stop();
DialogProperties Properties(this, ass); DialogProperties Properties(this, ass);
int res = Properties.ShowModal(); Properties.ShowModal();
if (res) {
SubsGrid->CommitChanges();
}
} }
/// @brief Open styles manager /// @brief Open styles manager
@ -925,8 +922,6 @@ void FrameMain::OnOpenStylesManager(wxCommandEvent&) {
VideoContext::Get()->Stop(); VideoContext::Get()->Stop();
DialogStyleManager StyleManager(this,SubsGrid); DialogStyleManager StyleManager(this,SubsGrid);
StyleManager.ShowModal(); StyleManager.ShowModal();
EditBox->UpdateGlobals();
SubsGrid->CommitChanges();
} }
/// @brief Open attachments /// @brief Open attachments
@ -1040,10 +1035,7 @@ void FrameMain::OnAutomationMacro (wxCommandEvent &event) {
int first_sel = SubsGrid->GetFirstSelRow(); int first_sel = SubsGrid->GetFirstSelRow();
// 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
SubsGrid->UpdateMaps();
SubsGrid->SetSelectionFromAbsolute(selected_lines); SubsGrid->SetSelectionFromAbsolute(selected_lines);
SubsGrid->CommitChanges();
SubsGrid->EndBatch(); SubsGrid->EndBatch();
#endif #endif
} }
@ -1113,9 +1105,7 @@ void FrameMain::OnSnapToScene (wxCommandEvent &) {
} }
// Commit // Commit
SubsGrid->editBox->Update(true); SubsGrid->ass->Commit(_("snap to scene"), AssFile::COMMIT_TIMES);
SubsGrid->ass->Commit(_("snap to scene"));
SubsGrid->CommitChanges();
} }
/// @brief Shift to frame /// @brief Shift to frame
@ -1141,27 +1131,19 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &) {
} }
// Commit // Commit
SubsGrid->ass->Commit(_("shift to frame")); SubsGrid->ass->Commit(_("shift to frame"), AssFile::COMMIT_TIMES);
SubsGrid->CommitChanges(false);
SubsGrid->editBox->Update(true);
} }
/// @brief Undo /// @brief Undo
void FrameMain::OnUndo(wxCommandEvent&) { void FrameMain::OnUndo(wxCommandEvent&) {
VideoContext::Get()->Stop(); VideoContext::Get()->Stop();
ass->Undo(); ass->Undo();
UpdateTitle();
SubsGrid->UpdateMaps(true);
VideoContext::Get()->Refresh();
} }
/// @brief Redo /// @brief Redo
void FrameMain::OnRedo(wxCommandEvent&) { void FrameMain::OnRedo(wxCommandEvent&) {
VideoContext::Get()->Stop(); VideoContext::Get()->Stop();
ass->Redo(); ass->Redo();
UpdateTitle();
SubsGrid->UpdateMaps(true);
VideoContext::Get()->Refresh();
} }
/// @brief Find /// @brief Find
@ -1331,22 +1313,16 @@ void FrameMain::OnSelect (wxCommandEvent &) {
void FrameMain::OnSortStart (wxCommandEvent &) { void FrameMain::OnSortStart (wxCommandEvent &) {
ass->Sort(); ass->Sort();
ass->Commit(_("sort")); ass->Commit(_("sort"));
SubsGrid->UpdateMaps();
SubsGrid->CommitChanges();
} }
/// @brief Sort subtitles by end time /// @brief Sort subtitles by end time
void FrameMain::OnSortEnd (wxCommandEvent &) { void FrameMain::OnSortEnd (wxCommandEvent &) {
ass->Sort(AssFile::CompEnd); ass->Sort(AssFile::CompEnd);
ass->Commit(_("sort")); ass->Commit(_("sort"));
SubsGrid->UpdateMaps();
SubsGrid->CommitChanges();
} }
/// @brief Sort subtitles by style name /// @brief Sort subtitles by style name
void FrameMain::OnSortStyle (wxCommandEvent &) { void FrameMain::OnSortStyle (wxCommandEvent &) {
ass->Sort(AssFile::CompStyle); ass->Sort(AssFile::CompStyle);
ass->Commit(_("sort")); ass->Commit(_("sort"));
SubsGrid->UpdateMaps();
SubsGrid->CommitChanges();
} }
/// @brief Open styling assistant /// @brief Open styling assistant
@ -1535,7 +1511,6 @@ void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
audioBox->audioDisplay->curStartMS += 10; audioBox->audioDisplay->curStartMS += 10;
audioBox->audioDisplay->Update(); audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update(); audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
} }
/// @brief DOCME /// @brief DOCME
@ -1543,7 +1518,6 @@ void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
audioBox->audioDisplay->curStartMS -= 10; audioBox->audioDisplay->curStartMS -= 10;
audioBox->audioDisplay->Update(); audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update(); audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
} }
/// @brief DOCME /// @brief DOCME
@ -1551,7 +1525,6 @@ void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
audioBox->audioDisplay->curEndMS += 10; audioBox->audioDisplay->curEndMS += 10;
audioBox->audioDisplay->Update(); audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update(); audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
} }
/// @brief DOCME /// @brief DOCME
@ -1559,7 +1532,6 @@ void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
audioBox->audioDisplay->curEndMS -= 10; audioBox->audioDisplay->curEndMS -= 10;
audioBox->audioDisplay->Update(); audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update(); audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
} }
/// @brief DOCME /// @brief DOCME
@ -1590,3 +1562,11 @@ void FrameMain::OnMedusaPrev(wxCommandEvent &) {
void FrameMain::OnMedusaEnter(wxCommandEvent &) { void FrameMain::OnMedusaEnter(wxCommandEvent &) {
audioBox->audioDisplay->CommitChanges(true); audioBox->audioDisplay->CommitChanges(true);
} }
void FrameMain::OnSubtitlesFileChanged() {
if (OPT_GET("App/Auto/Save on Every Change")->GetBool()) {
if (ass->IsModified() && !ass->filename.empty()) SaveSubtitles(false);
}
UpdateTitle();
}

View file

@ -159,12 +159,11 @@ void bind_focus_handler(T *control, Event event, wxString value, wxString alt, w
control->Bind(event, handler); control->Bind(event, handler);
} }
SubsEditBox::SubsEditBox (wxWindow *parent, SubtitlesGrid *grid, AudioDisplay *audio) SubsEditBox::SubsEditBox(wxWindow *parent, SubtitlesGrid *grid)
: wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxRAISED_BORDER, "SubsEditBox") : wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxRAISED_BORDER, "SubsEditBox")
, line(NULL) , line(NULL)
, splitLineMode(false) , splitLineMode(false)
, controlState(true) , controlState(true)
, audio(audio)
, grid(grid) , grid(grid)
{ {
grid->editBox = this; grid->editBox = this;
@ -329,12 +328,35 @@ SubsEditBox::SubsEditBox (wxWindow *parent, SubtitlesGrid *grid, AudioDisplay *a
OnSize(evt); OnSize(evt);
grid->AddSelectionListener(this); grid->AddSelectionListener(this);
grid->ass->AddCommitListener(&SubsEditBox::Update, this);
} }
SubsEditBox::~SubsEditBox() { SubsEditBox::~SubsEditBox() {
grid->RemoveSelectionListener(this); grid->RemoveSelectionListener(this);
} }
void SubsEditBox::Update(bool timeOnly, bool setAudio) { void SubsEditBox::Update(int type) {
if (type == AssFile::COMMIT_FULL || type == AssFile::COMMIT_UNDO) {
/// @todo maybe preserve selection over undo?
StyleBox->Clear();
StyleBox->Append(grid->ass->GetStyles());
ActorBox->Freeze();
ActorBox->Clear();
int nrows = grid->GetRows();
for (int i=0;i<nrows;i++) {
wxString actor = grid->GetDialogue(i)->Actor;
// OSX doesn't like combo boxes that are empty.
if (actor.empty()) actor = "Actor";
if (ActorBox->FindString(actor) == wxNOT_FOUND) {
ActorBox->Append(actor);
}
}
ActorBox->Thaw();
TextEdit->SetSelection(0,0);
return;
}
SetControlsState(!!line); SetControlsState(!!line);
if (!line) { if (!line) {
return; return;
@ -344,7 +366,7 @@ void SubsEditBox::Update(bool timeOnly, bool setAudio) {
StartTime->SetTime(line->Start); StartTime->SetTime(line->Start);
EndTime->SetTime(line->End); EndTime->SetTime(line->End);
Duration->SetTime(line->End-line->Start); Duration->SetTime(line->End-line->Start);
if (!timeOnly) { if (type != AssFile::COMMIT_TIMES) {
TextEdit->SetTextTo(line->Text); TextEdit->SetTextTo(line->Text);
Layer->SetValue(line->Layer); Layer->SetValue(line->Layer);
MarginL->ChangeValue(line->GetMarginString(0,false)); MarginL->ChangeValue(line->GetMarginString(0,false));
@ -357,32 +379,6 @@ void SubsEditBox::Update(bool timeOnly, bool setAudio) {
ActorBox->SetStringSelection(line->Actor); ActorBox->SetStringSelection(line->Actor);
} }
if (setAudio) audio->SetDialogue(grid,line,grid->GetDialogueIndex(line));
SetEvtHandlerEnabled(true);
}
void SubsEditBox::UpdateGlobals() {
SetEvtHandlerEnabled(false);
StyleBox->Clear();
StyleBox->Append(grid->ass->GetStyles());
ActorBox->Freeze();
ActorBox->Clear();
int nrows = grid->GetRows();
for (int i=0;i<nrows;i++) {
wxString actor = grid->GetDialogue(i)->Actor;
// OSX doesn't like combo boxes that are empty.
if (actor.empty()) actor = "Actor";
if (ActorBox->FindString(actor) == wxNOT_FOUND) {
ActorBox->Append(actor);
}
}
ActorBox->Thaw();
// Set subs update
OnActiveLineChanged(grid->GetActiveLine());
TextEdit->SetSelection(0,0);
SetEvtHandlerEnabled(true); SetEvtHandlerEnabled(true);
} }
@ -390,7 +386,7 @@ void SubsEditBox::OnActiveLineChanged(AssDialogue *new_line) {
SetEvtHandlerEnabled(false); SetEvtHandlerEnabled(false);
line = new_line; line = new_line;
Update(); Update(AssFile::COMMIT_TEXT);
/// @todo VideoContext should be doing this /// @todo VideoContext should be doing this
if (VideoContext::Get()->IsLoaded()) { if (VideoContext::Get()->IsLoaded()) {
@ -464,9 +460,8 @@ void SubsEditBox::SetSelectedRows(setter set, T value, wxString desc, bool amend
for_each(sel.begin(), sel.end(), std::tr1::bind(set, _1, value)); for_each(sel.begin(), sel.end(), std::tr1::bind(set, _1, value));
commitId = grid->ass->Commit(desc, (amend && desc == lastCommitType) ? commitId : -1); commitId = grid->ass->Commit(desc, AssFile::COMMIT_TEXT, (amend && desc == lastCommitType) ? commitId : -1);
lastCommitType = desc; lastCommitType = desc;
grid->CommitChanges(false);
} }
template<class T> template<class T>
@ -476,7 +471,6 @@ void SubsEditBox::SetSelectedRows(T AssDialogue::*field, T value, wxString desc,
void SubsEditBox::CommitText(wxString desc) { void SubsEditBox::CommitText(wxString desc) {
SetSelectedRows(&AssDialogue::Text, TextEdit->GetText(), desc, true); SetSelectedRows(&AssDialogue::Text, TextEdit->GetText(), desc, true);
audio->SetDialogue(grid,line,grid->GetDialogueIndex(line));
} }
void SubsEditBox::CommitTimes(TimeField field) { void SubsEditBox::CommitTimes(TimeField field) {
@ -499,10 +493,7 @@ void SubsEditBox::CommitTimes(TimeField field) {
} }
} }
timeCommitId[field] = grid->ass->Commit(_("modify times"), timeCommitId[field]); timeCommitId[field] = grid->ass->Commit(_("modify times"), AssFile::COMMIT_TIMES, timeCommitId[field]);
grid->CommitChanges();
int sel0 = grid->GetFirstSelRow();
audio->SetDialogue(grid,grid->GetDialogue(sel0),sel0);
} }
void SubsEditBox::OnSize(wxSizeEvent &evt) { void SubsEditBox::OnSize(wxSizeEvent &evt) {

View file

@ -42,7 +42,6 @@
#include "selection_controller.h" #include "selection_controller.h"
class AudioDisplay;
class AssDialogue; class AssDialogue;
class SubtitlesGrid; class SubtitlesGrid;
class SubsTextEditCtrl; class SubsTextEditCtrl;
@ -63,8 +62,6 @@ class wxTextCtrl;
/// ///
/// Controls the text edit and all surrounding controls /// Controls the text edit and all surrounding controls
class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> { class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
friend class AudioDisplay;
enum TimeField { enum TimeField {
TIME_START = 0, TIME_START = 0,
TIME_END, TIME_END,
@ -85,7 +82,6 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
wxColour origBgColour; wxColour origBgColour;
// Externally supplied controls // Externally supplied controls
AudioDisplay *audio;
SubtitlesGrid *grid; SubtitlesGrid *grid;
// Box controls // Box controls
@ -185,23 +181,19 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
/// @param amend Coalesce sequences of commits of the same type /// @param amend Coalesce sequences of commits of the same type
template<class T> template<class T>
void SetSelectedRows(T AssDialogue::*field, T value, wxString desc, bool amend = false); void SetSelectedRows(T AssDialogue::*field, T value, wxString desc, bool amend = false);
/// @brief Reload the current line from the file
/// @param type AssFile::CommitType
void Update(int type);
public: public:
SubsTextEditCtrl *TextEdit; SubsTextEditCtrl *TextEdit;
/// @brief Constructor /// @brief Constructor
/// @param parent Parent window /// @param parent Parent window
/// @param grid Associated grid /// @param grid Associated grid
/// @param audio Associated audio display SubsEditBox(wxWindow *parent, SubtitlesGrid *grid);
SubsEditBox(wxWindow *parent, SubtitlesGrid *grid, AudioDisplay *audio);
~SubsEditBox(); ~SubsEditBox();
/// @brief Reload the current line from the file
/// @param timeOnly Only reload times
/// @param setAudio Also update the audio display
void Update(bool timeOnly = false, bool setAudio = true);
/// Reload non-line-specific things like styles from the file
void UpdateGlobals();
/// @brief Enable or disable frame timing mode /// @brief Enable or disable frame timing mode
void UpdateFrameTiming(); void UpdateFrameTiming();
}; };

View file

@ -111,6 +111,7 @@ SubtitlesGrid::SubtitlesGrid(FrameMain* parentFr, wxWindow *parent, wxWindowID i
OnHighlightVisibleChange(*OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame")); OnHighlightVisibleChange(*OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame"));
OPT_SUB("Subtitle/Grid/Highlight Subtitles in Frame", &SubtitlesGrid::OnHighlightVisibleChange, this); OPT_SUB("Subtitle/Grid/Highlight Subtitles in Frame", &SubtitlesGrid::OnHighlightVisibleChange, this);
ass->AddCommitListener(&SubtitlesGrid::OnCommit, this);
} }
/// @brief Destructor /// @brief Destructor
@ -118,6 +119,17 @@ SubtitlesGrid::~SubtitlesGrid() {
ClearMaps(); ClearMaps();
} }
void SubtitlesGrid::OnCommit(int type) {
if (type == AssFile::COMMIT_FULL)
UpdateMaps();
else if (type == AssFile::COMMIT_UNDO)
UpdateMaps(true);
if (type != AssFile::COMMIT_TIMES)
SetColumnWidths();
Refresh(false);
}
/// @brief Popup menu /// @brief Popup menu
/// @param alternate /// @param alternate
void SubtitlesGrid::OnPopupMenu(bool alternate) { void SubtitlesGrid::OnPopupMenu(bool alternate) {
@ -385,7 +397,6 @@ void SubtitlesGrid::OnSplitByKaraoke (wxCommandEvent &) {
} }
if (didSplit) { if (didSplit) {
ass->Commit(_("splitting")); ass->Commit(_("splitting"));
CommitChanges();
} }
EndBatch(); EndBatch();
} }
@ -615,8 +626,6 @@ void SubtitlesGrid::OnRecombine(wxCommandEvent &) {
} }
ass->Commit(_("combining")); ass->Commit(_("combining"));
UpdateMaps();
CommitChanges();
// Remove now non-existent lines from the selection // Remove now non-existent lines from the selection
Selection lines; Selection lines;
@ -724,15 +733,6 @@ void SubtitlesGrid::LoadDefault () {
SelectRow(0); SelectRow(0);
} }
/// @brief Update internal data structures
void SubtitlesGrid::UpdateMaps(bool preserve_selected_rows) {
BaseGrid::UpdateMaps(preserve_selected_rows);
if (editBox) {
editBox->UpdateGlobals();
}
}
/// @brief Swaps two lines /// @brief Swaps two lines
/// @param n1 /// @param n1
/// @param n2 /// @param n2
@ -744,7 +744,6 @@ void SubtitlesGrid::SwapLines(int n1,int n2) {
std::swap(*dlg1, *dlg2); std::swap(*dlg1, *dlg2);
ass->Commit(_("swap lines")); ass->Commit(_("swap lines"));
CommitChanges();
} }
/// @brief Insert a line /// @brief Insert a line
@ -758,12 +757,13 @@ void SubtitlesGrid::InsertLine(AssDialogue *line,int n,bool after,bool update) {
if (after) ++pos; if (after) ++pos;
entryIter newIter = ass->Line.insert(pos,line); entryIter newIter = ass->Line.insert(pos,line);
BaseGrid::UpdateMaps();
// Update // Update
if (update) { if (update) {
ass->Commit(_("line insertion")); ass->Commit(_("line insertion"));
CommitChanges(); }
else {
UpdateMaps();
} }
} }
@ -876,10 +876,7 @@ void SubtitlesGrid::PasteLines(int n,bool pasteOver) {
// Update data post-insertion // Update data post-insertion
if (inserted > 0) { if (inserted > 0) {
// Commit ass->Commit(_("paste"), pasteOver ? AssFile::COMMIT_TEXT : AssFile::COMMIT_FULL);
UpdateMaps();
ass->Commit(_("paste"));
CommitChanges();
// Set selection // Set selection
if (!pasteOver) { if (!pasteOver) {
@ -920,11 +917,11 @@ void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
old_active_line_index = 0; old_active_line_index = 0;
} }
UpdateMaps();
if (flagModified) { if (flagModified) {
ass->Commit(_("delete")); ass->Commit(_("delete"));
CommitChanges(); }
else {
UpdateMaps();
} }
} }
@ -975,7 +972,6 @@ void SubtitlesGrid::JoinLines(int n1,int n2,bool concat) {
DeleteLines(GetRangeArray(n1+1,n2), false); DeleteLines(GetRangeArray(n1+1,n2), false);
ass->Commit(_("join lines")); ass->Commit(_("join lines"));
CommitChanges();
// Select new line // Select new line
SetActiveLine(cur); SetActiveLine(cur);
@ -1016,7 +1012,6 @@ void SubtitlesGrid::AdjoinLines(int n1,int n2,bool setStart) {
} }
ass->Commit(_("adjoin")); ass->Commit(_("adjoin"));
CommitChanges();
} }
void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) { void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) {
@ -1059,7 +1054,6 @@ void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) {
DeleteLines(GetRangeArray(n1+1,n2), false); DeleteLines(GetRangeArray(n1+1,n2), false);
ass->Commit(_("join as karaoke")); ass->Commit(_("join as karaoke"));
CommitChanges();
// Select new line // Select new line
SetActiveLine(cur); SetActiveLine(cur);
@ -1128,7 +1122,6 @@ void SubtitlesGrid::SplitLine(AssDialogue *n1,int pos,bool estimateTimes) {
} }
ass->Commit(_("split")); ass->Commit(_("split"));
CommitChanges();
} }
bool SubtitlesGrid::SplitLineByKaraoke(int lineNumber) { bool SubtitlesGrid::SplitLineByKaraoke(int lineNumber) {
@ -1170,35 +1163,6 @@ bool SubtitlesGrid::SplitLineByKaraoke(int lineNumber) {
return true; return true;
} }
void SubtitlesGrid::CommitChanges(bool ebox, bool video, bool autosave) {
if (video && context->IsLoaded()) {
bool playing = false;
if (context->IsPlaying()) {
playing = true;
context->Stop();
}
context->Refresh();
if (playing) context->Play();
}
if (autosave) {
// Autosave if option is enabled
if (OPT_GET("App/Auto/Save on Every Change")->GetBool()) {
if (ass->IsModified() && !ass->filename.IsEmpty()) parentFrame->SaveSubtitles(false);
}
// Update parent frame
parentFrame->UpdateTitle();
SetColumnWidths();
Refresh(false);
}
if (ebox) {
editBox->Update(false, false);
}
}
void SubtitlesGrid::SetSubsToVideo(bool start) { void SubtitlesGrid::SetSubsToVideo(bool start) {
if (!context->IsLoaded()) return; if (!context->IsLoaded()) return;
@ -1218,9 +1182,7 @@ void SubtitlesGrid::SetSubsToVideo(bool start) {
} }
if (modified) { if (modified) {
ass->Commit(_("timing")); ass->Commit(_("timing"), AssFile::COMMIT_TIMES);
CommitChanges();
editBox->Update(true);
} }
} }

View file

@ -97,6 +97,8 @@ private:
void OnHighlightVisibleChange(agi::OptionValue const& opt); void OnHighlightVisibleChange(agi::OptionValue const& opt);
void OnCommit(int type);
public: public:
/// Currently open file /// Currently open file
AssFile *ass; AssFile *ass;
@ -105,13 +107,6 @@ public:
~SubtitlesGrid(); ~SubtitlesGrid();
void LoadDefault(); void LoadDefault();
/// @brief Commit changes and update the current file
/// @param ebox Update the edit box
/// @param video Update the video display
/// @param complete Autosave (if enabled) and update other things which care about the file
void CommitChanges(bool ebox = true, bool video = true, bool complete = true);
void UpdateMaps(bool preserve_selected_rows = false);
/// @brief Jump to the start/end time of the current subtitle line /// @brief Jump to the start/end time of the current subtitle line
/// @param start Start vs. End time /// @param start Start vs. End time

View file

@ -63,7 +63,7 @@
/// @param parent /// @param parent
/// @param isDetached /// @param isDetached
/// ///
VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox) VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox, AssFile *ass)
: wxPanel (parent,-1) : wxPanel (parent,-1)
{ {
// Parent // Parent
@ -112,7 +112,7 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox)
visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
// Display // Display
videoDisplay = new VideoDisplay(this,videoSlider,VideoPosition,VideoSubsPos,zoomBox,videoPage,-1,wxDefaultPosition,wxDefaultSize,wxSUNKEN_BORDER); videoDisplay = new VideoDisplay(this,VideoPosition,VideoSubsPos,zoomBox,videoPage,ass);
// Set display // Set display
videoSlider->Display = videoDisplay; videoSlider->Display = videoDisplay;

View file

@ -34,11 +34,6 @@
/// @ingroup main_ui video /// @ingroup main_ui video
/// ///
///////////
// Headers
#ifndef AGI_PRE #ifndef AGI_PRE
#include <wx/panel.h> #include <wx/panel.h>
#include <wx/sizer.h> #include <wx/sizer.h>
@ -47,9 +42,7 @@
#include <wx/toolbar.h> #include <wx/toolbar.h>
#endif #endif
class AssFile;
//////////////
// Prototypes
class VideoDisplay; class VideoDisplay;
class VideoSlider; class VideoSlider;
class ToggleBitmap; class ToggleBitmap;
@ -104,7 +97,7 @@ public:
/// DOCME /// DOCME
VideoSlider *videoSlider; VideoSlider *videoSlider;
VideoBox (wxWindow *parent, bool isDetached, wxComboBox *zoomBox); VideoBox (wxWindow *parent, bool isDetached, wxComboBox *zoomBox, AssFile *ass);
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };

View file

@ -30,7 +30,7 @@
// $Id$ // $Id$
/// @file video_context.cpp /// @file video_context.cpp
/// @brief Keep track of loaded video and video displays /// @brief Keep track of loaded video
/// @ingroup video /// @ingroup video
/// ///
@ -73,7 +73,6 @@
#include "utils.h" #include "utils.h"
#include "video_box.h" #include "video_box.h"
#include "video_context.h" #include "video_context.h"
#include "video_display.h"
#include "video_frame.h" #include "video_frame.h"
/// IDs /// IDs
@ -100,7 +99,6 @@ VideoContext::VideoContext()
, arType(0) , arType(0)
, hasSubtitles(false) , hasSubtitles(false)
, playAudioOnStep(OPT_GET("Audio/Plays When Stepping Video")) , playAudioOnStep(OPT_GET("Audio/Plays When Stepping Video"))
, singleFrame(false)
, grid(NULL) , grid(NULL)
, audio(NULL) , audio(NULL)
, VFR_Input(videoFPS) , VFR_Input(videoFPS)
@ -167,8 +165,6 @@ void VideoContext::SetVideo(const wxString &filename) {
if (filename.empty()) return; if (filename.empty()) return;
try { try {
grid->CommitChanges(true);
provider.reset(new ThreadedFrameSource(filename, this)); provider.reset(new ThreadedFrameSource(filename, this));
videoProvider = provider->GetVideoProvider(); videoProvider = provider->GetVideoProvider();
videoFile = filename; videoFile = filename;
@ -207,6 +203,7 @@ void VideoContext::SetVideo(const wxString &filename) {
} }
provider->LoadSubtitles(grid->ass); provider->LoadSubtitles(grid->ass);
grid->ass->AddCommitListener(&VideoContext::SubtitlesChanged, this);
VideoOpen(); VideoOpen();
KeyframesOpen(keyFrames); KeyframesOpen(keyFrames);
} }
@ -228,11 +225,16 @@ void VideoContext::Reload() {
} }
} }
void VideoContext::Refresh() { void VideoContext::SubtitlesChanged() {
if (!IsLoaded()) return; if (!IsLoaded()) return;
bool wasPlaying = isPlaying;
Stop();
provider->LoadSubtitles(grid->ass); provider->LoadSubtitles(grid->ass);
SubtitlesChange(); GetFrameAsync(frame_n);
if (wasPlaying) Play();
} }
void VideoContext::JumpToFrame(int n) { void VideoContext::JumpToFrame(int n) {
@ -446,6 +448,7 @@ void VideoContext::SetAspectRatio(int type, double value) {
arType = type; arType = type;
arValue = MID(.5, value, 5.); arValue = MID(.5, value, 5.);
ARChange(arType, arValue);
} }
void VideoContext::LoadKeyframes(wxString filename) { void VideoContext::LoadKeyframes(wxString filename) {
@ -488,7 +491,7 @@ void VideoContext::LoadTimecodes(wxString filename) {
ovrFPS = agi::vfr::Framerate(STD_STR(filename)); ovrFPS = agi::vfr::Framerate(STD_STR(filename));
ovrTimecodeFile = filename; ovrTimecodeFile = filename;
config::mru->Add("Timecodes", STD_STR(filename)); config::mru->Add("Timecodes", STD_STR(filename));
Refresh(); SubtitlesChanged();
} }
catch (const agi::acs::AcsError&) { catch (const agi::acs::AcsError&) {
wxLogError(L"Could not open file " + filename); wxLogError(L"Could not open file " + filename);
@ -510,7 +513,7 @@ void VideoContext::SaveTimecodes(wxString filename) {
void VideoContext::CloseTimecodes() { void VideoContext::CloseTimecodes() {
ovrFPS = agi::vfr::Framerate(); ovrFPS = agi::vfr::Framerate();
ovrTimecodeFile.clear(); ovrTimecodeFile.clear();
Refresh(); SubtitlesChanged();
} }
int VideoContext::TimeAtFrame(int frame, agi::vfr::Time type) const { int VideoContext::TimeAtFrame(int frame, agi::vfr::Time type) const {

View file

@ -62,7 +62,6 @@ class SubtitlesProviderErrorEvent;
class ThreadedFrameSource; class ThreadedFrameSource;
class VideoProvider; class VideoProvider;
class VideoProviderErrorEvent; class VideoProviderErrorEvent;
class VideoDisplay;
namespace agi { namespace agi {
class OptionValue; class OptionValue;
@ -77,20 +76,16 @@ class VideoContext : public wxEvtHandler {
friend class AudioProvider; friend class AudioProvider;
friend class KeyFrameFile; friend class KeyFrameFile;
/// Current frame number changed /// Current frame number changed (new frame number)
agi::signal::Signal<int> Seek; agi::signal::Signal<int> Seek;
/// A new video was opened /// A new video was opened
agi::signal::Signal<> VideoOpen; agi::signal::Signal<> VideoOpen;
/// Subtitles file changed /// New keyframes opened (new keyframe data)
/// @todo Move this to AssFile
agi::signal::Signal<> SubtitlesChange;
/// New keyframes opened
agi::signal::Signal<std::vector<int> const&> KeyframesOpen; agi::signal::Signal<std::vector<int> const&> KeyframesOpen;
/// Aspect ratio was changed (type, value)
agi::signal::Signal<int, double> ARChange;
private: private:
/// DOCME
std::list<VideoDisplay*> displayList;
/// DOCME /// DOCME
std::tr1::shared_ptr<VideoProvider> videoProvider; std::tr1::shared_ptr<VideoProvider> videoProvider;
@ -156,8 +151,6 @@ private:
agi::vfr::Framerate videoFPS; agi::vfr::Framerate videoFPS;
agi::vfr::Framerate ovrFPS; agi::vfr::Framerate ovrFPS;
bool singleFrame;
void OnVideoError(VideoProviderErrorEvent const& err); void OnVideoError(VideoProviderErrorEvent const& err);
void OnSubtitlesError(SubtitlesProviderErrorEvent const& err); void OnSubtitlesError(SubtitlesProviderErrorEvent const& err);
@ -240,7 +233,7 @@ public:
void JumpToTime(int ms, agi::vfr::Time end = agi::vfr::START); void JumpToTime(int ms, agi::vfr::Time end = agi::vfr::START);
/// @brief Refresh the subtitle provider /// @brief Refresh the subtitle provider
void Refresh(); void SubtitlesChanged();
/// @brief Get the height and width of the current script /// @brief Get the height and width of the current script
/// @param[out] w Width /// @param[out] w Width
@ -263,7 +256,7 @@ public:
DEFINE_SIGNAL_ADDERS(Seek, AddSeekListener) DEFINE_SIGNAL_ADDERS(Seek, AddSeekListener)
DEFINE_SIGNAL_ADDERS(VideoOpen, AddVideoOpenListener) DEFINE_SIGNAL_ADDERS(VideoOpen, AddVideoOpenListener)
DEFINE_SIGNAL_ADDERS(KeyframesOpen, AddKeyframesOpenListener) DEFINE_SIGNAL_ADDERS(KeyframesOpen, AddKeyframesOpenListener)
DEFINE_SIGNAL_ADDERS(SubtitlesChange, AddSubtitlesChangeListener) DEFINE_SIGNAL_ADDERS(ARChange, AddARChangeListener)
const std::vector<int>& GetKeyFrames() const { return keyFrames; }; const std::vector<int>& GetKeyFrames() const { return keyFrames; };
wxString GetKeyFramesName() const { return keyFramesFilename; } wxString GetKeyFramesName() const { return keyFramesFilename; }

View file

@ -59,6 +59,7 @@
#include "video_display.h" #include "video_display.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h"
#include "hotkeys.h" #include "hotkeys.h"
#include "main.h" #include "main.h"
#include "subs_grid.h" #include "subs_grid.h"
@ -66,7 +67,6 @@
#include "video_out_gl.h" #include "video_out_gl.h"
#include "video_box.h" #include "video_box.h"
#include "video_context.h" #include "video_context.h"
#include "video_slider.h"
#include "visual_tool.h" #include "visual_tool.h"
#include "visual_tool_clip.h" #include "visual_tool_clip.h"
#include "visual_tool_cross.h" #include "visual_tool_cross.h"
@ -97,7 +97,6 @@ BEGIN_EVENT_TABLE(VideoDisplay, wxGLCanvas)
EVT_PAINT(VideoDisplay::OnPaint) EVT_PAINT(VideoDisplay::OnPaint)
EVT_SIZE(VideoDisplay::OnSizeEvent) EVT_SIZE(VideoDisplay::OnSizeEvent)
EVT_ERASE_BACKGROUND(VideoDisplay::OnEraseBackground) EVT_ERASE_BACKGROUND(VideoDisplay::OnEraseBackground)
EVT_SHOW(VideoDisplay::OnShow)
EVT_MENU(VIDEO_MENU_COPY_COORDS,VideoDisplay::OnCopyCoords) EVT_MENU(VIDEO_MENU_COPY_COORDS,VideoDisplay::OnCopyCoords)
EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD,VideoDisplay::OnCopyToClipboard) EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD,VideoDisplay::OnCopyToClipboard)
@ -125,24 +124,17 @@ public:
VideoDisplay::VideoDisplay( VideoDisplay::VideoDisplay(
VideoBox *box, VideoBox *box,
VideoSlider *ControlSlider,
wxTextCtrl *PositionDisplay, wxTextCtrl *PositionDisplay,
wxTextCtrl *SubsPosition, wxTextCtrl *SubsPosition,
wxComboBox *zoomBox, wxComboBox *zoomBox,
wxWindow* parent, wxWindow* parent,
wxWindowID id, AssFile *model)
const wxPoint& pos, : wxGLCanvas (parent, -1, attribList, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER, wxPanelNameStr)
const wxSize& size,
long style,
const wxString& name)
: wxGLCanvas (parent, id, attribList, pos, size, style, name)
, alwaysShowTools(OPT_GET("Tool/Visual/Always Show")) , alwaysShowTools(OPT_GET("Tool/Visual/Always Show"))
, origSize(size) , vc(VideoContext::Get())
, currentFrame(-1) , currentFrame(-1)
, w(8), h(8), viewport_x(0), viewport_width(0), viewport_bottom(0), viewport_top(0), viewport_height(0) , w(8), h(8), viewport_x(0), viewport_width(0), viewport_bottom(0), viewport_top(0), viewport_height(0)
, locked(false)
, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125) , zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125)
, ControlSlider(ControlSlider)
, SubsPosition(SubsPosition) , SubsPosition(SubsPosition)
, PositionDisplay(PositionDisplay) , PositionDisplay(PositionDisplay)
, videoOut(new VideoOutGL()) , videoOut(new VideoOutGL())
@ -151,23 +143,28 @@ VideoDisplay::VideoDisplay(
, scriptW(INT_MIN) , scriptW(INT_MIN)
, scriptH(INT_MIN) , scriptH(INT_MIN)
, zoomBox(zoomBox) , zoomBox(zoomBox)
, model(model)
, box(box) , box(box)
, freeSize(false) , freeSize(false)
{ {
assert(vc);
assert(box);
assert(model);
if (zoomBox) zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.)); if (zoomBox) zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VideoDisplay::OnMode, this, Video_Mode_Standard, Video_Mode_Vector_Clip); box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VideoDisplay::OnMode, this, Video_Mode_Standard, Video_Mode_Vector_Clip);
VideoContext *vc = VideoContext::Get();
vc->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this); vc->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
slots.push_back(vc->AddSeekListener(&VideoDisplay::SetFrame, this)); slots.push_back(vc->AddSeekListener(&VideoDisplay::SetFrame, this));
slots.push_back(vc->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, this)); slots.push_back(vc->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, this));
slots.push_back(vc->AddSubtitlesChangeListener(&VideoDisplay::Refresh, this)); slots.push_back(vc->AddARChangeListener(&VideoDisplay::UpdateSize, this));
slots.push_back(model->AddCommitListener(&VideoDisplay::OnCommit, this));
SetCursor(wxNullCursor); SetCursor(wxNullCursor);
} }
VideoDisplay::~VideoDisplay () { VideoDisplay::~VideoDisplay () {
VideoContext::Get()->Unbind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this); vc->Unbind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
} }
bool VideoDisplay::InitContext() { bool VideoDisplay::InitContext() {
@ -195,7 +192,7 @@ void VideoDisplay::UpdateRelativeTimes(int time) {
int startOff = 0; int startOff = 0;
int endOff = 0; int endOff = 0;
if (AssDialogue *curLine = VideoContext::Get()->grid->GetActiveLine()) { if (AssDialogue *curLine = vc->grid->GetActiveLine()) {
startOff = time - curLine->Start.GetMS(); startOff = time - curLine->Start.GetMS();
endOff = time - curLine->End.GetMS(); endOff = time - curLine->End.GetMS();
} }
@ -210,13 +207,11 @@ void VideoDisplay::UpdateRelativeTimes(int time) {
void VideoDisplay::SetFrame(int frameNumber) { void VideoDisplay::SetFrame(int frameNumber) {
VideoContext *context = VideoContext::Get();
currentFrame = frameNumber; currentFrame = frameNumber;
// Get time for frame // Get time for frame
{ {
int time = context->TimeAtFrame(frameNumber, agi::vfr::EXACT); int time = vc->TimeAtFrame(frameNumber, agi::vfr::EXACT);
int h = time / 3600000; int h = time / 3600000;
int m = time % 3600000 / 60000; int m = time % 3600000 / 60000;
int s = time % 60000 / 1000; int s = time % 60000 / 1000;
@ -224,7 +219,7 @@ void VideoDisplay::SetFrame(int frameNumber) {
// Set the text box for frame number and time // Set the text box for frame number and time
PositionDisplay->SetValue(wxString::Format(L"%01i:%02i:%02i.%03i - %i", h, m, s, ms, frameNumber)); PositionDisplay->SetValue(wxString::Format(L"%01i:%02i:%02i.%03i - %i", h, m, s, ms, frameNumber));
if (std::binary_search(context->GetKeyFrames().begin(), context->GetKeyFrames().end(), frameNumber)) { if (std::binary_search(vc->GetKeyFrames().begin(), vc->GetKeyFrames().end(), frameNumber)) {
// Set the background color to indicate this is a keyframe // Set the background color to indicate this is a keyframe
PositionDisplay->SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColour())); PositionDisplay->SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColour()));
PositionDisplay->SetForegroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); PositionDisplay->SetForegroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour()));
@ -238,9 +233,9 @@ void VideoDisplay::SetFrame(int frameNumber) {
} }
// Render the new frame // Render the new frame
if (context->IsLoaded()) { if (vc->IsLoaded()) {
tool->SetFrame(frameNumber); tool->SetFrame(frameNumber);
context->GetFrameAsync(currentFrame); vc->GetFrameAsync(currentFrame);
} }
} }
@ -256,7 +251,7 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
L"programs and updating your video card drivers may fix this.\n" L"programs and updating your video card drivers may fix this.\n"
L"Error message reported: %s", L"Error message reported: %s",
err.GetMessage().c_str()); err.GetMessage().c_str());
VideoContext::Get()->Reset(); vc->Reset();
} }
catch (const VideoOutRenderException& err) { catch (const VideoOutRenderException& err) {
wxLogError( wxLogError(
@ -267,23 +262,24 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
Render(); Render();
} }
void VideoDisplay::Refresh() {
if (!tool.get()) tool.reset(new VisualToolCross(this, video, toolBar));
if (!InitContext()) return;
VideoContext::Get()->GetFrameAsync(currentFrame);
tool->Refresh();
UpdateRelativeTimes(VideoContext::Get()->TimeAtFrame(currentFrame, agi::vfr::EXACT));
}
void VideoDisplay::OnVideoOpen() { void VideoDisplay::OnVideoOpen() {
UpdateSize(); UpdateSize();
Refresh(); currentFrame = 0;
vc->GetFrameAsync(0);
UpdateRelativeTimes(0);
if (!tool.get()) tool.reset(new VisualToolCross(this, video, toolBar));
tool->Refresh();
}
void VideoDisplay::OnCommit(int type) {
if (type == AssFile::COMMIT_FULL || type == AssFile::COMMIT_UNDO)
vc->GetScriptSize(scriptW, scriptH);
if (tool.get()) tool->Refresh();
UpdateRelativeTimes(vc->TimeAtFrame(currentFrame, agi::vfr::EXACT));
} }
void VideoDisplay::Render() try { void VideoDisplay::Render() try {
if (!InitContext()) return; if (!InitContext()) return;
VideoContext *context = VideoContext::Get(); if (!vc->IsLoaded()) return;
if (!context->IsLoaded()) return;
assert(wxIsMainThread()); assert(wxIsMainThread());
if (!viewport_height || !viewport_width) UpdateSize(); if (!viewport_height || !viewport_width) UpdateSize();
@ -295,7 +291,7 @@ void VideoDisplay::Render() try {
E(glOrtho(0.0f, w, h, 0.0f, -1000.0f, 1000.0f)); E(glOrtho(0.0f, w, h, 0.0f, -1000.0f, 1000.0f));
if (OPT_GET("Video/Overscan Mask")->GetBool()) { if (OPT_GET("Video/Overscan Mask")->GetBool()) {
double ar = context->GetAspectRatioValue(); double ar = vc->GetAspectRatioValue();
// Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf // Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf
// 16:9 or wider // 16:9 or wider
@ -312,7 +308,6 @@ void VideoDisplay::Render() try {
} }
if (video.x > INT_MIN || video.y > INT_MIN || alwaysShowTools->GetBool()) { if (video.x > INT_MIN || video.y > INT_MIN || alwaysShowTools->GetBool()) {
context->GetScriptSize(scriptW, scriptH);
tool->Draw(); tool->Draw();
} }
@ -324,27 +319,27 @@ catch (const VideoOutException &err) {
L"An error occurred trying to render the video frame on the screen.\n" L"An error occurred trying to render the video frame on the screen.\n"
L"Error message reported: %s", L"Error message reported: %s",
err.GetMessage().c_str()); err.GetMessage().c_str());
VideoContext::Get()->Reset(); vc->Reset();
} }
catch (const OpenGlException &err) { catch (const OpenGlException &err) {
wxLogError( wxLogError(
L"An error occurred trying to render visual overlays on the screen.\n" L"An error occurred trying to render visual overlays on the screen.\n"
L"Error message reported: %s", L"Error message reported: %s",
err.GetMessage().c_str()); err.GetMessage().c_str());
VideoContext::Get()->Reset(); vc->Reset();
} }
catch (const wchar_t *err) { catch (const wchar_t *err) {
wxLogError( wxLogError(
L"An error occurred trying to render the video frame on the screen.\n" L"An error occurred trying to render the video frame on the screen.\n"
L"Error message reported: %s", L"Error message reported: %s",
err); err);
VideoContext::Get()->Reset(); vc->Reset();
} }
catch (...) { catch (...) {
wxLogError( wxLogError(
L"An error occurred trying to render the video frame to screen.\n" L"An error occurred trying to render the video frame to screen.\n"
L"No further error message given."); L"No further error message given.");
VideoContext::Get()->Reset(); vc->Reset();
} }
void VideoDisplay::DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const { void VideoDisplay::DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const {
@ -372,15 +367,17 @@ void VideoDisplay::DrawOverscanMask(int sizeH, int sizeV, wxColor color, double
E(glDisable(GL_BLEND)); E(glDisable(GL_BLEND));
} }
void VideoDisplay::UpdateSize(int arType, double arValue) {
void VideoDisplay::UpdateSize() { if (!vc->IsLoaded()) return;
VideoContext *con = VideoContext::Get();
wxASSERT(con);
if (!con->IsLoaded()) return;
if (!IsShownOnScreen()) return; if (!IsShownOnScreen()) return;
int vidW = con->GetWidth(); int vidW = vc->GetWidth();
int vidH = con->GetHeight(); int vidH = vc->GetHeight();
if (arType == -1) {
arType = vc->GetAspectRatioType();
arValue = vc->GetAspectRatioValue();
}
if (freeSize) { if (freeSize) {
GetClientSize(&w,&h); GetClientSize(&w,&h);
@ -391,8 +388,8 @@ void VideoDisplay::UpdateSize() {
viewport_height = h; viewport_height = h;
// Set aspect ratio // Set aspect ratio
float displayAr = float(w) / float(h); double displayAr = double(w) / h;
float videoAr = con->GetAspectRatioType() == 0 ? float(vidW)/float(vidH) : con->GetAspectRatioValue(); double videoAr = arType == 0 ? double(vidW)/vidH : arValue;
// Window is wider than video, blackbox left/right // Window is wider than video, blackbox left/right
if (displayAr - videoAr > 0.01f) { if (displayAr - videoAr > 0.01f) {
@ -415,7 +412,7 @@ void VideoDisplay::UpdateSize() {
parent->GetClientSize(&maxW, &maxH); parent->GetClientSize(&maxW, &maxH);
h = vidH * zoomValue; h = vidH * zoomValue;
w = con->GetAspectRatioType() == 0 ? vidW * zoomValue : vidH * zoomValue * con->GetAspectRatioValue(); w = arType == 0 ? vidW * zoomValue : vidH * zoomValue * arValue;
// Cap the canvas size to the window size // Cap the canvas size to the window size
int cw = std::min(w, maxW), ch = std::min(h, maxH); int cw = std::min(w, maxW), ch = std::min(h, maxH);
@ -430,7 +427,7 @@ void VideoDisplay::UpdateSize() {
SetMinClientSize(size); SetMinClientSize(size);
SetMaxClientSize(size); SetMaxClientSize(size);
locked = true; SetEvtHandlerEnabled(false);
box->GetParent()->Layout(); box->GetParent()->Layout();
// The sizer makes us use the full width, which at very low zoom levels // The sizer makes us use the full width, which at very low zoom levels
@ -438,10 +435,10 @@ void VideoDisplay::UpdateSize() {
// parent window sizes, reset our size to the correct value // parent window sizes, reset our size to the correct value
SetSize(cw, ch); SetSize(cw, ch);
locked = false; SetEvtHandlerEnabled(true);
} }
con->GetScriptSize(scriptW, scriptH); vc->GetScriptSize(scriptW, scriptH);
video.w = w; video.w = w;
video.h = h; video.h = h;
@ -450,22 +447,7 @@ void VideoDisplay::UpdateSize() {
wxGLCanvas::Refresh(false); wxGLCanvas::Refresh(false);
} }
void VideoDisplay::Reset() {
// Only calculate sizes if it's visible
if (!IsShownOnScreen()) return;
int w = origSize.GetX();
int h = origSize.GetY();
wxASSERT(w > 0);
wxASSERT(h > 0);
SetClientSize(w,h);
GetSize(&w,&h);
wxASSERT(w > 0);
wxASSERT(h > 0);
SetSizeHints(w,h,w,h);
}
void VideoDisplay::OnPaint(wxPaintEvent&) { void VideoDisplay::OnPaint(wxPaintEvent&) {
wxPaintDC dc(this);
Render(); Render();
} }
@ -475,11 +457,10 @@ void VideoDisplay::OnSizeEvent(wxSizeEvent &event) {
} }
void VideoDisplay::OnMouseEvent(wxMouseEvent& event) { void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
if (locked) return;
assert(w > 0); assert(w > 0);
// Disable when playing // Disable when playing
if (VideoContext::Get()->IsPlaying()) return; if (vc->IsPlaying()) return;
if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) { if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) {
wxMenu menu; wxMenu menu;
@ -554,10 +535,6 @@ double VideoDisplay::GetZoom() const {
return zoomValue; return zoomValue;
} }
void VideoDisplay::OnShow(wxShowEvent&) {
OnVideoOpen();
}
template<class T> template<class T>
void VideoDisplay::SetTool() { void VideoDisplay::SetTool() {
tool.reset(); tool.reset();
@ -609,24 +586,24 @@ void VideoDisplay::FromScriptCoords(int *x, int *y) const {
void VideoDisplay::OnCopyToClipboard(wxCommandEvent &) { void VideoDisplay::OnCopyToClipboard(wxCommandEvent &) {
if (wxTheClipboard->Open()) { if (wxTheClipboard->Open()) {
wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(currentFrame)->GetImage(),24))); wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(vc->GetFrame(currentFrame)->GetImage(),24)));
wxTheClipboard->Close(); wxTheClipboard->Close();
} }
} }
void VideoDisplay::OnCopyToClipboardRaw(wxCommandEvent &) { void VideoDisplay::OnCopyToClipboardRaw(wxCommandEvent &) {
if (wxTheClipboard->Open()) { if (wxTheClipboard->Open()) {
wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(currentFrame,true)->GetImage(),24))); wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(vc->GetFrame(currentFrame,true)->GetImage(),24)));
wxTheClipboard->Close(); wxTheClipboard->Close();
} }
} }
void VideoDisplay::OnSaveSnapshot(wxCommandEvent &) { void VideoDisplay::OnSaveSnapshot(wxCommandEvent &) {
VideoContext::Get()->SaveSnapshot(false); vc->SaveSnapshot(false);
} }
void VideoDisplay::OnSaveSnapshotRaw(wxCommandEvent &) { void VideoDisplay::OnSaveSnapshotRaw(wxCommandEvent &) {
VideoContext::Get()->SaveSnapshot(true); vc->SaveSnapshot(true);
} }
void VideoDisplay::OnCopyCoords(wxCommandEvent &) { void VideoDisplay::OnCopyCoords(wxCommandEvent &) {

View file

@ -45,9 +45,10 @@
#include <libaegisub/signals.h> #include <libaegisub/signals.h>
// Prototypes // Prototypes
class AssFile;
class FrameReadyEvent; class FrameReadyEvent;
class VideoSlider;
class VideoBox; class VideoBox;
class VideoContext;
class VideoOutGL; class VideoOutGL;
class IVisualTool; class IVisualTool;
class wxToolBar; class wxToolBar;
@ -70,8 +71,9 @@ class VideoDisplay : public wxGLCanvas {
std::list<agi::signal::Connection> slots; std::list<agi::signal::Connection> slots;
const agi::OptionValue* alwaysShowTools; const agi::OptionValue* alwaysShowTools;
/// The unscaled size of the displayed video
wxSize origSize; /// The video context providing video to this display
VideoContext *vc;
/// The frame number currently being displayed /// The frame number currently being displayed
int currentFrame; int currentFrame;
@ -92,9 +94,6 @@ class VideoDisplay : public wxGLCanvas {
/// The height of the video in screen pixels /// The height of the video in screen pixels
int viewport_height; int viewport_height;
/// Lock to disable mouse updates during resize operations
bool locked;
/// @brief Draw an overscan mask /// @brief Draw an overscan mask
/// @param sizeH The amount of horizontal overscan on one side /// @param sizeH The amount of horizontal overscan on one side
/// @param sizeV The amount of vertical overscan on one side /// @param sizeV The amount of vertical overscan on one side
@ -134,9 +133,6 @@ class VideoDisplay : public wxGLCanvas {
/// The current zoom level, where 1.0 = 100% /// The current zoom level, where 1.0 = 100%
double zoomValue; double zoomValue;
/// The video position slider
VideoSlider *ControlSlider;
/// The display for the the video position relative to the current subtitle line /// The display for the the video position relative to the current subtitle line
wxTextCtrl *SubsPosition; wxTextCtrl *SubsPosition;
@ -167,12 +163,9 @@ class VideoDisplay : public wxGLCanvas {
/// @brief Set this video display to the given frame /// @brief Set this video display to the given frame
/// @frameNumber The desired frame number /// @frameNumber The desired frame number
void SetFrame(int frameNumber); void SetFrame(int frameNumber);
/// @brief Signal that the file has changed
void Refresh();
void OnVideoOpen(); void OnVideoOpen();
void OnCommit(int type);
void OnShow(wxShowEvent &event);
void OnMode(const wxCommandEvent &event); void OnMode(const wxCommandEvent &event);
void SetMode(int mode); void SetMode(int mode);
@ -190,6 +183,8 @@ class VideoDisplay : public wxGLCanvas {
/// The dropdown box for selecting zoom levels /// The dropdown box for selecting zoom levels
wxComboBox *zoomBox; wxComboBox *zoomBox;
AssFile *model;
public: public:
/// The VideoBox this display is contained in /// The VideoBox this display is contained in
VideoBox *box; VideoBox *box;
@ -198,27 +193,14 @@ public:
bool freeSize; bool freeSize;
/// @brief Constructor /// @brief Constructor
/// @param parent Pointer to a parent window.
/// @param id Window identifier. If -1, will automatically create an identifier.
/// @param pos Window position. wxDefaultPosition is (-1, -1) which indicates that wxWidgets should generate a default position for the window.
/// @param size Window size. wxDefaultSize is (-1, -1) which indicates that wxWidgets should generate a default size for the window. If no suitable size can be found, the window will be sized to 20x20 pixels so that the window is visible but obviously not correctly sized.
/// @param style Window style.
/// @param name Window name.
VideoDisplay( VideoDisplay(
VideoBox *box, VideoBox *box,
VideoSlider *ControlSlider,
wxTextCtrl *PositionDisplay, wxTextCtrl *PositionDisplay,
wxTextCtrl *SubsPosition, wxTextCtrl *SubsPosition,
wxComboBox *zoomBox, wxComboBox *zoomBox,
wxWindow* parent, wxWindow* parent,
wxWindowID id, AssFile *model);
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxPanelNameStr);
~VideoDisplay(); ~VideoDisplay();
/// @brief Reset the size of the display to the video size
void Reset();
/// @brief Render the currently visible frame /// @brief Render the currently visible frame
void Render(); void Render();
@ -227,7 +209,7 @@ public:
/// @param show Whether or not the cursor should be visible /// @param show Whether or not the cursor should be visible
void ShowCursor(bool show); void ShowCursor(bool show);
/// @brief Set the size of the display based on the current zoom and video resolution /// @brief Set the size of the display based on the current zoom and video resolution
void UpdateSize(); void UpdateSize(int arType = -1, double arValue = -1.);
/// @brief Set the zoom level /// @brief Set the zoom level
/// @param value The new zoom level /// @param value The new zoom level
void SetZoom(double value); void SetZoom(double value);
@ -245,6 +227,5 @@ public:
/// @param y y coordinate; in/out /// @param y y coordinate; in/out
void FromScriptCoords(int *x, int *y) const; void FromScriptCoords(int *x, int *y) const;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };

View file

@ -246,9 +246,7 @@ void VisualTool<FeatureType>::Commit(wxString message) {
if (message.empty()) { if (message.empty()) {
message = _("visual typesetting"); message = _("visual typesetting");
} }
commitId = grid->ass->Commit(message, commitId); commitId = grid->ass->Commit(message, AssFile::COMMIT_TEXT, commitId);
grid->CommitChanges();
externalChange = true; externalChange = true;
} }