From 13c6fdf6636df239e5f2e39c5cc12058dfbd29fe Mon Sep 17 00:00:00 2001 From: James Crook Date: Mon, 11 Dec 2017 18:41:48 +0000 Subject: [PATCH] VZooming Changes 1: Guard zone 8 pixels wide in VRuler to reduce risk of accidental use. 2: VerticalZooming preference, for VRuler zooming, off by default, 3: Enabled Paul's right-click menu in VRuler with some extra presets (x2 and x0.5) 4: Rearranged some messy code with lots of ifs to use a switch. Also, with EXPERIMENTAL_HALF_WAVE defined we now get a 'half wave' option in the VRuler menu, that shows the wave top half. We also use it in collapsed waves (and collapsing and restoring a WaveTrack will get you back to normal zoom. --- src/Experimental.h | 4 + src/Track.h | 2 +- src/TrackPanel.cpp | 15 +- src/TrackPanelMouseEvent.h | 4 + src/WaveTrack.cpp | 20 + src/WaveTrack.h | 2 + src/prefs/TracksBehaviorsPrefs.cpp | 3 + .../wavetrack/ui/WaveTrackVRulerControls.cpp | 18 +- .../wavetrack/ui/WaveTrackVRulerControls.h | 2 +- .../wavetrack/ui/WaveTrackVZoomHandle.cpp | 417 ++++++++++++------ .../wavetrack/ui/WaveTrackVZoomHandle.h | 13 +- 11 files changed, 355 insertions(+), 145 deletions(-) diff --git a/src/Experimental.h b/src/Experimental.h index a2694d6d2..251c972f3 100644 --- a/src/Experimental.h +++ b/src/Experimental.h @@ -67,6 +67,10 @@ // Wavetrack, and draws its notes and lines over the top. #define EXPERIMENTAL_NOTETRACK_OVERLAY +// Define this, and the option to zoom to half wave is added in the VZoom menu. +// Also we go to half wave on collapse, full wave on restore. +#define EXPERIMENTAL_HALF_WAVE + // EXPERIMENTAL_THEMING is mostly mainstream now. // the define is still present to mark out old code before theming, that we might // conceivably need. diff --git a/src/Track.h b/src/Track.h index 51750777b..b9d98751e 100644 --- a/src/Track.h +++ b/src/Track.h @@ -187,7 +187,7 @@ class AUDACITY_DLL_API Track /* not final */ virtual void SetHeight(int h); #endif bool GetMinimized() const; - void SetMinimized(bool isMinimized); + virtual void SetMinimized(bool isMinimized); #ifdef EXPERIMENTAL_OUTPUT_DISPLAY float GetVirtualTrackPercentage() const { return mPerY;} void SetVirtualTrackPercentage(float val) { mPerY = val;} diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index cf4a9b89d..fe4dac4b6 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1572,7 +1572,9 @@ void TrackPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ClearTargets(); + // This is bad. We are lying abou the event by saying it is a mouse up. wxMouseEvent e(wxEVT_LEFT_UP); + e.SetId( kCaptureLostEventId ); e.m_x = mMouseMostRecentX; e.m_y = mMouseMostRecentY; @@ -3496,11 +3498,14 @@ void TrackPanelCellIterator::UpdateRect() break; } case CellType::VRuler: - mRect.x = kTrackInfoWidth; - // Only half the VRuler is active. - mRect.width = (mPanel->GetLeftOffset() - mRect.x)/2.0; - mRect.y += kTopMargin; - mRect.height -= (kBottomMargin + kTopMargin); + { + const int kGuard = 8; // 8 pixels to reduce risk of VZooming accidentally + mRect.x = kTrackInfoWidth; + // Right edge of the VRuler is inactive. + mRect.width = mPanel->GetLeftOffset() - mRect.x -kGuard; + mRect.y += kTopMargin; + mRect.height -= (kBottomMargin + kTopMargin); + } break; case CellType::Resizer: { // The resizer region encompasses the bottom margin proper to this diff --git a/src/TrackPanelMouseEvent.h b/src/TrackPanelMouseEvent.h index 7d21cca4a..6be261be9 100644 --- a/src/TrackPanelMouseEvent.h +++ b/src/TrackPanelMouseEvent.h @@ -18,6 +18,10 @@ class wxSize; class TrackPanelCell; #include "MemoryX.h" +// This is a hack so that the code that fakes a MOUSE_LEFT_BTN_UP on +// capture lost doesn't get in the way of handling MOUSE_RIGHT_BTN_UP. +const int kCaptureLostEventId = 19019; + // Augment a mouse state with information about which track panel cell and // sub-rectangle was hit. struct TrackPanelMouseState diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 8309bc5ef..3bd5fec25 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -61,6 +61,10 @@ Track classes. #include "Experimental.h" #include "TrackPanel.h" // for TrackInfo +// Assumptions in objects separation were wrong. We need to activate +// VZooming (that lives in WaveTrackVRulerHandle) from an action on the +// TCP collapse/expand. So we need visibility here. +#include "tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.h" using std::max; @@ -540,6 +544,22 @@ float WaveTrack::GetChannelGain(int channel) const return right*mGain; } +void WaveTrack::SetMinimized(bool isMinimized){ + +#ifdef EXPERIMENTAL_HALF_WAVE + // Show half wave on collapse, full on restore. + std::shared_ptr pTvc = GetVRulerControls(); + + // An awkward workaround for a function that lives 'in the wrong place'. + // We use magic numbers, 0 and 1, to tell it to zoom reset or zoom half-wave. + WaveTrackVRulerControls * pWtvc = reinterpret_cast(pTvc.get()); + if( pWtvc ) + pWtvc->DoZoomPreset( isMinimized ? 1:0); +#endif + + Track::SetMinimized( isMinimized ); +} + void WaveTrack::SetWaveColorIndex(int colorIndex) // STRONG-GUARANTEE { diff --git a/src/WaveTrack.h b/src/WaveTrack.h index 9393673f0..275d399dd 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -162,6 +162,8 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { void SetVirtualState(bool state, bool half=false); #endif + void SetMinimized(bool isMinimized) override; + int GetWaveColorIndex() const { return mWaveColorIndex; }; void SetWaveColorIndex(int colorIndex); diff --git a/src/prefs/TracksBehaviorsPrefs.cpp b/src/prefs/TracksBehaviorsPrefs.cpp index 47bb0c262..040473238 100644 --- a/src/prefs/TracksBehaviorsPrefs.cpp +++ b/src/prefs/TracksBehaviorsPrefs.cpp @@ -85,6 +85,9 @@ void TracksBehaviorsPrefs::PopulateOrExchange(ShuttleGui & S) ScrollingPreferenceKey(), ScrollingPreferenceDefault()); #endif + S.TieCheckBox(_("Enable Vertical Zooming"), + wxT("/GUI/VerticalZooming"), + false); S.AddSpace(10); diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.cpp index b8f8d1d07..0b66e3a06 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.cpp @@ -45,6 +45,22 @@ std::vector WaveTrackVRulerControls::HitTest return results; } +void WaveTrackVRulerControls::DoZoomPreset( int i) +{ + + const auto pTrack = FindTrack(); + if (!pTrack) + return; + wxASSERT(pTrack->GetKind() == Track::Wave); + + const auto wt = static_cast(pTrack.get()); + + WaveTrackVZoomHandle::DoZoom( + NULL, wt, (i==1)?kZoomHalfWave: kZoom1to1, + wxRect(0,0,0,0), 0,0, true); +} + + unsigned WaveTrackVRulerControls::HandleWheelRotation (const TrackPanelMouseEvent &evt, AudacityProject *pProject) { @@ -122,7 +138,7 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation else if (event.CmdDown() && !event.ShiftDown()) { const int yy = event.m_y; WaveTrackVZoomHandle::DoZoom( - pProject, wt, false, (steps < 0), + pProject, wt, (steps < 0)?kZoomOut:kZoomIn, evt.rect, yy, yy, true); } else if (!event.CmdDown() && event.ShiftDown()) { diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.h b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.h index ea02cd280..1f9636151 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.h +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVRulerControls.h @@ -33,7 +33,7 @@ public: unsigned HandleWheelRotation (const TrackPanelMouseEvent &event, AudacityProject *pProject) override; - + void DoZoomPreset( int i); private: std::weak_ptr mVZoomHandle; }; diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.cpp index 7bea8878f..06fc63f2b 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.cpp @@ -23,6 +23,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../../../WaveTrack.h" #include "../../../../widgets/PopupMenuTable.h" #include "../../../../../images/Cursors.h" +#include "../../../../Prefs.h" namespace { @@ -39,7 +40,9 @@ public: bool IsDragZooming(int zoomStart, int zoomEnd) { const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click. - return (abs(zoomEnd - zoomStart) > DragThreshold); + bool bVZoom; + gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false); + return bVZoom && (abs(zoomEnd - zoomStart) > DragThreshold); } } @@ -58,9 +61,12 @@ void WaveTrackVZoomHandle::Enter(bool) #endif } +// ZoomKind says how to zoom. +// If ZoomStart and ZoomEnd are not equal, this may override +// the zoomKind and cause a drag-zoom-in. void WaveTrackVZoomHandle::DoZoom (AudacityProject *pProject, - WaveTrack *pTrack, bool shiftDown, bool rightUp, + WaveTrack *pTrack, int ZoomKind, const wxRect &rect, int zoomStart, int zoomEnd, bool fixedMousePoint) { @@ -83,6 +89,20 @@ void WaveTrackVZoomHandle::DoZoom const bool spectrumLinear = spectral && (pTrack->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear); + + bool bDragZoom = IsDragZooming(zoomStart, zoomEnd); + const int kSpectral = 8; + + // Possibly override the zoom kind. + if( bDragZoom ) + ZoomKind = kZoomInByDrag; + + // If we are actually zooming a spectrum rather than a wave. + ZoomKind += spectral ? kSpectral:0; + + float top=2.0; + float half=0.5; + if (spectral) { pTrack->GetSpectrumBounds(&min, &max); scale = (settings.GetScale(min, max)); @@ -96,14 +116,141 @@ void WaveTrackVZoomHandle::DoZoom const int minBins = 1; minBand = minBins * binSize; } - else + else{ pTrack->GetDisplayBounds(&min, &max); + const WaveformSettings &settings = pTrack->GetWaveformSettings(); + const bool linear = settings.isLinear(); + if( !linear ){ + top = (LINEAR_TO_DB(2.0) + settings.dBRange) / settings.dBRange; + half = (LINEAR_TO_DB(0.5) + settings.dBRange) / settings.dBRange; + } + } - if (IsDragZooming(zoomStart, zoomEnd)) { - // Drag Zoom - const float tmin = min, tmax = max; - if (spectral) { + // Compute min and max. + switch(ZoomKind) + { + default: + // If we have covered all the cases, this won't happen. + // In release builds Audacity will ignore the zoom. + wxFAIL_MSG("Zooming Case not implemented by Audacity"); + break; + case kZoom1to1: + { + // Zoom out full + min = -1.0; + max = 1.0; + } + break; + case kZoomDiv2: + { + // Zoom out even more than full :-) + // -2.0..+2.0 (or logarithmic equivalent) + min = -top; + max = top; + } + break; + case kZoomTimes2: + { + // Zoom in to -0.5..+0.5 + min = -half; + max = half; + } + break; + case kZoomHalfWave: + { + // Zoom to show fractionally more than the top half of the wave. + min = -0.01f; + max = 1.0; + } + break; + case kZoomInByDrag: + { + const float tmin = min, tmax = max; + const float p1 = (zoomStart - ypos) / (float)height; + const float p2 = (zoomEnd - ypos) / (float)height; + max = (tmax * (1.0 - p1) + tmin * p1); + min = (tmax * (1.0 - p2) + tmin * p2); + + // Waveform view - allow zooming down to a range of ZOOMLIMIT + if (max - min < ZOOMLIMIT) { // if user attempts to go smaller... + c = (min + max) / 2; // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below + min = c - ZOOMLIMIT / 2.0; + max = c + ZOOMLIMIT / 2.0; + } + } + break; + case kZoomIn: + { + // Zoom in centered on cursor + if (min < -1.0 || max > 1.0) { + min = -1.0; + max = 1.0; + } + else { + // Enforce maximum vertical zoom + const float oldRange = max - min; + const float l = std::max(ZOOMLIMIT, 0.5f * oldRange); + const float ratio = l / (max - min); + + const float p1 = (zoomStart - ypos) / (float)height; + const float c = (max * (1.0 - p1) + min * p1); + if (fixedMousePoint) + min = c - ratio * (1.0f - p1) * oldRange, + max = c + ratio * p1 * oldRange; + else + min = c - 0.5 * l, + max = c + 0.5 * l; + } + } + break; + case kZoomOut: + { + // Zoom out + if (min <= -1.0 && max >= 1.0) { + min = -top; + max = top; + } + else { + // limit to +/- 1 range unless already outside that range... + float minRange = (min < -1) ? -top : -1.0; + float maxRange = (max > 1) ? top : 1.0; + // and enforce vertical zoom limits. + const float p1 = (zoomStart - ypos) / (float)height; + if (fixedMousePoint) { + const float oldRange = max - min; + const float c = (max * (1.0 - p1) + min * p1); + min = std::min(maxRange - ZOOMLIMIT, + std::max(minRange, c - 2 * (1.0f - p1) * oldRange)); + max = std::max(minRange + ZOOMLIMIT, + std::min(maxRange, c + 2 * p1 * oldRange)); + } + else { + const float c = p1 * min + (1 - p1) * max; + const float l = (max - min); + min = std::min(maxRange - ZOOMLIMIT, + std::max(minRange, c - l)); + max = std::max(minRange + ZOOMLIMIT, + std::min(maxRange, c + l)); + } + } + } + break; + + // VZooming on spectral we don't implement the other zoom presets. + // They are also not in the menu. + case kZoom1to1 + kSpectral: + case kZoomDiv2 + kSpectral: + case kZoomTimes2 + kSpectral: + case kZoomHalfWave + kSpectral: + { + // Zoom out full + min = spectrumLinear ? 0.0f : 1.0f; + max = halfrate; + } + break; + case kZoomInByDrag + kSpectral: + { double xmin = 1 - (zoomEnd - ypos) / (float)height; double xmax = 1 - (zoomStart - ypos) / (float)height; const float middle = (xmin + xmax) / 2; @@ -118,97 +265,9 @@ void WaveTrackVZoomHandle::DoZoom scale.PositionToValue(xmax) )); } - else { - const float p1 = (zoomStart - ypos) / (float)height; - const float p2 = (zoomEnd - ypos) / (float)height; - max = (tmax * (1.0 - p1) + tmin * p1); - min = (tmax * (1.0 - p2) + tmin * p2); - - // Waveform view - allow zooming down to a range of ZOOMLIMIT - if (max - min < ZOOMLIMIT) { // if user attempts to go smaller... - c = (min + max) / 2; // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below - min = c - ZOOMLIMIT / 2.0; - max = c + ZOOMLIMIT / 2.0; - } - } - } - else if (shiftDown || rightUp) { - // Zoom OUT - if (spectral) { - if (shiftDown && rightUp) { - // Zoom out full - min = spectrumLinear ? 0.0f : 1.0f; - max = halfrate; - } - else { - // Zoom out - - const float p1 = (zoomStart - ypos) / (float)height; - // (Used to zoom out centered at midline, ignoring the click, if linear view. - // I think it is better to be consistent. PRL) - // Center zoom-out at the midline - const float middle = // spectrumLinear ? 0.5f : - 1.0f - p1; - - if (fixedMousePoint) { - min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(-middle)); - max = std::min(halfrate, scale.PositionToValue(1.0f + p1)); - } - else { - min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f)); - max = std::min(halfrate, scale.PositionToValue(middle + 1.0f)); - } - } - } - else { - // Zoom out to -1.0...1.0 first, then, and only - // then, if they click again, allow one more - // zoom out. - if (shiftDown && rightUp) { - // Zoom out full - min = -1.0; - max = 1.0; - } - else { - // Zoom out - const WaveformSettings &settings = pTrack->GetWaveformSettings(); - const bool linear = settings.isLinear(); - const float top = linear - ? 2.0 - : (LINEAR_TO_DB(2.0) + settings.dBRange) / settings.dBRange; - if (min <= -1.0 && max >= 1.0) { - min = -top; - max = top; - } - else { - // limit to +/- 1 range unless already outside that range... - float minRange = (min < -1) ? -top : -1.0; - float maxRange = (max > 1) ? top : 1.0; - // and enforce vertical zoom limits. - const float p1 = (zoomStart - ypos) / (float)height; - if (fixedMousePoint) { - const float oldRange = max - min; - const float c = (max * (1.0 - p1) + min * p1); - min = std::min(maxRange - ZOOMLIMIT, - std::max(minRange, c - 2 * (1.0f - p1) * oldRange)); - max = std::max(minRange + ZOOMLIMIT, - std::min(maxRange, c + 2 * p1 * oldRange)); - } - else { - const float c = p1 * min + (1 - p1) * max; - const float l = (max - min); - min = std::min(maxRange - ZOOMLIMIT, - std::max(minRange, c - l)); - max = std::max(minRange + ZOOMLIMIT, - std::min(maxRange, c + l)); - } - } - } - } - } - else { - // Zoom IN - if (spectral) { + break; + case kZoomIn + kSpectral: + { // Center the zoom-in at the click const float p1 = (zoomStart - ypos) / (float)height; const float middle = 1.0f - p1; @@ -235,30 +294,30 @@ void WaveTrackVZoomHandle::DoZoom )); } } - else { - // Zoom in centered on cursor - if (min < -1.0 || max > 1.0) { - min = -1.0; - max = 1.0; + break; + case kZoomOut + kSpectral: + { + // Zoom out + const float p1 = (zoomStart - ypos) / (float)height; + // (Used to zoom out centered at midline, ignoring the click, if linear view. + // I think it is better to be consistent. PRL) + // Center zoom-out at the midline + const float middle = // spectrumLinear ? 0.5f : + 1.0f - p1; + + if (fixedMousePoint) { + min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(-middle)); + max = std::min(halfrate, scale.PositionToValue(1.0f + p1)); } else { - // Enforce maximum vertical zoom - const float oldRange = max - min; - const float l = std::max(ZOOMLIMIT, 0.5f * oldRange); - const float ratio = l / (max - min); - - const float p1 = (zoomStart - ypos) / (float)height; - const float c = (max * (1.0 - p1) + min * p1); - if (fixedMousePoint) - min = c - ratio * (1.0f - p1) * oldRange, - max = c + ratio * p1 * oldRange; - else - min = c - 0.5 * l, - max = c + 0.5 * l; + min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f)); + max = std::min(halfrate, scale.PositionToValue(middle + 1.0f)); } } + break; } + // Now actually apply the zoom. if (spectral) { pTrack->SetSpectrumBounds(min, max); if (partner) @@ -271,13 +330,17 @@ void WaveTrackVZoomHandle::DoZoom } zoomEnd = zoomStart = 0; - pProject->ModifyState(true); + if( pProject ) + pProject->ModifyState(true); } enum { - OnZoomInVerticalID = 20000, + OnZoomFitVerticalID = 20000, + OnZoomDiv2ID, + OnZoomTimes2ID, + OnZoomHalfWaveID, + OnZoomInVerticalID, OnZoomOutVerticalID, - OnZoomFitVerticalID, // Reserve an ample block of ids for waveform scale types OnFirstWaveformScaleID, @@ -307,9 +370,12 @@ private: protected: InitMenuData *mpData {}; + void OnZoomFitVertical(wxCommandEvent&); + void OnZoomDiv2Vertical(wxCommandEvent&); + void OnZoomTimes2Vertical(wxCommandEvent&); + void OnZoomHalfWave(wxCommandEvent&); void OnZoomInVertical(wxCommandEvent&); void OnZoomOutVertical(wxCommandEvent&); - void OnZoomFitVertical(wxCommandEvent&); }; void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData) @@ -320,7 +386,7 @@ void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData) void WaveTrackVRulerMenuTable::OnZoomInVertical(wxCommandEvent &) { WaveTrackVZoomHandle::DoZoom - (::GetActiveProject(), mpData->pTrack, false, false, mpData->rect, mpData->yy, mpData->yy, false); + (::GetActiveProject(), mpData->pTrack, kZoomIn, mpData->rect, mpData->yy, mpData->yy, false); using namespace RefreshCode; mpData->result = UpdateVRuler | RefreshAll; @@ -329,7 +395,7 @@ void WaveTrackVRulerMenuTable::OnZoomInVertical(wxCommandEvent &) void WaveTrackVRulerMenuTable::OnZoomOutVertical(wxCommandEvent &) { WaveTrackVZoomHandle::DoZoom - (::GetActiveProject(), mpData->pTrack, true, false, mpData->rect, mpData->yy, mpData->yy, false); + (::GetActiveProject(), mpData->pTrack, kZoomOut, mpData->rect, mpData->yy, mpData->yy, false); using namespace RefreshCode; mpData->result = UpdateVRuler | RefreshAll; @@ -338,7 +404,34 @@ void WaveTrackVRulerMenuTable::OnZoomOutVertical(wxCommandEvent &) void WaveTrackVRulerMenuTable::OnZoomFitVertical(wxCommandEvent &) { WaveTrackVZoomHandle::DoZoom - (::GetActiveProject(), mpData->pTrack, true, true, mpData->rect, mpData->yy, mpData->yy, false); + (::GetActiveProject(), mpData->pTrack, kZoom1to1, mpData->rect, mpData->yy, mpData->yy, false); + + using namespace RefreshCode; + mpData->result = UpdateVRuler | RefreshAll; +} + +void WaveTrackVRulerMenuTable::OnZoomDiv2Vertical(wxCommandEvent &) +{ + WaveTrackVZoomHandle::DoZoom + (::GetActiveProject(), mpData->pTrack, kZoomDiv2, mpData->rect, mpData->yy, mpData->yy, false); + + using namespace RefreshCode; + mpData->result = UpdateVRuler | RefreshAll; +} + +void WaveTrackVRulerMenuTable::OnZoomTimes2Vertical(wxCommandEvent &) +{ + WaveTrackVZoomHandle::DoZoom + (::GetActiveProject(), mpData->pTrack, kZoomTimes2, mpData->rect, mpData->yy, mpData->yy, false); + + using namespace RefreshCode; + mpData->result = UpdateVRuler | RefreshAll; +} + +void WaveTrackVRulerMenuTable::OnZoomHalfWave(wxCommandEvent &) +{ + WaveTrackVZoomHandle::DoZoom + (::GetActiveProject(), mpData->pTrack, kZoomHalfWave, mpData->rect, mpData->yy, mpData->yy, false); using namespace RefreshCode; mpData->result = UpdateVRuler | RefreshAll; @@ -372,14 +465,32 @@ void WaveformVRulerMenuTable::InitMenu(Menu *pMenu, void *pUserData) { WaveTrackVRulerMenuTable::InitMenu(pMenu, pUserData); +// DB setting is already on track drop down. +#if 0 WaveTrack *const wt = mpData->pTrack; const int id = OnFirstWaveformScaleID + (int)(wt->GetWaveformSettings().scaleType); pMenu->Check(id, true); +#endif } BEGIN_POPUP_MENU(WaveformVRulerMenuTable) + POPUP_MENU_ITEM(OnZoomFitVerticalID, _("Zoom Reset\tShift-Right-Click"), OnZoomFitVertical) + POPUP_MENU_ITEM(OnZoomDiv2ID, _("Zoom x1/2"), OnZoomDiv2Vertical) + POPUP_MENU_ITEM(OnZoomTimes2ID, _("Zoom x2"), OnZoomTimes2Vertical) + +#ifdef EXPERIMENTAL_HALF_WAVE + POPUP_MENU_ITEM(OnZoomHalfWaveID, _("Half Wave"), OnZoomHalfWave) +#endif + + POPUP_MENU_SEPARATOR() + POPUP_MENU_ITEM(OnZoomInVerticalID, _("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical) + POPUP_MENU_ITEM(OnZoomOutVerticalID, _("Zoom Out\tShift-Left-Click"), OnZoomOutVertical) +// The log and linear options are already available as waveform db. +// So don't repeat them here. +#if 0 + POPUP_MENU_SEPARATOR() { const wxArrayString & names = WaveformSettings::GetScaleNames(); for (int ii = 0, nn = names.size(); ii < nn; ++ii) { @@ -387,11 +498,7 @@ BEGIN_POPUP_MENU(WaveformVRulerMenuTable) OnWaveformScaleType); } } - - POPUP_MENU_SEPARATOR() - POPUP_MENU_ITEM(OnZoomInVerticalID, _("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical) - POPUP_MENU_ITEM(OnZoomOutVerticalID, _("Zoom Out\tShift-Left-Click"), OnZoomOutVertical) - POPUP_MENU_ITEM(OnZoomFitVerticalID, _("Zoom to Fit\tShift-Right-Click"), OnZoomFitVertical) +#endif END_POPUP_MENU() void WaveformVRulerMenuTable::OnWaveformScaleType(wxCommandEvent &evt) @@ -498,11 +605,17 @@ HitTestPreview WaveTrackVZoomHandle::HitPreview(const wxMouseState &state) ::MakeCursor(wxCURSOR_MAGNIFIER, ZoomInCursorXpm, 19, 15); static auto zoomOutCursor = ::MakeCursor(wxCURSOR_MAGNIFIER, ZoomOutCursorXpm, 19, 15); - const auto message = -_("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region."); + static wxCursor arrowCursor{ wxCURSOR_ARROW }; + bool bVZoom; + gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false); + bVZoom &= !state.RightIsDown(); + const auto message = bVZoom ? + _("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region.") : + _("Right-click for menu."); + return { message, - (state.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor) + bVZoom ? (state.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor) : &arrowCursor // , message }; } @@ -526,6 +639,8 @@ UIHandle::Result WaveTrackVZoomHandle::Drag return Cancelled; const wxMouseEvent &event = evt.event; + if ( event.RightIsDown() ) + return RefreshNone; mZoomEnd = event.m_y; if (IsDragZooming(mZoomStart, mZoomEnd)) return RefreshAll; @@ -551,8 +666,8 @@ UIHandle::Result WaveTrackVZoomHandle::Release const bool shiftDown = event.ShiftDown(); const bool rightUp = event.RightUp(); - // Popup menu... disabled - if (false && + // Popup menu... + if ( rightUp && !(event.ShiftDown() || event.CmdDown())) { @@ -566,14 +681,44 @@ UIHandle::Result WaveTrackVZoomHandle::Release : (PopupMenuTable *) &WaveformVRulerMenuTable::Instance(); std::unique_ptr pMenu(PopupMenuTable::BuildMenu(pParent, pTable, &data)); + bool bVZoom; + gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false); + + // Accelerators only if zooming enabled. + if( !bVZoom ) + { + wxMenuItemList & L = pMenu->GetMenuItems(); + // let's iterate over the list in STL syntax + wxMenuItemList::iterator iter; + for (iter = L.begin(); iter != L.end(); ++iter) + { + wxMenuItem *pItem = *iter; + // Remove accelerator, if any. + pItem->SetText( (pItem->GetText() + "\t" ).BeforeFirst('\t') ); + } + } + pParent->PopupMenu(pMenu.get(), event.m_x, event.m_y); return data.result; } - else - DoZoom(pProject, pTrack.get(), shiftDown, rightUp, - mRect, mZoomStart, mZoomEnd, false); + else{ + bool bVZoom; + gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false); + // Ignore Capture Lost event + bVZoom &= event.GetId() != kCaptureLostEventId; + // shiftDown | rightUp | ZoomKind + // T | T | 1to1 + // T | F | Out + // F | - | In + if( bVZoom ){ + if( shiftDown ) + mZoomStart=mZoomEnd; + DoZoom(pProject, pTrack.get(), shiftDown ? (rightUp ? kZoom1to1 : kZoomOut) : kZoomIn, + mRect, mZoomStart, mZoomEnd, false); + } + } return UpdateVRuler | RefreshAll; } diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.h b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.h index 1daef22fb..6bfaaaae8 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.h +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackVZoomHandle.h @@ -17,6 +17,17 @@ class WaveTrack; #include "../../../../MemoryX.h" #include "../../../../UIHandle.h" + +// Note that these can be with or without spectrum view which +// adds a constant. +const int kZoom1to1 = 1; +const int kZoomTimes2 = 2; +const int kZoomDiv2 = 3; +const int kZoomHalfWave = 4; +const int kZoomInByDrag = 5; +const int kZoomIn = 6; +const int kZoomOut = 7; + class WaveTrackVZoomHandle : public UIHandle { WaveTrackVZoomHandle(const WaveTrackVZoomHandle&); @@ -30,7 +41,7 @@ public: static void DoZoom (AudacityProject *pProject, - WaveTrack *pTrack, bool shiftDown, bool rightUp, + WaveTrack *pTrack, int ZoomKind, const wxRect &rect, int zoomStart, int zoomEnd, bool fixedMousePoint);