1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 16:10:06 +02:00

Bugzilla#115. Split TimeConverter from the TimeTextCtrl GUI class so that we do not create a ctrl every time we want to do a time conversion.

Also avoided creating a SnapManager when snap-to is disabled.
This commit is contained in:
james.k.crook 2010-02-12 21:28:34 +00:00
parent c6ca8c2018
commit e801b39943
4 changed files with 143 additions and 60 deletions

View File

@ -31,6 +31,13 @@ SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions,
// Grab time-snapping prefs (unless otherwise requested) // Grab time-snapping prefs (unless otherwise requested)
mSnapToTime = false; mSnapToTime = false;
TimeTextCtrl *ttc = NULL; 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) if (gPrefs->Read(wxT("/SnapTo"), 0L) != 0L && !noTimeSnap)
{ {
// Look up the format string // Look up the format string
@ -249,11 +256,26 @@ bool SnapManager::Snap(Track *currentTrack,
else { else {
// Snap time to the grid // Snap time to the grid
AudacityProject *p = GetActiveProject(); 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()); TimeTextCtrl ttc(p, wxID_ANY, wxT(""), 0.0, p->GetRate());
ttc.SetFormatString(mFormat); ttc.SetFormatString(mFormat);
ttc.SetTimeValue(t); ttc.SetTimeValue(t);
*out_t = ttc.GetTimeValue(); *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
*snappedTime = true; *snappedTime = true;
} }
} }

View File

