From 8f3b027881db6a96f6d4c3ffba7b539557e0a5d7 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 2 May 2012 22:42:25 +0000 Subject: [PATCH] Improve the negative-duration-avoiding behavior of the time edit boxes Save the initial start and end times of lines before adjusting them to avoid negative line durations, so that if further changes to the edit boxes make the adjustment unneccesary the original values can be restored. This Fixes the problem where changing a line visible from frames 800-900 to 800-901 would actually result in 90-901, due to the end frame briefly being 90. Originally committed to SVN as r6741. --- aegisub/src/subs_edit_box.cpp | 50 ++++++++++++++++++++++------------- aegisub/src/subs_edit_box.h | 19 ++++++++++--- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp index 9f61178cb..ebe00f07c 100644 --- a/aegisub/src/subs_edit_box.cpp +++ b/aegisub/src/subs_edit_box.cpp @@ -288,6 +288,8 @@ wxRadioButton *SubsEditBox::MakeRadio(wxString const& text, bool start, wxString void SubsEditBox::OnCommit(int type) { wxEventBlocker blocker(this); + initialTimes.clear(); + if (type == AssFile::COMMIT_NEW || type & AssFile::COMMIT_STYLES) { wxString style = StyleBox->GetValue(); StyleBox->Clear(); @@ -384,6 +386,7 @@ void SubsEditBox::OnActiveLineChanged(AssDialogue *new_line) { } void SubsEditBox::OnSelectedSetChanged(const Selection &, const Selection &) { sel = c->selectionController->GetSelectedSet(); + initialTimes.clear(); } void SubsEditBox::UpdateFrameTiming(agi::vfr::Framerate const& fps) { @@ -423,6 +426,8 @@ void SubsEditBox::SetSelectedRows(setter set, T value, wxString desc, int type, commitId = c->ass->Commit(desc, type, (amend && desc == lastCommitType) ? commitId : -1, sel.size() == 1 ? *sel.begin() : 0); file_changed_slot.Unblock(); lastCommitType = desc; + lastTimeCommitType = -1; + initialTimes.clear(); undoTimer.Start(10000, wxTIMER_ONE_SHOT); } @@ -436,35 +441,48 @@ void SubsEditBox::CommitText(wxString desc) { } void SubsEditBox::CommitTimes(TimeField field) { - if (ByFrame->GetValue()) - Duration->SetFrame(EndTime->GetFrame() - StartTime->GetFrame() + 1); - else - Duration->SetTime(EndTime->GetTime() - StartTime->GetTime()); - - // Update lines for (Selection::iterator cur = sel.begin(); cur != sel.end(); ++cur) { AssDialogue *d = *cur; + + if (!initialTimes.count(d)) + initialTimes[d] = std::make_pair(d->Start, d->End); + switch (field) { case TIME_START: - d->Start = StartTime->GetTime(); - if (d->Start > d->End) - d->End = d->Start; + initialTimes[d].first = d->Start = StartTime->GetTime(); + d->End = std::max(d->Start, initialTimes[d].second); break; + case TIME_END: - d->End = EndTime->GetTime(); - if (d->Start > d->End) - d->Start = d->End; + initialTimes[d].second = d->End = EndTime->GetTime(); + d->Start = std::min(d->End, initialTimes[d].first); break; + case TIME_DURATION: if (ByFrame->GetValue()) d->End = c->videoController->TimeAtFrame(c->videoController->FrameAtTime(d->Start, agi::vfr::START) + Duration->GetFrame(), agi::vfr::END); else d->End = d->Start + Duration->GetTime(); + initialTimes[d].second = d->End; break; } } - timeCommitId[field] = c->ass->Commit(_("modify times"), AssFile::COMMIT_DIAG_TIME, timeCommitId[field], sel.size() == 1 ? *sel.begin() : 0); + StartTime->SetTime(line->Start); + EndTime->SetTime(line->End); + + if (ByFrame->GetValue()) + Duration->SetFrame(EndTime->GetFrame() - StartTime->GetFrame() + 1); + else + Duration->SetTime(EndTime->GetTime() - StartTime->GetTime()); + + if (field != lastTimeCommitType) + commitId = -1; + + lastTimeCommitType = field; + file_changed_slot.Block(); + commitId = c->ass->Commit(_("modify times"), AssFile::COMMIT_DIAG_TIME, commitId, sel.size() == 1 ? *sel.begin() : 0); + file_changed_slot.Unblock(); } void SubsEditBox::OnSize(wxSizeEvent &evt) { @@ -530,20 +548,14 @@ void SubsEditBox::OnLayerEnter(wxCommandEvent &) { } void SubsEditBox::OnStartTimeChange(wxCommandEvent &) { - if (StartTime->GetTime() > EndTime->GetTime()) EndTime->SetTime(StartTime->GetTime()); CommitTimes(TIME_START); } void SubsEditBox::OnEndTimeChange(wxCommandEvent &) { - if (StartTime->GetTime() > EndTime->GetTime()) StartTime->SetTime(EndTime->GetTime()); CommitTimes(TIME_END); } void SubsEditBox::OnDurationChange(wxCommandEvent &) { - if (ByFrame->GetValue()) - EndTime->SetFrame(StartTime->GetFrame() + Duration->GetFrame() - 1); - else - EndTime->SetTime(StartTime->GetTime() + Duration->GetTime()); CommitTimes(TIME_DURATION); } void SubsEditBox::OnMarginLChange(wxCommandEvent &) { diff --git a/aegisub/src/subs_edit_box.h b/aegisub/src/subs_edit_box.h index e53d74e57..687193206 100644 --- a/aegisub/src/subs_edit_box.h +++ b/aegisub/src/subs_edit_box.h @@ -35,6 +35,7 @@ /// #ifndef AGI_PRE +#include #include #include @@ -50,6 +51,7 @@ namespace agi { struct Context; } struct AssColor; class AssDialogue; class AssStyle; +class AssTime; class SubsTextEditCtrl; class TimeEdit; class wxButton; @@ -118,14 +120,23 @@ class SubsEditBox : public wxPanel, protected SelectionListener { /// @param desc Undo description to use void CommitText(wxString desc); - /// Move to the next line, creating it if needed - void NextLine(); - - int timeCommitId[3]; + /// Last commit ID for undo coalescing int commitId; + + /// Last used commit message to avoid coalescing different types of changes wxString lastCommitType; + + /// Last field to get a time commit, as they all have the same commit message + int lastTimeCommitType; + + /// Timer to stop coalescing changes after a break with no edits wxTimer undoTimer; + /// The start and end times of the selected lines without changes made to + /// avoid negative durations, so that they can be restored if future changes + /// eliminate the negative durations + std::map > initialTimes; + // Constructor helpers wxTextCtrl *MakeMarginCtrl(wxString const& tooltip, void (SubsEditBox::*handler)(wxCommandEvent&)); TimeEdit *MakeTimeCtrl(bool end, wxString const& tooltip, void (SubsEditBox::*handler)(wxCommandEvent&));