Refactor note track rendering/position height code into own class
This will make later refactoring easier, and also fixes some const-correctness issues
This commit is contained in:
parent
3b312f9d1b
commit
8e8d838a08
|
@ -214,9 +214,11 @@ double NoteTrack::GetEndTime() const
|
|||
void NoteTrack::DoSetHeight(int h)
|
||||
{
|
||||
auto oldHeight = GetHeight();
|
||||
auto oldMargin = GetNoteMargin(oldHeight);
|
||||
NoteTrackDisplayData oldData = NoteTrackDisplayData(this, wxRect(0, 0, 1, oldHeight));
|
||||
auto oldMargin = oldData.GetNoteMargin();
|
||||
PlayableTrack::DoSetHeight(h);
|
||||
auto margin = GetNoteMargin(h);
|
||||
NoteTrackDisplayData newData = NoteTrackDisplayData(this, wxRect(0, 0, 1, h));
|
||||
auto margin = newData.GetNoteMargin();
|
||||
Zoom(
|
||||
wxRect{ 0, 0, 1, h }, // only height matters
|
||||
h - margin - 1, // preserve bottom note
|
||||
|
@ -979,17 +981,17 @@ void NoteTrack::Zoom(const wxRect &rect, int y, float multiplier, bool center)
|
|||
// Construct track rectangle to map pitch to screen coordinates
|
||||
// Only y and height are needed:
|
||||
wxRect trackRect(0, rect.GetY(), 1, rect.GetHeight());
|
||||
PrepareIPitchToY(trackRect);
|
||||
int clickedPitch = YToIPitch(y);
|
||||
NoteTrackDisplayData data = NoteTrackDisplayData(this, trackRect);
|
||||
int clickedPitch = data.YToIPitch(y);
|
||||
// zoom by changing the pitch height
|
||||
SetPitchHeight(rect.height, mPitchHeight * multiplier);
|
||||
PrepareIPitchToY(trackRect); // update because mPitchHeight changed
|
||||
NoteTrackDisplayData newData = NoteTrackDisplayData(this, trackRect); // update because mPitchHeight changed
|
||||
if (center) {
|
||||
int newCenterPitch = YToIPitch(rect.GetY() + rect.GetHeight() / 2);
|
||||
int newCenterPitch = newData.YToIPitch(rect.GetY() + rect.GetHeight() / 2);
|
||||
// center the pitch that the user clicked on
|
||||
SetBottomNote(mBottomNote + (clickedPitch - newCenterPitch));
|
||||
} else {
|
||||
int newClickedPitch = YToIPitch(y);
|
||||
int newClickedPitch = newData.YToIPitch(y);
|
||||
// align to keep the pitch that the user clicked on in the same place
|
||||
SetBottomNote(mBottomNote + (clickedPitch - newClickedPitch));
|
||||
}
|
||||
|
@ -999,9 +1001,9 @@ void NoteTrack::Zoom(const wxRect &rect, int y, float multiplier, bool center)
|
|||
void NoteTrack::ZoomTo(const wxRect &rect, int start, int end)
|
||||
{
|
||||
wxRect trackRect(0, rect.GetY(), 1, rect.GetHeight());
|
||||
PrepareIPitchToY(trackRect);
|
||||
int topPitch = YToIPitch(start);
|
||||
int botPitch = YToIPitch(end);
|
||||
NoteTrackDisplayData data = NoteTrackDisplayData(this, trackRect);
|
||||
int topPitch = data.YToIPitch(start);
|
||||
int botPitch = data.YToIPitch(end);
|
||||
if (topPitch < botPitch) { // swap
|
||||
int temp = topPitch; topPitch = botPitch; botPitch = temp;
|
||||
}
|
||||
|
@ -1013,7 +1015,20 @@ void NoteTrack::ZoomTo(const wxRect &rect, int start, int end)
|
|||
Zoom(rect, (start + end) / 2, trialPitchHeight / mPitchHeight, true);
|
||||
}
|
||||
|
||||
int NoteTrack::YToIPitch(int y)
|
||||
NoteTrackDisplayData::NoteTrackDisplayData(const NoteTrack* track, const wxRect &r)
|
||||
{
|
||||
mPitchHeight = track->mPitchHeight;
|
||||
mMargin = std::min(r.height / 4, (GetPitchHeight(1) + 1) / 2);
|
||||
|
||||
mBottom = r.y + r.height - GetNoteMargin() - 1 - GetPitchHeight(1) +
|
||||
(track->GetBottomNote() / 12) * GetOctaveHeight() +
|
||||
GetNotePos(track->GetBottomNote() % 12);
|
||||
}
|
||||
|
||||
int NoteTrackDisplayData::IPitchToY(int p) const
|
||||
{ return mBottom - (p / 12) * GetOctaveHeight() - GetNotePos(p % 12); }
|
||||
|
||||
int NoteTrackDisplayData::YToIPitch(int y) const
|
||||
{
|
||||
y = mBottom - y; // pixels above pitch 0
|
||||
int octave = (y / GetOctaveHeight());
|
||||
|
|
|
@ -64,9 +64,12 @@ using QuantizedTimeAndBeat = std::pair< double, double >;
|
|||
|
||||
class StretchHandle;
|
||||
|
||||
class NoteTrackDisplayData;
|
||||
|
||||
class AUDACITY_DLL_API NoteTrack final
|
||||
: public NoteTrackBase
|
||||
{
|
||||
friend class NoteTrackDisplayData;
|
||||
public:
|
||||
NoteTrack(const std::shared_ptr<DirManager> &projDirManager);
|
||||
virtual ~NoteTrack();
|
||||
|
@ -145,44 +148,6 @@ class AUDACITY_DLL_API NoteTrack final
|
|||
/// If center is true, the result will be centered at y.
|
||||
void Zoom(const wxRect &rect, int y, float multiplier, bool center);
|
||||
void ZoomTo(const wxRect &rect, int start, int end);
|
||||
int GetNoteMargin(int height) const
|
||||
{ return std::min(height / 4, (GetPitchHeight(1) + 1) / 2); }
|
||||
int GetOctaveHeight() const { return GetPitchHeight(12) + 2; }
|
||||
// call this once before a series of calls to IPitchToY(). It
|
||||
// sets mBottom to offset of octave 0 so that mBottomNote
|
||||
// is located at r.y + r.height - (GetNoteMargin() + 1 + GetPitchHeight())
|
||||
void PrepareIPitchToY(const wxRect &r) const {
|
||||
mBottom =
|
||||
r.y + r.height - GetNoteMargin(r.height) - 1 - GetPitchHeight(1) +
|
||||
(mBottomNote / 12) * GetOctaveHeight() +
|
||||
GetNotePos(mBottomNote % 12);
|
||||
}
|
||||
// IPitchToY returns Y coordinate of top of pitch p
|
||||
int IPitchToY(int p) const {
|
||||
return mBottom - (p / 12) * GetOctaveHeight() - GetNotePos(p % 12);
|
||||
}
|
||||
// compute the window coordinate of the bottom of an octave: This is
|
||||
// the bottom of the line separating B and C.
|
||||
int GetOctaveBottom(int oct) const {
|
||||
return IPitchToY(oct * 12) + GetPitchHeight(1) + 1;
|
||||
}
|
||||
// Y coordinate for given floating point pitch (rounded to int)
|
||||
int PitchToY(double p) const {
|
||||
return IPitchToY((int) (p + 0.5));
|
||||
}
|
||||
// Integer pitch corresponding to a Y coordinate
|
||||
int YToIPitch(int y);
|
||||
// map pitch class number (0-11) to pixel offset from bottom of octave
|
||||
// (the bottom of the black line between B and C) to the top of the
|
||||
// note. Note extra pixel separates B(11)/C(0) and E(4)/F(5).
|
||||
int GetNotePos(int p) const
|
||||
{ return 1 + GetPitchHeight(p + 1) + (p > 4); }
|
||||
// get pixel offset to top of ith black key note
|
||||
int GetBlackPos(int i) const { return GetNotePos(i * 2 + 1 + (i > 1)); }
|
||||
// GetWhitePos tells where to draw lines between keys as an offset from
|
||||
// GetOctaveBottom. GetWhitePos(0) returns 1, which matches the location
|
||||
// of the line separating B and C
|
||||
int GetWhitePos(int i) const { return 1 + (i * GetOctaveHeight()) / 7; }
|
||||
void SetBottomNote(int note)
|
||||
{
|
||||
if (note < 0)
|
||||
|
@ -254,10 +219,11 @@ class AUDACITY_DLL_API NoteTrack final
|
|||
float mVelocity; // velocity offset
|
||||
#endif
|
||||
|
||||
// mBottom is the Y offset of pitch 0 (normally off screen)
|
||||
mutable int mBottom;
|
||||
int mBottomNote;
|
||||
#if 0
|
||||
// Also unused from vertical scrolling
|
||||
int mStartBottomNote;
|
||||
#endif
|
||||
|
||||
// Remember continuous variation for zooming,
|
||||
// but it is rounded off whenever drawing:
|
||||
|
@ -275,6 +241,47 @@ protected:
|
|||
std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override;
|
||||
};
|
||||
|
||||
class NoteTrackDisplayData {
|
||||
private:
|
||||
float mPitchHeight;
|
||||
// mBottom is the Y offset of pitch 0 (normally off screen)
|
||||
// Used so that mBottomNote is located at
|
||||
// mY + mHeight - (GetNoteMargin() + 1 + GetPitchHeight())
|
||||
int mBottom;
|
||||
int mMargin;
|
||||
public:
|
||||
NoteTrackDisplayData(const NoteTrack* track, const wxRect &r);
|
||||
|
||||
int GetPitchHeight(int factor) const
|
||||
{ return std::max(1, (int)(factor * mPitchHeight)); }
|
||||
int GetNoteMargin() const { return mMargin; };
|
||||
int GetOctaveHeight() const { return GetPitchHeight(12) + 2; }
|
||||
// IPitchToY returns Y coordinate of top of pitch p
|
||||
int IPitchToY(int p) const;
|
||||
// compute the window coordinate of the bottom of an octave: This is
|
||||
// the bottom of the line separating B and C.
|
||||
int GetOctaveBottom(int oct) const {
|
||||
return IPitchToY(oct * 12) + GetPitchHeight(1) + 1;
|
||||
}
|
||||
// Y coordinate for given floating point pitch (rounded to int)
|
||||
int PitchToY(double p) const {
|
||||
return IPitchToY((int) (p + 0.5));
|
||||
}
|
||||
// Integer pitch corresponding to a Y coordinate
|
||||
int YToIPitch(int y) const;
|
||||
// map pitch class number (0-11) to pixel offset from bottom of octave
|
||||
// (the bottom of the black line between B and C) to the top of the
|
||||
// note. Note extra pixel separates B(11)/C(0) and E(4)/F(5).
|
||||
int GetNotePos(int p) const
|
||||
{ return 1 + GetPitchHeight(p + 1) + (p > 4); }
|
||||
// get pixel offset to top of ith black key note
|
||||
int GetBlackPos(int i) const { return GetNotePos(i * 2 + 1 + (i > 1)); }
|
||||
// GetWhitePos tells where to draw lines between keys as an offset from
|
||||
// GetOctaveBottom. GetWhitePos(0) returns 1, which matches the location
|
||||
// of the line separating B and C
|
||||
int GetWhitePos(int i) const { return 1 + (i * GetOctaveHeight()) / 7; }
|
||||
};
|
||||
|
||||
#endif // USE_MIDI
|
||||
|
||||
#ifndef SONIFY
|
||||
|
|
|
@ -138,36 +138,6 @@ namespace {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_MIDI
|
||||
/*
|
||||
const int octaveHeight = 62;
|
||||
const int blackPos[5] = { 6, 16, 32, 42, 52 };
|
||||
const int whitePos[7] = { 0, 9, 17, 26, 35, 44, 53 };
|
||||
const int notePos[12] = { 1, 6, 11, 16, 21, 27,
|
||||
32, 37, 42, 47, 52, 57 };
|
||||
|
||||
// map pitch number to window coordinate of the *top* of the note
|
||||
// Note the "free" variable bottom, which is assumed to be a local
|
||||
// variable set to the offset of pitch 0 relative to the window
|
||||
#define IPITCH_TO_Y(t, p) (bottom - ((p) / 12) * octaveHeight - \
|
||||
notePos[(p) % 12] - (t)->GetPitchHeight())
|
||||
|
||||
// GetBottom is called from a couple of places to compute the hypothetical
|
||||
// coordinate of the bottom of pitch 0 in window coordinates. See
|
||||
// IPITCH_TO_Y above, which computes coordinates relative to GetBottom()
|
||||
// Note the -NOTE_MARGIN, which leaves a little margin to draw notes that
|
||||
// are out of bounds. I'm not sure why the -2 is necessary.
|
||||
int TrackArt::GetBottom(NoteTrack *t, const wxRect &rect)
|
||||
{
|
||||
int bottomNote = t->GetBottomNote();
|
||||
int bottom = rect.y + rect.height - 2 - t->GetNoteMargin() +
|
||||
((bottomNote / 12) * octaveHeight + notePos[bottomNote % 12]);
|
||||
return bottom;
|
||||
|
||||
}
|
||||
*/
|
||||
#endif // USE_MIDI
|
||||
|
||||
TrackArtist::TrackArtist( TrackPanel *parent_ )
|
||||
: parent( parent_ )
|
||||
{
|
||||
|
@ -549,8 +519,7 @@ void TrackArt::DrawVRuler
|
|||
rect.y += 1;
|
||||
rect.height -= 1;
|
||||
|
||||
//int bottom = GetBottom(track, rect);
|
||||
track->PrepareIPitchToY(rect);
|
||||
NoteTrackDisplayData data = NoteTrackDisplayData(track, rect);
|
||||
|
||||
wxPen hilitePen;
|
||||
hilitePen.SetColour(120, 120, 120);
|
||||
|
@ -568,13 +537,13 @@ void TrackArt::DrawVRuler
|
|||
dc->SetFont(labelFont);
|
||||
|
||||
int octave = 0;
|
||||
int obottom = track->GetOctaveBottom(octave);
|
||||
int marg = track->GetNoteMargin(rect.height);
|
||||
//IPITCH_TO_Y(octave * 12) + PITCH_HEIGHT + 1;
|
||||
int obottom = data.GetOctaveBottom(octave);
|
||||
int marg = data.GetNoteMargin();
|
||||
|
||||
while (obottom >= rect.y) {
|
||||
dc->SetPen(*wxBLACK_PEN);
|
||||
for (int white = 0; white < 7; white++) {
|
||||
int pos = track->GetWhitePos(white);
|
||||
int pos = data.GetWhitePos(white);
|
||||
if (obottom - pos > rect.y + marg + 1 &&
|
||||
// don't draw too close to margin line -- it's annoying
|
||||
obottom - pos < rect.y + rect.height - marg - 3)
|
||||
|
@ -582,11 +551,11 @@ void TrackArt::DrawVRuler
|
|||
rect.x + rect.width, obottom - pos);
|
||||
}
|
||||
wxRect br = rect;
|
||||
br.height = track->GetPitchHeight(1);
|
||||
br.height = data.GetPitchHeight(1);
|
||||
br.x++;
|
||||
br.width = 17;
|
||||
for (int black = 0; black < 5; black++) {
|
||||
br.y = obottom - track->GetBlackPos(black);
|
||||
br.y = obottom - data.GetBlackPos(black);
|
||||
if (br.y > rect.y + marg - 2 && br.y + br.height < rect.y + rect.height - marg) {
|
||||
dc->SetPen(hilitePen);
|
||||
dc->DrawRectangle(br);
|
||||
|
@ -614,7 +583,7 @@ void TrackArt::DrawVRuler
|
|||
obottom - height + 2);
|
||||
}
|
||||
}
|
||||
obottom = track->GetOctaveBottom(++octave);
|
||||
obottom = data.GetOctaveBottom(++octave);
|
||||
}
|
||||
// draw lines delineating the out-of-bounds margins
|
||||
dc->SetPen(*wxBLACK_PEN);
|
||||
|
@ -2844,16 +2813,17 @@ void TrackArt::DrawNoteBackground(TrackPanelDrawingContext &context,
|
|||
// need overlap between MIDI data and the background region
|
||||
if (left >= right) return;
|
||||
|
||||
NoteTrackDisplayData data = NoteTrackDisplayData(track, rect);
|
||||
dc.SetBrush(bb);
|
||||
int octave = 0;
|
||||
// obottom is the window coordinate of octave divider line
|
||||
int obottom = track->GetOctaveBottom(octave);
|
||||
int obottom = data.GetOctaveBottom(octave);
|
||||
// eOffset is for the line between E and F; there's another line
|
||||
// between B and C, hence the offset of 2 for two line thicknesses
|
||||
int eOffset = track->GetPitchHeight(5) + 2;
|
||||
while (obottom > rect.y + track->GetNoteMargin(rect.height) + 3) {
|
||||
int eOffset = data.GetPitchHeight(5) + 2;
|
||||
while (obottom > rect.y + data.GetNoteMargin() + 3) {
|
||||
// draw a black line separating octaves if this octave botton is visible
|
||||
if (obottom < rect.y + rect.height - track->GetNoteMargin(rect.height)) {
|
||||
if (obottom < rect.y + rect.height - data.GetNoteMargin()) {
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
// obottom - 1 because obottom is at the bottom of the line
|
||||
AColor::Line(dc, left, obottom - 1, right, obottom - 1);
|
||||
|
@ -2869,14 +2839,14 @@ void TrackArt::DrawNoteBackground(TrackPanelDrawingContext &context,
|
|||
wxRect br;
|
||||
br.x = left;
|
||||
br.width = right - left;
|
||||
br.height = track->GetPitchHeight(1);
|
||||
br.height = data.GetPitchHeight(1);
|
||||
for (int black = 0; black < 5; black++) {
|
||||
br.y = obottom - track->GetBlackPos(black);
|
||||
br.y = obottom - data.GetBlackPos(black);
|
||||
if (br.y > rect.y && br.y + br.height < rect.y + rect.height) {
|
||||
dc.DrawRectangle(br); // draw each black key background stripe
|
||||
}
|
||||
}
|
||||
obottom = track->GetOctaveBottom(++octave);
|
||||
obottom = data.GetOctaveBottom(++octave);
|
||||
}
|
||||
|
||||
// draw bar lines
|
||||
|
@ -2940,17 +2910,13 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
if (!track->GetSelected())
|
||||
sel0 = sel1 = 0.0;
|
||||
|
||||
NoteTrackDisplayData data = NoteTrackDisplayData(track, rect);
|
||||
|
||||
// reserve 1/2 note height at top and bottom of track for
|
||||
// out-of-bounds notes
|
||||
int numPitches = (rect.height) / track->GetPitchHeight(1);
|
||||
int numPitches = (rect.height) / data.GetPitchHeight(1);
|
||||
if (numPitches < 0) numPitches = 0; // cannot be negative
|
||||
|
||||
// bottom is the hypothetical location of the bottom of pitch 0 relative to
|
||||
// the top of the clipping region rect: rect.height - PITCH_HEIGHT/2 is where the
|
||||
// bottomNote is displayed, and to that
|
||||
// we add the height of bottomNote from the position of pitch 0
|
||||
track->PrepareIPitchToY(rect);
|
||||
|
||||
#ifdef EXPERIMENTAL_NOTETRACK_OVERLAY
|
||||
DrawBackgroundWithSelection(context, rect, track,
|
||||
AColor::labelSelectedBrush, AColor::labelUnselectedBrush);
|
||||
|
@ -3005,7 +2971,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
selectedBarLinePen);
|
||||
SonifyEndNoteBackground();
|
||||
SonifyBeginNoteForeground();
|
||||
int marg = track->GetNoteMargin(rect.height);
|
||||
int marg = data.GetNoteMargin();
|
||||
|
||||
// NOTE: it would be better to put this in some global initialization
|
||||
// function rather than do lookups every time.
|
||||
|
@ -3051,8 +3017,8 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
const char *shape = NULL;
|
||||
if (note->loud > 0.0 || 0 == (shape = IsShape(note))) {
|
||||
wxRect nr; // "note rectangle"
|
||||
nr.y = track->PitchToY(note->pitch);
|
||||
nr.height = track->GetPitchHeight(1);
|
||||
nr.y = data.PitchToY(note->pitch);
|
||||
nr.height = data.GetPitchHeight(1);
|
||||
|
||||
nr.x = TIME_TO_X(xx);
|
||||
nr.width = TIME_TO_X(x1) - nr.x;
|
||||
|
@ -3093,7 +3059,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
else
|
||||
AColor::MIDIChannel(&dc, note->chan + 1);
|
||||
dc.DrawRectangle(nr);
|
||||
if (track->GetPitchHeight(1) > 2) {
|
||||
if (data.GetPitchHeight(1) > 2) {
|
||||
AColor::LightMIDIChannel(&dc, note->chan + 1);
|
||||
AColor::Line(dc, nr.x, nr.y, nr.x + nr.width-2, nr.y);
|
||||
AColor::Line(dc, nr.x, nr.y, nr.x, nr.y + nr.height-2);
|
||||
|
@ -3111,7 +3077,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
// add 0.5 to pitch because pitches are plotted with
|
||||
// height = PITCH_HEIGHT; thus, the center is raised
|
||||
// by PITCH_HEIGHT * 0.5
|
||||
int yy = track->PitchToY(note->pitch);
|
||||
int yy = data.PitchToY(note->pitch);
|
||||
long linecolor = LookupIntAttribute(note, linecolori, -1);
|
||||
long linethick = LookupIntAttribute(note, linethicki, 1);
|
||||
long fillcolor = -1;
|
||||
|
@ -3137,7 +3103,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
wxBRUSHSTYLE_SOLID));
|
||||
if (!fillflag) dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
}
|
||||
int y1 = track->PitchToY(LookupRealAttribute(note, y1r, note->pitch));
|
||||
int y1 = data.PitchToY(LookupRealAttribute(note, y1r, note->pitch));
|
||||
if (shape == line) {
|
||||
// extreme zooms caues problems under windows, so we have to do some
|
||||
// clipping before calling display routine
|
||||
|
@ -3168,7 +3134,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
points[1].y = y1;
|
||||
points[2].x = TIME_TO_X(LookupRealAttribute(note, x2r, xx));
|
||||
CLIP(points[2].x);
|
||||
points[2].y = track->PitchToY(LookupRealAttribute(note, y2r, note->pitch));
|
||||
points[2].y = data.PitchToY(LookupRealAttribute(note, y2r, note->pitch));
|
||||
dc.DrawPolygon(3, points);
|
||||
} else if (shape == polygon) {
|
||||
wxPoint points[20]; // upper bound of 20 sides
|
||||
|
@ -3180,7 +3146,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
points[1].y = y1;
|
||||
points[2].x = TIME_TO_X(LookupRealAttribute(note, x2r, xx));
|
||||
CLIP(points[2].x);
|
||||
points[2].y = track->PitchToY(LookupRealAttribute(note, y2r, note->pitch));
|
||||
points[2].y = data.PitchToY(LookupRealAttribute(note, y2r, note->pitch));
|
||||
int n = 3;
|
||||
while (n < 20) {
|
||||
char name[8];
|
||||
|
@ -3194,7 +3160,7 @@ void TrackArt::DrawNoteTrack(TrackPanelDrawingContext &context,
|
|||
attr = symbol_table.insert_string(name);
|
||||
double yn = LookupRealAttribute(note, attr, -1000000.0);
|
||||
if (yn == -1000000.0) break;
|
||||
points[n].y = track->PitchToY(yn);
|
||||
points[n].y = data.PitchToY(yn);
|
||||
n++;
|
||||
}
|
||||
dc.DrawPolygon(n, points);
|
||||
|
|
|
@ -92,7 +92,6 @@ namespace TrackArt {
|
|||
const WaveTrack *track,
|
||||
const wxRect & rect);
|
||||
#ifdef USE_MIDI
|
||||
int GetBottom(NoteTrack *t, const wxRect &rect);
|
||||
void DrawNoteBackground(TrackPanelDrawingContext &context,
|
||||
const NoteTrack *track,
|
||||
const wxRect &rect, const wxRect &sel,
|
||||
|
|
Loading…
Reference in New Issue