@ -1789,12 +1789,20 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
bool startNewSelection = true; bool startNewSelection = true;
mMouseCapture=IsSelecting; mMouseCapture=IsSelecting;
// Need a comment explaining why we need a new SnapManager
// with each mouse-down.
if (mSnapManager) if (mSnapManager)
delete mSnapManager; delete mSnapManager;
mSnapManager = NULL;
// If we're not snapping, we don't need a snap manager.
if( GetActiveProject()->GetSnapTo() )
{
mSnapManager = new SnapManager(mTracks, NULL, mSnapManager = new SnapManager(mTracks, NULL,
mViewInfo->zoom, mViewInfo->zoom,
4); // pixel tolerance 4); // pixel tolerance
}
mSnapLeft = -1; mSnapLeft = -1;
mSnapRight = -1; mSnapRight = -1;

View File

@ -129,6 +129,14 @@ in the status bar of Audacity.
\class TimeTextCtrlAx \class TimeTextCtrlAx
\brief TimeTextCtrlAx gives the TimeTextCtrl Accessibility. \brief TimeTextCtrlAx gives the TimeTextCtrl Accessibility.
*******************************************************************//**
\class TimeConverter
\brief TimeConverter has all the time conversion and snapping
functionality that used to live in TimeTextCtrl. The idea is to have
a GUI-less class which can do the conversions, so that we can use it
in sanpping without having a window created each time.
*//****************************************************************//** *//****************************************************************//**
\class BuiltinFormatString \class BuiltinFormatString
@ -252,7 +260,6 @@ TimeTextCtrl::TimeTextCtrl(wxWindow *parent,
bool autoPos): bool autoPos):
wxControl(parent, id, pos, size, wxSUNKEN_BORDER | wxWANTS_CHARS), wxControl(parent, id, pos, size, wxSUNKEN_BORDER | wxWANTS_CHARS),
mTimeValue(timeValue), mTimeValue(timeValue),
mSampleRate(sampleRate),
mFormatString(formatString), mFormatString(formatString),
mBackgroundBitmap(NULL), mBackgroundBitmap(NULL),
mDigitFont(NULL), mDigitFont(NULL),
@ -261,6 +268,7 @@ TimeTextCtrl::TimeTextCtrl(wxWindow *parent,
mLastField(1), mLastField(1),
mAutoPos(autoPos) mAutoPos(autoPos)
{ {
mConverter.mSampleRate = sampleRate;
/* i18n-hint: Name of time display format that shows time in seconds */ /* i18n-hint: Name of time display format that shows time in seconds */
BuiltinFormatStrings[0].name = _("seconds"); BuiltinFormatStrings[0].name = _("seconds");
/* i18n-hint: Format string for displaying time in seconds. Change the comma /* i18n-hint: Format string for displaying time in seconds. Change the comma
@ -396,7 +404,7 @@ TimeTextCtrl::TimeTextCtrl(wxWindow *parent,
mMenuEnabled = true; mMenuEnabled = true;
mButtonWidth = 9; mButtonWidth = 9;
ParseFormatString(); mConverter.ParseFormatString( mFormatString);
Layout(); Layout();
Fit(); Fit();
ValueToControls(); ValueToControls();
@ -433,7 +441,7 @@ void TimeTextCtrl::UpdateAutoFocus()
mFocusedDigit = 0; mFocusedDigit = 0;
while (mFocusedDigit < ((int)mDigits.GetCount() - 1)) { while (mFocusedDigit < ((int)mDigits.GetCount() - 1)) {
wxChar dgt = mValueString[mDigits[mFocusedDigit].pos]; wxChar dgt = mConverter.mValueString[mDigits[mFocusedDigit].pos];
if (dgt != '0') { if (dgt != '0') {
break; break;
} }
@ -444,7 +452,7 @@ void TimeTextCtrl::UpdateAutoFocus()
void TimeTextCtrl::SetFormatString(wxString formatString) void TimeTextCtrl::SetFormatString(wxString formatString)
{ {
mFormatString = formatString; mFormatString = formatString;
ParseFormatString(); mConverter.ParseFormatString( mFormatString);
Layout(); Layout();
Fit(); Fit();
ValueToControls(); ValueToControls();
@ -454,8 +462,8 @@ void TimeTextCtrl::SetFormatString(wxString formatString)
void TimeTextCtrl::SetSampleRate(double sampleRate) void TimeTextCtrl::SetSampleRate(double sampleRate)
{ {
mSampleRate = sampleRate; mConverter.mSampleRate = sampleRate;
ParseFormatString(); mConverter.ParseFormatString( mFormatString);
Layout(); Layout();
Fit(); Fit();
ValueToControls(); ValueToControls();
@ -561,13 +569,24 @@ wxString TimeTextCtrl::GetBuiltinFormat(const wxString &name)
return TimeTextCtrl::GetBuiltinFormat(ndx); return TimeTextCtrl::GetBuiltinFormat(ndx);
} }
void TimeTextCtrl::ParseFormatString() TimeConverter::TimeConverter()
{
mPrefix = wxT("");
mValueTemplate = wxT("");
mValueMask = wxT("");
mValueString = wxT("");
mScalingFactor = 1.0f;
mSampleRate = 1.0f;
mNtscDrop = false;
}
void TimeConverter::ParseFormatString( const wxString & format)
{ {
mPrefix = wxT(""); mPrefix = wxT("");
mFields.Clear(); mFields.Clear();
mScalingFactor = 1.0; mScalingFactor = 1.0;
const wxString format = mFormatString;
bool inFrac = false; bool inFrac = false;
int fracMult = 1; int fracMult = 1;
int numWholeFields = 0; int numWholeFields = 0;
@ -709,7 +728,7 @@ void TimeTextCtrl::ParseFormatString()
} }
} }
void TimeTextCtrl::PrintDebugInfo() void TimeConverter::PrintDebugInfo()
{ {
unsigned int i; unsigned int i;
@ -738,7 +757,7 @@ wxString TimeTextCtrl::GetTimeString()
{ {
ValueToControls(); ValueToControls();
return mValueString; return mConverter.mValueString;
} }
bool TimeTextCtrl::Layout() bool TimeTextCtrl::Layout()
@ -795,9 +814,12 @@ bool TimeTextCtrl::Layout()
pos = 0; pos = 0;
memDC.SetFont(*mLabelFont); memDC.SetFont(*mLabelFont);
memDC.GetTextExtent(mPrefix, &strW, &strH); memDC.GetTextExtent(mConverter.mPrefix, &strW, &strH);
x += strW; x += strW;
pos += mPrefix.Length(); pos += mConverter.mPrefix.Length();
// Slightly messy trick to save us some prefixing.
TimeFieldArray & mFields = mConverter.mFields;
for(i=0; i<mFields.GetCount(); i++) { for(i=0; i<mFields.GetCount(); i++) {
mFields[i].fieldX = x; mFields[i].fieldX = x;
@ -838,7 +860,7 @@ bool TimeTextCtrl::Layout()
memDC.SetTextForeground(*wxBLACK); memDC.SetTextForeground(*wxBLACK);
memDC.SetTextBackground(*wxLIGHT_GREY); memDC.SetTextBackground(*wxLIGHT_GREY);
memDC.DrawText(mPrefix, mBorderLeft, labelTop); memDC.DrawText(mConverter.mPrefix, mBorderLeft, labelTop);
theTheme.SetBrushColour( Brush, clrTimeBack ); theTheme.SetBrushColour( Brush, clrTimeBack );
memDC.SetBrush(Brush); memDC.SetBrush(Brush);
@ -914,7 +936,7 @@ void TimeTextCtrl::OnPaint(wxPaintEvent &event)
dc.SetTextBackground(theTheme.Colour( clrTimeBackFocus )); dc.SetTextBackground(theTheme.Colour( clrTimeBackFocus ));
} }
int pos = mDigits[i].pos; int pos = mDigits[i].pos;
wxString digit = mValueString.Mid(pos, 1); wxString digit = mConverter.mValueString.Mid(pos, 1);
int x = box.x + (mDigitBoxW - mDigitW)/2; int x = box.x + (mDigitBoxW - mDigitW)/2;
int y = box.y + (mDigitBoxH - mDigitH)/2; int y = box.y + (mDigitBoxH - mDigitH)/2;
dc.DrawText(digit, x, y); dc.DrawText(digit, x, y);
@ -1071,7 +1093,7 @@ void TimeTextCtrl::OnKeyDown(wxKeyEvent &event)
if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9)) keyCode -= WXK_NUMPAD0 - '0'; if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9)) keyCode -= WXK_NUMPAD0 - '0';
if (keyCode >= '0' && keyCode <= '9') { if (keyCode >= '0' && keyCode <= '9') {
mValueString[mDigits[mFocusedDigit].pos] = wxChar(keyCode); mConverter.mValueString[mDigits[mFocusedDigit].pos] = wxChar(keyCode);
ControlsToValue(); ControlsToValue();
ValueToControls(); ValueToControls();
mFocusedDigit = (mFocusedDigit+1)%(mDigits.GetCount()); mFocusedDigit = (mFocusedDigit+1)%(mDigits.GetCount());
@ -1083,7 +1105,7 @@ void TimeTextCtrl::OnKeyDown(wxKeyEvent &event)
mFocusedDigit--; mFocusedDigit--;
mFocusedDigit += mDigits.GetCount(); mFocusedDigit += mDigits.GetCount();
mFocusedDigit %= mDigits.GetCount(); mFocusedDigit %= mDigits.GetCount();
mValueString[mDigits[mFocusedDigit].pos] = '0'; mConverter.mValueString[mDigits[mFocusedDigit].pos] = '0';
ControlsToValue(); ControlsToValue();
ValueToControls(); ValueToControls();
Updated(); Updated();
@ -1195,36 +1217,39 @@ void TimeTextCtrl::Updated()
void TimeTextCtrl::Increase(int steps) void TimeTextCtrl::Increase(int steps)
{ {
// Slightly messy trick to save us some prefixing.
TimeFieldArray & mFields = mConverter.mFields;
while(steps > 0) { while(steps > 0) {
for(unsigned int i=0; i<mFields.GetCount(); i++) { for(unsigned int 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( (mDigits[mFocusedDigit].pos>=mFields[i].pos) && (mDigits[mFocusedDigit].pos<mFields[i].pos+mFields[i].digits)) { //it's this field
if(!mNtscDrop) if(!mConverter.mNtscDrop)
ControlsToValue(); ControlsToValue();
else { else {
mNtscDrop = false; mConverter.mNtscDrop = false;
ControlsToValue(); ControlsToValue();
mNtscDrop = true; mConverter.mNtscDrop = true;
} }
mTimeValue *= mScalingFactor; mTimeValue *= mConverter.mScalingFactor;
double mult = pow(10.,mFields[i].digits-(mDigits[mFocusedDigit].pos-mFields[i].pos)-1); double mult = pow(10.,mFields[i].digits-(mDigits[mFocusedDigit].pos-mFields[i].pos)-1);
if (mFields[i].frac) if (mFields[i].frac)
mTimeValue += mult/(double)mFields[i].base; mTimeValue += mult/(double)mFields[i].base;
else else
mTimeValue += mult*(double)mFields[i].base; mTimeValue += mult*(double)mFields[i].base;
if(mNtscDrop) { if(mConverter.mNtscDrop) {
if( (mTimeValue - (int)mTimeValue)*30 < 2 ) if( (mTimeValue - (int)mTimeValue)*30 < 2 )
if( (((int)mTimeValue)%60 == 0) && (((int)mTimeValue)%600 != 0) ) if( (((int)mTimeValue)%60 == 0) && (((int)mTimeValue)%600 != 0) )
mTimeValue = (int)mTimeValue + 2./30.; mTimeValue = (int)mTimeValue + 2./30.;
} }
if(mTimeValue<0.) if(mTimeValue<0.)
mTimeValue=0.; mTimeValue=0.;
mTimeValue /= mScalingFactor; mTimeValue /= mConverter.mScalingFactor;
if(!mNtscDrop) if(!mConverter.mNtscDrop)
ValueToControls(); ValueToControls();
else { else {
mNtscDrop = false; mConverter.mNtscDrop = false;
ValueToControls(); ValueToControls();
mNtscDrop = true; mConverter.mNtscDrop = true;
ControlsToValue(); ControlsToValue();
} }
break; break;
@ -1238,36 +1263,39 @@ void TimeTextCtrl::Increase(int steps)
void TimeTextCtrl::Decrease(int steps) void TimeTextCtrl::Decrease(int steps)
{ {
// Slightly messy trick to save us some prefixing.
TimeFieldArray & mFields = mConverter.mFields;
while(steps > 0) { while(steps > 0) {
for(unsigned int i=0; i<mFields.GetCount(); i++) { for(unsigned int 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( (mDigits[mFocusedDigit].pos>=mFields[i].pos) && (mDigits[mFocusedDigit].pos<mFields[i].pos+mFields[i].digits)) { //it's this field
if(!mNtscDrop) if(!mConverter.mNtscDrop)
ControlsToValue(); ControlsToValue();
else { else {
mNtscDrop = false; mConverter.mNtscDrop = false;
ControlsToValue(); ControlsToValue();
mNtscDrop = true; mConverter.mNtscDrop = true;
} }
mTimeValue *= mScalingFactor; mTimeValue *= mConverter.mScalingFactor;
double mult = pow(10.,mFields[i].digits-(mDigits[mFocusedDigit].pos-mFields[i].pos)-1); double mult = pow(10.,mFields[i].digits-(mDigits[mFocusedDigit].pos-mFields[i].pos)-1);
if (mFields[i].frac) if (mFields[i].frac)
mTimeValue -= mult/(double)mFields[i].base; mTimeValue -= mult/(double)mFields[i].base;
else else
mTimeValue -= mult*(double)mFields[i].base; mTimeValue -= mult*(double)mFields[i].base;
if(mNtscDrop) { if(mConverter.mNtscDrop) {
if( (mTimeValue - (int)mTimeValue)*30 < 2 ) if( (mTimeValue - (int)mTimeValue)*30 < 2 )
if( (((int)mTimeValue)%60 == 0) && (((int)mTimeValue)%600 != 0) ) if( (((int)mTimeValue)%60 == 0) && (((int)mTimeValue)%600 != 0) )
mTimeValue = (int)mTimeValue - 1./30.; mTimeValue = (int)mTimeValue - 1./30.;
} }
if(mTimeValue<0.) if(mTimeValue<0.)
mTimeValue=0.; mTimeValue=0.;
mTimeValue /= mScalingFactor; mTimeValue /= mConverter.mScalingFactor;
if(!mNtscDrop) if(!mConverter.mNtscDrop)
ValueToControls(); ValueToControls();
else { else {
mNtscDrop = false; mConverter.mNtscDrop = false;
ValueToControls(); ValueToControls();
mNtscDrop = true; mConverter.mNtscDrop = true;
ControlsToValue(); ControlsToValue();
} }
break; break;
@ -1281,7 +1309,13 @@ void TimeTextCtrl::Decrease(int steps)
void TimeTextCtrl::ValueToControls() void TimeTextCtrl::ValueToControls()
{ {
double theValue = mTimeValue * mScalingFactor + .000001; mConverter.ValueToControls( mTimeValue );
Refresh(false);
}
void TimeConverter::ValueToControls( double RawTime )
{
double theValue = RawTime * mScalingFactor + .000001;
int t_int = int(theValue); int t_int = int(theValue);
double t_frac = (theValue - t_int); double t_frac = (theValue - t_int);
unsigned int i; unsigned int i;
@ -1337,10 +1371,16 @@ void TimeTextCtrl::ValueToControls()
mValueString += mFields[i].label; mValueString += mFields[i].label;
} }
Refresh(false);
} }
void TimeTextCtrl::ControlsToValue() void TimeTextCtrl::ControlsToValue()
{
mTimeValue = mConverter.ControlsToValue();
}
double TimeConverter::ControlsToValue()
{ {
unsigned int i; unsigned int i;
double t = 0.0; double t = 0.0;
@ -1382,7 +1422,7 @@ void TimeTextCtrl::ControlsToValue()
t = frames * 1.001 / 30.; t = frames * 1.001 / 30.;
} }
mTimeValue = t; return t;
} }
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
@ -1510,6 +1550,9 @@ wxAccStatus TimeTextCtrlAx::GetLocation(wxRect & rect, int elementId)
// Gets the name of the specified object. // Gets the name of the specified object.
wxAccStatus TimeTextCtrlAx::GetName(int childId, wxString *name) wxAccStatus TimeTextCtrlAx::GetName(int childId, wxString *name)
{ {
// Slightly messy trick to save us some prefixing.
TimeFieldArray & mFields = mCtrl->mConverter.mFields;
wxString value = mCtrl->GetTimeString(); wxString value = mCtrl->GetTimeString();
int field = mCtrl->GetFocusedField(); int field = mCtrl->GetFocusedField();
@ -1528,15 +1571,15 @@ wxAccStatus TimeTextCtrlAx::GetName(int childId, wxString *name)
// The user has moved from one field of the time to another so // The user has moved from one field of the time to another so
// report the value of the field and the field's label. // report the value of the field and the field's label.
else if (mLastField != field) { else if (mLastField != field) {
wxString label = mCtrl->mFields[field - 1].label; wxString label = mFields[field - 1].label;
int cnt = mCtrl->mFields.GetCount(); int cnt = mFields.GetCount();
wxString decimal = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); wxString decimal = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
// If the new field is the last field, then check it to see if // If the new field is the last field, then check it to see if
// it represents fractions of a second. // it represents fractions of a second.
if (field > 1 && field == cnt) { if (field > 1 && field == cnt) {
if (mCtrl->mFields[field - 2].label == decimal) { if (mFields[field - 2].label == decimal) {
int digits = mCtrl->mFields[field - 1].digits; int digits = mFields[field - 1].digits;
if (digits == 2) { if (digits == 2) {
label = _("centiseconds"); label = _("centiseconds");
} }
@ -1548,10 +1591,10 @@ wxAccStatus TimeTextCtrlAx::GetName(int childId, wxString *name)
// If the field following this one represents fractions of a // If the field following this one represents fractions of a
// second then use that label instead of the decimal point. // second then use that label instead of the decimal point.
else if (label == decimal && field == cnt - 1) { else if (label == decimal && field == cnt - 1) {
label = mCtrl->mFields[field].label; label = mFields[field].label;
} }
*name = mCtrl->mFields[field - 1].str + *name = mFields[field - 1].str +
wxT(" ") + wxT(" ") +
label + label +
wxT(" ") + wxT(" ") +
@ -1568,7 +1611,7 @@ wxAccStatus TimeTextCtrlAx::GetName(int childId, wxString *name)
// The user has updated the value of a field, so report the field's // The user has updated the value of a field, so report the field's
// value only. // value only.
else { else {
*name = mCtrl->mFields[field - 1].str; *name = mFields[field - 1].str;
} }
return wxACC_OK; return wxACC_OK;

View File

@ -43,6 +43,26 @@ WX_DECLARE_OBJARRAY(TimeField, TimeFieldArray);
class DigitInfo; class DigitInfo;
WX_DECLARE_OBJARRAY(DigitInfo, DigitInfoArray); WX_DECLARE_OBJARRAY(DigitInfo, DigitInfoArray);
class TimeConverter
{
public:
TimeConverter();
TimeFieldArray mFields;
wxString mPrefix;
wxString mValueTemplate;
wxString mValueMask;
wxString mValueString;
double mScalingFactor;
double mSampleRate;
bool mNtscDrop;
void ParseFormatString( const wxString & format );
void PrintDebugInfo();
void ValueToControls( double RawTime );
double ControlsToValue();
};
class TimeTextCtrl: public wxControl{ class TimeTextCtrl: public wxControl{
friend class TimeTextCtrlAx; friend class TimeTextCtrlAx;
@ -97,8 +117,6 @@ private:
void OnContext(wxContextMenuEvent &event); void OnContext(wxContextMenuEvent &event);
void OnMenu(wxCommandEvent &event); void OnMenu(wxCommandEvent &event);
void ParseFormatString();
void ValueToControls(); void ValueToControls();
void ControlsToValue(); void ControlsToValue();
@ -118,16 +136,10 @@ private:
* need adjusting if new time formats are added */ * need adjusting if new time formats are added */
BuiltinFormatString BuiltinFormatStrings[16]; BuiltinFormatString BuiltinFormatStrings[16];
double mTimeValue; double mTimeValue;
double mSampleRate;
wxString mFormatString; wxString mFormatString;
wxString mValueString;
wxString mValueTemplate;
wxString mValueMask;
bool mMenuEnabled; bool mMenuEnabled;
wxString mPrefix;
wxBitmap *mBackgroundBitmap; wxBitmap *mBackgroundBitmap;
wxFont *mDigitFont; wxFont *mDigitFont;
@ -151,10 +163,8 @@ private:
bool mAutoPos; bool mAutoPos;
DigitInfoArray mDigits; DigitInfoArray mDigits;
TimeConverter mConverter;
TimeFieldArray mFields;
double mScalingFactor;
bool mNtscDrop;
// Keeps track of extra fractional scrollwheel steps // Keeps track of extra fractional scrollwheel steps
double mScrollRemainder; double mScrollRemainder;