Audacity 3.2.0
NoteTrackVRulerControls.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5NoteTrackVRulerControls.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12
13#ifdef USE_MIDI
15
17
18#include "../../../../HitTestResult.h"
19#include "../../../../NoteTrack.h"
20#include "ProjectHistory.h"
21#include "../../../../RefreshCode.h"
22#include "../../../../TrackArtist.h"
23#include "../../../../TrackPanelMouseEvent.h"
24
25#include "AColor.h"
26#include "../../../../TrackPanelDrawingContext.h"
27#include "../../../../widgets/LinearUpdater.h"
28#include "../../../../widgets/RealFormat.h"
29#include "../../../../widgets/Ruler.h"
30
31#include <wx/dc.h>
32#include <wx/event.h>
33
36{
37}
38
39std::vector<UIHandlePtr> NoteTrackVRulerControls::HitTest
40(const TrackPanelMouseState &st,
41 const AudacityProject *pProject)
42{
43 std::vector<UIHandlePtr> results;
44 UIHandlePtr result;
45
46 if ( st.state.GetX() <= st.rect.GetRight() - kGuard ) {
47 auto track = std::static_pointer_cast<NoteTrack>(FindTrack());
49 mVZoomHandle, st.state, track, st.rect);
50 if (result)
51 results.push_back(result);
52 }
53
54 auto more = TrackVRulerControls::HitTest(st, pProject);
55 std::copy(more.begin(), more.end(), std::back_inserter(results));
56
57 return results;
58}
59
61(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
62{
63 using namespace RefreshCode;
64 const wxMouseEvent &event = evt.event;
65
66 if (!(event.ShiftDown() || event.CmdDown()))
67 return RefreshNone;
68
69 // Always stop propagation even if the ruler didn't change. The ruler
70 // is a narrow enough target.
71 evt.event.Skip(false);
72
73 const auto pTrack = FindTrack();
74 if (!pTrack)
75 return RefreshNone;
76
77 auto steps = evt.steps;
78 const auto nt = static_cast<NoteTrack*>(pTrack.get());
79
80 if (event.CmdDown() && !event.ShiftDown()) {
81 if (steps > 0)
82 nt->ZoomIn(evt.rect, evt.event.m_y);
83 else
84 nt->ZoomOut(evt.rect, evt.event.m_y);
85 } else if (!event.CmdDown() && event.ShiftDown()) {
86 // Scroll some fixed number of notes, independent of zoom level or track height:
87 static const int movement = 6; // 6 semitones is half an octave
88 nt->ShiftNoteRange((int) (steps * movement));
89 } else {
90 return RefreshNone;
91 }
92
93 ProjectHistory::Get( *pProject ).ModifyState(false);
94
96}
97
100 const wxRect &rect_, unsigned iPass )
101{
102 TrackVRulerControls::Draw( context, rect_, iPass );
103
104 // Draw on a later pass like other vertical rulers,
105 // although the bevel is done a little differently
106
107 if ( iPass == TrackArtist::PassControls ) {
108 // The note track draws a vertical keyboard to label pitches
109 auto track = std::static_pointer_cast<NoteTrack>( FindTrack() );
110 if ( !track )
111 return;
112
113 auto rect = rect_;
114 --rect.width;
115 --rect.height;
116
117 bool highlight = false;
118#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
119 highlight = rect.Contains(context.lastState.GetPosition());
120#endif
121
122 const auto artist = TrackArtist::Get( context );
123 UpdateRuler(rect);
124
125 auto dc = &context.dc;
126
127 dc->SetPen(highlight ? AColor::uglyPen : *wxTRANSPARENT_PEN);
128 dc->SetBrush(*wxWHITE_BRUSH);
129 wxRect bev = rect;
130 bev.x++;
131 bev.width--;
132 dc->DrawRectangle(bev);
133
134 rect.y += 1;
135 rect.height -= 1;
136
137 NoteTrackDisplayData data{ track.get(), rect };
138
139 wxPen hilitePen;
140 hilitePen.SetColour(120, 120, 120);
141 wxBrush blackKeyBrush;
142 blackKeyBrush.SetColour(70, 70, 70);
143
144 dc->SetBrush(blackKeyBrush);
145
146 int fontSize = 10;
147#ifdef __WXMSW__
148 fontSize = 8;
149#endif
150
151 wxFont labelFont(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
152 dc->SetFont(labelFont);
153
154 int octave = 0;
155 int obottom = data.GetOctaveBottom(octave);
156 int marg = data.GetNoteMargin();
157
158 while (obottom >= rect.y) {
159 dc->SetPen(*wxBLACK_PEN);
160 for (int white = 0; white < 7; white++) {
161 int pos = data.GetWhitePos(white);
162 if (obottom - pos > rect.y + marg + 1 &&
163 // don't draw too close to margin line -- it's annoying
164 obottom - pos < rect.y + rect.height - marg - 3)
165 AColor::Line(*dc, rect.x, obottom - pos,
166 rect.x + rect.width, obottom - pos);
167 }
168 wxRect br = rect;
169 br.height = data.GetPitchHeight(1);
170 br.x++;
171 br.width = 17;
172 for (int black = 0; black < 5; black++) {
173 br.y = obottom - data.GetBlackPos(black);
174 if (br.y > rect.y + marg - 2 && br.y + br.height < rect.y + rect.height - marg) {
175 dc->SetPen(hilitePen);
176 dc->DrawRectangle(br);
177 dc->SetPen(*wxBLACK_PEN);
178 AColor::Line(*dc,
179 br.x + 1, br.y + br.height - 1,
180 br.x + br.width - 1, br.y + br.height - 1);
181 AColor::Line(*dc,
182 br.x + br.width - 1, br.y + 1,
183 br.x + br.width - 1, br.y + br.height - 1);
184 }
185 }
186
187 if (octave >= 1 && octave <= 10) {
188 wxString s;
189 // ISO standard: A440 is in the 4th octave, denoted
190 // A4 <- the "4" should be a subscript.
191 s.Printf(wxT("C%d"), octave - 1);
192 wxCoord width, height;
193 dc->GetTextExtent(s, &width, &height);
194 if (obottom - height + 4 > rect.y &&
195 obottom + 4 < rect.y + rect.height) {
196 dc->SetTextForeground(wxColour(60, 60, 255));
197 dc->DrawText(s, rect.x + rect.width - width,
198 obottom - height + 2);
199 }
200 }
201 obottom = data.GetOctaveBottom(++octave);
202 }
203 // draw lines delineating the out-of-bounds margins
204 dc->SetPen(*wxBLACK_PEN);
205 // you would think the -1 offset here should be -2 to match the
206 // adjustment to rect.y (see above), but -1 produces correct output
207 AColor::Line(*dc, rect.x, rect.y + marg - 1, rect.x + rect.width, rect.y + marg - 1);
208 // since the margin gives us the bottom of the line,
209 // the extra -1 gets us to the top
210 AColor::Line(*dc, rect.x, rect.y + rect.height - marg - 1,
211 rect.x + rect.width, rect.y + rect.height - marg - 1);
212
213 }
214}
215
216
217void NoteTrackVRulerControls::UpdateRuler( const wxRect &rect )
218{
219 // The note track isn't drawing a ruler at all!
220 // But it needs to!
221
222 const auto nt = std::static_pointer_cast< NoteTrack >( FindTrack() );
223 if (!nt)
224 return;
225
226 static Ruler ruler{
228 const auto vruler = &ruler;
229
230 vruler->SetBounds(rect.x, rect.y, rect.x + 1, rect.y + rect.height-1);
231 vruler->SetOrientation(wxVERTICAL);
232
233 vruler->GetMaxSize( &nt->vrulerSize.first, &nt->vrulerSize.second );
234}
235#endif
wxT("CloseDown"))
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
const int kGuard
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static wxPen uglyPen
Definition: AColor.h:141
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
std::shared_ptr< Track > FindTrack()
static const LinearUpdater & Instance()
Data used to display a note track.
Definition: NoteTrack.h:250
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:63
void ZoomIn(const wxRect &rect, int y)
Zooms in a constant factor (subject to zoom limits)
Definition: NoteTrack.h:142
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
std::weak_ptr< NoteTrackVZoomHandle > mVZoomHandle
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
void UpdateRuler(const wxRect &rect) override
unsigned HandleWheelRotation(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
static UIHandlePtr HitTest(std::weak_ptr< NoteTrackVZoomHandle > &holder, const wxMouseState &state, const std::shared_ptr< NoteTrack > &pTrack, const wxRect &rect)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static const RealFormat & LinearInstance()
Definition: RealFormat.cpp:14
Used to display a Ruler.
Definition: Ruler.h:28
void SetBounds(int left, int top, int right, int bottom)
Definition: Ruler.cpp:303
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:69
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16