Audacity 3.2.0
WaveformVZoomHandle.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5WaveformVZoomHandle.cpp
6
7Paul Licameli split from WaveTrackVZoomHandle.cpp
8
9**********************************************************************/
10
11
12#include "WaveformVZoomHandle.h"
13
15
16#include "../../../../HitTestResult.h"
17#include "NumberScale.h"
18#include "Prefs.h"
19#include "ProjectHistory.h"
20#include "../../../../RefreshCode.h"
21#include "../../../../TrackPanelMouseEvent.h"
22#include "WaveTrack.h"
23#include "../../../../prefs/WaveformSettings.h"
24
26 const std::shared_ptr<WaveTrack> &pTrack, const wxRect &rect, int y)
27 : mpTrack{ pTrack } , mZoomStart(y), mZoomEnd(y), mRect(rect)
28{
29}
30
32
34{
35#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
37#endif
38}
39
41{
42 return true;
43}
44
47{
49}
50
52(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
53{
54 using namespace RefreshCode;
55 auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack);
56 if (!pTrack)
57 return Cancelled;
58 return WaveTrackVZoomHandle::DoDrag( evt, pProject, mZoomStart, mZoomEnd );
59}
60
63{
65}
66
68(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
69 wxWindow *pParent)
70{
71 auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack);
73 evt, pProject, pParent, pTrack.get(), mRect,
76}
77
79{
80 // Cancel is implemented! And there is no initial state to restore,
81 // so just return a code.
83}
84
87 const wxRect &rect, unsigned iPass )
88{
89 if (!mpTrack.lock()) //? TrackList::Lock()
90 return;
92 context, rect, iPass, mZoomStart, mZoomEnd );
93}
94
97 const wxRect &rect, const wxRect &panelRect, unsigned iPass )
98{
99 return WaveTrackVZoomHandle::DoDrawingArea( rect, panelRect, iPass );
100}
101
102// ZoomKind says how to zoom.
103// If ZoomStart and ZoomEnd are not equal, this may override
104// the zoomKind and cause a drag-zoom-in.
106 AudacityProject *pProject,
107 WaveTrack *pTrack,
109 const wxRect &rect, int zoomStart, int zoomEnd,
110 bool fixedMousePoint)
111{
112 using namespace WaveTrackViewConstants;
113 static const float ZOOMLIMIT = 0.001f;
114
115 int height = rect.height;
116 int ypos = rect.y;
117
118 // Ensure start and end are in order (swap if not).
119 if (zoomEnd < zoomStart)
120 std::swap( zoomStart, zoomEnd );
121
122 float min, max, minBand = 0;
123 const double rate = pTrack->GetRate();
124 const float halfrate = rate / 2;
125 float maxFreq = 8000.0;
126
127 bool bDragZoom = WaveTrackVZoomHandle::IsDragZooming(zoomStart, zoomEnd);
128
129 // Possibly override the zoom kind.
130 if( bDragZoom )
131 ZoomKind = kZoomInByDrag;
132
133 float top=2.0;
134 float half=0.5;
135
136 {
137 auto &cache = WaveformScale::Get(*pTrack);
138 cache.GetDisplayBounds(min, max);
139 auto &waveSettings = WaveformSettings::Get(*pTrack);
140 const bool linear = waveSettings.isLinear();
141 if( !linear ){
142 top = (LINEAR_TO_DB(2.0) + waveSettings.dBRange) / waveSettings.dBRange;
143 half = (LINEAR_TO_DB(0.5) + waveSettings.dBRange) / waveSettings.dBRange;
144 }
145 }
146
147
148 // Compute min and max.
149 switch(ZoomKind)
150 {
151 default:
152 // If we have covered all the cases, this won't happen.
153 // In release builds Audacity will ignore the zoom.
154 wxFAIL_MSG("Zooming Case not implemented by Audacity");
155 break;
156 case kZoomReset:
157 case kZoom1to1:
158 {
159 // Zoom out full
160 min = -1.0;
161 max = 1.0;
162 }
163 break;
164 case kZoomDiv2:
165 {
166 // Zoom out even more than full :-)
167 // -2.0..+2.0 (or logarithmic equivalent)
168 min = -top;
169 max = top;
170 }
171 break;
172 case kZoomTimes2:
173 {
174 // Zoom in to -0.5..+0.5
175 min = -half;
176 max = half;
177 }
178 break;
179 case kZoomHalfWave:
180 {
181 // Zoom to show fractionally more than the top half of the wave.
182 min = -0.01f;
183 max = 1.0;
184 }
185 break;
186 case kZoomInByDrag:
187 {
188 const float tmin = min, tmax = max;
189 const float p1 = (zoomStart - ypos) / (float)height;
190 const float p2 = (zoomEnd - ypos) / (float)height;
191 max = (tmax * (1.0 - p1) + tmin * p1);
192 min = (tmax * (1.0 - p2) + tmin * p2);
193
194 // Waveform view - allow zooming down to a range of ZOOMLIMIT
195 if (max - min < ZOOMLIMIT) { // if user attempts to go smaller...
196 float c = (min + max) / 2; // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below
197 min = c - ZOOMLIMIT / 2.0;
198 max = c + ZOOMLIMIT / 2.0;
199 }
200 }
201 break;
202 case kZoomIn:
203 {
204 // Enforce maximum vertical zoom
205 const float oldRange = max - min;
206 const float l = std::max(ZOOMLIMIT, 0.5f * oldRange);
207 const float ratio = l / (max - min);
208
209 const float p1 = (zoomStart - ypos) / (float)height;
210 float c = (max * (1.0 - p1) + min * p1);
211 if (fixedMousePoint)
212 min = c - ratio * (1.0f - p1) * oldRange,
213 max = c + ratio * p1 * oldRange;
214 else
215 min = c - 0.5 * l,
216 max = c + 0.5 * l;
217 }
218 break;
219 case kZoomOut:
220 {
221 // Zoom out
222 if (min <= -1.0 && max >= 1.0) {
223 min = -top;
224 max = top;
225 }
226 else {
227 // limit to +/- 1 range unless already outside that range...
228 float minRange = (min < -1) ? -top : -1.0;
229 float maxRange = (max > 1) ? top : 1.0;
230 // and enforce vertical zoom limits.
231 const float p1 = (zoomStart - ypos) / (float)height;
232 if (fixedMousePoint) {
233 const float oldRange = max - min;
234 const float c = (max * (1.0 - p1) + min * p1);
235 min = std::min(maxRange - ZOOMLIMIT,
236 std::max(minRange, c - 2 * (1.0f - p1) * oldRange));
237 max = std::max(minRange + ZOOMLIMIT,
238 std::min(maxRange, c + 2 * p1 * oldRange));
239 }
240 else {
241 const float c = p1 * min + (1 - p1) * max;
242 const float l = (max - min);
243 min = std::min(maxRange - ZOOMLIMIT,
244 std::max(minRange, c - l));
245 max = std::max(minRange + ZOOMLIMIT,
246 std::min(maxRange, c + l));
247 }
248 }
249 }
250 break;
251 }
252
253 // Now actually apply the zoom.
254 for (auto channel : TrackList::Channels(pTrack))
256
257 zoomEnd = zoomStart = 0;
258 if( pProject )
259 ProjectHistory::Get( *pProject ).ModifyState(true);
260}
261
263// Table class
264
266{
267 static WaveformVRulerMenuTable instance;
268 return instance;
269}
270
272 // Accelerators only if zooming enabled.
273 bool bVZoom;
274 gPrefs->Read(wxT("/GUI/VerticalZooming"), &bVZoom, false);
275
276 BeginSection( "Scales" );
277 {
278 const auto & names = WaveformSettings::GetScaleNames();
279 for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
281 OnFirstWaveformScaleID + ii, names[ii].Msgid(),
282 POPUP_MENU_FN( OnWaveformScaleType ),
283 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
284 const auto pData =
285 static_cast< WaveformVRulerMenuTable& >( handler ).mpData;
286 WaveTrack *const wt = pData->pTrack;
287 if ( id ==
289 static_cast<int>(WaveformSettings::Get(*wt).scaleType) )
290 menu.Check(id, true);
291 }
292 );
293 }
294 }
296
297 BeginSection( "Zoom" );
298 BeginSection( "Basic" );
300 MakeLabel( XXO("Zoom Reset"), bVZoom, XXO("Shift-Right-Click") ),
301 POPUP_MENU_FN( OnZoomReset ) );
302 AppendItem( "TimesHalf", OnZoomDiv2ID, XXO("Zoom x1/2"),
303 POPUP_MENU_FN( OnZoomDiv2Vertical ) );
304 AppendItem( "TimesTwo", OnZoomTimes2ID, XXO("Zoom x2"), POPUP_MENU_FN( OnZoomTimes2Vertical ) );
305
306 #ifdef EXPERIMENTAL_HALF_WAVE
307 AppendItem( "HalfWave", OnZoomHalfWaveID, XXO("Half Wave"), POPUP_MENU_FN( OnZoomHalfWave ) );
308 #endif
309 EndSection();
310
311 BeginSection( "InOut" );
313 MakeLabel( XXO("Zoom In"), bVZoom, XXO("Left-Click/Left-Drag") ),
314 POPUP_MENU_FN( OnZoomInVertical ) );
316 MakeLabel( XXO("Zoom Out"), bVZoom, XXO("Shift-Left-Click") ),
317 POPUP_MENU_FN( OnZoomOutVertical ) );
318 EndSection();
319 EndSection();
320
322
323void WaveformVRulerMenuTable::OnWaveformScaleType(wxCommandEvent &evt)
324{
325 WaveTrack *const wt = mpData->pTrack;
326 // Assume linked track is wave or null
327 const WaveformSettings::ScaleType newScaleType =
329 std::max(0,
331 evt.GetId() - OnFirstWaveformScaleID
332 )));
333
334 if (WaveformSettings::Get(*wt).scaleType != newScaleType) {
335 for (auto channel : TrackList::Channels(wt)) {
336 WaveformSettings::Get(*channel).scaleType = newScaleType;
337 }
338
339 AudacityProject *const project = &mpData->project;
340 ProjectHistory::Get( *project ).ModifyState(true);
341
342 using namespace RefreshCode;
343 mpData->result = UpdateVRuler | RefreshAll;
344 }
345}
wxT("CloseDown"))
@ Internal
Indicates internal failure from Audacity.
int min(int a, int b)
XXO("&Cut/Copy/Paste Toolbar")
#define LINEAR_TO_DB(x)
Definition: MemoryX.h:561
@ OnZoomTimes2ID
@ OnZoomOutVerticalID
@ OnZoomFitVerticalID
@ OnZoomHalfWaveID
@ OnZoomInVerticalID
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
FileConfig * gPrefs
Definition: Prefs.cpp:70
static TranslatableStrings names
Definition: TagsEditor.cpp:152
@ OnFirstWaveformScaleID
gPrefs Read(wxT("/GUI/VerticalZooming"), &bVZoom, false)
EndSection()
bool bVZoom
BeginSection("Scales")
AppendItem("Reset", OnZoomFitVerticalID, MakeLabel(XXO("Zoom Reset"), bVZoom, XXO("Shift-Right-Click")), POPUP_MENU_FN(OnZoomReset))
AppendRadioItem("Instrument1", OnInstrument1ID, GetWaveColorStr(0), POPUP_MENU_FN(OnWaveColorChange), fn)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1606
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:487
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1544
Result mChangeHighlight
Definition: UIHandle.h:139
unsigned Result
Definition: UIHandle.h:38
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
double GetRate() const override
Definition: WaveTrack.cpp:360
void SetDisplayBounds(float min, float max)
static WaveformScale & Get(const WaveTrack &track)
Mutative access to attachment even if the track argument is const.
static const EnumValueSymbols & GetScaleNames()
static WaveformSettings & Get(const WaveTrack &track)
static PopupMenuTable & Instance()
void Enter(bool forward, AudacityProject *) override
~WaveformVZoomHandle() override
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
wxRect DrawingArea(TrackPanelDrawingContext &, const wxRect &rect, const wxRect &panelRect, unsigned iPass) override
std::weak_ptr< WaveTrack > mpTrack
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
static void DoZoom(AudacityProject *pProject, WaveTrack *pTrack, WaveTrackViewConstants::ZoomActions ZoomKind, const wxRect &rect, int zoomStart, int zoomEnd, bool fixedMousePoint)
WaveformVZoomHandle(const WaveformVZoomHandle &)
Result Cancel(AudacityProject *pProject) override
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
AUDACITY_DLL_API HitTestPreview HitPreview(const wxMouseState &state)
AUDACITY_DLL_API void DoDraw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass, int zoomStart, int zoomEnd)
AUDACITY_DLL_API Result DoRelease(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent, WaveTrack *pTrack, const wxRect &mRect, DoZoomFunction doZoom, PopupMenuTable &table, int zoomStart, int zoomEnd)
AUDACITY_DLL_API wxRect DoDrawingArea(const wxRect &rect, const wxRect &panelRect, unsigned iPass)
AUDACITY_DLL_API bool IsDragZooming(int zoomStart, int zoomEnd)
AUDACITY_DLL_API Result DoDrag(const TrackPanelMouseEvent &event, AudacityProject *pProject, int zoomStart, int &zoomEnd)
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:752