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

View file

@ -45,6 +45,8 @@
#include <wx/arrstr.h>
#endif
#include <libaegisub/signals.h>
class FrameRate;
class AssDialogue;
class AssStyle;
@ -70,6 +72,8 @@ class AssFile {
/// Last saved version of this file
int savedCommitId;
agi::signal::Signal<int> AnnounceCommit;
public:
/// The lines in the file
std::list<AssEntry*> Line;
@ -150,11 +154,28 @@ public:
/// @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);
/// 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
/// @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
/// @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
void Undo();
/// @brief Redo the last undone changes

View file

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

View file

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

View file

@ -79,9 +79,9 @@
/// @brief Constructor
/// @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"))
, grid(0)
, grid(grid)
{
// Set variables
origImage = NULL;
@ -99,7 +99,6 @@ AudioDisplay::AudioDisplay(wxWindow *parent)
loaded = false;
temporary = false;
blockUpdate = false;
dontReadTimes = false;
holding = false;
draggingScale = false;
Position = 0;
@ -127,6 +126,9 @@ AudioDisplay::AudioDisplay(wxWindow *parent)
if (OPT_GET("Audio/Display/Draw/Video Position")->GetBool())
vc->AddSeekListener(&AudioDisplay::UpdateImage, this, false);
grid->AddSelectionListener(this);
commitListener = grid->ass->AddCommitListener(&AudioDisplay::OnCommit, this);
// Set cursor
//wxCursor cursor(wxCURSOR_BLANK);
//SetCursor(cursor);
@ -1119,28 +1121,24 @@ void AudioDisplay::SetSelection(int start, int end) {
/// @param diag
/// @param n
/// @return
void AudioDisplay::SetDialogue(SubtitlesGrid *_grid,AssDialogue *diag,int n) {
// Actual parameters
if (_grid) {
// Set variables
grid = _grid;
line_n = n;
dialogue = diag;
void AudioDisplay::SetDialogue(SubtitlesGrid *,AssDialogue *diag,int n) {
// Set variables
line_n = n;
dialogue = diag;
// Set flags
diagUpdated = false;
NeedCommit = false;
// Set flags
diagUpdated = false;
NeedCommit = false;
// Set times
if (dialogue && !dontReadTimes && OPT_GET("Audio/Grab Times on Select")->GetBool()) {
int s = dialogue->Start.GetMS();
int e = dialogue->End.GetMS();
// Set times
if (dialogue && OPT_GET("Audio/Grab Times on Select")->GetBool()) {
int s = dialogue->Start.GetMS();
int e = dialogue->End.GetMS();
// Never do it for 0:00:00.00->0:00:00.00 lines
if (s != 0 || e != 0) {
curStartMS = s;
curEndMS = e;
}
// Never do it for 0:00:00.00->0:00:00.00 lines
if (s != 0 || e != 0) {
curStartMS = s;
curEndMS = e;
}
}
@ -1163,11 +1161,11 @@ void AudioDisplay::SetDialogue(SubtitlesGrid *_grid,AssDialogue *diag,int n) {
void AudioDisplay::CommitChanges (bool nextLine) {
// Loaded?
if (!loaded) return;
commitListener.Block();
// 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;
if (timeNeedsCommit || textNeedsCommit) NeedCommit = true;
NeedCommit = timeNeedsCommit;
bool wasKaraSplitting = false;
bool validCommit = true;
if (!karaoke->enabled && !karaoke->splitting) {
@ -1208,7 +1206,7 @@ void AudioDisplay::CommitChanges (bool nextLine) {
curDiag->Start.SetMS(curStartMS);
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,
// so only update from editbox when not in kara mode
curDiag->Text = grid->editBox->TextEdit->GetText();
@ -1216,15 +1214,7 @@ void AudioDisplay::CommitChanges (bool nextLine) {
if (!grid->IsInSelection(line_n)) break;
}
// Update edit box
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();
grid->ass->Commit(_T(""), karaoke->enabled ? AssFile::COMMIT_TEXT : AssFile::COMMIT_TIMES);
karaoke->SetSelection(karaSelStart, karaSelEnd);
blockUpdate = false;
}
@ -1240,24 +1230,19 @@ void AudioDisplay::CommitChanges (bool nextLine) {
def->End.SetMS(def->End.GetMS()+OPT_GET("Timing/Default Duration")->GetInt());
def->Style = grid->GetDialogue(line_n)->Style;
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) {
curStartMS = curEndMS;
curEndMS = curStartMS + OPT_GET("Timing/Default Duration")->GetInt();
int endMs = curEndMS;
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();
}
@ -1277,7 +1262,6 @@ void AudioDisplay::AddLead(bool in,bool out) {
}
// Set changes
UpdateTimeEditCtrls();
NeedCommit = true;
if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges();
Update();
@ -1674,7 +1658,6 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
diagUpdated = false;
NeedCommit = true;
if (curStartMS <= curEndMS) {
UpdateTimeEditCtrls();
if (OPT_GET("Audio/Auto/Commit")->GetBool()) CommitChanges();
}
@ -2218,10 +2201,12 @@ void AudioDisplay::OnLoseFocus(wxFocusEvent &event) {
Refresh(false);
}
}
/// @brief Update time edit controls
void AudioDisplay::UpdateTimeEditCtrls() {
grid->editBox->StartTime->SetTime(curStartMS);
grid->editBox->EndTime->SetTime(curEndMS);
grid->editBox->Duration->SetTime(curEndMS-curStartMS);
void AudioDisplay::OnActiveLineChanged(AssDialogue *new_line) {
SetDialogue(grid,new_line,grid->GetDialogueIndex(new_line));
}
void AudioDisplay::OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) {
}
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>
#endif
#include <libaegisub/signals.h>
#include "audio_renderer_spectrum.h"
#include "selection_controller.h"
class AudioBox;
class AudioKaraoke;
@ -61,7 +64,7 @@ class VideoProvider;
/// @brief DOCME
///
/// DOCME
class AudioDisplay: public wxWindow {
class AudioDisplay: public wxWindow, private SelectionListener<AssDialogue> {
friend class FrameMain;
private:
@ -201,6 +204,11 @@ private:
int GetBoundarySnap(int x,int range,bool shiftHeld,bool start=true);
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:
/// DOCME
@ -235,7 +243,7 @@ public:
/// DOCME
wxTimer UpdateTimer;
AudioDisplay(wxWindow *parent);
AudioDisplay(wxWindow *parent, SubtitlesGrid *grid);
~AudioDisplay();
void UpdateImage(bool weak=false);
@ -251,7 +259,6 @@ public:
void Next(bool play=true);
void Prev(bool play=true);
void UpdateTimeEditCtrls();
void CommitChanges(bool nextLine=false);
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));
}
active_line = NULL;
index_line_map.clear();
line_index_map.clear();
@ -238,8 +237,14 @@ void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
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
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()) {
SetActiveLine(index_line_map[active_row]);
}
@ -250,6 +255,9 @@ void BaseGrid::UpdateMaps(bool preserve_selected_rows) {
SetActiveLine(index_line_map.back());
}
}
else {
SetActiveLine(line);
}
if (selection.empty() && active_line) {
Selection sel;

View file

@ -45,6 +45,7 @@
#include "dialog_detached_video.h"
#include "frame_main.h"
#include "main.h"
#include "subs_grid.h"
#include "video_box.h"
#include "video_context.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);
// Video area;
videoBox = new VideoBox(panel, true, NULL);
videoBox = new VideoBox(panel, true, NULL, VideoContext::Get()->grid->ass);
videoBox->videoDisplay->freeSize = true;
videoBox->videoDisplay->SetClientSize(initialDisplaySize);
videoBox->videoSlider->grid = par->SubsGrid;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -914,10 +914,7 @@ void FrameMain::OnShift(wxCommandEvent&) {
void FrameMain::OnOpenProperties (wxCommandEvent &) {
VideoContext::Get()->Stop();
DialogProperties Properties(this, ass);
int res = Properties.ShowModal();
if (res) {
SubsGrid->CommitChanges();
}
Properties.ShowModal();
}
/// @brief Open styles manager
@ -925,8 +922,6 @@ void FrameMain::OnOpenStylesManager(wxCommandEvent&) {
VideoContext::Get()->Stop();
DialogStyleManager StyleManager(this,SubsGrid);
StyleManager.ShowModal();
EditBox->UpdateGlobals();
SubsGrid->CommitChanges();
}
/// @brief Open attachments
@ -1040,10 +1035,7 @@ void FrameMain::OnAutomationMacro (wxCommandEvent &event) {
int first_sel = SubsGrid->GetFirstSelRow();
// Run the macro...
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->CommitChanges();
SubsGrid->EndBatch();
#endif
}
@ -1113,9 +1105,7 @@ void FrameMain::OnSnapToScene (wxCommandEvent &) {
}
// Commit
SubsGrid->editBox->Update(true);
SubsGrid->ass->Commit(_("snap to scene"));
SubsGrid->CommitChanges();
SubsGrid->ass->Commit(_("snap to scene"), AssFile::COMMIT_TIMES);
}
/// @brief Shift to frame
@ -1141,27 +1131,19 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &) {
}
// Commit
SubsGrid->ass->Commit(_("shift to frame"));
SubsGrid->CommitChanges(false);
SubsGrid->editBox->Update(true);
SubsGrid->ass->Commit(_("shift to frame"), AssFile::COMMIT_TIMES);
}
/// @brief Undo
void FrameMain::OnUndo(wxCommandEvent&) {
VideoContext::Get()->Stop();
ass->Undo();
UpdateTitle();
SubsGrid->UpdateMaps(true);
VideoContext::Get()->Refresh();
}
/// @brief Redo
void FrameMain::OnRedo(wxCommandEvent&) {
VideoContext::Get()->Stop();
ass->Redo();
UpdateTitle();
SubsGrid->UpdateMaps(true);
VideoContext::Get()->Refresh();
}
/// @brief Find
@ -1331,22 +1313,16 @@ void FrameMain::OnSelect (wxCommandEvent &) {
void FrameMain::OnSortStart (wxCommandEvent &) {
ass->Sort();
ass->Commit(_("sort"));
SubsGrid->UpdateMaps();
SubsGrid->CommitChanges();
}
/// @brief Sort subtitles by end time
void FrameMain::OnSortEnd (wxCommandEvent &) {
ass->Sort(AssFile::CompEnd);
ass->Commit(_("sort"));
SubsGrid->UpdateMaps();
SubsGrid->CommitChanges();
}
/// @brief Sort subtitles by style name
void FrameMain::OnSortStyle (wxCommandEvent &) {
ass->Sort(AssFile::CompStyle);
ass->Commit(_("sort"));
SubsGrid->UpdateMaps();
SubsGrid->CommitChanges();
}
/// @brief Open styling assistant
@ -1535,7 +1511,6 @@ void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
audioBox->audioDisplay->curStartMS += 10;
audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
}
/// @brief DOCME
@ -1543,7 +1518,6 @@ void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
audioBox->audioDisplay->curStartMS -= 10;
audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
}
/// @brief DOCME
@ -1551,7 +1525,6 @@ void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
audioBox->audioDisplay->curEndMS += 10;
audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
}
/// @brief DOCME
@ -1559,7 +1532,6 @@ void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
audioBox->audioDisplay->curEndMS -= 10;
audioBox->audioDisplay->Update();
audioBox->audioDisplay->wxWindow::Update();
audioBox->audioDisplay->UpdateTimeEditCtrls();
}
/// @brief DOCME
@ -1590,3 +1562,11 @@ void FrameMain::OnMedusaPrev(wxCommandEvent &) {
void FrameMain::OnMedusaEnter(wxCommandEvent &) {
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);
}
SubsEditBox::SubsEditBox (wxWindow *parent, SubtitlesGrid *grid, AudioDisplay *audio)
SubsEditBox::SubsEditBox(wxWindow *parent, SubtitlesGrid *grid)
: wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxRAISED_BORDER, "SubsEditBox")
, line(NULL)
, splitLineMode(false)
, controlState(true)
, audio(audio)
, grid(grid)
{
grid->editBox = this;
@ -329,12 +328,35 @@ SubsEditBox::SubsEditBox (wxWindow *parent, SubtitlesGrid *grid, AudioDisplay *a
OnSize(evt);
grid->AddSelectionListener(this);
grid->ass->AddCommitListener(&SubsEditBox::Update, this);
}
SubsEditBox::~SubsEditBox() {
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);
if (!line) {
return;
@ -344,7 +366,7 @@ void SubsEditBox::Update(bool timeOnly, bool setAudio) {
StartTime->SetTime(line->Start);
EndTime->SetTime(line->End);
Duration->SetTime(line->End-line->Start);
if (!timeOnly) {
if (type != AssFile::COMMIT_TIMES) {
TextEdit->SetTextTo(line->Text);
Layer->SetValue(line->Layer);
MarginL->ChangeValue(line->GetMarginString(0,false));
@ -357,32 +379,6 @@ void SubsEditBox::Update(bool timeOnly, bool setAudio) {
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);
}
@ -390,7 +386,7 @@ void SubsEditBox::OnActiveLineChanged(AssDialogue *new_line) {
SetEvtHandlerEnabled(false);
line = new_line;
Update();
Update(AssFile::COMMIT_TEXT);
/// @todo VideoContext should be doing this
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));
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;
grid->CommitChanges(false);
}
template<class T>
@ -476,7 +471,6 @@ void SubsEditBox::SetSelectedRows(T AssDialogue::*field, T value, wxString desc,
void SubsEditBox::CommitText(wxString desc) {
SetSelectedRows(&AssDialogue::Text, TextEdit->GetText(), desc, true);
audio->SetDialogue(grid,line,grid->GetDialogueIndex(line));
}
void SubsEditBox::CommitTimes(TimeField field) {
@ -499,10 +493,7 @@ void SubsEditBox::CommitTimes(TimeField field) {
}
}
timeCommitId[field] = grid->ass->Commit(_("modify times"), timeCommitId[field]);
grid->CommitChanges();
int sel0 = grid->GetFirstSelRow();
audio->SetDialogue(grid,grid->GetDialogue(sel0),sel0);
timeCommitId[field] = grid->ass->Commit(_("modify times"), AssFile::COMMIT_TIMES, timeCommitId[field]);
}
void SubsEditBox::OnSize(wxSizeEvent &evt) {

View file

@ -42,7 +42,6 @@
#include "selection_controller.h"
class AudioDisplay;
class AssDialogue;
class SubtitlesGrid;
class SubsTextEditCtrl;
@ -63,8 +62,6 @@ class wxTextCtrl;
///
/// Controls the text edit and all surrounding controls
class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
friend class AudioDisplay;
enum TimeField {
TIME_START = 0,
TIME_END,
@ -85,7 +82,6 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
wxColour origBgColour;
// Externally supplied controls
AudioDisplay *audio;
SubtitlesGrid *grid;
// Box controls
@ -185,23 +181,19 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
/// @param amend Coalesce sequences of commits of the same type
template<class T>
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:
SubsTextEditCtrl *TextEdit;
/// @brief Constructor
/// @param parent Parent window
/// @param grid Associated grid
/// @param audio Associated audio display
SubsEditBox(wxWindow *parent, SubtitlesGrid *grid, AudioDisplay *audio);
SubsEditBox(wxWindow *parent, SubtitlesGrid *grid);
~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
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"));
OPT_SUB("Subtitle/Grid/Highlight Subtitles in Frame", &SubtitlesGrid::OnHighlightVisibleChange, this);
ass->AddCommitListener(&SubtitlesGrid::OnCommit, this);
}
/// @brief Destructor
@ -118,6 +119,17 @@ SubtitlesGrid::~SubtitlesGrid() {
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
/// @param alternate
void SubtitlesGrid::OnPopupMenu(bool alternate) {
@ -385,7 +397,6 @@ void SubtitlesGrid::OnSplitByKaraoke (wxCommandEvent &) {
}
if (didSplit) {
ass->Commit(_("splitting"));
CommitChanges();
}
EndBatch();
}
@ -615,8 +626,6 @@ void SubtitlesGrid::OnRecombine(wxCommandEvent &) {
}
ass->Commit(_("combining"));
UpdateMaps();
CommitChanges();
// Remove now non-existent lines from the selection
Selection lines;
@ -724,15 +733,6 @@ void SubtitlesGrid::LoadDefault () {
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
/// @param n1
/// @param n2
@ -744,7 +744,6 @@ void SubtitlesGrid::SwapLines(int n1,int n2) {
std::swap(*dlg1, *dlg2);
ass->Commit(_("swap lines"));
CommitChanges();
}
/// @brief Insert a line
@ -758,12 +757,13 @@ void SubtitlesGrid::InsertLine(AssDialogue *line,int n,bool after,bool update) {
if (after) ++pos;
entryIter newIter = ass->Line.insert(pos,line);
BaseGrid::UpdateMaps();
// Update
if (update) {
ass->Commit(_("line insertion"));
CommitChanges();
}
else {
UpdateMaps();
}
}
@ -876,10 +876,7 @@ void SubtitlesGrid::PasteLines(int n,bool pasteOver) {
// Update data post-insertion
if (inserted > 0) {
// Commit
UpdateMaps();
ass->Commit(_("paste"));
CommitChanges();
ass->Commit(_("paste"), pasteOver ? AssFile::COMMIT_TEXT : AssFile::COMMIT_FULL);
// Set selection
if (!pasteOver) {
@ -920,11 +917,11 @@ void SubtitlesGrid::DeleteLines(wxArrayInt target, bool flagModified) {
old_active_line_index = 0;
}
UpdateMaps();
if (flagModified) {
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);
ass->Commit(_("join lines"));
CommitChanges();
// Select new line
SetActiveLine(cur);
@ -1016,7 +1012,6 @@ void SubtitlesGrid::AdjoinLines(int n1,int n2,bool setStart) {
}
ass->Commit(_("adjoin"));
CommitChanges();
}
void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) {
@ -1059,7 +1054,6 @@ void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) {
DeleteLines(GetRangeArray(n1+1,n2), false);
ass->Commit(_("join as karaoke"));
CommitChanges();
// Select new line
SetActiveLine(cur);
@ -1128,7 +1122,6 @@ void SubtitlesGrid::SplitLine(AssDialogue *n1,int pos,bool estimateTimes) {
}
ass->Commit(_("split"));
CommitChanges();
}
bool SubtitlesGrid::SplitLineByKaraoke(int lineNumber) {
@ -1170,35 +1163,6 @@ bool SubtitlesGrid::SplitLineByKaraoke(int lineNumber) {
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) {
if (!context->IsLoaded()) return;
@ -1218,9 +1182,7 @@ void SubtitlesGrid::SetSubsToVideo(bool start) {
}
if (modified) {
ass->Commit(_("timing"));
CommitChanges();
editBox->Update(true);
ass->Commit(_("timing"), AssFile::COMMIT_TIMES);
}
}

View file

@ -97,6 +97,8 @@ private:
void OnHighlightVisibleChange(agi::OptionValue const& opt);
void OnCommit(int type);
public:
/// Currently open file
AssFile *ass;
@ -105,13 +107,6 @@ public:
~SubtitlesGrid();
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
/// @param start Start vs. End time

View file

@ -63,7 +63,7 @@
/// @param parent
/// @param isDetached
///
VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox)
VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox, AssFile *ass)
: wxPanel (parent,-1)
{
// Parent
@ -112,7 +112,7 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached, wxComboBox *zoomBox)
visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
// 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
videoSlider->Display = videoDisplay;

View file

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

View file

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

View file

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

View file

@ -59,6 +59,7 @@
#include "video_display.h"
#include "ass_dialogue.h"
#include "ass_file.h"
#include "hotkeys.h"
#include "main.h"
#include "subs_grid.h"
@ -66,7 +67,6 @@
#include "video_out_gl.h"
#include "video_box.h"
#include "video_context.h"
#include "video_slider.h"
#include "visual_tool.h"
#include "visual_tool_clip.h"
#include "visual_tool_cross.h"
@ -97,7 +97,6 @@ BEGIN_EVENT_TABLE(VideoDisplay, wxGLCanvas)
EVT_PAINT(VideoDisplay::OnPaint)
EVT_SIZE(VideoDisplay::OnSizeEvent)
EVT_ERASE_BACKGROUND(VideoDisplay::OnEraseBackground)
EVT_SHOW(VideoDisplay::OnShow)
EVT_MENU(VIDEO_MENU_COPY_COORDS,VideoDisplay::OnCopyCoords)
EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD,VideoDisplay::OnCopyToClipboard)
@ -125,24 +124,17 @@ public:
VideoDisplay::VideoDisplay(
VideoBox *box,
VideoSlider *ControlSlider,
wxTextCtrl *PositionDisplay,
wxTextCtrl *SubsPosition,
wxComboBox *zoomBox,
wxWindow* parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
: wxGLCanvas (parent, id, attribList, pos, size, style, name)
AssFile *model)
: wxGLCanvas (parent, -1, attribList, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER, wxPanelNameStr)
, alwaysShowTools(OPT_GET("Tool/Visual/Always Show"))
, origSize(size)
, vc(VideoContext::Get())
, currentFrame(-1)
, 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)
, ControlSlider(ControlSlider)
, SubsPosition(SubsPosition)
, PositionDisplay(PositionDisplay)
, videoOut(new VideoOutGL())
@ -151,23 +143,28 @@ VideoDisplay::VideoDisplay(
, scriptW(INT_MIN)
, scriptH(INT_MIN)
, zoomBox(zoomBox)
, model(model)
, box(box)
, freeSize(false)
{
assert(vc);
assert(box);
assert(model);
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);
VideoContext *vc = VideoContext::Get();
vc->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
slots.push_back(vc->AddSeekListener(&VideoDisplay::SetFrame, 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);
}
VideoDisplay::~VideoDisplay () {
VideoContext::Get()->Unbind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
vc->Unbind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
}
bool VideoDisplay::InitContext() {
@ -195,7 +192,7 @@ void VideoDisplay::UpdateRelativeTimes(int time) {
int startOff = 0;
int endOff = 0;
if (AssDialogue *curLine = VideoContext::Get()->grid->GetActiveLine()) {
if (AssDialogue *curLine = vc->grid->GetActiveLine()) {
startOff = time - curLine->Start.GetMS();
endOff = time - curLine->End.GetMS();
}
@ -210,13 +207,11 @@ void VideoDisplay::UpdateRelativeTimes(int time) {
void VideoDisplay::SetFrame(int frameNumber) {
VideoContext *context = VideoContext::Get();
currentFrame = frameNumber;
// 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 m = time % 3600000 / 60000;
int s = time % 60000 / 1000;
@ -224,7 +219,7 @@ void VideoDisplay::SetFrame(int frameNumber) {
// Set the text box for frame number and time
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
PositionDisplay->SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/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
if (context->IsLoaded()) {
if (vc->IsLoaded()) {
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"Error message reported: %s",
err.GetMessage().c_str());
VideoContext::Get()->Reset();
vc->Reset();
}
catch (const VideoOutRenderException& err) {
wxLogError(
@ -267,23 +262,24 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
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() {
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 {
if (!InitContext()) return;
VideoContext *context = VideoContext::Get();
if (!context->IsLoaded()) return;
if (!vc->IsLoaded()) return;
assert(wxIsMainThread());
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));
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
// 16:9 or wider
@ -312,7 +308,6 @@ void VideoDisplay::Render() try {
}
if (video.x > INT_MIN || video.y > INT_MIN || alwaysShowTools->GetBool()) {
context->GetScriptSize(scriptW, scriptH);
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"Error message reported: %s",
err.GetMessage().c_str());
VideoContext::Get()->Reset();
vc->Reset();
}
catch (const OpenGlException &err) {
wxLogError(
L"An error occurred trying to render visual overlays on the screen.\n"
L"Error message reported: %s",
err.GetMessage().c_str());
VideoContext::Get()->Reset();
vc->Reset();
}
catch (const wchar_t *err) {
wxLogError(
L"An error occurred trying to render the video frame on the screen.\n"
L"Error message reported: %s",
err);
VideoContext::Get()->Reset();
vc->Reset();
}
catch (...) {
wxLogError(
L"An error occurred trying to render the video frame to screen.\n"
L"No further error message given.");
VideoContext::Get()->Reset();
vc->Reset();
}
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));
}
void VideoDisplay::UpdateSize() {
VideoContext *con = VideoContext::Get();
wxASSERT(con);
if (!con->IsLoaded()) return;
void VideoDisplay::UpdateSize(int arType, double arValue) {
if (!vc->IsLoaded()) return;
if (!IsShownOnScreen()) return;
int vidW = con->GetWidth();
int vidH = con->GetHeight();
int vidW = vc->GetWidth();
int vidH = vc->GetHeight();
if (arType == -1) {
arType = vc->GetAspectRatioType();
arValue = vc->GetAspectRatioValue();
}
if (freeSize) {
GetClientSize(&w,&h);
@ -391,8 +388,8 @@ void VideoDisplay::UpdateSize() {
viewport_height = h;
// Set aspect ratio
float displayAr = float(w) / float(h);
float videoAr = con->GetAspectRatioType() == 0 ? float(vidW)/float(vidH) : con->GetAspectRatioValue();
double displayAr = double(w) / h;
double videoAr = arType == 0 ? double(vidW)/vidH : arValue;
// Window is wider than video, blackbox left/right
if (displayAr - videoAr > 0.01f) {
@ -415,7 +412,7 @@ void VideoDisplay::UpdateSize() {
parent->GetClientSize(&maxW, &maxH);
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
int cw = std::min(w, maxW), ch = std::min(h, maxH);
@ -430,7 +427,7 @@ void VideoDisplay::UpdateSize() {
SetMinClientSize(size);
SetMaxClientSize(size);
locked = true;
SetEvtHandlerEnabled(false);
box->GetParent()->Layout();
// 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
SetSize(cw, ch);
locked = false;
SetEvtHandlerEnabled(true);
}
con->GetScriptSize(scriptW, scriptH);
vc->GetScriptSize(scriptW, scriptH);
video.w = w;
video.h = h;
@ -450,22 +447,7 @@ void VideoDisplay::UpdateSize() {
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&) {
wxPaintDC dc(this);
Render();
}
@ -475,11 +457,10 @@ void VideoDisplay::OnSizeEvent(wxSizeEvent &event) {
}
void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
if (locked) return;
assert(w > 0);
// Disable when playing
if (VideoContext::Get()->IsPlaying()) return;
if (vc->IsPlaying()) return;
if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) {
wxMenu menu;
@ -554,10 +535,6 @@ double VideoDisplay::GetZoom() const {
return zoomValue;
}
void VideoDisplay::OnShow(wxShowEvent&) {
OnVideoOpen();
}
template<class T>
void VideoDisplay::SetTool() {
tool.reset();
@ -609,24 +586,24 @@ void VideoDisplay::FromScriptCoords(int *x, int *y) const {
void VideoDisplay::OnCopyToClipboard(wxCommandEvent &) {
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();
}
}
void VideoDisplay::OnCopyToClipboardRaw(wxCommandEvent &) {
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();
}
}
void VideoDisplay::OnSaveSnapshot(wxCommandEvent &) {
VideoContext::Get()->SaveSnapshot(false);
vc->SaveSnapshot(false);
}
void VideoDisplay::OnSaveSnapshotRaw(wxCommandEvent &) {
VideoContext::Get()->SaveSnapshot(true);
vc->SaveSnapshot(true);
}
void VideoDisplay::OnCopyCoords(wxCommandEvent &) {

View file

@ -45,9 +45,10 @@
#include <libaegisub/signals.h>
// Prototypes
class AssFile;
class FrameReadyEvent;
class VideoSlider;
class VideoBox;
class VideoContext;
class VideoOutGL;
class IVisualTool;
class wxToolBar;
@ -70,8 +71,9 @@ class VideoDisplay : public wxGLCanvas {
std::list<agi::signal::Connection> slots;
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
int currentFrame;
@ -92,9 +94,6 @@ class VideoDisplay : public wxGLCanvas {
/// The height of the video in screen pixels
int viewport_height;
/// Lock to disable mouse updates during resize operations
bool locked;
/// @brief Draw an overscan mask
/// @param sizeH The amount of horizontal 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%
double zoomValue;
/// The video position slider
VideoSlider *ControlSlider;
/// The display for the the video position relative to the current subtitle line
wxTextCtrl *SubsPosition;
@ -167,12 +163,9 @@ class VideoDisplay : public wxGLCanvas {
/// @brief Set this video display to the given frame
/// @frameNumber The desired frame number
void SetFrame(int frameNumber);
/// @brief Signal that the file has changed
void Refresh();
void OnVideoOpen();
void OnShow(wxShowEvent &event);
void OnCommit(int type);
void OnMode(const wxCommandEvent &event);
void SetMode(int mode);
@ -190,6 +183,8 @@ class VideoDisplay : public wxGLCanvas {
/// The dropdown box for selecting zoom levels
wxComboBox *zoomBox;
AssFile *model;
public:
/// The VideoBox this display is contained in
VideoBox *box;
@ -198,27 +193,14 @@ public:
bool freeSize;
/// @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(
VideoBox *box,
VideoSlider *ControlSlider,
wxTextCtrl *PositionDisplay,
wxTextCtrl *SubsPosition,
wxComboBox *zoomBox,
wxWindow* parent,
wxWindowID id,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxPanelNameStr);
AssFile *model);
~VideoDisplay();
/// @brief Reset the size of the display to the video size
void Reset();
/// @brief Render the currently visible frame
void Render();
@ -227,7 +209,7 @@ public:
/// @param show Whether or not the cursor should be visible
void ShowCursor(bool show);
/// @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
/// @param value The new zoom level
void SetZoom(double value);
@ -245,6 +227,5 @@ public:
/// @param y y coordinate; in/out
void FromScriptCoords(int *x, int *y) const;
DECLARE_EVENT_TABLE()
};

View file

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