From 28239dfa1d1c5dbe3d0583c0b7e786f778e19c98 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 20 Aug 2015 15:52:56 -0400 Subject: [PATCH 01/13] Add one big, artistic comment to TrackPanel.cpp explaining the track rectangle --- src/TrackPanel.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 727b02650..7087b426f 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -206,6 +206,59 @@ is time to refresh some aspect of the screen. DEFINE_EVENT_TYPE(EVT_TRACK_PANEL_TIMER) +/* + +This is a diagram of TrackPanel's division of one (non-stereo) track rectangle. +Total height equals Track::GetHeight()'s value. Total width is the wxWindow's width. +Each charater that is not . represents one pixel. + +Inset space of this track, and top inset of the next track, are used to draw the focus highlight. + +Top inset of the right channel of a stereo track, and bottom shadow line of the +left channel, are used for the channel separator. + +TrackInfo::GetTrackInfoWidth() == GetVRulerOffset() +counts columns from the left edge up to and including controls, and is a constant. + +GetVRulerWidth() is variable -- all tracks have the same ruler width at any time, +but that width may be adjusted when tracks change their vertical scales. + +GetLabelWidth() counts columns up to and including the VRuler. +GetLeftOffset() is yet one more -- it counts the "one pixel" column. + +FindTrack() for label returns a rectangle with width equal to GetLeftOffset(), +and OMITS left and top insets + +FindTrack() for !label returns a rectangle with x == GetLeftOffset(), and INCLUDES +right and top insets + ++--------------- ... ------ ... --------------------- ... ... -------------+ +| Top Inset | +| | +| +------------ ... ------ ... --------------------- ... ... ----------+ | +| L|+-Border---- ... ------ ... --------------------- ... ... -Border-+ |R | +| e||+---------- ... -++--- ... -+++----------------- ... ... -------+| |i | +| f|B| || ||| |BS|g | +| t|o| Controls || V |O| The good stuff |oh|h | +| |r| || R |n| |ra|t | +| I|d| || u |e| |dd| | +| n|e| || l | | |eo|I | +| s|r| || e |P| |rw|n | +| e||| || r |i| ||||s | +| t||| || |x| ||||e | +| ||| || |e| ||||t | +| ||| || |l| |||| | +| ||| || ||| |||| | + +. ... .. ... .... . +. ... .. ... .... . +. ... .. ... .... . + +| ||| || ||| |||| | +| ||+---------- -++-- ... -+++----------------- ... ... -------+||| | +| |+-Border---- ... ----- ... --------------------- ... ... -Border-+|| | +| | Shadow---- ... ----- ... --------------------- ... ... --Shadow-+| | +*/ enum { kLeftInset = 4, kTopInset = 4, From 0eca2bb23da8246d10f4b5a99c77d75891cb7421 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 20 Aug 2015 15:58:54 -0400 Subject: [PATCH 02/13] Fix an inaccuracy in the comment --- src/TrackPanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 7087b426f..b6c5acd79 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -226,8 +226,8 @@ but that width may be adjusted when tracks change their vertical scales. GetLabelWidth() counts columns up to and including the VRuler. GetLeftOffset() is yet one more -- it counts the "one pixel" column. -FindTrack() for label returns a rectangle with width equal to GetLeftOffset(), -and OMITS left and top insets +FindTrack() for label returns a rectangle with right edge coinciding with +that of Controls, and OMITS left and top insets FindTrack() for !label returns a rectangle with x == GetLeftOffset(), and INCLUDES right and top insets From 9a01c46c6989bd22f1879f99fc13af509ba9aa93 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 20 Aug 2015 16:01:58 -0400 Subject: [PATCH 03/13] Fix that comment again... --- src/TrackPanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index b6c5acd79..81e0c78df 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -226,8 +226,8 @@ but that width may be adjusted when tracks change their vertical scales. GetLabelWidth() counts columns up to and including the VRuler. GetLeftOffset() is yet one more -- it counts the "one pixel" column. -FindTrack() for label returns a rectangle with right edge coinciding with -that of Controls, and OMITS left and top insets +FindTrack() for label returns a rectangle up to and including the One Pixel column, +but OMITS left and top insets FindTrack() for !label returns a rectangle with x == GetLeftOffset(), and INCLUDES right and top insets From 23facd70c67816020812e12fcb19e705adfaf475 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 20 Aug 2015 23:02:39 -0400 Subject: [PATCH 04/13] Bug1155: Fix off-by-one errors in painting of wave or label track backgrounds. --- src/TrackArtist.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index e8fb61653..bad6f11b1 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -3282,12 +3282,12 @@ void TrackArtist::DrawBackgroundWithSelection(wxDC *dc, const wxRect &rect, dc->SetBrush(unselBrush); dc->DrawRectangle(before); - within.x = before.GetRight(); + within.x = 1 + before.GetRight(); } within.width = rect.x + int(zoomInfo.TimeToPosition(sel1) + 2) - within.x; if (within.GetRight() > rect.GetRight()) { - within.width = rect.GetRight() - within.x; + within.width = 1 + rect.GetRight() - within.x; } if (within.width > 0) { @@ -3302,14 +3302,14 @@ void TrackArtist::DrawBackgroundWithSelection(wxDC *dc, const wxRect &rect, DrawSyncLockTiles(dc, within); } - after.x = within.GetRight(); + after.x = 1 + within.GetRight(); } else { // `within` not drawn; start where it would have gone after.x = within.x; } - after.width = rect.GetRight() - after.x; + after.width = 1 + rect.GetRight() - after.x; if (after.width > 0) { dc->SetBrush(unselBrush); dc->DrawRectangle(after); From 684bd0285c068cba6fcdb5917c80d9b1cbd90cec Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 20 Aug 2015 20:57:24 -0400 Subject: [PATCH 05/13] Replace some unexplained magic numbers with constants, add comments... ... This commit changes no behavior, fixes no bugs --- src/LabelTrack.cpp | 2 +- src/TrackPanel.cpp | 56 ++++++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index f1ed4aa1f..1b850d090 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -1387,7 +1387,7 @@ bool LabelTrack::HandleGlyphDragRelease(const wxMouseEvent & evt, //just reset its value and redraw. // LL: Constrain to inside track rectangle for now. Should be changed // to allow scrolling while dragging labels - int x = Constrain( evt.m_x + mxMouseDisplacement - r.x, 0, r.width - 2); + int x = Constrain( evt.m_x + mxMouseDisplacement - r.x, 0, r.width); // If exactly one edge is selected we allow swapping bool bAllowSwapping = (mMouseOverLabelLeft >=0 ) ^ ( mMouseOverLabelRight >= 0); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 81e0c78df..405f10983 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -261,7 +261,15 @@ right and top insets */ enum { kLeftInset = 4, + kRightInset = kLeftInset, kTopInset = 4, + kShadowThickness = 1, + kBorderThickness = 1, + kTopMargin = kTopInset + kBorderThickness, + kBottomMargin = kShadowThickness + kBorderThickness, + kLeftMargin = kLeftInset + kBorderThickness, + kRightMargin = kRightInset + kShadowThickness + kBorderThickness, + kTimerInterval = 50, // milliseconds kOneSecondCountdown = 1000 / kTimerInterval, }; @@ -589,7 +597,7 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, BuildMenus(); mTrackArtist = new TrackArtist(); - mTrackArtist->SetInset(1, kTopInset + 1, kLeftInset + 2, 2); + mTrackArtist->SetInset(1, kTopMargin, kRightMargin, kBottomMargin); mCapturedTrack = NULL; mPopupMenuTarget = NULL; @@ -1067,8 +1075,7 @@ void TrackPanel::GetTracksUsableArea(int *width, int *height) const { GetSize(width, height); *width -= GetLabelWidth(); - // AS: MAGIC NUMBER: What does 2 represent? - *width -= 2 + kLeftInset; + *width -= kRightMargin; *width = std::max(0, *width); } @@ -1241,9 +1248,10 @@ void TrackPanel::DrawQuickPlayIndicator(wxDC & dc, double pos) // Draw the new indicator in its new location AColor::Line(dc, pos, - y + kTopInset + 1, + y + kTopMargin, pos, - y + t->GetHeight() - 3 ); + // Minus one more because AColor::Line includes both endpoints + y + t->GetHeight() - kBottomMargin - 1 ); } mOldQPIndicatorPos = pos; } @@ -1354,8 +1362,7 @@ void TrackPanel::DoDrawIndicator(wxDC & dc) // Ensure that we don't draw through the TrackInfo or vertical ruler. wxRect clip = GetRect(); int leftCutoff = clip.x + GetLabelWidth(); - int rightInset = kLeftInset + 2; // See the call to SetInset - int rightCutoff = clip.x + clip.width - rightInset; + int rightCutoff = clip.x + clip.width - kRightMargin; if (!between_inclusive(leftCutoff, mLastIndicatorX, rightCutoff)) { return; @@ -1377,9 +1384,10 @@ void TrackPanel::DoDrawIndicator(wxDC & dc) // Draw the new indicator in its new location AColor::Line(dc, mLastIndicatorX, - y + kTopInset + 1, + y + kTopMargin, mLastIndicatorX, - y + t->GetHeight() - 3 ); + // Minus one more because AColor::Line includes both endpoints + y + t->GetHeight() - kBottomMargin - 1); } } @@ -1449,9 +1457,10 @@ void TrackPanel::DoDrawCursor(wxDC & dc) { if( t->GetSelected() || mAx->IsFocused( t ) ) { - int y = t->GetY() - mViewInfo->vpos + 1; - wxCoord top = y + kTopInset; - wxCoord bottom = y + t->GetHeight() - kTopInset; + int y = t->GetY() - mViewInfo->vpos; + wxCoord top = y + kTopMargin; + // Minus one more because AColor::Line includes both endpoints + wxCoord bottom = y + t->GetHeight() - kBottomMargin - 1; // MB: warp() is not needed here as far as I know, in fact it creates a bug. Removing it fixes that. AColor::Line(dc, mLastCursorX, top, mLastCursorX, bottom); // <-- The whole point of this routine. @@ -6750,8 +6759,7 @@ bool TrackPanel::HandleLabelTrackClick(LabelTrack * lTrack, wxRect &rect, wxMous } mCapturedRect = rect; - mCapturedRect.x += kLeftInset; - mCapturedRect.width -= kLeftInset; + mCapturedRect.width -= kRightMargin; lTrack->HandleClick(event, mCapturedRect, *mViewInfo, &mViewInfo->selectedRegion); @@ -7231,10 +7239,12 @@ void TrackPanel::RefreshTrack(Track *trk, bool refreshbacking) link = trk->GetLink(); } + // subtract insets and shadows from the rectangle, but not border + // This matters because some separators do paint over the border wxRect rect(kLeftInset, -mViewInfo->vpos + trk->GetY() + kTopInset, - GetRect().GetWidth() - kLeftInset * 2 - 1, - trk->GetHeight() - kTopInset - 1); + GetRect().GetWidth() - kLeftInset - kRightInset - kShadowThickness, + trk->GetHeight() - kTopInset - kShadowThickness); if (link) { rect.height += link->GetHeight(); @@ -7805,9 +7815,11 @@ void TrackPanel::DrawOutsideOfTrack(Track * t, wxDC * dc, const wxRect & rect) } #else if (t->GetLinked()) { + // Paint the channel separator over (what would be) the shadow of the top + // channel, and the top inset of the bottom channel side = rect; - side.y += t->GetHeight() - 1; - side.height = kTopInset + 1; + side.y += t->GetHeight() - kShadowThickness; + side.height = kTopInset + kShadowThickness; dc->DrawRectangle(side); } #endif @@ -9094,8 +9106,11 @@ void TrackPanel::DrawBordersAroundTrack(Track * t, wxDC * dc, } #else if (t->GetLinked()) { + // The given rect has had the top inset subtracted int h1 = rect.y + t->GetHeight() - kTopInset; - AColor::Line(*dc, vrul, h1 - 2, rect.x + rect.width - 1, h1 - 2); + // h1 is the top coordinate of the second tracks' rectangle + // Draw (part of) the bottom border of the top channel and top border of the bottom + AColor::Line(*dc, vrul, h1 - kBottomMargin, rect.x + rect.width - 1, h1 - kBottomMargin); AColor::Line(*dc, vrul, h1 + kTopInset, rect.x + rect.width - 1, h1 + kTopInset); } #endif @@ -9966,6 +9981,9 @@ void TrackPanel::OnSetFont(wxCommandEvent & WXUNUSED(event)) Track *TrackPanel::FindTrack(int mouseX, int mouseY, bool label, bool link, wxRect * trackRect) { + // If label is true, resulting rectangle OMITS left and top insets. + // If label is false, resulting rectangle INCLUDES right and top insets. + wxRect rect; rect.x = 0; rect.y = -mViewInfo->vpos; From 49ff3ae78f305612a0988e4d0e17e67b6c528135 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 06:23:33 -0400 Subject: [PATCH 06/13] Be sure OK button of preferences dialog is default --- src/prefs/PrefsDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prefs/PrefsDialog.cpp b/src/prefs/PrefsDialog.cpp index 2ef329b1f..6dc15f307 100644 --- a/src/prefs/PrefsDialog.cpp +++ b/src/prefs/PrefsDialog.cpp @@ -267,6 +267,7 @@ PrefsDialog::PrefsDialog S.EndVerticalLay(); S.AddStandardButtons(eOkButton | eCancelButton | eApplyButton); + static_cast(wxWindow::FindWindowById(wxID_OK, this))->SetDefault(); if (mUniquePage && !mUniquePage->ShowsApplyButton()) { wxWindow *const applyButton = From bc5aed746541d64e968141244c6a69dac6c43424 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 11:04:30 -0400 Subject: [PATCH 07/13] Bug1156, fix inconsistencies in mapping pixel heights to track vertical scales --- src/NumberScale.h | 8 ++++++-- src/TrackArtist.cpp | 21 ++++++++++++--------- src/TrackPanel.cpp | 44 ++++++++++++++++++++------------------------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/NumberScale.h b/src/NumberScale.h index b68a557f5..653977354 100644 --- a/src/NumberScale.h +++ b/src/NumberScale.h @@ -241,10 +241,14 @@ public: case nstErb: case nstUndertone: return Iterator - (mType, (mValue1 - mValue0) / nPositions, mValue0, mUnit); + (mType, + nPositions == 1 ? 0 : (mValue1 - mValue0) / (nPositions - 1), + mValue0, mUnit); case nstLogarithmic: return Iterator - (mType, exp((mValue1 - mValue0) / nPositions), exp(mValue0), mUnit); + (mType, + nPositions == 1 ? 1 : exp((mValue1 - mValue0) / (nPositions - 1)), + exp(mValue0), mUnit); } } diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index bad6f11b1..361513171 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -571,8 +571,8 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & rect) bev.height--; dc->DrawRectangle(bev); - rect.y += 2; - rect.height -= 2; + rect.y += 1; + rect.height -= 1; //int bottom = GetBottom((NoteTrack *) t, rect); NoteTrack *track = (NoteTrack *) t; @@ -671,7 +671,7 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect) min = tt->GetRangeLower() * 100.0; max = tt->GetRangeUpper() * 100.0; - vruler->SetBounds(rect.x, rect.y+1, rect.x + rect.width, rect.y + rect.height-1); + vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height-1); vruler->SetOrientation(wxVERTICAL); vruler->SetRange(max, min); vruler->SetFormat((tt->GetDisplayLog()) ? Ruler::RealLogFormat : Ruler::RealFormat); @@ -720,7 +720,7 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect) wt->SetDisplayBounds(min, max); } - vruler->SetBounds(rect.x, rect.y + 1, rect.x + rect.width, rect.y + rect.height - 1); + vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1); vruler->SetOrientation(wxVERTICAL); vruler->SetRange(max, min); vruler->SetFormat(Ruler::RealFormat); @@ -782,7 +782,7 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect) botval = -((1 - min) * dBRange); } - vruler->SetBounds(rect.x, rect.y + top + 1, rect.x + rect.width, rect.y + bot - 1); + vruler->SetBounds(rect.x, rect.y + top, rect.x + rect.width, rect.y + bot - 1); vruler->SetOrientation(wxVERTICAL); vruler->SetRange(topval, botval); } @@ -815,7 +815,7 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect) we will use Hz if maxFreq is < 2000, otherwise we represent kHz, and append to the numbers a "k" */ - vruler->SetBounds(rect.x, rect.y + 1, rect.x + rect.width, rect.y + rect.height - 1); + vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1); vruler->SetOrientation(wxVERTICAL); vruler->SetFormat(Ruler::RealFormat); vruler->SetLabelEdges(true); @@ -853,7 +853,7 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect) we will use Hz if maxFreq is < 2000, otherwise we represent kHz, and append to the numbers a "k" */ - vruler->SetBounds(rect.x, rect.y + 1, rect.x + rect.width, rect.y + rect.height - 1); + vruler->SetBounds(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height - 1); vruler->SetOrientation(wxVERTICAL); vruler->SetFormat(Ruler::IntFormat); vruler->SetLabelEdges(true); @@ -873,7 +873,7 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect) // The note track isn't drawing a ruler at all! // But it needs to! else if (t->GetKind() == Track::Note) { - vruler->SetBounds(rect.x, rect.y+1, rect.x + 1, rect.y + rect.height-1); + vruler->SetBounds(rect.x, rect.y, rect.x + 1, rect.y + rect.height-1); vruler->SetOrientation(wxVERTICAL); } #endif // USE_MIDI @@ -946,7 +946,10 @@ float ValueOfPixel(int yy, int height, bool offset, bool dB, double dBRange, float zoomMin, float zoomMax) { wxASSERT(height > 0); - float v = zoomMax - (yy / (float)height) * (zoomMax - zoomMin); + // Map 0 to max and height - 1 (not height) to min + float v = + height == 1 ? (zoomMin + zoomMax) / 2 : + zoomMax - (yy / (float)(height - 1)) * (zoomMax - zoomMin); if (offset) { if (v > 0.0) v += .5; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 405f10983..ae958580f 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -2540,6 +2540,8 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event, { Track *rightTrack = NULL; mCapturedTrack = pTrack; + rect.y += kTopMargin; + rect.height -= kTopMargin + kBottomMargin; mCapturedRect = rect; mMouseCapture=IsSelecting; @@ -3414,9 +3416,11 @@ void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack) wxRect rect = mCapturedRect; Track *pTrack = mCapturedTrack; - // AS: Note that FindTrack will replace rect's value. - if (!pTrack) + if (!pTrack) { pTrack = FindTrack(event.m_x, event.m_y, false, false, &rect); + rect.y += kTopMargin; + rect.height -= kTopMargin + kBottomMargin; + } // Also fuhggeddaboudit if not in a track. if (!pTrack) @@ -3705,8 +3709,8 @@ void TrackPanel::HandleEnvelope(wxMouseEvent & event) } mCapturedRect = rect; - mCapturedRect.y += kTopInset; - mCapturedRect.height -= kTopInset; + mCapturedRect.y += kTopMargin; + mCapturedRect.height -= kTopMargin + kBottomMargin; } // AS: if there's actually a selected track, then forward all of the // mouse events to its envelope. @@ -3732,8 +3736,6 @@ void TrackPanel::ForwardEventToTimeTrackEnvelope(wxMouseEvent & event) Envelope *pspeedenvelope = ptimetrack->GetEnvelope(); wxRect envRect = mCapturedRect; - envRect.y++; - envRect.height -= 2; double lower = ptimetrack->GetRangeLower(), upper = ptimetrack->GetRangeUpper(); const double dBRange = mViewInfo->dBr; if (ptimetrack->GetDisplayLog()) { @@ -3775,8 +3777,6 @@ void TrackPanel::ForwardEventToWaveTrackEnvelope(wxMouseEvent & event) // AS: Then forward our mouse event to the envelope. // It'll recalculate and then tell us whether or not to redraw. wxRect envRect = mCapturedRect; - envRect.y++; - envRect.height -= 2; float zoomMin, zoomMax; pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax); needUpdate = penvelope->MouseEvent( @@ -3794,8 +3794,6 @@ void TrackPanel::ForwardEventToWaveTrackEnvelope(wxMouseEvent & event) bool updateNeeded = false; if (e2) { wxRect envRect = mCapturedRect; - envRect.y++; - envRect.height -= 2; float zoomMin, zoomMax; pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax); updateNeeded = e2->MouseEvent(event, envRect, @@ -3808,8 +3806,6 @@ void TrackPanel::ForwardEventToWaveTrackEnvelope(wxMouseEvent & event) if( (e2 = link->GetActiveEnvelope()) != 0 ) // search for any active DragPoint { wxRect envRect = mCapturedRect; - envRect.y++; - envRect.height -= 2; float zoomMin, zoomMax; pwavetrack->GetDisplayBounds(&zoomMin, &zoomMax); needUpdate |= e2->MouseEvent(event, envRect, @@ -4663,8 +4659,8 @@ void TrackPanel::HandleWaveTrackVZoom bool fixedMousePoint) { WaveTrack *const partner = static_cast(tracks->GetLink(track)); - int height = track->GetHeight(); - int ypos = rect.y; + int height = track->GetHeight() - (kTopMargin + kBottomMargin); + int ypos = rect.y + kBorderThickness; // Ensure start and end are in order (swap if not). if (zoomEnd < zoomStart) @@ -4955,7 +4951,7 @@ float TrackPanel::FindSampleEditingLevel(wxMouseEvent &event, double dBRange, do mDrawingTrack->GetDisplayBounds(&zoomMin, &zoomMax); const int y = event.m_y - mDrawingTrackTop; - const int height = mDrawingTrack->GetHeight(); + const int height = mDrawingTrack->GetHeight() - (kTopMargin + kBottomMargin); const bool dB = !mDrawingTrack->GetWaveformSettings().isLinear(); float newLevel = ::ValueOfPixel(y, height, false, dB, dBRange, zoomMin, zoomMax); @@ -4996,7 +4992,7 @@ void TrackPanel::HandleSampleEditingClick( wxMouseEvent & event ) /// \todo Should mCapturedTrack take the place of mDrawingTrack?? mDrawingTrack = static_cast(t); - mDrawingTrackTop=rect.y; + mDrawingTrackTop=rect.y + kTopMargin; //If we are still around, we are drawing in earnest. Set some member data structures up: //First, calculate the starting sample. To get this, we need the time @@ -7395,9 +7391,9 @@ void TrackPanel::DrawEverythingElse(wxDC * dc, if (region.Contains(0, trackRect.y, GetLeftOffset(), trackRect.height)) { wxRect rect = trackRect; rect.x += GetVRulerOffset(); - rect.y += kTopInset; + rect.y += kTopMargin; rect.width = GetVRulerWidth(); - rect.height -= (kTopInset + 2); + rect.height -= (kTopMargin + kBottomMargin); mTrackArtist->DrawVRuler(t, dc, rect); } @@ -7408,9 +7404,9 @@ void TrackPanel::DrawEverythingElse(wxDC * dc, if (region.Contains(0, trackRect.y, GetLeftOffset(), trackRect.height)) { wxRect rect = trackRect; rect.x += GetVRulerOffset(); - rect.y += kTopInset; + rect.y += kTopMargin; rect.width = GetVRulerWidth(); - rect.height -= (kTopInset + 2); + rect.height -= (kTopMargin + kBottomMargin); mTrackArtist->DrawVRuler(t, dc, rect); } } @@ -7953,20 +7949,20 @@ void TrackPanel::UpdateTrackVRuler(Track *t) return; wxRect rect(GetVRulerOffset(), - kTopInset, + kTopMargin, GetVRulerWidth(), - t->GetHeight() - (kTopInset + 2)); + t->GetHeight() - (kTopMargin + kBottomMargin)); mTrackArtist->UpdateVRuler(t, rect); Track *l = t->GetLink(); if (l) { - rect.height = l->GetHeight() - (kTopInset + 2); + rect.height = l->GetHeight() - (kTopMargin + kBottomMargin); mTrackArtist->UpdateVRuler(l, rect); } #ifdef EXPERIMENTAL_OUTPUT_DISPLAY else if(MONO_WAVE_PAN(t)){ - rect.height = t->GetHeight(true) - (kTopInset + 2); + rect.height = t->GetHeight(true) - (kTopMargin + kBottomMargin); mTrackArtist->UpdateVRuler(t, rect); } #endif From 68cbd4fbfec011a30874e92328d2a7cf911be1bf Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 11:32:27 -0400 Subject: [PATCH 08/13] Fix bevels on vertical rulers --- src/TrackArtist.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index 361513171..a62a67645 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -503,7 +503,7 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & rect) // But give it a beveled area if (kind == Track::Label) { wxRect bev = rect; - bev.Inflate(-1, -1); + bev.Inflate(-1, 0); bev.width += 1; AColor::BevelTrackInfo(*dc, true, bev); @@ -513,7 +513,7 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & rect) // Time tracks if (kind == Track::Time) { wxRect bev = rect; - bev.Inflate(-1, -1); + bev.Inflate(-1, 0); bev.width += 1; AColor::BevelTrackInfo(*dc, true, bev); @@ -537,7 +537,7 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & rect) // The ruler needs a bevelled surround. if (kind == Track::Wave) { wxRect bev = rect; - bev.Inflate(-1, -1); + bev.Inflate(-1, 0); bev.width += 1; AColor::BevelTrackInfo(*dc, true, bev); @@ -566,9 +566,7 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & rect) dc->SetBrush(*wxWHITE_BRUSH); wxRect bev = rect; bev.x++; - bev.y++; bev.width--; - bev.height--; dc->DrawRectangle(bev); rect.y += 1; From 4b028995cb952da77cd69c0fd5fb70f5c26b0e8b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 11:32:53 -0400 Subject: [PATCH 09/13] Fix off-by-ones in drawing of zoom rectangles... ... If one dashed boundary goes through the click point, the other should go through the drag point, not one next to it. This applies to zoom in the vertical ruler, and to horizontal zoom with the magnifier. --- src/TrackPanel.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index ae958580f..b475c6ef3 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -4441,18 +4441,16 @@ void TrackPanel::HandleZoomClick(wxMouseEvent & event) /// Zoom drag void TrackPanel::HandleZoomDrag(wxMouseEvent & event) { - int left, width, height; - - left = GetLeftOffset(); - GetTracksUsableArea(&width, &height); + const int left = GetLeftOffset(); + const int right = GetSize().x - kRightMargin - 1; mZoomEnd = event.m_x; if (event.m_x < left) { mZoomEnd = left; } - else if (event.m_x >= left + width - 1) { - mZoomEnd = left + width - 1; + else if (event.m_x > right) { + mZoomEnd = right; } if (IsDragZooming()) { @@ -7633,17 +7631,18 @@ void TrackPanel::DrawZooming(wxDC * dc, const wxRect & clip) if (mMouseCapture==IsVZooming) { int width, height; - GetTracksUsableArea(&width, &height); - rect.y = mZoomStart; + rect.y = std::min(mZoomStart, mZoomEnd); + rect.height = 1 + abs(mZoomEnd - mZoomStart); + rect.x = GetVRulerOffset(); - rect.width = width + GetVRulerWidth() + 1; //+1 extends into border rect - rect.height = mZoomEnd - mZoomStart; + rect.SetRight(GetSize().x - kRightMargin); // extends into border rect } else { - rect.x = mZoomStart; + rect.x = std::min(mZoomStart, mZoomEnd); + rect.width = 1 + abs(mZoomEnd - mZoomStart); + rect.y = -1; - rect.width = mZoomEnd - mZoomStart; rect.height = clip.height + 2; } From e7c7bb84a966c3b3cc4b3a9717d5f247f25e7296 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 11:49:49 -0400 Subject: [PATCH 10/13] Fix off-by-one width in TrackPanel::GetTracksUsableArea() --- src/TrackPanel.cpp | 2 +- src/TrackPanel.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index b475c6ef3..be1716227 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1074,7 +1074,7 @@ void TrackPanel::SelectTrackLength(Track *t) void TrackPanel::GetTracksUsableArea(int *width, int *height) const { GetSize(width, height); - *width -= GetLabelWidth(); + *width -= GetLeftOffset(); *width -= kRightMargin; *width = std::max(0, *width); } diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 5e782a1ff..d30165cdc 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -165,6 +165,7 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel { virtual int GetLeftOffset() const { return GetLabelWidth() + 1;} + // Width and height, relative to upper left corner at (GetLeftOffset(), 0) virtual void GetTracksUsableArea(int *width, int *height) const; virtual void SelectNone(); From a9ab31dedbc7cb10ed368ef3f56b50c7e8237185 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 12:02:48 -0400 Subject: [PATCH 11/13] Allow NULL arguments in TrackPanel::GetTracksUsableArea() --- src/Menus.cpp | 8 ++++---- src/TrackPanel.cpp | 16 +++++++++------- src/TrackPanel.h | 1 + src/widgets/Ruler.cpp | 4 ++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 48a00426a..4a768e86e 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4952,8 +4952,8 @@ void AudacityProject::OnZoomFit() if (len <= 0.0) return; - int w, h; - mTrackPanel->GetTracksUsableArea(&w, &h); + int w; + mTrackPanel->GetTracksUsableArea(&w, NULL); w -= 10; Zoom(w / len); @@ -4962,9 +4962,9 @@ void AudacityProject::OnZoomFit() void AudacityProject::DoZoomFitV() { - int width, height, count; + int height, count; - mTrackPanel->GetTracksUsableArea(&width, &height); + mTrackPanel->GetTracksUsableArea(NULL, &height); height -= 28; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index be1716227..a1472eb76 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1074,9 +1074,11 @@ void TrackPanel::SelectTrackLength(Track *t) void TrackPanel::GetTracksUsableArea(int *width, int *height) const { GetSize(width, height); - *width -= GetLeftOffset(); - *width -= kRightMargin; - *width = std::max(0, *width); + if (width) { + *width -= GetLeftOffset(); + *width -= kRightMargin; + *width = std::max(0, *width); + } } /// Gets the pointer to the AudacityProject that @@ -4150,8 +4152,8 @@ void TrackPanel::DoSlide(wxMouseEvent & event) if (mouseTrack == NULL) { // Allow sliding if the pointer is not over any track, but only if x is // within the bounds of the tracks area. - int width, height; - GetTracksUsableArea(&width, &height); + int width; + GetTracksUsableArea(&width, NULL); if (event.m_x >= GetLeftOffset() && event.m_x < GetLeftOffset() + width) mouseTrack = mCapturedTrack; else @@ -8254,8 +8256,8 @@ void TrackPanel::ScrollIntoView(double pos) { const int screenWidth = rint(mViewInfo->GetScreenWidth()); - int w, h; - GetTracksUsableArea( &w, &h ); + int w; + GetTracksUsableArea( &w, NULL ); // Or should we just set w = screenWidth ? int pixel = mViewInfo->TimeToPosition(pos); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index d30165cdc..c823c39d6 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -166,6 +166,7 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel { virtual int GetLeftOffset() const { return GetLabelWidth() + 1;} // Width and height, relative to upper left corner at (GetLeftOffset(), 0) + // Either argument may be NULL virtual void GetTracksUsableArea(int *width, int *height) const; virtual void SelectNone(); diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp index 9e19fd1b2..533c65a0b 100644 --- a/src/widgets/Ruler.cpp +++ b/src/widgets/Ruler.cpp @@ -1936,8 +1936,8 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt) // Keep Quick-Play within usable track area. TrackPanel *tp = mProject->GetTrackPanel(); - int mousePosX, width, height; - tp->GetTracksUsableArea(&width, &height); + int mousePosX, width; + tp->GetTracksUsableArea(&width, NULL); mousePosX = std::max(evt.GetX(), tp->GetLeftOffset()); mousePosX = std::min(mousePosX, tp->GetLeftOffset() + width - 1); From 1b8f44d0537d987c59653b11ed75a842b48896ea Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 13:22:44 -0400 Subject: [PATCH 12/13] ViewInfo does not redundantly (or inconsistently!) store the screen width --- src/Menus.cpp | 44 ++++++++++++++------- src/Printing.cpp | 2 +- src/Project.cpp | 36 ++++++++++------- src/Project.h | 1 + src/TrackArtist.cpp | 2 +- src/TrackPanel.cpp | 61 ++++++++++++++++------------- src/TrackPanel.h | 4 ++ src/ViewInfo.cpp | 17 ++++---- src/ViewInfo.h | 24 +++--------- src/effects/Equalization.cpp | 4 +- src/widgets/AttachableScrollBar.cpp | 8 +++- 11 files changed, 114 insertions(+), 89 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 4a768e86e..763ff9404 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -4824,6 +4824,11 @@ void AudacityProject::OnZoomIn() ZoomInByFactor( 2.0 ); } +double AudacityProject::GetScreenEndTime() const +{ + return mTrackPanel->GetScreenEndTime(); +} + void AudacityProject::ZoomInByFactor( double ZoomFactor ) { // LLL: Handling positioning differently when audio is active @@ -4838,13 +4843,16 @@ void AudacityProject::ZoomInByFactor( double ZoomFactor ) // when there's a selection that's currently at least // partially on-screen + const double endTime = GetScreenEndTime(); + const double duration = endTime - mViewInfo.h; + bool selectionIsOnscreen = - (mViewInfo.selectedRegion.t0() < mViewInfo.h + mViewInfo.screen) && + (mViewInfo.selectedRegion.t0() < endTime) && (mViewInfo.selectedRegion.t1() >= mViewInfo.h); bool selectionFillsScreen = (mViewInfo.selectedRegion.t0() < mViewInfo.h) && - (mViewInfo.selectedRegion.t1() > mViewInfo.h + mViewInfo.screen); + (mViewInfo.selectedRegion.t1() > endTime); if (selectionIsOnscreen && !selectionFillsScreen) { // Start with the center of the selection @@ -4856,24 +4864,26 @@ void AudacityProject::ZoomInByFactor( double ZoomFactor ) if (selCenter < mViewInfo.h) selCenter = mViewInfo.h + (mViewInfo.selectedRegion.t1() - mViewInfo.h) / 2; - if (selCenter > mViewInfo.h + mViewInfo.screen) - selCenter = mViewInfo.h + mViewInfo.screen - - (mViewInfo.h + mViewInfo.screen - mViewInfo.selectedRegion.t0()) / 2; + if (selCenter > endTime) + selCenter = endTime - + (endTime - mViewInfo.selectedRegion.t0()) / 2; // Zoom in ZoomBy(ZoomFactor); + const double newDuration = GetScreenEndTime() - mViewInfo.h; // Recenter on selCenter - TP_ScrollWindow(selCenter - mViewInfo.screen / 2); + TP_ScrollWindow(selCenter - newDuration / 2); return; } double origLeft = mViewInfo.h; - double origWidth = mViewInfo.screen; + double origWidth = duration; ZoomBy(ZoomFactor); - double newh = origLeft + (origWidth - mViewInfo.screen) / 2; + const double newDuration = GetScreenEndTime() - mViewInfo.h; + double newh = origLeft + (origWidth - newDuration) / 2; // MM: Commented this out because it was confusing users /* @@ -4900,12 +4910,13 @@ void AudacityProject::OnZoomOut() void AudacityProject::ZoomOutByFactor( double ZoomFactor ) { //Zoom() may change these, so record original values: - double origLeft = mViewInfo.h; - double origWidth = mViewInfo.screen; + const double origLeft = mViewInfo.h; + const double origWidth = GetScreenEndTime() - origLeft; ZoomBy(ZoomFactor); + const double newWidth = GetScreenEndTime() - mViewInfo.h; - double newh = origLeft + (origWidth - mViewInfo.screen) / 2; + const double newh = origLeft + (origWidth - newWidth) / 2; // newh = (newh > 0) ? newh : 0; TP_ScrollWindow(newh); @@ -5023,16 +5034,19 @@ void AudacityProject::OnZoomSel() // where the selected region may be scrolled off the left of the screen. // I know this isn't right, but until the real rounding or 1-off issue is // found, this will have to work. - Zoom((mViewInfo.GetScreenWidth() - 1) / denom); + // PRL: Did I fix this? I am not sure, so I leave the hack in place. + int width; + mTrackPanel->GetTracksUsableArea(&width, NULL); + Zoom((width - 1) / denom); TP_ScrollWindow(mViewInfo.selectedRegion.t0()); -} +} void AudacityProject::OnGoSelStart() { if (mViewInfo.selectedRegion.isPoint()) return; - TP_ScrollWindow(mViewInfo.selectedRegion.t0() - (mViewInfo.screen / 2)); + TP_ScrollWindow(mViewInfo.selectedRegion.t0() - ((GetScreenEndTime() - mViewInfo.h) / 2)); } void AudacityProject::OnGoSelEnd() @@ -5040,7 +5054,7 @@ void AudacityProject::OnGoSelEnd() if (mViewInfo.selectedRegion.isPoint()) return; - TP_ScrollWindow(mViewInfo.selectedRegion.t1() - (mViewInfo.screen / 2)); + TP_ScrollWindow(mViewInfo.selectedRegion.t1() - ((GetScreenEndTime() - mViewInfo.h) / 2)); } void AudacityProject::OnShowClipping() diff --git a/src/Printing.cpp b/src/Printing.cpp index 18362f1e9..a8db2aa1d 100644 --- a/src/Printing.cpp +++ b/src/Printing.cpp @@ -80,7 +80,7 @@ bool AudacityPrintout::OnPrintPage(int WXUNUSED(page)) artist.SetBackgroundBrushes(*wxWHITE_BRUSH, *wxWHITE_BRUSH, *wxWHITE_PEN, *wxWHITE_PEN); const double screenDuration = mTracks->GetEndTime(); - ZoomInfo zoomInfo(0.0, screenDuration, width / screenDuration); + ZoomInfo zoomInfo(0.0, width / screenDuration); int y = rulerPageHeight; TrackListIterator iter(mTracks); diff --git a/src/Project.cpp b/src/Project.cpp index 42c3c576b..146b498d4 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1472,9 +1472,10 @@ void AudacityProject::OnScrollRightButton(wxScrollEvent & event) double AudacityProject::ScrollingLowerBoundTime() const { - return mScrollBeyondZero - ? std::min(mTracks->GetStartTime(), -mViewInfo.screen / 2.0) - : 0; + if (!mScrollBeyondZero) + return 0; + const double screen = mTrackPanel->GetScreenEndTime() - mViewInfo.h; + return std::min(mTracks->GetStartTime(), -screen / 2.0); } wxInt64 AudacityProject::PixelWidthBeforeTime(double scrollto) const @@ -1556,8 +1557,8 @@ void AudacityProject::FixScrollbars() double LastTime = std::max(mTracks->GetEndTime(), mViewInfo.selectedRegion.t1()); - mViewInfo.SetScreenWidth(panelWidth); - const double halfScreen = mViewInfo.screen / 2.0; + const double screen = GetScreenEndTime() - mViewInfo.h; + const double halfScreen = screen / 2.0; // If we can scroll beyond zero, // Add 1/2 of a screen of blank space to the end @@ -1567,13 +1568,13 @@ void AudacityProject::FixScrollbars() // May add even more to the end, so that you can always scroll the starting time to zero. const double lowerBound = ScrollingLowerBoundTime(); const double additional = mScrollBeyondZero - ? -lowerBound + std::max(halfScreen, mViewInfo.screen - LastTime) - : mViewInfo.screen / 4.0; + ? -lowerBound + std::max(halfScreen, screen - LastTime) + : screen / 4.0; mViewInfo.total = LastTime + additional; // Don't remove time from total that's still on the screen - mViewInfo.total = std::max(mViewInfo.total, mViewInfo.h + mViewInfo.screen); + mViewInfo.total = std::max(mViewInfo.total, mViewInfo.h + screen); if (mViewInfo.h < lowerBound) { mViewInfo.h = lowerBound; @@ -1581,7 +1582,7 @@ void AudacityProject::FixScrollbars() } mViewInfo.sbarTotal = (wxInt64) (mViewInfo.GetTotalWidth()); - mViewInfo.sbarScreen = (wxInt64) (mViewInfo.GetScreenWidth()); + mViewInfo.sbarScreen = (wxInt64)(panelWidth); mViewInfo.sbarH = (wxInt64) (mViewInfo.GetBeforeScreenWidth()); int lastv = mViewInfo.vpos; @@ -1603,7 +1604,7 @@ void AudacityProject::FixScrollbars() bool oldhstate; bool oldvstate; - bool newhstate = !mViewInfo.ZoomedAll(); + bool newhstate = (GetScreenEndTime() - mViewInfo.h) < mViewInfo.total; bool newvstate = panelHeight < totalHeight; #ifdef __WXGTK__ @@ -1614,7 +1615,7 @@ void AudacityProject::FixScrollbars() #else oldhstate = mHsbar->IsEnabled(); oldvstate = mVsbar->IsEnabled(); - mHsbar->Enable(!mViewInfo.ZoomedAll()); + mHsbar->Enable(newhstate); mVsbar->Enable(panelHeight < totalHeight); #endif @@ -1624,7 +1625,7 @@ void AudacityProject::FixScrollbars() refresh = true; rescroll = false; } - if (mViewInfo.ZoomedAll() && mViewInfo.sbarH != 0) { + if (!newhstate && mViewInfo.sbarH != 0) { mViewInfo.sbarH = 0; refresh = true; @@ -1666,7 +1667,8 @@ void AudacityProject::FixScrollbars() panelHeight / mViewInfo.scrollStep, TRUE); mVsbar->Refresh(); - if (refresh || (rescroll && !mViewInfo.ZoomedAll())) { + if (refresh || (rescroll && + (GetScreenEndTime() - mViewInfo.h) < mViewInfo.total)) { mTrackPanel->Refresh(false); } @@ -1849,8 +1851,12 @@ void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event)) mViewInfo.sbarH = (wxInt64)(mHsbar->GetThumbPosition() / mViewInfo.sbarScale) - offset; - if (mViewInfo.sbarH != hlast) - mViewInfo.SetBeforeScreenWidth(mViewInfo.sbarH, lowerBound); + if (mViewInfo.sbarH != hlast) { + int width; + mTrackPanel->GetTracksUsableArea(&width, NULL); + mViewInfo.SetBeforeScreenWidth(mViewInfo.sbarH, width, lowerBound); + } + if (mScrollBeyondZero) { enum { SCROLL_PIXEL_TOLERANCE = 10 }; diff --git a/src/Project.h b/src/Project.h index d93d4fafa..451affea7 100644 --- a/src/Project.h +++ b/src/Project.h @@ -301,6 +301,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame, void HandleResize(); void UpdateLayout(); + double GetScreenEndTime() const; void ZoomInByFactor( double ZoomFactor ); void ZoomOutByFactor( double ZoomFactor ); diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index a62a67645..fe4817901 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -1663,7 +1663,7 @@ void FindWavePortions // the fisheye. ZoomInfo::Intervals intervals; - zoomInfo.FindIntervals(params.rate, intervals, rect.x); + zoomInfo.FindIntervals(params.rate, intervals, rect.width, rect.x); ZoomInfo::Intervals::const_iterator it = intervals.begin(), end = intervals.end(), prev; wxASSERT(it != end && it->position == rect.x); const int rightmost = rect.x + rect.width; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index a1472eb76..c69dfe2e5 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1259,6 +1259,13 @@ void TrackPanel::DrawQuickPlayIndicator(wxDC & dc, double pos) } } +double TrackPanel::GetScreenEndTime() const +{ + int width; + GetTracksUsableArea(&width, NULL); + return mViewInfo->PositionToTime(width, true); +} + void TrackPanel::TimerUpdateIndicator() { double pos = 0.0; @@ -1272,7 +1279,8 @@ void TrackPanel::TimerUpdateIndicator() #ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL if (mSmoothScrollingScrub) { // Pan the view, so that we center the play indicator. - mViewInfo->h = pos - mViewInfo->screen / 2.0; + const double duration = GetScreenEndTime() - mViewInfo->h; + mViewInfo->h = pos - duration / 2.0; if (!mScrollBeyondZero) // Can't scroll too far left mViewInfo->h = std::max(0.0, mViewInfo->h); @@ -1283,7 +1291,7 @@ void TrackPanel::TimerUpdateIndicator() const bool onScreen = between_inclusive(mViewInfo->h, pos, - mViewInfo->h + mViewInfo->screen); + GetScreenEndTime()); // This displays the audio time, too... DisplaySelection(); @@ -1326,10 +1334,12 @@ void TrackPanel::UndrawIndicator(wxDC & dc) // Erase the old indicator. if (mLastIndicatorX != -1) { + int width; + GetTracksUsableArea(&width, NULL); const bool onScreen = between_inclusive(GetLeftOffset(), mLastIndicatorX, - GetLeftOffset() + mViewInfo->GetScreenWidth()); + GetLeftOffset() + width); if (onScreen) { // LL: Keep from trying to blit outsize of the source DC. This results in a crash on @@ -1429,9 +1439,11 @@ void TrackPanel::UndrawCursor(wxDC & dc) if( mLastCursorX != -1 ) { + int width; + GetTracksUsableArea(&width, NULL); onScreen = between_inclusive(GetLeftOffset(), mLastCursorX, - GetLeftOffset() + mViewInfo->GetScreenWidth()); + GetLeftOffset() + width); if( onScreen ) dc.Blit(mLastCursorX, 0, 1, mBacking->GetHeight(), &mBackingDC, mLastCursorX, 0); } @@ -1446,7 +1458,7 @@ void TrackPanel::DoDrawCursor(wxDC & dc) const bool onScreen = between_inclusive( mViewInfo->h, mCursorTime, - mViewInfo->h + mViewInfo->screen ); + GetScreenEndTime() ); if( !onScreen ) return; @@ -1672,12 +1684,12 @@ void TrackPanel::HandleControlKey(bool down) void TrackPanel::HandlePageUpKey() { - mListener->TP_ScrollWindow(mViewInfo->h + mViewInfo->screen); + mListener->TP_ScrollWindow(GetScreenEndTime()); } void TrackPanel::HandlePageDownKey() { - mListener->TP_ScrollWindow(mViewInfo->h - mViewInfo->screen); + mListener->TP_ScrollWindow(2 * mViewInfo->h - GetScreenEndTime()); } void TrackPanel::HandleCursorForLastMouseEvent() @@ -2316,7 +2328,7 @@ double TrackPanel::FindScrubSpeed(double timeAtMouse) const // and the extremes to the maximum scrub speed. // Width of visible track area, in time terms: - const double screen = mViewInfo->screen; + const double screen = GetScreenEndTime() - mViewInfo->h; const double origin = mViewInfo->h + screen / 2.0; // There are various snapping zones that are this fraction of screen: @@ -2363,7 +2375,7 @@ double TrackPanel::FindSeekSpeed(double timeAtMouse) const const double extreme = std::max(1.0, mMaxScrubSpeed * ARBITRARY_MULTIPLIER); // Width of visible track area, in time terms: - const double screen = mViewInfo->screen; + const double screen = GetScreenEndTime() - mViewInfo->h; const double halfScreen = screen / 2.0; const double origin = mViewInfo->h + halfScreen; @@ -4463,11 +4475,8 @@ void TrackPanel::HandleZoomDrag(wxMouseEvent & event) /// Zoom button up void TrackPanel::HandleZoomButtonUp(wxMouseEvent & event) { - if (mZoomEnd < mZoomStart) { - int temp = mZoomEnd; - mZoomEnd = mZoomStart; - mZoomStart = temp; - } + if (mZoomEnd < mZoomStart) + std::swap(mZoomStart, mZoomEnd); if (IsDragZooming()) DragZoom(event, GetLeftOffset()); @@ -4501,8 +4510,7 @@ void TrackPanel::DragZoom(wxMouseEvent & event, int trackLeftEdge) { double left = mViewInfo->PositionToTime(mZoomStart, trackLeftEdge); double right = mViewInfo->PositionToTime(mZoomEnd, trackLeftEdge); - - double multiplier = mViewInfo->screen / (right - left); + double multiplier = (GetScreenEndTime() - mViewInfo->h) / (right - left); if (event.ShiftDown()) multiplier = 1.0 / multiplier; @@ -4883,14 +4891,14 @@ void TrackPanel::HandleWaveTrackVZoom namespace { // Is the sample horizontally nearest to the cursor sufficiently separated from // its neighbors that the pencil tool should be allowed to drag it? -bool SampleResolutionTest(const ViewInfo &viewInfo, const WaveTrack *wt, double time, double rate) +bool SampleResolutionTest(const ViewInfo &viewInfo, const WaveTrack *wt, double time, double rate, int width) { // Require more than 3 pixels per sample // Round to an exact sample time const double adjustedTime = wt->LongSamplesToTime(wt->TimeToLongSamples(time)); const wxInt64 xx = std::max(wxInt64(0), viewInfo.TimeToPosition(adjustedTime)); ZoomInfo::Intervals intervals; - viewInfo.FindIntervals(rate, intervals); + viewInfo.FindIntervals(rate, intervals, width); ZoomInfo::Intervals::const_iterator it = intervals.begin(), end = intervals.end(), prev; wxASSERT(it != end && it->position == 0); do @@ -4932,7 +4940,9 @@ bool TrackPanel::IsSampleEditingPossible( wxMouseEvent &event, Track * t ) WaveTrack *const wt = static_cast(t); const double rate = wt->GetRate(); const double time = mViewInfo->PositionToTime(event.m_x, rect.x); - showPoints = SampleResolutionTest(*mViewInfo, wt, time, rate); + int width; + GetTracksUsableArea(&width, NULL); + showPoints = SampleResolutionTest(*mViewInfo, wt, time, rate, width); } //If we aren't zoomed in far enough, show a message dialog. @@ -6290,7 +6300,7 @@ void TrackPanel::HandleWheelRotation(wxMouseEvent & event) #ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL if (mSmoothScrollingScrub) { // Expand or contract about the center, ignoring mouse position - center_h = mViewInfo->h + mViewInfo->screen / 2.0; + center_h = mViewInfo->h + (GetScreenEndTime() - mViewInfo->h) / 2.0; xx = mViewInfo->TimeToPosition(center_h, trackLeftEdge); } else @@ -7169,7 +7179,9 @@ bool TrackPanel::HitTestSamples(Track *track, wxRect &rect, wxMouseEvent & event const bool dB = !wavetrack->GetWaveformSettings().isLinear(); const double tt = mViewInfo->PositionToTime(event.m_x, rect.x); - if (!SampleResolutionTest(*mViewInfo, wavetrack, tt, rate)) + int width; + GetTracksUsableArea(&width, NULL); + if (!SampleResolutionTest(*mViewInfo, wavetrack, tt, rate, width)) return false; // Just get one sample. @@ -7632,8 +7644,6 @@ void TrackPanel::DrawZooming(wxDC * dc, const wxRect & clip) dc->SetPen(*wxBLACK_DASHED_PEN); if (mMouseCapture==IsVZooming) { - int width, height; - rect.y = std::min(mZoomStart, mZoomEnd); rect.height = 1 + abs(mZoomEnd - mZoomStart); @@ -8254,14 +8264,11 @@ void TrackPanel::OnToggle() // Make sure selection edge is in view void TrackPanel::ScrollIntoView(double pos) { - const int screenWidth = rint(mViewInfo->GetScreenWidth()); - int w; GetTracksUsableArea( &w, NULL ); - // Or should we just set w = screenWidth ? int pixel = mViewInfo->TimeToPosition(pos); - if (pixel < 0 || pixel >= screenWidth) + if (pixel < 0 || pixel >= w) { mListener->TP_ScrollWindow (mViewInfo->OffsetTimeByPixels(pos, -(w / 2))); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index c823c39d6..3edcc5f44 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -234,6 +234,10 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel { virtual void DrawQuickPlayIndicator(wxDC & dc, double pos); + // Returns the time corresponding to the pixel column one past the track area + // (ignoring any fisheye) + virtual double GetScreenEndTime() const; + protected: virtual MixerBoard* GetMixerBoard(); /** @brief Populates the track pop-down menu with the common set of diff --git a/src/ViewInfo.cpp b/src/ViewInfo.cpp index 7746b297b..c707d80af 100644 --- a/src/ViewInfo.cpp +++ b/src/ViewInfo.cpp @@ -22,10 +22,9 @@ static const double gMaxZoom = 6000000; static const double gMinZoom = 0.001; } -ZoomInfo::ZoomInfo(double start, double screenDuration, double pixelsPerSecond) +ZoomInfo::ZoomInfo(double start, double pixelsPerSecond) : vpos(0) , h(start) - , screen(screenDuration) , zoom(pixelsPerSecond) { UpdatePrefs(); @@ -84,12 +83,12 @@ void ZoomInfo::ZoomBy(double multiplier) } void ZoomInfo::FindIntervals - (double /*rate*/, Intervals &results, wxInt64 origin) const + (double /*rate*/, Intervals &results, wxInt64 width, wxInt64 origin) const { results.clear(); results.reserve(2); - const wxInt64 rightmost(origin + (0.5 + screen * zoom)); + const wxInt64 rightmost(origin + (0.5 + width)); wxASSERT(origin <= rightmost); { results.push_back(Interval(origin, zoom, false)); @@ -101,10 +100,10 @@ void ZoomInfo::FindIntervals } ViewInfo::ViewInfo(double start, double screenDuration, double pixelsPerSecond) - : ZoomInfo(start, screenDuration, pixelsPerSecond) + : ZoomInfo(start, pixelsPerSecond) , selectedRegion() , track(NULL) - , total(screen) + , total(screenDuration) , sbarH(0) , sbarScreen(1) , sbarTotal(1) @@ -114,12 +113,12 @@ ViewInfo::ViewInfo(double start, double screenDuration, double pixelsPerSecond) { } -void ViewInfo::SetBeforeScreenWidth(wxInt64 width, double lowerBoundTime) +void ViewInfo::SetBeforeScreenWidth(wxInt64 beforeWidth, wxInt64 screenWidth, double lowerBoundTime) { h = std::max(lowerBoundTime, - std::min(total - screen, - width / zoom)); + std::min(total - screenWidth / zoom, + beforeWidth / zoom)); } void ViewInfo::WriteXMLAttributes(XMLWriter &xmlFile) diff --git a/src/ViewInfo.h b/src/ViewInfo.h index 836ef04f9..7768dc31c 100644 --- a/src/ViewInfo.h +++ b/src/ViewInfo.h @@ -29,7 +29,7 @@ class Track; class AUDACITY_DLL_API ZoomInfo { public: - ZoomInfo(double start, double duration, double pixelsPerSecond); + ZoomInfo(double start, double pixelsPerSecond); ~ZoomInfo(); void UpdatePrefs(); @@ -38,8 +38,6 @@ public: double h; // h pos in secs - double screen; // screen width in secs - protected: double zoom; // pixels per second @@ -53,7 +51,7 @@ public: double PositionToTime(wxInt64 position, wxInt64 origin = 0 , bool ignoreFisheye = false - ) const; + ) const; // do NOT use this once to convert a duration to a pixel width! // Instead, call twice to convert start and end positions, @@ -62,7 +60,7 @@ public: wxInt64 TimeToPosition(double time, wxInt64 origin = 0 , bool ignoreFisheye = false - ) const; + ) const; double OffsetTimeByPixels(double time, wxInt64 offset) const { @@ -72,13 +70,6 @@ public: bool ZoomInAvailable() const; bool ZoomOutAvailable() const; - // Return pixels, but maybe not a whole number - double GetScreenWidth() const - { return screen * zoom; } - - void SetScreenWidth(wxInt64 width) - { screen = width / zoom; } - static double GetDefaultZoom() { return 44100.0 / 512.0; } @@ -107,7 +98,7 @@ public: // first entry equals origin. // @param origin specifies the pixel position corresponding to time ViewInfo::h. void FindIntervals - (double rate, Intervals &results, wxInt64 origin = 0) const; + (double rate, Intervals &results, wxInt64 width, wxInt64 origin = 0) const; enum FisheyeState { HIDDEN, @@ -120,7 +111,7 @@ public: // Return true if the mouse position is anywhere in the fisheye // origin specifies the pixel corresponding to time h - bool InFisheye(wxInt64 position, wxInt64 WXUNUSED(origin = 0)) const + bool InFisheye(wxInt64 /*position*/, wxInt64 WXUNUSED(origin = 0)) const {return false;} // stub // These accessors ignore the fisheye hiding state. @@ -143,14 +134,11 @@ public: { return h * zoom; } - void SetBeforeScreenWidth(wxInt64 width, double lowerBoundTime = 0.0); + void SetBeforeScreenWidth(wxInt64 beforeWidth, wxInt64 screenWidth, double lowerBoundTime = 0.0); double GetTotalWidth() const { return total * zoom; } - bool ZoomedAll() const - { return screen >= total; } - // Current selection SelectedRegion selectedRegion; diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index a3ff7ec1b..3eca6ffe7 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -2908,7 +2908,7 @@ void EqualizationPanel::OnPaint(wxPaintEvent & WXUNUSED(event)) memDC.SetPen(*wxBLACK_PEN); if( mEffect->mDraw->GetValue() ) { - mEffect->mEnvelope->DrawPoints(memDC, mEnvRect, ZoomInfo(0.0, 1.0, mEnvRect.width-1), false, 0.0, + mEffect->mEnvelope->DrawPoints(memDC, mEnvRect, ZoomInfo(0.0, mEnvRect.width-1), false, 0.0, mEffect->mdBMin, mEffect->mdBMax); } @@ -2927,7 +2927,7 @@ void EqualizationPanel::OnMouseEvent(wxMouseEvent & event) CaptureMouse(); } - if (mEffect->mEnvelope->MouseEvent(event, mEnvRect, ZoomInfo(0.0, 1.0, mEnvRect.width), + if (mEffect->mEnvelope->MouseEvent(event, mEnvRect, ZoomInfo(0.0, mEnvRect.width), false, 0.0, mEffect->mdBMin, mEffect->mdBMax)) { diff --git a/src/widgets/AttachableScrollBar.cpp b/src/widgets/AttachableScrollBar.cpp index 5ffb2fefd..bc07536aa 100644 --- a/src/widgets/AttachableScrollBar.cpp +++ b/src/widgets/AttachableScrollBar.cpp @@ -56,6 +56,8 @@ AttachableScrollBar::~AttachableScrollBar(void) // Essentially a float to int conversion. void AttachableScrollBar::SetScrollBarFromViewInfo() { + // fix me +#if 0 ViewInfo & mViewInfo = *mpViewInfo; mViewInfo.sbarTotal = (int) (mViewInfo.GetTotalWidth()); @@ -64,11 +66,14 @@ void AttachableScrollBar::SetScrollBarFromViewInfo() SetScrollbar(mViewInfo.sbarH, mViewInfo.sbarScreen, mViewInfo.sbarTotal, mViewInfo.sbarScreen, TRUE); +#endif } // Essentially an int to float conversion. void AttachableScrollBar::SetViewInfoFromScrollBar() { + // fixme +#if 0 ViewInfo & mViewInfo = *mpViewInfo; int hlast = mViewInfo.sbarH; @@ -76,7 +81,8 @@ void AttachableScrollBar::SetViewInfoFromScrollBar() mViewInfo.sbarH = GetThumbPosition(); if (mViewInfo.sbarH != hlast) - mViewInfo.SetBeforeScreenWidth(mViewInfo.sbarH); + mViewInfo.SetBeforeScreenWidth(mViewInfo.sbarH); +#endif } // Used to associated a ViewInfo structure with a scrollbar. From 99f490c75fa53b16781b018d2d2dfe95565ae4fd Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 21 Aug 2015 22:47:43 -0400 Subject: [PATCH 13/13] Fix off-by-one errors in allowable ranges for drawing indicator and cursor --- src/TrackPanel.cpp | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index c69dfe2e5..30eea9d91 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -292,15 +292,9 @@ template < class A, class B, class DIST > bool within(A a, B b, DIST d) } template < class LOW, class MID, class HIGH > - bool between_inclusive(LOW l, MID m, HIGH h) + bool between_incexc(LOW l, MID m, HIGH h) { - return (m >= l && m <= h); -} - -template < class LOW, class MID, class HIGH > - bool between_exclusive(LOW l, MID m, HIGH h) -{ - return (m > l && m < h); + return (m >= l && m < h); } template < class CLIPPEE, class CLIPVAL > @@ -1289,9 +1283,9 @@ void TrackPanel::TimerUpdateIndicator() #endif AudacityProject *p = GetProject(); const bool - onScreen = between_inclusive(mViewInfo->h, - pos, - GetScreenEndTime()); + onScreen = between_incexc(mViewInfo->h, + pos, + GetScreenEndTime()); // This displays the audio time, too... DisplaySelection(); @@ -1337,9 +1331,9 @@ void TrackPanel::UndrawIndicator(wxDC & dc) int width; GetTracksUsableArea(&width, NULL); const bool - onScreen = between_inclusive(GetLeftOffset(), - mLastIndicatorX, - GetLeftOffset() + width); + onScreen = between_incexc(GetLeftOffset(), + mLastIndicatorX, + GetLeftOffset() + width); if (onScreen) { // LL: Keep from trying to blit outsize of the source DC. This results in a crash on @@ -1373,9 +1367,9 @@ void TrackPanel::DoDrawIndicator(wxDC & dc) // Ensure that we don't draw through the TrackInfo or vertical ruler. wxRect clip = GetRect(); - int leftCutoff = clip.x + GetLabelWidth(); + int leftCutoff = clip.x + GetLeftOffset(); int rightCutoff = clip.x + clip.width - kRightMargin; - if (!between_inclusive(leftCutoff, mLastIndicatorX, rightCutoff)) + if (!between_incexc(leftCutoff, mLastIndicatorX, rightCutoff)) { return; } @@ -1441,9 +1435,9 @@ void TrackPanel::UndrawCursor(wxDC & dc) { int width; GetTracksUsableArea(&width, NULL); - onScreen = between_inclusive(GetLeftOffset(), - mLastCursorX, - GetLeftOffset() + width); + onScreen = between_incexc(GetLeftOffset(), + mLastCursorX, + GetLeftOffset() + width); if( onScreen ) dc.Blit(mLastCursorX, 0, 1, mBacking->GetHeight(), &mBackingDC, mLastCursorX, 0); } @@ -1456,9 +1450,9 @@ void TrackPanel::DoDrawCursor(wxDC & dc) return; const bool - onScreen = between_inclusive( mViewInfo->h, - mCursorTime, - GetScreenEndTime() ); + onScreen = between_incexc(mViewInfo->h, + mCursorTime, + GetScreenEndTime() ); if( !onScreen ) return;