Only show user-presets in favorite sidebar
[ardour.git] / gtk2_ardour / piano_roll_header.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <iostream>
20 #include "evoral/midi_events.h"
21 #include "ardour/midi_track.h"
22
23 #include "gtkmm2ext/keyboard.h"
24
25 #include "editing.h"
26 #include "piano_roll_header.h"
27 #include "midi_time_axis.h"
28 #include "midi_streamview.h"
29 #include "public_editor.h"
30 #include "ui_config.h"
31
32 using namespace std;
33 using namespace Gtkmm2ext;
34
35 PianoRollHeader::Color PianoRollHeader::white = PianoRollHeader::Color(0.77f, 0.78f, 0.76f);
36 PianoRollHeader::Color PianoRollHeader::white_highlight = PianoRollHeader::Color(1.00f, 0.40f, 0.40f);
37 PianoRollHeader::Color PianoRollHeader::white_shade_light = PianoRollHeader::Color(0.95f, 0.95f, 0.95f);
38 PianoRollHeader::Color PianoRollHeader::white_shade_dark = PianoRollHeader::Color(0.56f, 0.56f, 0.56f);
39
40 PianoRollHeader::Color PianoRollHeader::black = PianoRollHeader::Color(0.24f, 0.24f, 0.24f);
41 PianoRollHeader::Color PianoRollHeader::black_highlight = PianoRollHeader::Color(0.60f, 0.10f, 0.10f);
42 PianoRollHeader::Color PianoRollHeader::black_shade_light = PianoRollHeader::Color(0.46f, 0.46f, 0.46f);
43 PianoRollHeader::Color PianoRollHeader::black_shade_dark = PianoRollHeader::Color(0.1f, 0.1f, 0.1f);
44
45 PianoRollHeader::Color::Color()
46         : r(1.0f)
47         , g(1.0f)
48         , b(1.0f)
49 {
50 }
51
52 PianoRollHeader::Color::Color(double _r, double _g, double _b)
53         : r(_r)
54         , g(_g)
55         , b(_b)
56 {
57 }
58
59 inline void
60 PianoRollHeader::Color::set(const PianoRollHeader::Color& c)
61 {
62         r = c.r;
63         g = c.g;
64         b = c.b;
65 }
66
67 PianoRollHeader::PianoRollHeader(MidiStreamView& v)
68         : _view(v)
69         , _highlighted_note(NO_MIDI_NOTE)
70         , _clicked_note(NO_MIDI_NOTE)
71         , _dragging(false)
72 {
73         add_events (Gdk::BUTTON_PRESS_MASK |
74                     Gdk::BUTTON_RELEASE_MASK |
75                     Gdk::POINTER_MOTION_MASK |
76                     Gdk::ENTER_NOTIFY_MASK |
77                     Gdk::LEAVE_NOTIFY_MASK |
78                     Gdk::SCROLL_MASK);
79
80         for (int i = 0; i < 128; ++i) {
81                 _active_notes[i] = false;
82         }
83
84         _view.NoteRangeChanged.connect (sigc::mem_fun (*this, &PianoRollHeader::note_range_changed));
85 }
86
87 inline void
88 create_path(Cairo::RefPtr<Cairo::Context> cr, double x[], double y[], int start, int stop)
89 {
90         cr->move_to(x[start], y[start]);
91
92         for (int i = start+1; i <= stop; ++i) {
93                 cr->line_to(x[i], y[i]);
94         }
95 }
96
97 inline void
98 render_rect(Cairo::RefPtr<Cairo::Context> cr, int /*note*/, double x[], double y[],
99              PianoRollHeader::Color& bg, PianoRollHeader::Color& tl_shadow, PianoRollHeader::Color& br_shadow)
100 {
101         cr->set_source_rgb(bg.r, bg.g, bg.b);
102         create_path(cr, x, y, 0, 4);
103         cr->fill();
104
105         cr->set_source_rgb(tl_shadow.r, tl_shadow.g, tl_shadow.b);
106         create_path(cr, x, y, 0, 2);
107         cr->stroke();
108
109         cr->set_source_rgb(br_shadow.r, br_shadow.g, br_shadow.b);
110         create_path(cr, x, y, 2, 4);
111         cr->stroke();
112 }
113
114 inline void
115 render_cf(Cairo::RefPtr<Cairo::Context> cr, int /*note*/, double x[], double y[],
116                 PianoRollHeader::Color& bg, PianoRollHeader::Color& tl_shadow, PianoRollHeader::Color& br_shadow)
117 {
118         cr->set_source_rgb(bg.r, bg.g, bg.b);
119         create_path(cr, x, y, 0, 6);
120         cr->fill();
121
122         cr->set_source_rgb(tl_shadow.r, tl_shadow.g, tl_shadow.b);
123         create_path(cr, x, y, 0, 4);
124         cr->stroke();
125
126         cr->set_source_rgb(br_shadow.r, br_shadow.g, br_shadow.b);
127         create_path(cr, x, y, 4, 6);
128         cr->stroke();
129 }
130
131 inline void
132 render_eb(Cairo::RefPtr<Cairo::Context> cr, int /*note*/, double x[], double y[],
133                 PianoRollHeader::Color& bg, PianoRollHeader::Color& tl_shadow, PianoRollHeader::Color& br_shadow)
134 {
135         cr->set_source_rgb(bg.r, bg.g, bg.b);
136         create_path(cr, x, y, 0, 6);
137         cr->fill();
138
139         cr->set_source_rgb(tl_shadow.r, tl_shadow.g, tl_shadow.b);
140         create_path(cr, x, y, 0, 2);
141         cr->stroke();
142         create_path(cr, x, y, 4, 5);
143         cr->stroke();
144
145         cr->set_source_rgb(br_shadow.r, br_shadow.g, br_shadow.b);
146         create_path(cr, x, y, 2, 4);
147         cr->stroke();
148         create_path(cr, x, y, 5, 6);
149         cr->stroke();
150 }
151
152 inline void
153 render_dga(Cairo::RefPtr<Cairo::Context> cr, int /*note*/, double x[], double y[],
154                  PianoRollHeader::Color& bg, PianoRollHeader::Color& tl_shadow, PianoRollHeader::Color& br_shadow)
155 {
156         cr->set_source_rgb(bg.r, bg.g, bg.b);
157         create_path(cr, x, y, 0, 8);
158         cr->fill();
159
160         cr->set_source_rgb(tl_shadow.r, tl_shadow.g, tl_shadow.b);
161         create_path(cr, x, y, 0, 4);
162         cr->stroke();
163         create_path(cr, x, y, 6, 7);
164         cr->stroke();
165
166         cr->set_source_rgb(br_shadow.r, br_shadow.g, br_shadow.b);
167         create_path(cr, x, y, 4, 6);
168         cr->stroke();
169         create_path(cr, x, y, 7, 8);
170         cr->stroke();
171 }
172
173 void
174 PianoRollHeader::get_path(PianoRollHeader::ItemType note_type, int note, double x[], double y[])
175 {
176         double y_pos = floor(_view.note_to_y(note)) + 1.5f;
177         double note_height;
178         double other_y1 = floor(_view.note_to_y(note+1)) + floor(_note_height / 2.0f) + 2.5f;
179         double other_y2 = floor(_view.note_to_y(note-1)) + floor(_note_height / 2.0f) + 1.0f;
180         double width = get_width();
181
182         if (note == 0) {
183                 note_height = floor(_view.contents_height()) - y_pos + 2.;
184         } else {
185                 note_height = floor(_view.note_to_y(note - 1)) - y_pos + 2.;
186         }
187
188         switch (note_type) {
189         case BLACK_SEPARATOR:
190                 x[0] = 1.5f;
191                 y[0] = y_pos;
192                 x[1] = _black_note_width;
193                 y[1] = y_pos;
194                 break;
195         case BLACK_MIDDLE_SEPARATOR:
196                 x[0] = _black_note_width;
197                 y[0] = y_pos + floor(_note_height / 2.0f);
198                 x[1] = width - 1.0f;
199                 y[1] = y[0];
200                 break;
201         case BLACK:
202                 x[0] = 1.5f;
203                 y[0] = y_pos + note_height - 0.5f;
204                 x[1] = 1.5f;
205                 y[1] = y_pos + 1.0f;
206                 x[2] = _black_note_width;
207                 y[2] = y_pos + 1.0f;
208                 x[3] = _black_note_width;
209                 y[3] = y_pos + note_height - 0.5f;
210                 x[4] = 1.5f;
211                 y[4] = y_pos + note_height - 0.5f;
212                 return;
213         case WHITE_SEPARATOR:
214                 x[0] = 1.5f;
215                 y[0] = y_pos;
216                 x[1] = width - 1.5f;
217                 y[1] = y_pos;
218                 break;
219         case WHITE_RECT:
220                 x[0] = 1.5f;
221                 y[0] = y_pos + note_height - 0.5f;
222                 x[1] = 1.5f;
223                 y[1] = y_pos + 1.0f;
224                 x[2] = width - 1.5f;
225                 y[2] = y_pos + 1.0f;
226                 x[3] = width - 1.5f;
227                 y[3] = y_pos + note_height - 0.5f;
228                 x[4] = 1.5f;
229                 y[4] = y_pos + note_height - 0.5f;
230                 return;
231         case WHITE_CF:
232                 x[0] = 1.5f;
233                 y[0] = y_pos + note_height - 1.5f;
234                 x[1] = 1.5f;
235                 y[1] = y_pos + 1.0f;
236                 x[2] = _black_note_width + 1.0f;
237                 y[2] = y_pos + 1.0f;
238                 x[3] = _black_note_width + 1.0f;
239                 y[3] = other_y1;
240                 x[4] = width - 1.5f;
241                 y[4] = other_y1;
242                 x[5] = width - 1.5f;
243                 y[5] = y_pos + note_height - 1.5f;
244                 x[6] = 1.5f;
245                 y[6] = y_pos + note_height - 1.5f;
246                 return;
247         case WHITE_EB:
248                 x[0] = 1.5f;
249                 y[0] = y_pos + note_height - 1.5f;
250                 x[1] = 1.5f;
251                 y[1] = y_pos + 1.0f;
252                 x[2] = width - 1.5f;
253                 y[2] = y_pos + 1.0f;
254                 x[3] = width - 1.5f;
255                 y[3] = other_y2;
256                 x[4] = _black_note_width + 1.0f;
257                 y[4] = other_y2;
258                 x[5] = _black_note_width + 1.0f;
259                 y[5] = y_pos + note_height - 1.5f;
260                 x[6] = 1.5f;
261                 y[6] = y_pos + note_height - 1.5f;
262                 return;
263         case WHITE_DGA:
264                 x[0] = 1.5f;
265                 y[0] = y_pos + note_height - 1.5f;
266                 x[1] = 1.5f;
267                 y[1] = y_pos + 1.0f;
268                 x[2] = _black_note_width + 1.0f;
269                 y[2] = y_pos + 1.0f;
270                 x[3] = _black_note_width + 1.0f;
271                 y[3] = other_y1;
272                 x[4] = width - 1.5f;
273                 y[4] = other_y1;
274                 x[5] = width - 1.5f;
275                 y[5] = other_y2;
276                 x[6] = _black_note_width + 1.0f;
277                 y[6] = other_y2;
278                 x[7] = _black_note_width + 1.0f;
279                 y[7] = y_pos + note_height - 1.5f;
280                 x[8] = 1.5f;
281                 y[8] = y_pos + note_height - 1.5f;
282                 return;
283         default:
284                 return;
285         }
286 }
287
288 bool
289 PianoRollHeader::on_expose_event (GdkEventExpose* ev)
290 {
291         GdkRectangle& rect = ev->area;
292         double font_size;
293         int lowest, highest;
294         Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
295         Cairo::RefPtr<Cairo::LinearGradient> pat = Cairo::LinearGradient::create(0, 0, _black_note_width, 0);
296         double x[9];
297         double y[9];
298         Color bg, tl_shadow, br_shadow;
299         int oct_rel;
300         int y1 = max(rect.y, 0);
301         int y2 = min(rect.y + rect.height, (int) floor(_view.contents_height() - 1.0f));
302
303         //Cairo::TextExtents te;
304         lowest = max(_view.lowest_note(), _view.y_to_note(y2));
305         highest = min(_view.highest_note(), _view.y_to_note(y1));
306
307         if (lowest > 127) {
308                 lowest = 0;
309         }
310
311         cr->select_font_face ("Georgia", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD);
312         font_size = min((double) 10.0f, _note_height - 4.0f);
313         cr->set_font_size(font_size);
314
315         /* fill the entire rect with the color for non-highlighted white notes.
316          * then we won't have to draw the background for those notes,
317          * and would only have to draw the background for the one highlighted white note*/
318         //cr->rectangle(rect.x, rect.y, rect.width, rect.height);
319         //cr->set_source_rgb(white.r, white.g, white.b);
320         //cr->fill();
321
322         cr->set_line_width(1.0f);
323
324         /* draw vertical lines with shade at both ends of the widget */
325         cr->set_source_rgb(0.0f, 0.0f, 0.0f);
326         cr->move_to(0.5f, rect.y);
327         cr->line_to(0.5f, rect.y + rect.height);
328         cr->stroke();
329         cr->move_to(get_width() - 0.5f, rect.y);
330         cr->line_to(get_width() - 0.5f, rect.y + rect.height);
331         cr->stroke();
332
333         //pat->add_color_stop_rgb(0.0, 0.33, 0.33, 0.33);
334         //pat->add_color_stop_rgb(0.2, 0.39, 0.39, 0.39);
335         //pat->add_color_stop_rgb(1.0, 0.22, 0.22, 0.22);
336         //cr->set_source(pat);
337
338         for (int i = lowest; i <= highest; ++i) {
339                 oct_rel = i % 12;
340
341                 switch (oct_rel) {
342                 case 1:
343                 case 3:
344                 case 6:
345                 case 8:
346                 case 10:
347                         /* black note */
348                         if (i == _highlighted_note) {
349                                 bg.set(black_highlight);
350                         } else {
351                                 bg.set(black);
352                         }
353
354                         if (_active_notes[i]) {
355                                 tl_shadow.set(black_shade_dark);
356                                 br_shadow.set(black_shade_light);
357                         } else {
358                                 tl_shadow.set(black_shade_light);
359                                 br_shadow.set(black_shade_dark);
360                         }
361
362                         /* draw black separators */
363                         cr->set_source_rgb(0.0f, 0.0f, 0.0f);
364                         get_path(BLACK_SEPARATOR, i, x, y);
365                         create_path(cr, x, y, 0, 1);
366                         cr->stroke();
367
368                         get_path(BLACK_MIDDLE_SEPARATOR, i, x, y);
369                         create_path(cr, x, y, 0, 1);
370                         cr->stroke();
371
372                         get_path(BLACK, i, x, y);
373                         render_rect(cr, i, x, y, bg, tl_shadow, br_shadow);
374                         break;
375
376                 default:
377                         /* white note */
378                         if (i == _highlighted_note) {
379                                 bg.set(white_highlight);
380                         } else {
381                                 bg.set(white);
382                         }
383
384                         if (_active_notes[i]) {
385                                 tl_shadow.set(white_shade_dark);
386                                 br_shadow.set(white_shade_light);
387                         } else {
388                                 tl_shadow.set(white_shade_light);
389                                 br_shadow.set(white_shade_dark);
390                         }
391
392                         switch(oct_rel) {
393                         case 0:
394                         case 5:
395                                 if (i == _view.highest_note()) {
396                                         get_path(WHITE_RECT, i, x, y);
397                                         render_rect(cr, i, x, y, bg, tl_shadow, br_shadow);
398                                 } else {
399                                         get_path(WHITE_CF, i, x, y);
400                                         render_cf(cr, i, x, y, bg, tl_shadow, br_shadow);
401                                 }
402                                 break;
403
404                         case 2:
405                         case 7:
406                         case 9:
407                                 if (i == _view.highest_note()) {
408                                         get_path(WHITE_EB, i, x, y);
409                                         render_eb(cr, i, x, y, bg, tl_shadow, br_shadow);
410                                 } else if (i == _view.lowest_note()) {
411                                         get_path(WHITE_CF, i, x, y);
412                                         render_cf(cr, i, x, y, bg, tl_shadow, br_shadow);
413                                 } else {
414                                         get_path(WHITE_DGA, i, x, y);
415                                         render_dga(cr, i, x, y, bg, tl_shadow, br_shadow);
416                                 }
417                                 break;
418
419                         case 4:
420                         case 11:
421                                 cr->set_source_rgb(0.0f, 0.0f, 0.0f);
422                                 get_path(WHITE_SEPARATOR, i, x, y);
423                                 create_path(cr, x, y, 0, 1);
424                                 cr->stroke();
425
426                                 if (i == _view.lowest_note()) {
427                                         get_path(WHITE_RECT, i, x, y);
428                                         render_rect(cr, i, x, y, bg, tl_shadow, br_shadow);
429                                 } else {
430                                         get_path(WHITE_EB, i, x, y);
431                                         render_eb(cr, i, x, y, bg, tl_shadow, br_shadow);
432                                 }
433                                 break;
434
435                         default:
436                                 break;
437
438                         }
439                         break;
440
441                 }
442
443                 /* render the name of which C this is */
444                 if (oct_rel == 0) {
445                         std::stringstream s;
446                         double y = floor(_view.note_to_y(i)) - 0.5f;
447                         double note_height = floor(_view.note_to_y(i - 1)) - y;
448
449                         int cn = i / 12 - 1;
450                         s << "C" << cn;
451
452                         //cr->get_text_extents(s.str(), te);
453                         cr->set_source_rgb(0.30f, 0.30f, 0.30f);
454                         cr->move_to(2.0f, y + note_height - 1.0f - (note_height - font_size) / 2.0f);
455                         cr->show_text(s.str());
456                 }
457         }
458
459         return true;
460 }
461
462 bool
463 PianoRollHeader::on_motion_notify_event (GdkEventMotion* ev)
464 {
465         int note = _view.y_to_note(ev->y);
466         set_note_highlight (note);
467
468         if (_dragging) {
469
470                 if ( false /*editor().current_mouse_mode() == Editing::MouseRange*/ ) {   //ToDo:  fix this.  this mode is buggy, and of questionable utility anyway
471
472                         /* select note range */
473
474                         if (Keyboard::no_modifiers_active (ev->state)) {
475                                 AddNoteSelection (note); // EMIT SIGNAL
476                         }
477
478                 } else {
479                         /* play notes */
480                         /* redraw already taken care of above in set_note_highlight */
481                         if (_clicked_note != NO_MIDI_NOTE && _clicked_note != note) {
482                                 _active_notes[_clicked_note] = false;
483                                 send_note_off(_clicked_note);
484
485                                 _clicked_note = note;
486
487                                 if (!_active_notes[note]) {
488                                         _active_notes[note] = true;
489                                         send_note_on(note);
490                                 }
491                         }
492                 }
493         }
494
495         //win->process_updates(false);
496
497         return true;
498 }
499
500 bool
501 PianoRollHeader::on_button_press_event (GdkEventButton* ev)
502 {
503         int note = _view.y_to_note(ev->y);
504         bool tertiary = Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier);
505
506         if (ev->button == 2 && Keyboard::no_modifiers_active (ev->state)) {
507                 SetNoteSelection (note); // EMIT SIGNAL
508                 return true;
509         } else if (tertiary && (ev->button == 1 || ev->button == 2)) {
510                 ExtendNoteSelection (note); // EMIT SIGNAL
511                 return true;
512         } else if (ev->button == 1 && note >= 0 && note < 128) {
513                 add_modal_grab();
514                 _dragging = true;
515
516                 if (!_active_notes[note]) {
517                         _active_notes[note] = true;
518                         _clicked_note = note;
519                         send_note_on(note);
520
521                         invalidate_note_range(note, note);
522                 } else {
523                         reset_clicked_note(note);
524                 }
525         }
526
527         return true;
528 }
529
530 bool
531 PianoRollHeader::on_button_release_event (GdkEventButton* ev)
532 {
533         int note = _view.y_to_note(ev->y);
534
535         if (false /*editor().current_mouse_mode() == Editing::MouseRange*/ ) {  //Todo:  this mode is buggy, and of questionable utility anyway
536
537                 if (Keyboard::no_modifiers_active (ev->state)) {
538                         AddNoteSelection (note); // EMIT SIGNAL
539                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
540                         ToggleNoteSelection (note); // EMIT SIGNAL
541                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
542                         ExtendNoteSelection (note); // EMIT SIGNAL
543                 }
544
545         } else {
546
547                 if (_dragging) {
548                         remove_modal_grab();
549
550                         if (note == _clicked_note) {
551                                 reset_clicked_note(note);
552                         }
553                 }
554         }
555
556         _dragging = false;
557         return true;
558 }
559
560 void
561 PianoRollHeader::set_note_highlight (uint8_t note) {
562         if (_highlighted_note == note) {
563                 return;
564         }
565
566         if (_highlighted_note != NO_MIDI_NOTE) {
567                 if (note > _highlighted_note) {
568                         invalidate_note_range (_highlighted_note, note);
569                 } else {
570                         invalidate_note_range (note, _highlighted_note);
571                 }
572         }
573
574         _highlighted_note = note;
575
576         if (_highlighted_note != NO_MIDI_NOTE) {
577                 invalidate_note_range (_highlighted_note, _highlighted_note);
578         }
579 }
580
581 bool
582 PianoRollHeader::on_enter_notify_event (GdkEventCrossing* ev)
583 {
584         set_note_highlight (_view.y_to_note(ev->y));
585         return true;
586 }
587
588 bool
589 PianoRollHeader::on_leave_notify_event (GdkEventCrossing*)
590 {
591         invalidate_note_range(_highlighted_note, _highlighted_note);
592
593         if (_clicked_note != NO_MIDI_NOTE) {
594                 reset_clicked_note(_clicked_note, _clicked_note != _highlighted_note);
595         }
596
597         _highlighted_note = NO_MIDI_NOTE;
598         return true;
599 }
600
601 bool
602 PianoRollHeader::on_scroll_event (GdkEventScroll*)
603 {
604         return true;
605 }
606
607 void
608 PianoRollHeader::note_range_changed()
609 {
610         _note_height = floor(_view.note_height()) + 0.5f;
611         queue_draw();
612 }
613
614 void
615 PianoRollHeader::invalidate_note_range(int lowest, int highest)
616 {
617         Glib::RefPtr<Gdk::Window> win = get_window();
618         Gdk::Rectangle rect;
619
620         // the non-rectangular geometry of some of the notes requires more
621         // redraws than the notes that actually changed.
622         switch(lowest % 12) {
623         case 0:
624         case 5:
625                 lowest = max((int) _view.lowest_note(), lowest);
626                 break;
627         default:
628                 lowest = max((int) _view.lowest_note(), lowest - 1);
629                 break;
630         }
631
632         switch(highest % 12) {
633         case 4:
634         case 11:
635                 highest = min((int) _view.highest_note(), highest);
636                 break;
637         case 1:
638         case 3:
639         case 6:
640         case 8:
641         case 10:
642                 highest = min((int) _view.highest_note(), highest + 1);
643                 break;
644         default:
645                 highest = min((int) _view.highest_note(), highest + 2);
646                 break;
647         }
648
649         double y = _view.note_to_y(highest);
650         double height = _view.note_to_y(lowest - 1) - y;
651
652         rect.set_x(0);
653         rect.set_width(get_width());
654         rect.set_y((int) floor(y));
655         rect.set_height((int) floor(height));
656
657         if (win) {
658                 win->invalidate_rect(rect, false);
659         }
660 }
661
662 void
663 PianoRollHeader::on_size_request(Gtk::Requisition* r)
664 {
665         r->width = std::max (20.f, rintf (20.f * UIConfiguration::instance().get_ui_scale()));
666 }
667
668 void
669 PianoRollHeader::on_size_allocate(Gtk::Allocation& a)
670 {
671         DrawingArea::on_size_allocate(a);
672
673         _black_note_width = floor(0.7 * get_width()) + 0.5f;
674 }
675
676 void
677 PianoRollHeader::send_note_on(uint8_t note)
678 {
679         boost::shared_ptr<ARDOUR::MidiTrack> track = _view.trackview().midi_track();
680         MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (&_view.trackview ());
681
682         //cerr << "note on: " << (int) note << endl;
683
684         if (track) {
685                 _event[0] = (MIDI_CMD_NOTE_ON | mtv->get_channel_for_add ());
686                 _event[1] = note;
687                 _event[2] = 100;
688
689                 track->write_immediate_event(3, _event);
690         }
691 }
692
693 void
694 PianoRollHeader::send_note_off(uint8_t note)
695 {
696         boost::shared_ptr<ARDOUR::MidiTrack> track = _view.trackview().midi_track();
697         MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (&_view.trackview ());
698
699         if (track) {
700                 _event[0] = (MIDI_CMD_NOTE_OFF | mtv->get_channel_for_add ());
701                 _event[1] = note;
702                 _event[2] = 100;
703
704                 track->write_immediate_event(3, _event);
705         }
706 }
707
708 void
709 PianoRollHeader::reset_clicked_note (uint8_t note, bool invalidate)
710 {
711         _active_notes[note] = false;
712         _clicked_note = NO_MIDI_NOTE;
713         send_note_off (note);
714         if (invalidate) {
715                 invalidate_note_range (note, note);
716         }
717 }
718
719 PublicEditor&
720 PianoRollHeader::editor() const
721 {
722         return _view.trackview().editor();
723 }