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.
This commit is contained in:
Thomas Goyne 2012-05-02 22:42:25 +00:00
parent 252351b7da
commit 8f3b027881
2 changed files with 46 additions and 23 deletions

View file

@ -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 &) {

View file

@ -35,6 +35,7 @@
///
#ifndef AGI_PRE
#include <map>
#include <vector>
#include <wx/panel.h>
@ -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<AssDialogue> {
/// @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<AssDialogue *, std::pair<AssTime, AssTime> > initialTimes;
// Constructor helpers
wxTextCtrl *MakeMarginCtrl(wxString const& tooltip, void (SubsEditBox::*handler)(wxCommandEvent&));
TimeEdit *MakeTimeCtrl(bool end, wxString const& tooltip, void (SubsEditBox::*handler)(wxCommandEvent&));