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
18
19#include "../../../ui/ChannelView.h"
20#include "../../../../HitTestResult.h"
21#include "NoteTrack.h"
22#include "ProjectHistory.h"
23#include "../../../../RefreshCode.h"
24#include "../../../../TrackArtist.h"
25#include "../../../../TrackPanelMouseEvent.h"
26
27#include "AColor.h"
28#include "../../../../TrackPanelDrawingContext.h"
29#include "../../../../widgets/LinearUpdater.h"
30#include "../../../../widgets/RealFormat.h"
31#include "../../../../widgets/Ruler.h"
32
33#include <wx/dc.h>
34#include <wx/event.h>
35
38{
39}
40
41std::vector<UIHandlePtr> NoteTrackVRulerControls::HitTest
42(const TrackPanelMouseState &st,
43 const AudacityProject *pProject)
44{
45 std::vector<UIHandlePtr> results;
46 UIHandlePtr result;
47
48 if ( st.state.GetX() <= st.rect.GetRight() - kGuard ) {
49 const auto track = FindNoteTrack();
51 mVZoomHandle, st.state, track, st.rect);
52 if (result)
53 results.push_back(result);
54 }
55
56 auto more = ChannelVRulerControls::HitTest(st, pProject);
57 std::copy(more.begin(), more.end(), std::back_inserter(results));
58
59 return results;
60}
61
62std::shared_ptr<NoteTrack> NoteTrackVRulerControls::FindNoteTrack()
63{
64 return FindChannel<NoteTrack>();
65}
66
68(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
69{
70 using namespace RefreshCode;
71 const wxMouseEvent &event = evt.event;
72
73 if (!(event.ShiftDown() || event.CmdDown()))
74 return RefreshNone;
75
76 // Always stop propagation even if the ruler didn't change. The ruler
77 // is a narrow enough target.
78 evt.event.Skip(false);
79
80 const auto nt = FindNoteTrack();
81 if (!nt)
82 return RefreshNone;
83
84 auto steps = evt.steps;
85
86 if (event.CmdDown() && !event.ShiftDown()) {
87 NoteTrackDisplayData data{ *nt, evt.rect };
88 if (steps > 0)
89 data.ZoomIn(evt.event.m_y);
90 else
91 data.ZoomOut(evt.event.m_y);
92 } else if (!event.CmdDown() && event.ShiftDown()) {
93 // Scroll some fixed number of notes, independent of zoom level or track height:
94 static const int movement = 6; // 6 semitones is half an octave
95 NoteTrackRange::Get(*nt).ShiftNoteRange((int) (steps * movement));
96 } else {
97 return RefreshNone;
98 }
99
100 ProjectHistory::Get( *pProject ).ModifyState(false);
101
102 return RefreshCell | UpdateVRuler;
103}
104
107 const wxRect &rect_, unsigned iPass )
108{
109 ChannelVRulerControls::Draw(context, rect_, iPass);
110
111 // Draw on a later pass like other vertical rulers,
112 // although the bevel is done a little differently
113
114 if ( iPass == TrackArtist::PassControls ) {
115 // The note track draws a vertical keyboard to label pitches
116 auto track = FindNoteTrack();
117 if (!track)
118 return;
119
120 auto rect = rect_;
121 --rect.width;
122 --rect.height;
123
124 bool highlight = false;
125#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
126 highlight = rect.Contains(context.lastState.GetPosition());
127#endif
128
129 const auto artist = TrackArtist::Get( context );
130 UpdateRuler(rect);
131
132 auto dc = &context.dc;
133
134 dc->SetPen(highlight ? AColor::uglyPen : *wxTRANSPARENT_PEN);
135 dc->SetBrush(*wxWHITE_BRUSH);
136 wxRect bev = rect;
137 bev.x++;
138 bev.width--;
139 dc->DrawRectangle(bev);
140
141 rect.y += 1;
142 rect.height -= 1;
143
144 NoteTrackDisplayData data{ *track, rect };
145
146 wxPen hilitePen;
147 hilitePen.SetColour(120, 120, 120);
148 wxBrush blackKeyBrush;
149 blackKeyBrush.SetColour(70, 70, 70);
150
151 dc->SetBrush(blackKeyBrush);
152
153 int fontSize = 10;
154#ifdef __WXMSW__
155 fontSize = 8;
156#endif
157
158 wxFont labelFont(fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
159 dc->SetFont(labelFont);
160
161 int octave = 0;
162 int obottom = data.GetOctaveBottom(octave);
163 int marg = data.GetNoteMargin();
164
165 while (obottom >= rect.y) {
166 dc->SetPen(*wxBLACK_PEN);
167 for (int white = 0; white < 7; white++) {
168 int pos = data.GetWhitePos(white);
169 if (obottom - pos > rect.y + marg + 1 &&
170 // don't draw too close to margin line -- it's annoying
171 obottom - pos < rect.y + rect.height - marg - 3)
172 AColor::Line(*dc, rect.x, obottom - pos,
173 rect.x + rect.width, obottom - pos);
174 }
175 wxRect br = rect;
176 br.height = data.GetPitchHeight(1);
177 br.x++;
178 br.width = 17;
179 for (int black = 0; black < 5; black++) {
180 br.y = obottom - data.GetBlackPos(black);
181 if (br.y > rect.y + marg - 2 && br.y + br.height < rect.y + rect.height - marg) {
182 dc->SetPen(hilitePen);
183 dc->DrawRectangle(br);
184 dc->SetPen(*wxBLACK_PEN);
185 AColor::Line(*dc,
186 br.x + 1, br.y + br.height - 1,
187 br.x + br.width - 1, br.y + br.height - 1);
188 AColor::Line(*dc,
189 br.x + br.width - 1, br.y + 1,
190 br.x + br.width - 1, br.y + br.height - 1);
191 }
192 }
193
194 if (octave >= 1 && octave <= 10) {
195 wxString s;
196 // ISO standard: A440 is in the 4th octave, denoted
197 // A4 <- the "4" should be a subscript.
198 s.Printf(wxT("C%d"), octave - 1);
199 wxCoord width, height;
200 dc->GetTextExtent(s, &width, &height);
201 if (obottom - height + 4 > rect.y &&
202 obottom + 4 < rect.y + rect.height) {
203 dc->SetTextForeground(wxColour(60, 60, 255));
204 dc->DrawText(s, rect.x + rect.width - width,
205 obottom - height + 2);
206 }
207 }
208 obottom = data.GetOctaveBottom(++octave);
209 }
210 // draw lines delineating the out-of-bounds margins
211 dc->SetPen(*wxBLACK_PEN);
212 // you would think the -1 offset here should be -2 to match the
213 // adjustment to rect.y (see above), but -1 produces correct output
214 AColor::Line(*dc, rect.x, rect.y + marg - 1, rect.x + rect.width, rect.y + marg - 1);
215 // since the margin gives us the bottom of the line,
216 // the extra -1 gets us to the top
217 AColor::Line(*dc, rect.x, rect.y + rect.height - marg - 1,
218 rect.x + rect.width, rect.y + rect.height - marg - 1);
219
220 }
221}
222
223
225{
226 // The note track isn't drawing a ruler at all!
227 // But it needs to!
228
229 const auto nt = FindNoteTrack();
230 if (!nt)
231 return;
232
233 static Ruler ruler{
235 const auto vruler = &ruler;
236
237 vruler->SetBounds(rect.x, rect.y, rect.x + 1, rect.y + rect.height - 1);
238 vruler->SetOrientation(wxVERTICAL);
239
240 auto &size = ChannelView::Get(*nt).vrulerSize;
241 vruler->GetMaxSize(&size.first, &size.second);
242}
243#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:194
static wxPen uglyPen
Definition: AColor.h:140
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::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
static ChannelView & Get(Channel &channel)
std::pair< int, int > vrulerSize
Definition: ChannelView.h:129
static const LinearUpdater & Instance()
Temporary data used to display a note track.
static NoteTrackRange & Get(const NoteTrack &track)
Allow mutative access to attached data of a const track.
void ShiftNoteRange(int offset)
Shifts all notes vertically by the given pitch.
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
std::shared_ptr< NoteTrack > FindNoteTrack()
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:34
void SetBounds(int left, int top, int right, int bottom)
Definition: Ruler.cpp:304
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:81
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40