Audacity 3.2.0
NoteTrackVZoomHandle.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5NoteTrackVZoomHandle.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12#ifdef USE_MIDI
15
16#include "../../../ui/ChannelVRulerControls.h"
17
18#include "../../../../HitTestResult.h"
19#include "NoteTrack.h"
20#include "Project.h"
21#include "ProjectHistory.h"
22#include "../../../../RefreshCode.h"
23#include "../../../../TrackArtist.h"
24#include "../../../../TrackPanelMouseEvent.h"
25#include "../../../../widgets/PopupMenuTable.h"
26#include "../../../../../images/Cursors.h"
27#include "Prefs.h"
28
29namespace
30{
31
33 {
34 public:
37 wxRect rect;
38 unsigned result;
39 int yy;
40 };
41
42 bool IsDragZooming(int zoomStart, int zoomEnd)
43 {
44 const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
45 return abs(zoomEnd - zoomStart) > DragThreshold;
46 }
47
48}
49
51
53(const std::shared_ptr<NoteTrack> &pTrack, const wxRect &rect, int y)
54 : mpTrack{ pTrack } , mZoomStart(y), mZoomEnd(y), mRect(rect)
55{
56}
57
59{
60#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
62#endif
63}
64
66{
67 static auto zoomInCursor =
68 ::MakeCursor(wxCURSOR_MAGNIFIER, ZoomInCursorXpm, 19, 15);
69 static auto zoomOutCursor =
70 ::MakeCursor(wxCURSOR_MAGNIFIER, ZoomOutCursorXpm, 19, 15);
71 static wxCursor arrowCursor{ wxCURSOR_ARROW };
72
73 const auto message =
74 XO("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region.");
75
76 return {
77 message,
78 state.ShiftDown() ? &*zoomOutCursor : &*zoomInCursor
79 };
80}
81
83(std::weak_ptr<NoteTrackVZoomHandle> &holder,
84 const wxMouseState &state,
85 const std::shared_ptr<NoteTrack> &pTrack, const wxRect &rect)
86{
87 if (pTrack) {
88 auto result = std::make_shared<NoteTrackVZoomHandle>(
89 pTrack, rect, state.m_y);
90 result = AssignUIHandlePtr(holder, result);
91 return result;
92 }
93 return {};
94}
95
97{
98}
99
100std::shared_ptr<const Track> NoteTrackVZoomHandle::FindTrack() const
101{
102 return mpTrack.lock();
103}
104
106{
107 return true;
108}
109
112{
113 // change note track to zoom like audio track
114 // mpTrack->StartVScroll();
115
117}
118
120(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
121{
122 using namespace RefreshCode;
123 auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack);
124 if (!pTrack)
125 return Cancelled;
126
127 const wxMouseEvent &event = evt.event;
128 mZoomEnd = event.m_y;
130 // changed Note track to work like audio track
131 // pTrack->VScroll(mZoomStart, mZoomEnd);
132 return RefreshAll;
133 }
134 return RefreshNone;
135}
136
139{
140 return HitPreview(st.state);
141}
142
143enum {
151
153
156};
158// Table class
159
161 : public PopupMenuTable
162 , private PrefsListener
163{
165 : PopupMenuTable{ "NoteTrackVRuler" }
166 {};
169
170public:
172
173protected:
174 enum {
175// Note that these can be with or without spectrum view which
176// adds a constant.
177//const int kZoom1to1 = 1;
178//const int kZoomHalfWave = 4;
179//const int kZoomInByDrag = 5;
186 };
187
188 InitMenuData *mpData {};
189 void OnZoom( int iZoomCode );
190// void OnZoomFitVertical(wxCommandEvent&){ OnZoom( kZoom1to1 );};
191 void OnZoomReset(wxCommandEvent&){ OnZoom( kZoomReset );};
192// void OnZoomHalfWave(wxCommandEvent&){ OnZoom( kZoomHalfWave );};
193 void OnZoomInVertical(wxCommandEvent&){ OnZoom( kZoomIn );};
194 void OnZoomOutVertical(wxCommandEvent&){ OnZoom( kZoomOut );};
195 void OnZoomMax(wxCommandEvent&){ OnZoom( kZoomMax );};
196 void OnUpOctave(wxCommandEvent&){ OnZoom( kUpOctave );};
197 void OnDownOctave(wxCommandEvent&){ OnZoom( kDownOctave );};
198
199private:
200 void InitUserData(void *pUserData) override;
201
202 void UpdatePrefs() override
203 {
204 // Because labels depend on advanced vertical zoom setting
206 }
207};
208
210{
211 static NoteTrackVRulerMenuTable instance;
212 return instance;
213}
214
216{
217 mpData = static_cast<InitMenuData*>(pUserData);
218}
219
221 auto &data = NoteTrackRange::Get(*mpData->pTrack);
222 switch( iZoomCode ){
223 case kZoomReset:
224 data.ZoomAllNotes(&mpData->pTrack->GetSeq());
225 break;
226 case kZoomIn:
227 NoteTrackDisplayData{ *mpData->pTrack, mpData->rect }.ZoomIn(mpData->yy);
228 break;
229 case kZoomOut:
230 NoteTrackDisplayData{ *mpData->pTrack, mpData->rect }.ZoomOut(mpData->yy);
231 break;
232 case kZoomMax:
233 data.ZoomMaxExtent();
234 break;
235 case kUpOctave:
236 data.ShiftNoteRange(12);
237 break;
238 case kDownOctave:
239 data.ShiftNoteRange(-12);
240 break;
241 }
242 AudacityProject *const project = &mpData->project;
243 ProjectHistory::Get( *project ).ModifyState(false);
244 using namespace RefreshCode;
245 mpData->result = UpdateVRuler | RefreshAll;
246}
247
248
250
251 // Accelerators only if zooming enabled.
252 bool bVZoom = true;
253
254 BeginSection( "Zoom" );
255 BeginSection( "Basic" );
257 MakeLabel( XXO("Zoom Reset"), bVZoom, XXO("Shift-Right-Click")),
258 POPUP_MENU_FN( OnZoomReset ) );
259 AppendItem( "Max", OnZoomMaxID, XXO("Max Zoom"), POPUP_MENU_FN( OnZoomMax ) );
261
262 BeginSection( "InOut" );
264 MakeLabel( XXO("Zoom In"), bVZoom, XXO("Left-Click/Left-Drag") ),
265 POPUP_MENU_FN( OnZoomInVertical ) );
267 MakeLabel( XXO("Zoom Out"), bVZoom, XXO("Shift-Left-Click") ),
268 POPUP_MENU_FN( OnZoomOutVertical ) );
269 EndSection();
270 EndSection();
271
272 BeginSection( "Pan" );
273 BeginSection( "Octaves" );
274 AppendItem( "Up", OnUpOctaveID, XXO("Up &Octave"), POPUP_MENU_FN( OnUpOctave) );
275 AppendItem( "Down", OnDownOctaveID, XXO("Down Octa&ve"), POPUP_MENU_FN( OnDownOctave ) );
276 EndSection();
277 EndSection();
278
280
281
282
284(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
285 wxWindow *pParent)
286{
287 using namespace RefreshCode;
288 auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack);
289 if (!pTrack)
290 return RefreshNone;
291
292 const wxMouseEvent &event = evt.event;
293 //const bool shiftDown = event.ShiftDown();
294 const bool rightUp = event.RightUp();
295
296
297 // Popup menu...
298 if (
299 rightUp &&
300 !(event.ShiftDown() || event.CmdDown()))
301 {
302 InitMenuData data {
303 *pProject, pTrack.get(), mRect, RefreshNone, event.m_y
304 };
305
306 PopupMenuTable *const pTable =
308 auto pMenu = PopupMenuTable::BuildMenu(pTable, &data);
309
310 pMenu->Popup( *pParent, { event.m_x, event.m_y } );
311
312 return data.result;
313 }
314
315 if( event.GetId() == kCaptureLostEventId )
316 return RefreshAll;
317
318 NoteTrackDisplayData data{ *pTrack, evt.rect };
319 if (IsDragZooming(mZoomStart, mZoomEnd)) {
320 data.ZoomTo(mZoomStart, mZoomEnd);
321 }
322 else if (event.ShiftDown() || event.RightUp()) {
323 if (event.ShiftDown() && event.RightUp()) {
324 auto &data = NoteTrackRange::Get(*pTrack);
325 auto oldBotNote = data.GetBottomNote();
326 auto oldTopNote = data.GetTopNote();
327 // Zoom out to show all notes
328 data.ZoomAllNotes(&pTrack->GetSeq());
329 if (data.GetBottomNote() == oldBotNote &&
330 data.GetTopNote() == oldTopNote) {
331 // However if we are already showing all notes, zoom out further
332 data.ZoomMaxExtent();
333 }
334 } else {
335 // Zoom out
336 data.ZoomOut(mZoomEnd);
337 }
338 }
339 else {
340 data.ZoomIn(mZoomEnd);
341 }
342
343 mZoomEnd = mZoomStart = 0;
344 ProjectHistory::Get( *pProject ).ModifyState(false);
345
346 return RefreshAll;
347}
348
350{
351 // Cancel is implemented! And there is no initial state to restore,
352 // so just return a code.
354}
355
358 const wxRect &rect, unsigned iPass )
359{
360 if ( iPass == TrackArtist::PassZooming ) {
361 if (!mpTrack.lock()) //? TrackList::Lock()
362 return;
363
366 context, rect, mZoomStart, mZoomEnd);
367 }
368}
369
372 const wxRect &rect, const wxRect &panelRect, unsigned iPass )
373{
374 if ( iPass == TrackArtist::PassZooming )
375 return ChannelVRulerControls::ZoomingArea(rect, panelRect);
376 else
377 return rect;
378}
379
380#endif
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
EndSection()
BeginSection("Zoom")
bool bVZoom
@ OnZoomTimes2ID
@ OnZoomOutVerticalID
@ OnZoomFitVerticalID
@ OnZoomHalfWaveID
@ OnDownOctaveID
@ OnZoomInVerticalID
AppendItem("Reset", OnZoomResetID, MakeLabel(XXO("Zoom Reset"), bVZoom, XXO("Shift-Right-Click")), POPUP_MENU_FN(OnZoomReset))
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
const auto project
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:189
const int DragThreshold
Definition: TrackPanel.h:57
const int kCaptureLostEventId
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:164
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static wxRect ZoomingArea(const wxRect &rect, const wxRect &panelRect)
static void DrawZooming(TrackPanelDrawingContext &context, const wxRect &rect, int zoomStart, int zoomEnd)
Temporary data used to display a note track.
void ZoomTo(int start, int end)
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:78
static NoteTrackRange & Get(const NoteTrack &track)
Allow mutative access to attached data of a const track.
void OnZoomInVertical(wxCommandEvent &)
void OnDownOctave(wxCommandEvent &)
void OnZoomOutVertical(wxCommandEvent &)
void OnUpOctave(wxCommandEvent &)
void InitUserData(void *pUserData) override
Called before the menu items are appended.
void OnZoomReset(wxCommandEvent &)
void OnZoomMax(wxCommandEvent &)
static NoteTrackVRulerMenuTable & Instance()
DECLARE_POPUP_MENU(NoteTrackVRulerMenuTable)
std::shared_ptr< const Track > FindTrack() const override
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
NoteTrackVZoomHandle(const NoteTrackVZoomHandle &)
std::weak_ptr< NoteTrack > mpTrack
wxRect DrawingArea(TrackPanelDrawingContext &, const wxRect &rect, const wxRect &panelRect, unsigned iPass) override
static HitTestPreview HitPreview(const wxMouseState &state)
Result Cancel(AudacityProject *pProject) override
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
void Enter(bool forward, AudacityProject *) override
static UIHandlePtr HitTest(std::weak_ptr< NoteTrackVZoomHandle > &holder, const wxMouseState &state, const std::shared_ptr< NoteTrack > &pTrack, const wxRect &rect)
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
static std::unique_ptr< PopupMenu > BuildMenu(PopupMenuTable *pTable, void *pUserData=NULL)
A listener notified of changes in preferences.
Definition: Prefs.h:652
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1079
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
Short-lived drawing and event-handling object associated with a TrackPanelCell.
Definition: UIHandle.h:37
Result mChangeHighlight
Definition: UIHandle.h:152
unsigned Result
Definition: UIHandle.h:40
void Release(wxWindow *handler)
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
bool IsDragZooming(int zoomStart, int zoomEnd)