21#include "../../../../HitTestResult.h"
24#include "../../../../TrackArt.h"
25#include "../../../../TrackArtist.h"
26#include "../../../../TrackPanelDrawingContext.h"
27#include "../../../../TrackPanelMouseEvent.h"
29#include "../../../ui/SelectHandle.h"
50 std::vector<UIHandlePtr> results;
52#ifdef EXPERIMENTAL_MIDI_STRETCHING
54 mStretchHandle, state, pProject, FindChannel<NoteTrack>());
56 results.push_back(result);
66 return std::make_shared<NoteTrackView>(
74 std::make_shared<NoteTrackVRulerControls>( shared_from_this() );
77#define TIME_TO_X(t) (zoomInfo.TimeToPosition((t), rect.x))
78#define X_TO_TIME(xx) (zoomInfo.PositionToTime((xx), rect.x))
146 Alg_parameters_ptr parameters = note->parameters;
148 if (strcmp(parameters->parm.attr_name(),
"shapea") == 0) {
149 return parameters->parm.a;
151 parameters = parameters->next;
159 Alg_parameters_ptr parameters = note->parameters;
161 if (parameters->parm.attr_name() == attr + 1 &&
162 parameters->parm.attr_type() ==
'r') {
163 return parameters->parm.r;
165 parameters = parameters->next;
173 Alg_parameters_ptr parameters = note->parameters;
175 if (parameters->parm.attr_name() == attr + 1 &&
176 parameters->parm.attr_type() ==
'i') {
177 return parameters->parm.i;
179 parameters = parameters->next;
187 Alg_parameters_ptr parameters = note->parameters;
189 if (parameters->parm.attr_name() == attr + 1 &&
190 parameters->parm.attr_type() ==
'l') {
191 return parameters->parm.l;
193 parameters = parameters->next;
201 Alg_parameters_ptr parameters = note->parameters;
203 if (parameters->parm.attr_name() == attr + 1 &&
204 parameters->parm.attr_type() ==
's') {
205 return parameters->parm.s;
207 parameters = parameters->next;
215 Alg_parameters_ptr parameters = note->parameters;
217 if (parameters->parm.attr_name() == attr + 1 &&
218 parameters->parm.attr_type() ==
'a') {
219 return parameters->parm.s;
221 parameters = parameters->next;
233#define CLIP_MAX 16000
234#define CLIP(xx) { long c = (xx); if (c < -CLIP_MAX) c = -CLIP_MAX; \
235 if (c > CLIP_MAX) c = CLIP_MAX; (xx) = c; }
237#define RED(i) ( unsigned char )( (((i) >> 16) & 0xff) )
238#define GREEN(i) ( unsigned char )( (((i) >> 8) & 0xff) )
239#define BLUE(i) ( unsigned char )( ((i) & 0xff) )
263 const NoteTrack &track,
const wxRect &rect,
const wxRect &sel,
264 const wxBrush &wb,
const wxPen &wp,
const wxBrush &bb,
const wxPen &bp,
267 auto &dc = context.
dc;
269 const auto &zoomInfo = *artist->pZoomInfo;
275 if (left < sel.x) left = sel.x;
278 if (right > sel.x + sel.width) right = sel.x + sel.width;
281 if (left >= right)
return;
287 int obottom = data.GetOctaveBottom(octave);
290 int eOffset = data.GetPitchHeight(5) + 2;
291 while (obottom > rect.y + data.GetNoteMargin() + 3) {
293 if (obottom < rect.y + rect.height - data.GetNoteMargin()) {
294 dc.SetPen(*wxBLACK_PEN);
296 AColor::Line(dc, left, obottom - 1, right, obottom - 1);
300 if (obottom - eOffset > rect.y && obottom - eOffset < rect.y + rect.height) {
302 right, obottom - eOffset);
308 br.width = right - left;
309 br.height = data.GetPitchHeight(1);
310 for (
int black = 0; black < 5; black++) {
311 br.y = obottom - data.GetBlackPos(black);
312 if (br.y > rect.y && br.y + br.height < rect.y + rect.height) {
313 dc.DrawRectangle(br);
316 obottom = data.GetOctaveBottom(++octave);
320 Alg_seq_ptr seq = &track.
GetSeq();
331 Alg_time_sigs &sigs = seq->time_sig;
333 double next_bar_beat = 0.0;
334 double beats_per_measure = 4.0;
336 if (i < sigs.length() && sigs[i].beat < next_bar_beat + ALG_EPS) {
338 Alg_time_sig &sig = sigs[i++];
339 next_bar_beat = sig.beat;
340 beats_per_measure = (sig.num * 4.0) / sig.den;
343 double t = seq->get_time_map()->beat_to_time(next_bar_beat);
346 if (xx > right)
break;
348 next_bar_beat += beats_per_measure;
359 const NoteTrack &track,
const wxRect & rect,
bool muted,
bool selected)
361 auto &dc = context.
dc;
363 const auto &selectedRegion = *artist->pSelectedRegion;
364 const auto &zoomInfo = *artist->pZoomInfo;
367 double sel0 = selectedRegion.t0();
368 double sel1 = selectedRegion.t1();
371 const double h1 =
X_TO_TIME(rect.x + rect.width);
373 Alg_seq_ptr seq = &track.
GetSeq();
382 int numPitches = (rect.height) / data.GetPitchHeight(1);
383 if (numPitches < 0) numPitches = 0;
391 wxPen blackStripePen;
393 wxBrush blackStripeBrush;
398 const auto &blankBrush = artist->blankBrush;
399 const auto &blankPen = artist->blankPen;
401 blackStripeBrush, blackStripePen, barLinePen);
403 dc.SetClippingRegion(rect);
410 selBG.height = rect.height;
414 wxPen selectedWhiteKeyPen;
415 selectedWhiteKeyPen.SetColour(165, 165, 190);
416 dc.SetPen(selectedWhiteKeyPen);
418 wxBrush selectedWhiteKeyBrush;
421 wxPen selectedBlackKeyPen;
423 wxBrush selectedBlackKeyBrush;
425 wxPen selectedBarLinePen;
429 selectedWhiteKeyBrush, selectedWhiteKeyPen,
430 selectedBlackKeyBrush, selectedBlackKeyPen,
434 int marg = data.GetNoteMargin();
438 Alg_attribute line = symbol_table.insert_string(
"line");
439 Alg_attribute
rectangle = symbol_table.insert_string(
"rectangle");
440 Alg_attribute
triangle = symbol_table.insert_string(
"triangle");
441 Alg_attribute polygon = symbol_table.insert_string(
"polygon");
442 Alg_attribute oval = symbol_table.insert_string(
"oval");
443 Alg_attribute text = symbol_table.insert_string(
"text");
444 Alg_attribute texts = symbol_table.insert_string(
"texts");
445 Alg_attribute x1r = symbol_table.insert_string(
"x1r");
446 Alg_attribute x2r = symbol_table.insert_string(
"x2r");
447 Alg_attribute y1r = symbol_table.insert_string(
"y1r");
448 Alg_attribute y2r = symbol_table.insert_string(
"y2r");
449 Alg_attribute linecolori = symbol_table.insert_string(
"linecolori");
450 Alg_attribute fillcolori = symbol_table.insert_string(
"fillcolori");
451 Alg_attribute linethicki = symbol_table.insert_string(
"linethicki");
452 Alg_attribute filll = symbol_table.insert_string(
"filll");
453 Alg_attribute fonta = symbol_table.insert_string(
"fonta");
454 Alg_attribute roman = symbol_table.insert_string(
"roman");
455 Alg_attribute swiss = symbol_table.insert_string(
"swiss");
456 Alg_attribute modern = symbol_table.insert_string(
"modern");
457 Alg_attribute weighta = symbol_table.insert_string(
"weighta");
458 Alg_attribute bold = symbol_table.insert_string(
"bold");
459 Alg_attribute sizei = symbol_table.insert_string(
"sizei");
460 Alg_attribute justifys = symbol_table.insert_string(
"justifys");
463 seq->convert_to_seconds();
465 Alg_iterator iterator(seq,
false);
469 while (0 != (evt = iterator.next())) {
470 if (evt->get_type() ==
'n') {
471 Alg_note_ptr note = (Alg_note_ptr) evt;
475 double x1 = xx + note->dur;
476 if (xx < h1 && x1 > h) {
477 const char *shape = NULL;
478 if (note->loud > 0.0 || 0 == (shape =
IsShape(note))) {
480 nr.y = data.PitchToY(note->pitch);
481 nr.height = data.GetPitchHeight(1);
486 if (nr.x + nr.width >= rect.x && nr.x < rect.x + rect.width) {
488 nr.width -= (rect.x - nr.x);
491 if (nr.x + nr.width > rect.x + rect.width)
492 nr.width = rect.x + rect.width - nr.x;
494 if (nr.y + nr.height < rect.y + marg + 3) {
498 dc.SetBrush(*wxBLACK_BRUSH);
499 dc.SetPen(*wxBLACK_PEN);
500 dc.DrawRectangle(nr);
501 }
else if (nr.y >= rect.y + rect.height - marg - 1) {
503 nr.y = rect.y + rect.height - marg;
505 dc.SetBrush(*wxBLACK_BRUSH);
506 dc.SetPen(*wxBLACK_PEN);
507 dc.DrawRectangle(nr);
509 if (nr.y + nr.height > rect.y + rect.height - marg)
510 nr.height = rect.y + rect.height - nr.y;
511 if (nr.y < rect.y + marg) {
512 int offset = rect.y + marg - nr.y;
521 dc.DrawRectangle(nr);
522 if (data.GetPitchHeight(1) > 2) {
528 nr.x+nr.width-1, nr.y+nr.height-1);
530 nr.x+nr.width-1, nr.y+nr.height-1);
540 int yy = data.PitchToY(note->pitch);
550 dc.SetPen(wxPen(wxColour(
RED(linecolor),
553 linethick, wxPENSTYLE_SOLID));
560 dc.SetBrush(wxBrush(wxColour(
RED(fillcolor),
563 wxBRUSHSTYLE_SOLID));
564 if (!fillflag) dc.SetBrush(*wxTRANSPARENT_BRUSH);
571 yy = (int)((yy + (y1 - yy) * (h - xx) / (x1 - xx)) + 0.5);
575 y1 = (int)((yy + (y1 - yy) * (h1 - xx) / (x1 - xx)) + 0.5);
581 xx =
X_TO_TIME(rect.x - (linethick + 10));
584 xx =
X_TO_TIME(rect.x + rect.width + linethick + 10);
598 dc.DrawPolygon(3, points);
599 }
else if (shape == polygon) {
613 sprintf(
name,
"x%dr", n);
614 Alg_attribute attr = symbol_table.insert_string(
name);
616 if (xn == -1000000.0)
break;
619 sprintf(
name,
"y%dr", n - 1);
620 attr = symbol_table.insert_string(
name);
622 if (yn == -1000000.0)
break;
623 points[n].y = data.PitchToY(yn);
626 dc.DrawPolygon(n, points);
627 }
else if (shape == oval) {
632 dc.DrawEllipse(ix, yy, ix1, y1 - yy + 1);
633 }
else if (shape == text) {
635 dc.SetTextForeground(wxColour(
RED(linecolor),
639 else dc.SetTextForeground(dc.GetBrush().GetColour());
654 wxfont.SetFamily(font == roman ? wxFONTFAMILY_ROMAN :
655 (font == swiss ? wxFONTFAMILY_SWISS :
656 (font == modern ? wxFONTFAMILY_MODERN : wxFONTFAMILY_DEFAULT)));
657 wxfont.SetStyle(wxFONTSTYLE_NORMAL);
658 wxfont.SetWeight(weight == bold ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL);
659 wxfont.SetPointSize(
size);
664 wxCoord textWidth, textHeight;
665 dc.GetTextExtent(wxString::FromUTF8(s), &textWidth, &textHeight);
667 long voffset = -textHeight;
669 if (strlen(justify) != 2) justify =
"ld";
671 if (justify[0] ==
'c') hoffset = -(textWidth/2);
672 else if (justify[0] ==
'r') hoffset = -textWidth;
674 if (justify[1] ==
't') voffset = 0;
675 else if (justify[1] ==
'c') voffset = -(textHeight/2);
676 else if (justify[1] ==
'b') voffset = -textHeight;
681 dc.SetPen(wxPen(wxColour(
RED(fillcolor),
684 1, wxPENSTYLE_SOLID));
685 dc.DrawRectangle(
TIME_TO_X(xx) + hoffset, yy + voffset,
686 textWidth, textHeight);
697 dc.SetPen(*wxBLACK_PEN);
698 AColor::Line(dc, rect.x, rect.y + marg, rect.x + rect.width, rect.y + marg);
699 AColor::Line(dc, rect.x, rect.y + rect.height - marg - 1,
700 rect.x + rect.width, rect.y + rect.height - marg - 1);
714 dc.DestroyClippingRegion();
722 const wxRect &rect,
unsigned iPass )
725 const auto &pendingTracks = *artist->pPendingTracks;
731 const auto &nt =
static_cast<const NoteTrack&
>(
732 pendingTracks.SubstitutePendingChangedChannel(*pChannel));
735 const auto hasSolo = artist->hasSolo;
736 muted = (hasSolo || nt.GetMute()) && !nt.GetSolo();
740 bool selected{
false };
741 if (
auto affordance = std::dynamic_pointer_cast<NoteTrackAffordanceControls>(
GetAffordanceControls()))
743 selected = affordance->IsSelected();
std::shared_ptr< UIHandle > UIHandlePtr
#define SonifyBeginNoteBackground()
#define SonifyEndNoteBackground()
#define SonifyBeginNoteForeground()
#define SonifyEndNoteForeground()
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetNoteTrackView)
@ Grouped
Can be part of a group.
static wxBrush labelSelectedBrush
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
static void LightMIDIChannel(wxDC *dc, int channel)
static void MIDIChannel(wxDC *dc, int channel)
static wxBrush labelUnselectedBrush
static void DarkMIDIChannel(wxDC *dc, int channel)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
double GetStartTime() const
Get the minimum of Start() values of intervals, or 0 when none.
std::shared_ptr< Track > DoFindTrack() override
auto FindChannel() -> std::shared_ptr< Subtype >
May return null.
Implements some hit-testing shared by many ChannelView subtypes.
Temporary data used to display a note track.
A Track that is used for Midi notes. (Somewhat old code).
bool IsVisibleChan(int c) const
std::shared_ptr< CommonTrackCell > mpAffordanceCellControl
std::vector< UIHandlePtr > DetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool) override
std::shared_ptr< CommonTrackCell > GetAffordanceControls() override
NoteTrackView(const NoteTrackView &)=delete
~NoteTrackView() override
std::shared_ptr< ChannelVRulerControls > DoGetVRulerControls() override
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
static UIHandlePtr HitTest(std::weak_ptr< StretchHandle > &holder, const TrackPanelMouseState &state, const AudacityProject *pProject, const std::shared_ptr< NoteTrack > &pTrack)
wxColour & Colour(int iIndex)
static TrackArtist * Get(TrackPanelDrawingContext &)
bool GetSelected() const
Selectedness is always the same for all channels of a group.
std::shared_ptr< Subclass > SharedPointer()
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
AUDACITY_DLL_API void DrawBackgroundWithSelection(TrackPanelDrawingContext &context, const wxRect &rect, const Channel &channel, const wxBrush &selBrush, const wxBrush &unselBrush, bool useSelection=true, bool useBeatsAlternateColor=false)
Helper: draws background with selection rect.
AUDACITY_DLL_API void DrawClipEdges(wxDC &dc, const wxRect &clipRect, bool selected=false)
AUDACITY_DLL_API void DrawNegativeOffsetTrackArrows(TrackPanelDrawingContext &context, const wxRect &rect)
bool LookupLogicalAttribute(Alg_note_ptr note, Alg_attribute attr, bool def)
const char * IsShape(Alg_note_ptr note)
const char * LookupStringAttribute(Alg_note_ptr note, Alg_attribute attr, const char *def)
const char * LookupAtomAttribute(Alg_note_ptr note, Alg_attribute attr, char *def)
double LookupRealAttribute(Alg_note_ptr note, Alg_attribute attr, double def)
void DrawNoteTrack(TrackPanelDrawingContext &context, const NoteTrack &track, const wxRect &rect, bool muted, bool selected)
void DrawNoteBackground(TrackPanelDrawingContext &context, const NoteTrack &track, const wxRect &rect, const wxRect &sel, const wxBrush &wb, const wxPen &wp, const wxBrush &bb, const wxPen &bp, const wxPen &mp)
long LookupIntAttribute(Alg_note_ptr note, Alg_attribute attr, long def)
For defining overrides of the method.