Audacity 3.2.0
NoteTrackControls.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5NoteTrackControls.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12#ifdef USE_MIDI
13#include "NoteTrackControls.h"
14
16#include "Observer.h"
17#include "Theme.h"
18
19#include "../../ui/PlayableTrackButtonHandles.h"
21
22#include "../../../../HitTestResult.h"
23#include "../../../../TrackArtist.h"
24#include "../../../../TrackPanel.h"
25#include "../../../../TrackPanelMouseEvent.h"
26#include "../../../../NoteTrack.h"
27#include "../../../../widgets/PopupMenuTable.h"
28#include "Project.h"
29#include "ProjectHistory.h"
30#include "../../../../ProjectWindows.h"
31#include "../../../../RefreshCode.h"
32#include "../../../../prefs/ThemePrefs.h"
33
34#include <mutex>
35#include <wx/app.h>
36#include <wx/frame.h>
37
40{
41}
42
43std::vector<UIHandlePtr> NoteTrackControls::HitTest
44(const TrackPanelMouseState & st,
45 const AudacityProject *pProject)
46{
47 // Hits are mutually exclusive, results single
48 std::vector<UIHandlePtr> results;
49 const wxMouseState &state = st.state;
50 const wxRect &rect = st.rect;
51 if (state.ButtonIsDown(wxMOUSE_BTN_ANY)) {
52 auto track = std::static_pointer_cast<NoteTrack>(FindTrack());
53 auto result = [&]{
54 UIHandlePtr result;
55 if (NULL != (result = MuteButtonHandle::HitTest(
56 mMuteHandle, state, rect, pProject, track)))
57 return result;
58
59 if (NULL != (result = SoloButtonHandle::HitTest(
60 mSoloHandle, state, rect, pProject, track)))
61 return result;
62#ifdef EXPERIMENTAL_MIDI_OUT
63 if (NULL != (result = VelocitySliderHandle::HitTest(
64 mVelocityHandle, state, rect, track)))
65 return result;
66 if (NULL != (result = NoteTrackButtonHandle::HitTest(
67 mClickHandle, state, rect, track)))
68 return result;
69#endif
70 return result;
71 }();
72 if (result) {
73 results.push_back(result);
74 return results;
75 }
76 }
77
78 return NoteTrackControlsBase::HitTest(st, pProject);
79}
80
82{
84 : PopupMenuTable{ "NoteTrack" }
85 {}
87
88public:
90
91private:
92 void InitUserData(void *pUserData) override
93 {
94 mpData = static_cast<NoteTrackControlsBase::InitMenuData*>(pUserData);
95 }
96
98
99 void OnChangeOctave(wxCommandEvent &);
100};
101
103{
104 static NoteTrackMenuTable instance;
105 return instance;
106}
107
108enum {
111};
112
114void NoteTrackMenuTable::OnChangeOctave(wxCommandEvent &event)
115{
116 NoteTrack *const pTrack = static_cast<NoteTrack*>(mpData->pTrack);
117
118 wxASSERT(event.GetId() == OnUpOctaveID
119 || event.GetId() == OnDownOctaveID);
120
121 const bool bDown = (OnDownOctaveID == event.GetId());
122 pTrack->ShiftNoteRange((bDown) ? -12 : 12);
123
124 AudacityProject *const project = &mpData->project;
125 ProjectHistory::Get( *project )
126 .ModifyState(false);
128}
129
131 BeginSection( "Basic" );
132 AppendItem( "Up", OnUpOctaveID, XXO("Up &Octave"), POPUP_MENU_FN( OnChangeOctave ) );
133 AppendItem( "Down", OnDownOctaveID, XXO("Down Octa&ve"), POPUP_MENU_FN( OnChangeOctave ) );
136
138{
139#if defined(USE_MIDI)
141#else
142 return NULL;
143#endif
144}
145
146// drawing related
147#include "../../../../widgets/ASlider.h"
148#include "../../../../TrackInfo.h"
149#include "../../../../TrackPanelDrawingContext.h"
150#include "ViewInfo.h"
151
153
154#ifdef USE_MIDI
155enum : int {
156 // PRL: was it correct to include the margin?
160#endif
161
164
165namespace {
166void GetMidiControlsHorizontalBounds( const wxRect &rect, wxRect &dest )
167{
168 dest.x = rect.x + 1; // To center slightly
169 // PRL: TODO: kMidiCellWidth is defined in terms of the other constant
170 // kTrackInfoWidth but I am trying to avoid use of that constant.
171 // Can cell width be computed from dest.width instead?
172 dest.width = kMidiCellWidth * 4;
173}
174
176( LWSlider *(*Selector)
177 (const wxRect &sliderRect, const NoteTrack *t, bool captured, wxWindow*),
178 wxDC *dc, const wxRect &rect, const Track *pTrack,
179 wxWindow *pParent,
180 bool captured, bool highlight )
181{
182 wxRect sliderRect = rect;
183 TrackInfo::GetSliderHorizontalBounds( rect.GetTopLeft(), sliderRect );
184 auto nt = static_cast<const NoteTrack*>( pTrack );
185 Selector( sliderRect, nt, captured, pParent )->OnPaint(*dc, highlight);
186}
187
188#ifdef EXPERIMENTAL_MIDI_OUT
189void VelocitySliderDrawFunction
190( TrackPanelDrawingContext &context,
191 const wxRect &rect, const Track *pTrack )
192{
193 auto dc = &context.dc;
194 auto target = dynamic_cast<VelocitySliderHandle*>( context.target.get() );
195 bool hit = target && target->GetTrack().get() == pTrack;
196 bool captured = hit && target->IsClicked();
197
198 const auto artist = TrackArtist::Get( context );
199 auto pParent = FindProjectFrame( artist->parent->GetProject() );
200
202 &NoteTrackControls::VelocitySlider, dc, rect, pTrack,
203 pParent, captured, hit);
204}
205#endif
206
208( TrackPanelDrawingContext &context,
209 const wxRect &rect, const Track *pTrack )
210{
211 auto target = dynamic_cast<NoteTrackButtonHandle*>( context.target.get() );
212 bool hit = target && target->GetTrack().get() == pTrack;
213 auto channel = hit ? target->GetChannel() : -1;
214 auto &dc = context.dc;
215 wxRect midiRect = rect;
216 GetMidiControlsHorizontalBounds(rect, midiRect);
218 ( static_cast<const NoteTrack *>(pTrack), dc, midiRect, channel );
219}
220}
221
222static const struct NoteTrackTCPLines
224 *static_cast<TCPLines*>(this) =
225 NoteTrackControlsBase::StaticNoteTCPLines();
226 insert( end(), {
229#ifdef EXPERIMENTAL_MIDI_OUT
231 VelocitySliderDrawFunction },
232#endif
233 } );
235
236void NoteTrackControls::GetVelocityRect(const wxPoint &topleft, wxRect & dest)
237{
240 dest.y = topleft.y + results.first;
241 dest.height = results.second;
242}
243
244void NoteTrackControls::GetMidiControlsRect(const wxRect & rect, wxRect & dest)
245{
247 auto results = TrackInfo::CalcItemY(
249 dest.y = rect.y + results.first;
250 dest.height = results.second;
251}
252
254{
256}
257
259{
260 return noteTrackTCPLines;
261};
262
263namespace {
264
265#ifdef EXPERIMENTAL_MIDI_OUT
266 std::unique_ptr<LWSlider>
267 gVelocityCaptured
268 , gVelocity
269 ;
270#endif
271
272}
273
274#ifdef EXPERIMENTAL_MIDI_OUT
276(const wxRect &sliderRect, const NoteTrack *t, bool captured, wxWindow *pParent)
277{
278 static std::once_flag flag;
279 std::call_once( flag, []{ ReCreateVelocitySlider({}); });
281
282 wxPoint pos = sliderRect.GetPosition();
283 float velocity = t ? t->GetVelocity() : 0.0;
284
285 gVelocity->Move(pos);
286 gVelocity->Set(velocity);
287 gVelocityCaptured->Move(pos);
288 gVelocityCaptured->Set(velocity);
289
290 auto slider = (captured ? gVelocityCaptured : gVelocity).get();
291 slider->SetParent( pParent );
292 return slider;
293}
294#endif
295
297{
298 if (message.appearance)
299 return;
300#ifdef EXPERIMENTAL_MIDI_OUT
301 wxPoint point{ 0, 0 };
302 wxRect sliderRect;
303 GetVelocityRect(point, sliderRect);
304
305 /* i18n-hint: Title of the Velocity slider, used to adjust the volume of note tracks */
306 gVelocity = std::make_unique<LWSlider>(nullptr, XO("Velocity"),
307 wxPoint(sliderRect.x, sliderRect.y),
308 wxSize(sliderRect.width, sliderRect.height),
309 VEL_SLIDER);
310 gVelocity->SetDefaultValue(0.0);
311 gVelocityCaptured = std::make_unique<LWSlider>(nullptr, XO("Velocity"),
312 wxPoint(sliderRect.x, sliderRect.y),
313 wxSize(sliderRect.width, sliderRect.height),
314 VEL_SLIDER);
315 gVelocityCaptured->SetDefaultValue(0.0);
316#endif
317}
318
321 return [](NoteTrack &track) {
322 return std::make_shared<NoteTrackControls>( track.SharedPointer() );
323 };
324}
325
326#include "../../../ui/TrackView.h"
327
330 return [](NoteTrack &) {
332 };
333}
334
335#endif
#define VEL_SLIDER
Definition: ASlider.h:37
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetNoteTrackControls)
EndSection()
NoteTrackTCPLines noteTrackTCPLines
@ OnUpOctaveID
@ OnDownOctaveID
TrackInfo::TCPLine TCPLine
BeginSection("Basic")
@ kMidiCellWidth
@ kMidiCellHeight
AppendItem("Up", OnUpOctaveID, XXO("Up &Octave"), POPUP_MENU_FN(OnChangeOctave))
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
THEME_API Theme theTheme
Definition: Theme.cpp:82
TrackInfo::TCPLines TCPLines
Definition: TrackInfo.cpp:98
@ kTrackInfoSliderExtra
Definition: ViewInfo.h:101
@ kTrackInfoBtnSize
Definition: ViewInfo.h:96
@ kTrackInfoSliderHeight
Definition: ViewInfo.h:98
static std::once_flag flag
@ kTrackInfoWidth
Definition: ZoomInfo.h:30
@ kLeftMargin
Definition: ZoomInfo.h:27
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
virtual std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *) override=0
std::shared_ptr< Track > FindTrack()
Lightweight version of ASlider. In other words it does not have a window permanently associated with ...
Definition: ASlider.h:64
static UIHandlePtr HitTest(std::weak_ptr< MuteButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
std::shared_ptr< NoteTrack > GetTrack() const
static UIHandlePtr HitTest(std::weak_ptr< NoteTrackButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< NoteTrack > &pTrack)
static void ReCreateVelocitySlider(struct ThemeChangeMessage)
static void GetMidiControlsRect(const wxRect &rect, wxRect &dest)
std::weak_ptr< NoteTrackButtonHandle > mClickHandle
std::weak_ptr< SoloButtonHandle > mSoloHandle
std::weak_ptr< VelocitySliderHandle > mVelocityHandle
static unsigned DefaultNoteTrackHeight()
const TCPLines & GetTCPLines() const override
static void GetVelocityRect(const wxPoint &topleft, wxRect &dest)
static LWSlider * VelocitySlider(const wxRect &sliderRect, const NoteTrack *t, bool captured, wxWindow *pParent)
std::weak_ptr< MuteButtonHandle > mMuteHandle
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:63
static void DrawLabelControls(const NoteTrack *pTrack, wxDC &dc, const wxRect &rect, int highlightedChannel=-1)
Definition: NoteTrack.cpp:255
void ShiftNoteRange(int offset)
Shifts all notes vertically by the given pitch.
Definition: NoteTrack.cpp:1028
void OnChangeOctave(wxCommandEvent &)
Scrolls the note track up or down by an octave.
void InitUserData(void *pUserData) override
Called before the menu items are appended.
DECLARE_POPUP_MENU(NoteTrackMenuTable)
NoteTrackControlsBase::InitMenuData * mpData
static NoteTrackMenuTable & Instance()
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static UIHandlePtr HitTest(std::weak_ptr< SoloButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:69
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:162
virtual ChannelType GetChannel() const
Definition: Track.h:411
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
AUDACITY_DLL_API void GetSliderHorizontalBounds(const wxPoint &topleft, wxRect &dest)
Definition: TrackInfo.cpp:484
AUDACITY_DLL_API unsigned DefaultTrackHeight(const TCPLines &topLines)
Definition: TrackInfo.cpp:562
AUDACITY_DLL_API std::pair< int, int > CalcItemY(const TCPLines &lines, unsigned iItem)
Definition: TrackInfo.cpp:142
void MidiControlsDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
void GetMidiControlsHorizontalBounds(const wxRect &rect, wxRect &dest)
void SliderDrawFunction(LWSlider *(*Selector)(const wxRect &sliderRect, const NoteTrack *t, bool captured, wxWindow *), wxDC *dc, const wxRect &rect, const Track *pTrack, wxWindow *pParent, bool captured, bool highlight)
For defining overrides of the method.
std::optional< PreferredSystemAppearance > appearance
Definition: Theme.h:112