diff --git a/src/AudacityHeaders.h b/src/AudacityHeaders.h index d60f65dc4..aacf0ee3f 100644 --- a/src/AudacityHeaders.h +++ b/src/AudacityHeaders.h @@ -59,7 +59,6 @@ #include "Resample.h" #include "SampleFormat.h" #include "Sequence.h" -#include "TimeDialog.h" #include "TimeTrack.h" #include "Track.h" #include "UndoManager.h" diff --git a/src/Snap.cpp b/src/Snap.cpp index 0c2841b2c..19b009229 100644 --- a/src/Snap.cpp +++ b/src/Snap.cpp @@ -30,25 +30,18 @@ SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions, // Grab time-snapping prefs (unless otherwise requested) mSnapToTime = false; - TimeTextCtrl *ttc = NULL; - // TODO: Switch over from using TimeTextCtrl to TimeConverter. - // This will prevent an annoying tiny toolbar appearing in top left - // every time we click the mouse left button. It's the time text - // ctrl. - - //TimeConverter *pTc=NULL; if (gPrefs->Read(wxT("/SnapTo"), 0L) != 0L && !noTimeSnap) { // Look up the format string AudacityProject *p = GetActiveProject(); + wxASSERT(p); if (p) { + mConverter.SetSampleRate(p->GetRate()); mSnapToTime = true; - ttc = new TimeTextCtrl(p, wxID_ANY, wxT(""), 0.0, p->GetRate()); wxString formatName; gPrefs->Read(wxT("/SelectionFormat"), &formatName); - mFormat = ttc->GetBuiltinFormat(formatName); - ttc->SetFormatString(mFormat); + mConverter.SetFormatString(mConverter.GetBuiltinFormat(formatName)); } } @@ -73,9 +66,9 @@ SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions, LabelTrack *labelTrack = (LabelTrack *)track; for(i = 0; i < labelTrack->GetNumLabels(); i++) { const LabelStruct *label = labelTrack->GetLabel(i); - CondListAdd(label->t, labelTrack, ttc); + CondListAdd(label->t, labelTrack); if (label->t1 != label->t) { - CondListAdd(label->t1, labelTrack, ttc); + CondListAdd(label->t1, labelTrack); } } } @@ -94,30 +87,26 @@ SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions, if (skip) continue; } - CondListAdd(clip->GetStartTime(), waveTrack, ttc); - CondListAdd(clip->GetEndTime(), waveTrack, ttc); + CondListAdd(clip->GetStartTime(), waveTrack); + CondListAdd(clip->GetEndTime(), waveTrack); } } #ifdef USE_MIDI else if (track->GetKind() == Track::Note) { - CondListAdd(track->GetStartTime(), track, ttc); - CondListAdd(track->GetEndTime(), track, ttc); + CondListAdd(track->GetStartTime(), track); + CondListAdd(track->GetEndTime(), track); } #endif track = iter.Next(); } - - if (ttc) - delete ttc; } -// Adds to mSnapPoints, filtering by ttc if it's not NULL -void SnapManager::CondListAdd(double t, Track *tr, TimeTextCtrl *ttc) +// Adds to mSnapPoints, filtering by TimeConverter +void SnapManager::CondListAdd(double t, Track *tr) { - if (ttc) - ttc->SetTimeValue(t); + mConverter.SetTimeValue(t); - if (!ttc || ttc->GetTimeValue() == t) + if (mConverter.GetTimeValue() == t) mSnapPoints->Add(new SnapPoint(t, tr)); } @@ -260,27 +249,9 @@ bool SnapManager::Snap(Track *currentTrack, } else { // Snap time to the grid - AudacityProject *p = GetActiveProject(); -#if 0 - // Old code for snapping. - // This created a new ctrl for every tiny drag. - TimeTextCtrl ttc(p, wxID_ANY, wxT(""), 0.0, p->GetRate()); - ttc.SetFormatString(mFormat); - ttc.SetTimeValue(t); - *out_t = ttc.GetTimeValue(); -#else - // Replacement code. It's still inefficient, since we - // repeatedly parse the format, but it now doesn't - // create a new ctrl too. - // TODO: Move Tc into being a member variable of - // SnapManager. Then we won't be repeatedly - // parsing the format string. - TimeConverter Tc; - Tc.mSampleRate = p->GetRate(); - Tc.ParseFormatString( mFormat ); - Tc.ValueToControls( t ); - *out_t = Tc.ControlsToValue(); -#endif + mConverter.ValueToControls(t, false); + mConverter.ControlsToValue(); + *out_t = mConverter.GetTimeValue(); *snappedTime = true; } } diff --git a/src/Snap.h b/src/Snap.h index a66ef5c66..3c22d8c1a 100644 --- a/src/Snap.h +++ b/src/Snap.h @@ -19,10 +19,9 @@ #include #include "Track.h" -#include "ViewInfo.h" +#include "widgets/TimeTextCtrl.h" class TrackClipArray; -class TimeTextCtrl; class SnapPoint { public: @@ -38,8 +37,6 @@ WX_DEFINE_SORTED_ARRAY(SnapPoint *, SnapPointArray); class SnapManager { public: - // Set gridCtrl to a TimeTextCtrl to use for snap-to-time; if NULL we won't - // snap to time SnapManager(TrackList *tracks, TrackClipArray *exclusions, double zoom, int pixelTolerance, bool noTimeSnap = false); @@ -57,7 +54,7 @@ class SnapManager { bool *snappedTime); private: - void CondListAdd(double t, Track *tr, TimeTextCtrl *ttc); + void CondListAdd(double t, Track *tr); double Get(int index); double Diff(double t, int index); int Find(double t, int i0, int i1); @@ -71,8 +68,8 @@ class SnapManager { SnapPointArray *mSnapPoints; // Info for snap-to-time + TimeConverter mConverter; bool mSnapToTime; - wxString mFormat; }; #endif diff --git a/src/TimeDialog.cpp b/src/TimeDialog.cpp index 14216b4ef..128946025 100644 --- a/src/TimeDialog.cpp +++ b/src/TimeDialog.cpp @@ -55,14 +55,13 @@ void TimeDialog::PopulateOrExchange(ShuttleGui &S) mTimeCtrl = new TimeTextCtrl(this, wxID_ANY, - wxT(""), + mFormat, mTime, mRate, wxDefaultPosition, wxDefaultSize, true); mTimeCtrl->SetName(mPrompt); - mTimeCtrl->SetFormatString(mTimeCtrl->GetBuiltinFormat(mFormat)); S.AddWindow(mTimeCtrl); mTimeCtrl->EnableMenu(); } diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp index 5ad4d7b9e..b02678a6a 100644 --- a/src/TimerRecordDialog.cpp +++ b/src/TimerRecordDialog.cpp @@ -342,8 +342,9 @@ void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S) m_pDatePickerCtrl_Start->SetRange(wxDateTime::Today(), wxInvalidDateTime); // No backdating. S.AddWindow(m_pDatePickerCtrl_Start); - m_pTimeTextCtrl_Start = new TimeTextCtrl(this, ID_TIMETEXT_START, strFormat); + m_pTimeTextCtrl_Start = new TimeTextCtrl(this, ID_TIMETEXT_START); m_pTimeTextCtrl_Start->SetName(_("Start Time")); + m_pTimeTextCtrl_Start->SetFormatString(strFormat); m_pTimeTextCtrl_Start->SetTimeValue(wxDateTime_to_AudacityTime(m_DateTime_Start)); S.AddWindow(m_pTimeTextCtrl_Start); m_pTimeTextCtrl_Start->EnableMenu(false); @@ -361,8 +362,9 @@ void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S) m_pDatePickerCtrl_End->SetName(_("End Date")); S.AddWindow(m_pDatePickerCtrl_End); - m_pTimeTextCtrl_End = new TimeTextCtrl(this, ID_TIMETEXT_END, strFormat); + m_pTimeTextCtrl_End = new TimeTextCtrl(this, ID_TIMETEXT_END); m_pTimeTextCtrl_End->SetName(_("End Time")); + m_pTimeTextCtrl_End->SetFormatString(strFormat); m_pTimeTextCtrl_End->SetTimeValue(wxDateTime_to_AudacityTime(m_DateTime_End)); S.AddWindow(m_pTimeTextCtrl_End); m_pTimeTextCtrl_End->EnableMenu(false); @@ -380,8 +382,9 @@ void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S) * seconds. */ wxString strFormat1 = _("099 days 024 h 060 m 060 s"); - m_pTimeTextCtrl_Duration = new TimeTextCtrl(this, ID_TIMETEXT_DURATION, strFormat1); + m_pTimeTextCtrl_Duration = new TimeTextCtrl(this, ID_TIMETEXT_DURATION); m_pTimeTextCtrl_Duration->SetName(_("Duration")); + m_pTimeTextCtrl_Duration->SetFormatString(strFormat1); m_pTimeTextCtrl_Duration->SetTimeValue(m_TimeSpan_Duration.GetSeconds().ToDouble()); S.AddWindow(m_pTimeTextCtrl_Duration); m_pTimeTextCtrl_Duration->EnableMenu(false); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index fc754b12c..7862d2139 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -22,6 +22,7 @@ #include "WaveClip.h" #include "WaveTrack.h" #include "UndoManager.h" //JKC: Included for PUSH_XXX definitions. +#include "widgets/TimeTextCtrl.h" class wxMenu; class wxRect; @@ -601,6 +602,8 @@ protected: wxInt64 mSnapRight; bool mSnapPreferRightEdge; + TimeConverter mConverter; + Track * mDrawingTrack; // Keeps track of which track you are drawing on between events cf. HandleDraw() int mDrawingTrackTop; // Keeps track of the top position of the drawing track. sampleCount mDrawingStartSample; // sample of last click-down diff --git a/src/effects/Contrast.cpp b/src/effects/Contrast.cpp index 5c152c7d1..12a6c7d77 100644 --- a/src/effects/Contrast.cpp +++ b/src/effects/Contrast.cpp @@ -260,14 +260,13 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id, mForegroundStartT = new TimeTextCtrl(this, ID_FOREGROUNDSTART_T, - wxT(""), + _("hh:mm:ss + hundredths"), 0.0, mProjectRate, wxDefaultPosition, wxDefaultSize, true); mForegroundStartT->SetName(_("Foreground start time")); - mForegroundStartT->SetFormatString(mForegroundStartT->GetBuiltinFormat(_("hh:mm:ss + hundredths"))); mForegroundStartT->EnableMenu(false); } S.AddWindow(mForegroundStartT); @@ -277,14 +276,13 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id, mForegroundEndT = new TimeTextCtrl(this, ID_FOREGROUNDEND_T, - wxT(""), + _("hh:mm:ss + hundredths"), 0.0, mProjectRate, wxDefaultPosition, wxDefaultSize, true); mForegroundEndT->SetName(_("Foreground end time")); - mForegroundEndT->SetFormatString(mForegroundEndT->GetBuiltinFormat(_("hh:mm:ss + hundredths"))); mForegroundEndT->EnableMenu(false); } S.AddWindow(mForegroundEndT); @@ -300,14 +298,13 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id, mBackgroundStartT = new TimeTextCtrl(this, ID_BACKGROUNDSTART_T, - wxT(""), + _("hh:mm:ss + hundredths"), 0.0, mProjectRate, wxDefaultPosition, wxDefaultSize, true); mBackgroundStartT->SetName(_("Background start time")); - mBackgroundStartT->SetFormatString(mBackgroundStartT->GetBuiltinFormat(_("hh:mm:ss + hundredths"))); mBackgroundStartT->EnableMenu(false); } S.AddWindow(mBackgroundStartT); @@ -317,14 +314,13 @@ ContrastDialog::ContrastDialog(wxWindow * parent, wxWindowID id, mBackgroundEndT = new TimeTextCtrl(this, ID_BACKGROUNDEND_T, - wxT(""), + _("hh:mm:ss + hundredths"), 0.0, mProjectRate, wxDefaultPosition, wxDefaultSize, true); mBackgroundEndT->SetName(_("Background end time")); - mBackgroundEndT->SetFormatString(mBackgroundEndT->GetBuiltinFormat(_("hh:mm:ss + hundredths"))); mBackgroundEndT->EnableMenu(false); } S.AddWindow(mBackgroundEndT); diff --git a/src/effects/DtmfGen.cpp b/src/effects/DtmfGen.cpp index 58057b51a..f3700b399 100644 --- a/src/effects/DtmfGen.cpp +++ b/src/effects/DtmfGen.cpp @@ -458,18 +458,17 @@ void DtmfDialog::PopulateOrExchange( ShuttleGui & S ) mDtmfDurationT = new TimeTextCtrl(this, ID_DTMF_DURATION_TEXT, - wxT(""), + /* use this instead of "seconds" because if a selection is passed to the + * effect, I want it (dDuration) to be used as the duration, and with + * "seconds" this does not always work properly. For example, it rounds + * down to zero... */ + dIsSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"), dDuration, mEffect->mProjectRate, wxDefaultPosition, wxDefaultSize, true); - /* use this instead of "seconds" because if a selection is passed to the - * effect, I want it (dDuration) to be used as the duration, and with - * "seconds" this does not always work properly. For example, it rounds - * down to zero... */ mDtmfDurationT->SetName(_("Duration")); - mDtmfDurationT->SetFormatString(mDtmfDurationT->GetBuiltinFormat(dIsSelection==true?(_("hh:mm:ss + samples")):(_("hh:mm:ss + milliseconds")))); mDtmfDurationT->EnableMenu(); } S.AddWindow(mDtmfDurationT); diff --git a/src/effects/ToneGen.cpp b/src/effects/ToneGen.cpp index 752ef7ab2..4072b778f 100644 --- a/src/effects/ToneGen.cpp +++ b/src/effects/ToneGen.cpp @@ -275,14 +275,13 @@ void ToneGenDialog::PopulateOrExchangeStandard( ShuttleGui & S ) mToneDurationT = new TimeTextCtrl(this, wxID_ANY, - wxT(""), + isSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"), mDuration, mEffect->mProjectRate, wxDefaultPosition, wxDefaultSize, true); mToneDurationT->SetName(_("Duration")); - mToneDurationT->SetFormatString(mToneDurationT->GetBuiltinFormat(isSelection==true?(_("hh:mm:ss + samples")):(_("hh:mm:ss + milliseconds")))); mToneDurationT->EnableMenu(); } S.AddWindow(mToneDurationT); @@ -323,14 +322,13 @@ void ToneGenDialog::PopulateOrExchangeExtended( ShuttleGui & S ) mToneDurationT = new TimeTextCtrl(this, wxID_ANY, - wxT(""), + isSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds"), mDuration, mEffect->mProjectRate, wxDefaultPosition, wxDefaultSize, true); mToneDurationT->SetName(_("Duration")); - mToneDurationT->SetFormatString(mToneDurationT->GetBuiltinFormat(isSelection==true?(_("hh:mm:ss + samples")):(_("hh:mm:ss + milliseconds")))); mToneDurationT->EnableMenu(); } S.AddWindow(mToneDurationT); diff --git a/src/toolbars/SelectionBar.cpp b/src/toolbars/SelectionBar.cpp index 95decdefa..e0436e7f8 100644 --- a/src/toolbars/SelectionBar.cpp +++ b/src/toolbars/SelectionBar.cpp @@ -114,11 +114,8 @@ void SelectionBar::Populate() * to do some look-ups, so we'll have to create one. We can't make the * look-ups static because they depend on translations which are done at * runtime */ - TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, mRate); wxString formatName; gPrefs->Read(wxT("/SelectionFormat"), &formatName); - wxString format = ttc->GetBuiltinFormat(formatName); - delete ttc; mainSizer = new wxFlexGridSizer(7, 1, 1); Add(mainSizer, 0, wxALIGN_CENTER_VERTICAL); @@ -255,13 +252,12 @@ void SelectionBar::Populate() NULL, this); - mLeftTime = new TimeTextCtrl(this, OnLeftTimeID, wxT(""), 0.0, mRate); - mLeftTime->SetFormatString(format); + mLeftTime = new TimeTextCtrl(this, OnLeftTimeID, formatName, 0.0, mRate); mLeftTime->SetName(_("Selection Start:")); mLeftTime->EnableMenu(); mainSizer->Add(mLeftTime, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); - mRightTime = new TimeTextCtrl(this, OnRightTimeID, format, 0.0, mRate); + mRightTime = new TimeTextCtrl(this, OnRightTimeID, formatName, 0.0, mRate); mRightTime->SetName(wxString(_("Selection ")) + (showSelectionLength ? _("Length") : _("End"))); @@ -273,7 +269,7 @@ void SelectionBar::Populate() wxLI_VERTICAL), 0, wxRIGHT, 5); - mAudioTime = new TimeTextCtrl(this, -1, format, 0.0, mRate); + mAudioTime = new TimeTextCtrl(this, wxID_ANY, formatName, 0.0, mRate); mAudioTime->SetName(_("Audio Position:")); mAudioTime->EnableMenu(); mainSizer->Add(mAudioTime, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 0); @@ -368,18 +364,17 @@ void SelectionBar::OnUpdate(wxCommandEvent &evt) evt.Skip(false); - /* we don't actually need a TimeTextCtrl, but need it's - * translations which are done at runtime */ - - TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, mRate); - wxString formatName(ttc->GetBuiltinName(index)); - gPrefs->Write(wxT("/SelectionFormat"), formatName); - gPrefs->Flush(); - #if wxUSE_TOOLTIPS - mSnapTo->SetToolTip(wxString::Format(_("Snap Clicks/Selections to %s"), formatName.c_str())); - #endif - delete ttc; + wxString format; + // Save format name before recreating the controls so they resize properly + format = mLeftTime->GetBuiltinName(index); + gPrefs->Write(wxT("/SelectionFormat"), format); + gPrefs->Flush(); + +#if wxUSE_TOOLTIPS + mSnapTo->SetToolTip(wxString::Format(_("Snap Clicks/Selections to %s"), format.c_str())); +#endif + // ToolBar::ReCreateButtons() will get rid of our sizers and controls // so reset pointers first. mLeftTime = @@ -396,10 +391,10 @@ void SelectionBar::OnUpdate(wxCommandEvent &evt) ValuesToControls(); - wxString formatString = mLeftTime->GetBuiltinFormat(index); - mLeftTime->SetFormatString(formatString); - mRightTime->SetFormatString(formatString); - mAudioTime->SetFormatString(formatString); + format = mLeftTime->GetBuiltinFormat(index); + mLeftTime->SetFormatString(format); + mRightTime->SetFormatString(format); + mAudioTime->SetFormatString(format); if (leftFocus) { mLeftTime->SetFocus(); diff --git a/src/widgets/Grid.cpp b/src/widgets/Grid.cpp index e82328db0..bd035862f 100644 --- a/src/widgets/Grid.cpp +++ b/src/widgets/Grid.cpp @@ -46,18 +46,12 @@ void TimeEditor::Create(wxWindow *parent, wxWindowID id, wxEvtHandler *handler) { m_control = new TimeTextCtrl(parent, wxID_ANY, - wxT(""), + mFormat, mOld, mRate, wxDefaultPosition, wxDefaultSize, true); - /* look up provided format string name to a format string, then set that as - * the format string for the control. Unfortunately m_control is a base - * class pointer not a TimeTextCtrl pointer, so we have to cast it. It can't - * fail to cast, however unless the preceeding new operation failed, so it's - * reasonably safe. */ - ((TimeTextCtrl *)m_control)->SetFormatString(((TimeTextCtrl *)m_control)->GetBuiltinFormat(mFormat)); wxGridCellEditor::Create(parent, id, handler); } @@ -164,13 +158,12 @@ void TimeRenderer::Draw(wxGrid &grid, TimeTextCtrl tt(&grid, wxID_ANY, - wxT(""), + te->GetFormat(), value, te->GetRate(), wxPoint(10000, 10000), // create offscreen wxDefaultSize, true); - tt.SetFormatString(tt.GetBuiltinFormat(te->GetFormat())); tstr = tt.GetTimeString(); te->DecRef(); @@ -221,13 +214,12 @@ wxSize TimeRenderer::GetBestSize(wxGrid &grid, table->GetValue(row, col).ToDouble(&value); TimeTextCtrl tt(&grid, wxID_ANY, - wxT(""), + te->GetFormat(), value, te->GetRate(), wxPoint(10000, 10000), // create offscreen wxDefaultSize, true); - tt.SetFormatString(tt.GetBuiltinFormat(te->GetFormat())); sz = tt.GetSize(); te->DecRef(); @@ -742,13 +734,12 @@ wxAccStatus GridAx::GetName(int childId, wxString *name) TimeTextCtrl tt(mGrid, wxID_ANY, - wxT(""), + c->GetFormat(), value, c->GetRate(), wxPoint(10000, 10000), // create offscreen wxDefaultSize, true); - tt.SetFormatString(tt.GetBuiltinFormat(c->GetFormat())); v = tt.GetTimeString(); } diff --git a/src/widgets/TimeTextCtrl.cpp b/src/widgets/TimeTextCtrl.cpp index ecefcef1b..6bafc28f2 100644 --- a/src/widgets/TimeTextCtrl.cpp +++ b/src/widgets/TimeTextCtrl.cpp @@ -185,34 +185,34 @@ different formats. #endif #endif -#define ID_MENU 9800 - -// Custom events - -DEFINE_EVENT_TYPE(EVT_TIMETEXTCTRL_UPDATED) - -BEGIN_EVENT_TABLE(TimeTextCtrl, wxControl) - EVT_ERASE_BACKGROUND(TimeTextCtrl::OnErase) - EVT_PAINT(TimeTextCtrl::OnPaint) - EVT_CONTEXT_MENU(TimeTextCtrl::OnContext) - EVT_MENU_RANGE(ID_MENU, ID_MENU+100, TimeTextCtrl::OnMenu) - EVT_MOUSE_EVENTS(TimeTextCtrl::OnMouse) - EVT_KEY_DOWN(TimeTextCtrl::OnKeyDown) - EVT_KEY_UP(TimeTextCtrl::OnKeyUp) - EVT_SET_FOCUS(TimeTextCtrl::OnFocus) - EVT_KILL_FOCUS(TimeTextCtrl::OnFocus) - EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, TimeTextCtrl::OnCaptureKey) -END_EVENT_TABLE() - -IMPLEMENT_CLASS(TimeTextCtrl, wxControl) - - - -class TimeField { +// +// ---------------------------------------------------------------------------- +// TimeField Class +// ---------------------------------------------------------------------------- +// +class TimeField +{ public: TimeField(bool _frac, int _base, int _range, bool _zeropad) - { frac = _frac; base = _base; range = _range; - zeropad = _zeropad; digits = 0; } + { + frac = _frac; + base = _base; + range = _range; + zeropad = _zeropad; + digits = 0; + } + void CreateDigitFormatStr() + { + if (range > 1) + digits = (int)ceil(log10(range-1.0)); + else + digits = 5; // hack: default + if (zeropad && range>1) + formatStr.Printf(wxT("%%0%dd"), digits); // ex. "%03d" if digits is 3 + else { + formatStr.Printf(wxT("%%0%dd"), digits); + } + } bool frac; // is it a fractional field int base; // divide by this (multiply, after decimal point) int range; // then take modulo this @@ -225,23 +225,23 @@ public: wxString label; wxString formatStr; wxString str; - void CreateDigitFormatStr() { - if (range > 1) - digits = (int)ceil(log10(range-1.0)); - else - digits = 5; // hack: default - if (zeropad && range>1) - formatStr.Printf(wxT("%%0%dd"), digits); // ex. "%03d" if digits is 3 - else { - formatStr.Printf(wxT("%%0%dd"), digits); - } - } }; -class DigitInfo { +// +// ---------------------------------------------------------------------------- +// DigitInfo Class +// ---------------------------------------------------------------------------- +// +class DigitInfo +{ public: DigitInfo(int _field, int _index, int _pos, wxRect _box) - { field = _field; index = _index; pos = _pos; digitBox = _box; } + { + field = _field; + index = _index; + pos = _pos; + digitBox = _box; + } int field; // Which field int index; // Index of this digit within the field int pos; // Position in the ValueString @@ -252,25 +252,15 @@ public: WX_DEFINE_OBJARRAY(TimeFieldArray); WX_DEFINE_OBJARRAY(DigitInfoArray); -TimeTextCtrl::TimeTextCtrl(wxWindow *parent, - wxWindowID id, - wxString formatString, - double timeValue, - double sampleRate, - const wxPoint &pos, - const wxSize &size, - bool autoPos): - wxControl(parent, id, pos, size, wxSUNKEN_BORDER | wxWANTS_CHARS), - mTimeValue(timeValue), - mFormatString(formatString), - mBackgroundBitmap(NULL), - mDigitFont(NULL), - mLabelFont(NULL), - mFocusedDigit(0), - mLastField(1), - mAutoPos(autoPos) +// +// ---------------------------------------------------------------------------- +// TimeConverter Class +// ---------------------------------------------------------------------------- +// +TimeConverter::TimeConverter(const wxString & formatName, + double timeValue, + double sampleRate) { - mConverter.mSampleRate = sampleRate; /* i18n-hint: Name of time display format that shows time in seconds */ BuiltinFormatStrings[0].name = _("seconds"); /* i18n-hint: Format string for displaying time in seconds. Change the comma @@ -402,179 +392,6 @@ TimeTextCtrl::TimeTextCtrl(wxWindow *parent, * frames. Translate 'frames' and leave the rest alone */ BuiltinFormatStrings[15].formatStr = _("01000,01000 frames|75"); - mDigitBoxW = 10; - mDigitBoxH = 16; - - mMenuEnabled = true; - mButtonWidth = 9; - - mConverter.ParseFormatString( mFormatString); - Layout(); - Fit(); - ValueToControls(); - //mchinen - aug 15 09 - this seems to put the mTimeValue back to zero, and do nothing else. - //ControlsToValue(); - -#if wxUSE_ACCESSIBILITY - SetLabel(wxT("")); - SetName(wxT("")); - SetAccessible(new TimeTextCtrlAx(this)); -#endif -} - -TimeTextCtrl::~TimeTextCtrl() -{ - wxCommandEvent e(EVT_RELEASE_KEYBOARD); - e.SetEventObject(this); - GetParent()->GetEventHandler()->ProcessEvent(e); - - if (mBackgroundBitmap) - delete mBackgroundBitmap; - if (mDigitFont) - delete mDigitFont; - if (mLabelFont) - delete mLabelFont; -} - -// Set the focus to the first (left-most) non-zero digit -// If all digits are zero, the right-most position is focused -void TimeTextCtrl::UpdateAutoFocus() -{ - if (!mAutoPos) - return; - - mFocusedDigit = 0; - while (mFocusedDigit < ((int)mDigits.GetCount() - 1)) { - wxChar dgt = mConverter.mValueString[mDigits[mFocusedDigit].pos]; - if (dgt != '0') { - break; - } - mFocusedDigit++; - } -} - -void TimeTextCtrl::SetFormatString(wxString formatString) -{ - mFormatString = formatString; - mConverter.ParseFormatString( mFormatString); - Layout(); - Fit(); - ValueToControls(); - ControlsToValue(); - UpdateAutoFocus(); -} - -void TimeTextCtrl::SetSampleRate(double sampleRate) -{ - mConverter.mSampleRate = sampleRate; - mConverter.ParseFormatString( mFormatString); - Layout(); - Fit(); - ValueToControls(); - ControlsToValue(); -} - -void TimeTextCtrl::SetTimeValue(double newTime) -{ - mTimeValue = newTime; - ValueToControls(); - ControlsToValue(); -} - -void TimeTextCtrl::Increment() -{ - mFocusedDigit = mDigits.GetCount() - 1; - Increase(1); -} - -void TimeTextCtrl::Decrement() -{ - mFocusedDigit = mDigits.GetCount() - 1; - Decrease(1); -} - -void TimeTextCtrl::EnableMenu(bool enable) -{ -#if wxUSE_TOOLTIPS - wxString tip(_("(Use context menu to change format.)")); - if (enable) - SetToolTip(tip); - else { - wxToolTip *tt = GetToolTip(); - if (tt && tt->GetTip() == tip) - SetToolTip(NULL); - } -#endif - mMenuEnabled = enable; - mButtonWidth = enable ? 9 : 0; - Layout(); - Fit(); -} - -const double TimeTextCtrl::GetTimeValue() -{ - ControlsToValue(); - return mTimeValue; -} - -wxString TimeTextCtrl::GetFormatString() -{ - return mFormatString; -} - -int TimeTextCtrl::GetFormatIndex() -{ - int ndx = 1; - int i; - - for (i = 0; i < TimeTextCtrl::GetNumBuiltins(); i++) { - if (mFormatString == TimeTextCtrl::GetBuiltinFormat(i)) { - ndx = i; - break; - } - } - - return ndx; -} - -int TimeTextCtrl::GetNumBuiltins() -{ - return (sizeof(BuiltinFormatStrings) / sizeof(BuiltinFormatStrings[0])); -} - -wxString TimeTextCtrl::GetBuiltinName(const int index) -{ - if (index >= 0 && index < GetNumBuiltins()) - return BuiltinFormatStrings[index].name; - else - return wxT(""); -} - -wxString TimeTextCtrl::GetBuiltinFormat(const int index) -{ - if (index >= 0 && index < GetNumBuiltins()) - return BuiltinFormatStrings[index].formatStr; - else - return wxT(""); -} - -wxString TimeTextCtrl::GetBuiltinFormat(const wxString &name) -{ - int ndx = 4; // Default to "hh:mm:ss + milliseconds". - int i; - - for (i=0; i= 1800) { + frames -= 1800; + mins++; + addMins = frames/1798; + frames -= addMins*1798; + mins += addMins; + secs = frames/30; + frames -= secs*30; + frames += 2; + if( frames >= 30 ) { + secs++; + frames -= 30; + } + } + else { + secs = frames/30; + frames -= secs*30; + } + t_int = mins * 60 + secs; + t_frac = frames / 30.; + } + + for(i=0; i 0) + // value = value % mFields[i].range; + } + else { + value = (t_int / mFields[i].base); + if (mFields[i].range > 0) + value = value % mFields[i].range; + } + + wxString field = wxString::Format(mFields[i].formatStr, value); + mValueString += field; + mValueString += mFields[i].label; + } +} + +void TimeConverter::ControlsToValue() +{ + unsigned int i; + double t = 0.0; + + for(i=0; i 0 ) { + frames += 1800; + addMins = mins - 1; + } + frames += addMins * 1798; + t_int -= mins*60; + if( mins == 0 ) //first min of a block of 10, don't drop frames 0 and 1 + frames += t_int * 30 + t_frac*30.; + else { //drop frames 0 and 1 of first seconds of these minutes + if( t_int > 0 ) + frames += 28 + (t_int-1)*30 + t_frac*30.; + else + frames += t_frac*30. -2.; + } + t = frames * 1.001 / 30.; + } + + mTimeValue = t; +} + +void TimeConverter::SetFormatString(const wxString & formatString) +{ + mFormatString = formatString; + ParseFormatString(mFormatString); + ValueToControls(); + ControlsToValue(); +} + +void TimeConverter::SetSampleRate(double sampleRate) +{ + mSampleRate = sampleRate; + ParseFormatString(mFormatString); + ValueToControls(); + ControlsToValue(); +} + +void TimeConverter::SetTimeValue(double newTime) +{ + mTimeValue = newTime; + ValueToControls(); + ControlsToValue(); +} + +double TimeConverter::GetTimeValue() +{ + ControlsToValue(); + return mTimeValue; +} + +wxString TimeConverter::GetFormatString() +{ + return mFormatString; +} + +int TimeConverter::GetFormatIndex() +{ + int ndx = 1; + int i; + + for (i = 0; i < GetNumBuiltins(); i++) { + if (mFormatString == GetBuiltinFormat(i)) { + ndx = i; + break; + } + } + + return ndx; +} + +int TimeConverter::GetNumBuiltins() +{ + return (sizeof(BuiltinFormatStrings) / sizeof(BuiltinFormatStrings[0])); +} + +wxString TimeConverter::GetBuiltinName(const int index) +{ + if (index >= 0 && index < GetNumBuiltins()) + return BuiltinFormatStrings[index].name; + + return wxEmptyString; +} + +wxString TimeConverter::GetBuiltinFormat(const int index) +{ + if (index >= 0 && index < GetNumBuiltins()) + return BuiltinFormatStrings[index].formatStr; + + return wxEmptyString; +} + +wxString TimeConverter::GetBuiltinFormat(const wxString &name) +{ + int ndx = 4; // Default to "hh:mm:ss + milliseconds". + int i; + + for (i = 0; i < GetNumBuiltins(); i++) { + if (name == GetBuiltinName(i)) { + ndx = i; + break; + } + } + + return GetBuiltinFormat(ndx); +} + +wxString TimeConverter::GetTimeString() { ValueToControls(); - return mConverter.mValueString; + return mValueString; +} + +void TimeConverter::Increment() +{ + mFocusedDigit = mDigits.GetCount() - 1; + Adjust(1, 1); +} + +void TimeConverter::Decrement() +{ + mFocusedDigit = mDigits.GetCount() - 1; + Adjust(1, -1); +} + +void TimeConverter::Adjust(int steps, int dir) +{ + wxASSERT(dir == -1 || dir == 1); + + while (steps != 0) + { + for (size_t i = 0; i < mFields.GetCount(); i++) + { + if ((mDigits[mFocusedDigit].pos >= mFields[i].pos) && (mDigits[mFocusedDigit].pos < mFields[i].pos + mFields[i].digits)) + { //it's this field + if (!mNtscDrop) + { + ControlsToValue(); + } + else + { + mNtscDrop = false; + ControlsToValue(); + mNtscDrop = true; + } + mTimeValue *= mScalingFactor; + + double mult = pow(10., mFields[i].digits - (mDigits[mFocusedDigit].pos - mFields[i].pos) - 1); + if (mFields[i].frac) + { + mTimeValue += ((mult / (double)mFields[i].base) * dir); + } + else + { + mTimeValue += ((mult * (double)mFields[i].base) * dir); + } + + if (mNtscDrop) + { + if ((mTimeValue - (int)mTimeValue) * 30 < 2) + { + if ((((int)mTimeValue) % 60 == 0) && (((int)mTimeValue) % 600 != 0)) + { + mTimeValue = (int)mTimeValue + (dir > 0 ? 2. : -1.) / 30.; + } + } + } + + if (mTimeValue < 0.) + { + mTimeValue = 0.; + } + + mTimeValue /= mScalingFactor; + + if (!mNtscDrop) + { + ValueToControls(); + } + else + { + mNtscDrop = false; + ValueToControls(); + mNtscDrop = true; + ControlsToValue(); + } + break; + } + } + steps--; + } + + ControlsToValue(); +} + +#define ID_MENU 9800 + +// Custom events + +DEFINE_EVENT_TYPE(EVT_TIMETEXTCTRL_UPDATED) + +BEGIN_EVENT_TABLE(TimeTextCtrl, wxControl) + EVT_ERASE_BACKGROUND(TimeTextCtrl::OnErase) + EVT_PAINT(TimeTextCtrl::OnPaint) + EVT_CONTEXT_MENU(TimeTextCtrl::OnContext) + EVT_MENU_RANGE(ID_MENU, ID_MENU+100, TimeTextCtrl::OnMenu) + EVT_MOUSE_EVENTS(TimeTextCtrl::OnMouse) + EVT_KEY_DOWN(TimeTextCtrl::OnKeyDown) + EVT_SET_FOCUS(TimeTextCtrl::OnFocus) + EVT_KILL_FOCUS(TimeTextCtrl::OnFocus) + EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, TimeTextCtrl::OnCaptureKey) +END_EVENT_TABLE() + +IMPLEMENT_CLASS(TimeTextCtrl, wxControl) + +TimeTextCtrl::TimeTextCtrl(wxWindow *parent, + wxWindowID id, + wxString formatString, + double timeValue, + double sampleRate, + const wxPoint &pos, + const wxSize &size, + bool autoPos): + wxControl(parent, id, pos, size, wxSUNKEN_BORDER | wxWANTS_CHARS), + TimeConverter(formatString, timeValue, sampleRate), + mBackgroundBitmap(NULL), + mDigitFont(NULL), + mLabelFont(NULL), + mLastField(1), + mAutoPos(autoPos) +{ + + mDigitBoxW = 10; + mDigitBoxH = 16; + + mMenuEnabled = true; + mButtonWidth = 9; + + Layout(); + Fit(); + ValueToControls(); + //mchinen - aug 15 09 - this seems to put the mTimeValue back to zero, and do nothing else. + //ControlsToValue(); + +#if wxUSE_ACCESSIBILITY + SetLabel(wxT("")); + SetName(wxT("")); + SetAccessible(new TimeTextCtrlAx(this)); +#endif +} + +TimeTextCtrl::~TimeTextCtrl() +{ + wxCommandEvent e(EVT_RELEASE_KEYBOARD); + e.SetEventObject(this); + GetParent()->GetEventHandler()->ProcessEvent(e); + + if (mBackgroundBitmap) + delete mBackgroundBitmap; + if (mDigitFont) + delete mDigitFont; + if (mLabelFont) + delete mLabelFont; +} + +// Set the focus to the first (left-most) non-zero digit +// If all digits are zero, the right-most position is focused +void TimeTextCtrl::UpdateAutoFocus() +{ + if (!mAutoPos) + return; + + mFocusedDigit = 0; + while (mFocusedDigit < ((int)mDigits.GetCount() - 1)) { + wxChar dgt = mValueString[mDigits[mFocusedDigit].pos]; + if (dgt != '0') { + break; + } + mFocusedDigit++; + } +} + +void TimeTextCtrl::SetFormatString(const wxString & formatString) +{ + TimeConverter::SetFormatString(formatString); + Layout(); + Fit(); + ValueToControls(); + ControlsToValue(); + UpdateAutoFocus(); +} + +void TimeTextCtrl::SetSampleRate(double sampleRate) +{ + TimeConverter::SetSampleRate(sampleRate); + Layout(); + Fit(); + ValueToControls(); + ControlsToValue(); +} + +void TimeTextCtrl::SetTimeValue(double newTime) +{ + TimeConverter::SetTimeValue(newTime); + ValueToControls(); + ControlsToValue(); +} + +void TimeTextCtrl::EnableMenu(bool enable) +{ +#if wxUSE_TOOLTIPS + wxString tip(_("(Use context menu to change format.)")); + if (enable) + SetToolTip(tip); + else { + wxToolTip *tt = GetToolTip(); + if (tt && tt->GetTip() == tip) + SetToolTip(NULL); + } +#endif + mMenuEnabled = enable; + mButtonWidth = enable ? 9 : 0; + Layout(); + Fit(); } bool TimeTextCtrl::Layout() @@ -818,12 +1076,9 @@ bool TimeTextCtrl::Layout() pos = 0; memDC.SetFont(*mLabelFont); - memDC.GetTextExtent(mConverter.mPrefix, &strW, &strH); + memDC.GetTextExtent(mPrefix, &strW, &strH); x += strW; - pos += mConverter.mPrefix.Length(); - - // Slightly messy trick to save us some prefixing. - TimeFieldArray & mFields = mConverter.mFields; + pos += mPrefix.Length(); for(i=0; i= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9)) keyCode -= WXK_NUMPAD0 - '0'; if (keyCode >= '0' && keyCode <= '9') { - mConverter.mValueString[mDigits[mFocusedDigit].pos] = wxChar(keyCode); + mValueString[mDigits[mFocusedDigit].pos] = wxChar(keyCode); ControlsToValue(); ValueToControls(); mFocusedDigit = (mFocusedDigit+1)%(mDigits.GetCount()); @@ -1133,7 +1382,7 @@ void TimeTextCtrl::OnKeyDown(wxKeyEvent &event) mFocusedDigit--; mFocusedDigit += mDigits.GetCount(); mFocusedDigit %= mDigits.GetCount(); - mConverter.mValueString[mDigits[mFocusedDigit].pos] = '0'; + mValueString[mDigits[mFocusedDigit].pos] = '0'; ControlsToValue(); ValueToControls(); Updated(); @@ -1163,12 +1412,12 @@ void TimeTextCtrl::OnKeyDown(wxKeyEvent &event) } else if (keyCode == WXK_UP) { - Increase(1); + Adjust(1, 1); Updated(); } else if (keyCode == WXK_DOWN) { - Decrease(1); + Adjust(1, -1); Updated(); } @@ -1255,239 +1504,16 @@ void TimeTextCtrl::Updated(bool keyup /* = false */) #endif } -void TimeTextCtrl::Increase(int steps) -{ - // Slightly messy trick to save us some prefixing. - TimeFieldArray & mFields = mConverter.mFields; - - while(steps > 0) { - for(unsigned int i=0; i=mFields[i].pos) && (mDigits[mFocusedDigit].pos 0) { - for(unsigned int i=0; i=mFields[i].pos) && (mDigits[mFocusedDigit].pos= 1800) { - frames -= 1800; - mins++; - addMins = frames/1798; - frames -= addMins*1798; - mins += addMins; - secs = frames/30; - frames -= secs*30; - frames += 2; - if( frames >= 30 ) { - secs++; - frames -= 30; - } - } - else { - secs = frames/30; - frames -= secs*30; - } - t_int = mins * 60 + secs; - t_frac = frames / 30.; - } - - for(i=0; i 0) - // value = value % mFields[i].range; - } - else { - value = (t_int / mFields[i].base); - if (mFields[i].range > 0) - value = value % mFields[i].range; - } - - wxString field = wxString::Format(mFields[i].formatStr, value); - mValueString += field; - mValueString += mFields[i].label; - } - -} - - void TimeTextCtrl::ControlsToValue() { - mTimeValue = mConverter.ControlsToValue(); -} - -double TimeConverter::ControlsToValue() -{ - unsigned int i; - double t = 0.0; - - for(i=0; i 0 ) { - frames += 1800; - addMins = mins - 1; - } - frames += addMins * 1798; - t_int -= mins*60; - if( mins == 0 ) //first min of a block of 10, don't drop frames 0 and 1 - frames += t_int * 30 + t_frac*30.; - else { //drop frames 0 and 1 of first seconds of these minutes - if( t_int > 0 ) - frames += 28 + (t_int-1)*30 + t_frac*30.; - else - frames += t_frac*30. -2.; - } - t = frames * 1.001 / 30.; - } - - return t; + TimeConverter::ControlsToValue(); } #if wxUSE_ACCESSIBILITY @@ -1622,7 +1648,7 @@ wxAccStatus TimeTextCtrlAx::GetLocation(wxRect & rect, int elementId) wxAccStatus TimeTextCtrlAx::GetName(int childId, wxString *name) { // Slightly messy trick to save us some prefixing. - TimeFieldArray & mFields = mCtrl->mConverter.mFields; + TimeFieldArray & mFields = mCtrl->mFields; wxString value = mCtrl->GetTimeString(); int field = mCtrl->GetFocusedField(); @@ -1730,3 +1756,4 @@ wxAccStatus TimeTextCtrlAx::GetValue(int WXUNUSED(childId), wxString * WXUNUSED( } #endif + diff --git a/src/widgets/TimeTextCtrl.h b/src/widgets/TimeTextCtrl.h index 3c925a70c..10a9389f1 100644 --- a/src/widgets/TimeTextCtrl.h +++ b/src/widgets/TimeTextCtrl.h @@ -32,7 +32,8 @@ DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TIMETEXTCTRL_UPDATED, -1); /** \brief struct to hold a formatting control string and it's user facing name * Used in an array to hold the built-in time formats that are always available * to the user */ -struct BuiltinFormatString { +struct BuiltinFormatString +{ wxString name; wxString formatStr; }; @@ -46,7 +47,49 @@ WX_DECLARE_OBJARRAY(DigitInfo, DigitInfoArray); class TimeConverter { public: - TimeConverter(); + TimeConverter::TimeConverter(const wxString & formatName = wxEmptyString, + double timeValue = 0.0f, + double sampleRate = 1.0f /* to prevent div by 0 */); + + virtual void ValueToControls(); + virtual void ValueToControls(double RawTime, bool nearest = true); + virtual void ControlsToValue(); + virtual void ParseFormatString(const wxString & format); + + void PrintDebugInfo(); + void SetFormatString(const wxString & formatName); + void SetSampleRate(double sampleRate); + void SetTimeValue(double newTime); + double GetTimeValue(); + + wxString GetTimeString(); + + wxString GetFormatString(); + int GetFormatIndex(); + + int GetNumBuiltins(); + wxString GetBuiltinName(const int index); + wxString GetBuiltinFormat(const int index); + wxString GetBuiltinFormat(const wxString & name); + + // Adjust the value by the number "steps" in the active format. + // Increment if "dir" is 1, descrement if "dir" is -1. + void Adjust(int steps, int dir); + + void Increment(); + void Decrement(); + +protected: + /** \brief array of formats the control knows about internally + * array of string pairs for name of the format and the format string + * needed to create that format output. This is used for the pop-up + * list of formats to choose from in the control. Note that the size will + * need adjusting if new time formats are added */ + BuiltinFormatString BuiltinFormatStrings[16]; + double mTimeValue; + + wxString mFormatString; + TimeFieldArray mFields; wxString mPrefix; wxString mValueTemplate; @@ -57,13 +100,12 @@ public: double mSampleRate; bool mNtscDrop; - void ParseFormatString( const wxString & format ); - void PrintDebugInfo(); - void ValueToControls( double RawTime ); - double ControlsToValue(); + int mFocusedDigit; + DigitInfoArray mDigits; }; -class TimeTextCtrl: public wxControl{ +class TimeTextCtrl: public wxControl, public TimeConverter +{ friend class TimeTextCtrlAx; public: @@ -71,7 +113,7 @@ class TimeTextCtrl: public wxControl{ TimeTextCtrl(wxWindow *parent, wxWindowID id, - wxString formatString = wxT(""), + wxString formatName = wxT(""), double timeValue = 0.0, double sampleRate = 44100, const wxPoint &pos = wxDefaultPosition, @@ -83,23 +125,11 @@ class TimeTextCtrl: public wxControl{ virtual bool Layout(); virtual void Fit(); - void SetFieldFocus(int digit); - void SetFormatString(wxString formatString); void SetSampleRate(double sampleRate); void SetTimeValue(double newTime); - void Increment(); - void Decrement(); - const double GetTimeValue(); + void SetFormatString(const wxString & formatString); - wxString GetTimeString(); - - wxString GetFormatString(); - int GetFormatIndex(); - - int GetNumBuiltins(); - wxString GetBuiltinName(const int index); - wxString GetBuiltinFormat(const int index); - wxString GetBuiltinFormat(const wxString &name); + void SetFieldFocus(int digit); void EnableMenu(bool enable = true); @@ -121,24 +151,13 @@ private: void ValueToControls(); void ControlsToValue(); - void PrintDebugInfo(); - // If autoPos was enabled, focus the first non-zero digit void UpdateAutoFocus(); void Updated(bool keyup = false); - void Increase(int steps); - void Decrease(int steps); - /** \brief array of formats the control knows about internally - * array of string pairs for name of the format and the format string - * needed to create that format output. This is used for the pop-up - * list of formats to choose from in the control. Note that the size will - * need adjusting if new time formats are added */ - BuiltinFormatString BuiltinFormatStrings[16]; - double mTimeValue; +private: - wxString mFormatString; bool mMenuEnabled; wxBitmap *mBackgroundBitmap; @@ -157,16 +176,11 @@ private: int mHeight; int mButtonWidth; - int mFocusedDigit; int mLastField; // If true, the focus will be set to the first non-zero digit bool mAutoPos; - DigitInfoArray mDigits; - TimeConverter mConverter; - - // Keeps track of extra fractional scrollwheel steps double mScrollRemainder;