diff --git a/gtk2_ardour/midi_cue_background.cc b/gtk2_ardour/midi_cue_background.cc index 50097938c4..7ca91d3638 100644 --- a/gtk2_ardour/midi_cue_background.cc +++ b/gtk2_ardour/midi_cue_background.cc @@ -42,6 +42,8 @@ CueMidiBackground::set_size (double w, double h) _height = h; update_contents_height (); + + HeightChanged (); /* EMIT SIGNAL */ } double diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index 94f96f531d..892fe4ae26 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -188,6 +188,15 @@ MidiCueEditor::build_canvas () bg = new CueMidiBackground (data_group); _canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &MidiCueEditor::canvas_allocate)); + prh = new ArdourCanvas::PianoRollHeader (v_scroll_group, *bg); + + double w, h; + prh->size_request (w, h); + + prh->set_position (Duple (0., n_timebars * timebar_height)); + data_group->set_position (ArdourCanvas::Duple (w, timebar_height * n_timebars)); + h_scroll_group->set_position (Duple (w, 0.)); + _canvas->set_name ("MidiCueCanvas"); _canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); _canvas->set_can_focus (); @@ -317,18 +326,16 @@ MidiCueEditor::set_region (std::shared_ptr t, std::shared_ptr view->set_region (r); bg->set_view (view); - - delete prh; - prh = new ArdourCanvas::PianoRollHeader (v_scroll_group, *view); + prh->set_view (*view); double w, h; prh->size_request (w, h); /* Move stuff around */ - prh->move (Duple (0., n_timebars * timebar_height)); - data_group->move (ArdourCanvas::Duple (w, timebar_height * n_timebars)); - h_scroll_group->move (Duple (w, 0.)); + prh->set_position (Duple (0., n_timebars * timebar_height)); + data_group->set_position (ArdourCanvas::Duple (w, timebar_height * n_timebars)); + h_scroll_group->set_position (Duple (w, 0.)); /* Compute zoom level to show entire source plus some margin if possible */ diff --git a/gtk2_ardour/midi_view_background.cc b/gtk2_ardour/midi_view_background.cc index 6d582d637f..c359be927c 100644 --- a/gtk2_ardour/midi_view_background.cc +++ b/gtk2_ardour/midi_view_background.cc @@ -52,6 +52,8 @@ MidiViewBackground::MidiViewBackground (ArdourCanvas::Item* parent) note_range_adjustment.set_page_size(_highest_note - _lowest_note); note_range_adjustment.set_value(_lowest_note); + note_range_adjustment.set_lower(0); + note_range_adjustment.set_upper(127); note_range_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &MidiViewBackground::note_range_adjustment_changed)); } diff --git a/gtk2_ardour/midi_view_background.h b/gtk2_ardour/midi_view_background.h index adcbb5d3dc..088a641457 100644 --- a/gtk2_ardour/midi_view_background.h +++ b/gtk2_ardour/midi_view_background.h @@ -27,6 +27,8 @@ #include +#include "pbd/signals.h" + #include "ardour/types.h" #include "gtkmm2ext/colors.h" @@ -97,6 +99,9 @@ class MidiViewBackground : public virtual ViewBackground virtual void set_note_highlight (bool) = 0; virtual void record_layer_check (std::shared_ptr, samplepos_t) = 0; + virtual void set_size (double w, double h) {} + PBD::Signal0 HeightChanged; + protected: bool _range_dirty; double _range_sum_cache; diff --git a/gtk2_ardour/prh.cc b/gtk2_ardour/prh.cc index 23e039ad29..1dacfae315 100644 --- a/gtk2_ardour/prh.cc +++ b/gtk2_ardour/prh.cc @@ -31,13 +31,15 @@ #include "gtkmm2ext/keyboard.h" #include "gtkmm2ext/rgb_macros.h" +#include "midi++/midnam_patch.h" + #include "editing.h" +#include "gui_thread.h" #include "midi_view.h" #include "midi_view_background.h" #include "prh.h" #include "editing_context.h" #include "ui_config.h" -#include "midi++/midnam_patch.h" #include "pbd/i18n.h" @@ -46,11 +48,11 @@ using namespace Gtkmm2ext; namespace ArdourCanvas { -PianoRollHeader::PianoRollHeader (Item* parent, MidiView& v) +PianoRollHeader::PianoRollHeader (Item* parent, MidiViewBackground& bg) : Rectangle (parent) - , have_note_names (false) - , _adj (v.midi_context().note_range_adjustment) - , _view (v) + , _midi_context (bg) + , _adj (_midi_context.note_range_adjustment) + , _view (nullptr) , _font_descript ("Sans Bold") , _font_descript_big_c ("Sans") , _font_descript_midnam ("Sans") @@ -67,6 +69,7 @@ PianoRollHeader::PianoRollHeader (Item* parent, MidiView& v) , _saved_bottom_val (127.0) , _mini_map_display (false) , entered (false) + , have_note_names (false) { Glib::RefPtr context = _canvas->get_pango_context(); @@ -76,26 +79,16 @@ PianoRollHeader::PianoRollHeader (Item* parent, MidiView& v) _big_c_layout->set_font_description(_font_descript_big_c); _midnam_layout = Pango::Layout::create (context); - _adj.set_lower(0); - _adj.set_upper(127); - - /* set minimum view range to one octave */ - //set_min_page_size(12); - - //_adj = v->note_range_adjustment; - for (int i = 0; i < 128; ++i) { _active_notes[i] = false; } - _view.midi_context().NoteRangeChanged.connect (sigc::mem_fun (*this, &PianoRollHeader::note_range_changed)); - - double w, h; - size_request (w, h); - - set (Rect (0., 0., w, h)); + resize (); + bg.HeightChanged.connect (height_connection, MISSING_INVALIDATOR, boost::bind (&PianoRollHeader::resize, this), gui_context()); /* draw vertical lines on both sides of the rectangle */ + set_fill (false); + set_fill (true); set_outline_color (0x000000ff); /* XXX theme me */ set_outline_what (Rectangle::What (Rectangle::LEFT|Rectangle::RIGHT)); @@ -103,23 +96,32 @@ PianoRollHeader::PianoRollHeader (Item* parent, MidiView& v) } void -PianoRollHeader::size_request (double& w, double& h) const +PianoRollHeader::resize () { - h = _view.midi_context().contents_height(); - - if (show_scroomer()) { - w = 60.f * UIConfiguration::instance().get_ui_scale(); - } else { - w = 20.f * UIConfiguration::instance().get_ui_scale(); - } - - w += 20.; + double w, h; + size_request (w, h); + set (Rect (0., 0., w, h)); } void -PianoRollHeader::size_allocate (ArdourCanvas::Rect const &r) +PianoRollHeader::set_view (MidiView& v) { - _alloc = r; + _view = &v; + _view->midi_context().NoteRangeChanged.connect (sigc::mem_fun (*this, &PianoRollHeader::note_range_changed)); +} + +void +PianoRollHeader::size_request (double& w, double& h) const +{ + h = _midi_context.contents_height(); + + if (show_scroomer()) { + _scroomer_size = 60.f * UIConfiguration::instance().get_ui_scale(); + } else { + _scroomer_size = 20.f * UIConfiguration::instance().get_ui_scale(); + } + + w = _scroomer_size + 20.; } bool @@ -174,7 +176,7 @@ render_rect(Cairo::RefPtr cr, int note, double x[], double y[], } void -PianoRollHeader::render_scroomer(Cairo::RefPtr cr) const +PianoRollHeader::render_scroomer (Cairo::RefPtr cr) const { double scroomer_top = max (1.0, (1.0 - ((_adj.get_value()+_adj.get_page_size()) / 127.0)) * get().height () ); double scroomer_bottom = (1.0 - (_adj.get_value () / 127.0)) * get().height (); @@ -212,16 +214,20 @@ PianoRollHeader::render_scroomer(Cairo::RefPtr cr) const bool PianoRollHeader::scroll_handler (GdkEventScroll* ev) { + if (!_view) { + return false; + } + int note_range = _adj.get_page_size (); int note_lower = _adj.get_value (); if(ev->state == GDK_SHIFT_MASK){ switch (ev->direction) { case GDK_SCROLL_UP: //ZOOM IN - _view.apply_note_range (min(note_lower + 1, 127), max(note_lower + note_range - 1,0), true); + _view->apply_note_range (min(note_lower + 1, 127), max(note_lower + note_range - 1,0), true); break; case GDK_SCROLL_DOWN: //ZOOM OUT - _view.apply_note_range (max(note_lower - 1,0), min(note_lower + note_range + 1, 127), true); + _view->apply_note_range (max(note_lower - 1,0), min(note_lower + note_range + 1, 127), true); break; default: return false; @@ -240,7 +246,7 @@ PianoRollHeader::scroll_handler (GdkEventScroll* ev) } Duple evd (canvas_to_item (Duple (ev->x, ev->y))); - set_note_highlight (_view.midi_context().y_to_note (evd.y)); + set_note_highlight (_view->midi_context().y_to_note (evd.y)); _adj.value_changed (); redraw (); @@ -251,14 +257,14 @@ PianoRollHeader::scroll_handler (GdkEventScroll* ev) void PianoRollHeader::get_path (int note, double x[], double y[]) const { - double y_pos = floor(_view.midi_context().note_to_y(note)); + double y_pos = floor(_midi_context.note_to_y(note)); double note_height; double width = get().width() - 1.0f; if (note == 0) { - note_height = floor(_view.midi_context().contents_height()) - y_pos; + note_height = floor(_midi_context.contents_height()) - y_pos; } else { - note_height = _view.midi_context().note_height() <= 3 ? _view.midi_context().note_height() : _view.midi_context().note_height() - 1.f; + note_height = _midi_context.note_height() <= 3 ? _midi_context.note_height() : _midi_context.note_height() - 1.f; } x[0] = _scroomer_size; @@ -288,6 +294,10 @@ PianoRollHeader::render (ArdourCanvas::Rect const & area, Cairo::RefPtrsave (); @@ -296,8 +306,8 @@ PianoRollHeader::render (ArdourCanvas::Rect const & area, Cairo::RefPtrset_font_description(_font_descript_midnam); - lowest = max(_view.midi_context().lowest_note(), _view.midi_context().y_to_note(y2)); - highest = min(_view.midi_context().highest_note(), _view.midi_context().y_to_note(y1)); + lowest = max(_midi_context.lowest_note(), _midi_context.y_to_note(y2)); + highest = min(_midi_context.highest_note(), _midi_context.y_to_note(y1)); if (lowest > 127) { lowest = 0; @@ -355,7 +365,7 @@ PianoRollHeader::render (ArdourCanvas::Rect const & area, Cairo::RefPtrset_text (note.name); @@ -466,19 +476,19 @@ PianoRollHeader::render (ArdourCanvas::Rect const & area, Cairo::RefPtr 12.0){ @@ -523,8 +533,9 @@ PianoRollHeader::instrument_info_change () width. */ - - _view.midi_track()->gui_changed ("visible_tracks", (void *) 0); /* EMIT SIGNAL */ + if (_view) { + _view->midi_track()->gui_changed ("visible_tracks", (void *) 0); /* EMIT SIGNAL */ + } } @@ -609,28 +620,34 @@ PianoRollHeader::get_note_name (int note) bool PianoRollHeader::motion_handler (GdkEventMotion* ev) { + if (!_view) { + return false; + } + Duple evd (canvas_to_item (Duple (ev->x, ev->y))); if (!_scroomer_drag && ev->x < _scroomer_size){ + Gdk::Cursor m_Cursor; double scroomer_top = max(1.0, (1.0 - ((_adj.get_value()+_adj.get_page_size()) / 127.0)) * get().height()); double scroomer_bottom = (1.0 - (_adj.get_value () / 127.0)) * get().height(); if (evd.y > scroomer_top - 5 && evd.y < scroomer_top + 5){ m_Cursor = Gdk::Cursor (Gdk::TOP_SIDE); - _view.editing_context().push_canvas_cursor (&m_Cursor); + _view->editing_context().push_canvas_cursor (&m_Cursor); _scroomer_state = TOP; - }else if (evd.y > scroomer_bottom - 5 && evd.y < scroomer_bottom + 5){ + } else if (evd.y > scroomer_bottom - 5 && evd.y < scroomer_bottom + 5){ m_Cursor = Gdk::Cursor (Gdk::BOTTOM_SIDE); - _view.editing_context().push_canvas_cursor (&m_Cursor); + _view->editing_context().push_canvas_cursor (&m_Cursor); _scroomer_state = BOTTOM; - }else { + } else { _scroomer_state = MOVE; - _view.editing_context().pop_canvas_cursor (); + _view->editing_context().pop_canvas_cursor (); } } if (_scroomer_drag){ + double pixel2val = 127.0 / get().height(); double delta = _old_y - evd.y; double val_at_pointer = (delta * pixel2val); @@ -647,30 +664,32 @@ PianoRollHeader::motion_handler (GdkEventMotion* ev) case TOP: real_val_at_pointer = real_val_at_pointer <= _saved_top_val? _adj.get_value() + _adj.get_page_size() : real_val_at_pointer; real_val_at_pointer = min(127.0, real_val_at_pointer); - if (_view.midi_context().note_height() >= UIConfiguration::instance().get_max_note_height()){ + if (_midi_context.note_height() >= UIConfiguration::instance().get_max_note_height()){ _saved_top_val = min(_adj.get_value() + _adj.get_page_size (), 127.0); } else { _saved_top_val = 0.0; } //if we are at largest note size & the user is moving down don't do anything //FIXME we are using a heuristic of 18.5 for max note size, but this changes when track size is small to 19.5? - _view.midi_context().apply_note_range (_adj.get_value (), real_val_at_pointer, true); + _midi_context.apply_note_range (_adj.get_value (), real_val_at_pointer, true); break; case BOTTOM: real_val_at_pointer = max(0.0, real_val_at_pointer); real_val_at_pointer = real_val_at_pointer >= _saved_bottom_val? _adj.get_value() : real_val_at_pointer; - if (_view.midi_context().note_height() >= UIConfiguration::instance().get_max_note_height()){ + if (_midi_context.note_height() >= UIConfiguration::instance().get_max_note_height()){ _saved_bottom_val = _adj.get_value(); } else { _saved_bottom_val = 127.0; } - _view.midi_context().apply_note_range (real_val_at_pointer, _adj.get_value () + _adj.get_page_size (), true); + _midi_context.apply_note_range (real_val_at_pointer, _adj.get_value () + _adj.get_page_size (), true); break; default: break; } - }else{ - int note = _view.midi_context().y_to_note(evd.y); + + } else { + + int note = _midi_context.y_to_note(evd.y); set_note_highlight (note); if (_dragging) { @@ -700,7 +719,7 @@ PianoRollHeader::motion_handler (GdkEventMotion* ev) } } } - _adj.value_changed (); + redraw (); _old_y = evd.y; //win->process_updates(false); @@ -711,6 +730,10 @@ PianoRollHeader::motion_handler (GdkEventMotion* ev) bool PianoRollHeader::button_press_handler (GdkEventButton* ev) { + if (!_view) { + return false; + } + /* Convert canvas-coordinates to item coordinates */ Duple evd (canvas_to_item (Duple (ev->x, ev->y))); @@ -719,7 +742,7 @@ PianoRollHeader::button_press_handler (GdkEventButton* ev) if (ev->button == 1 && ev->x <= _scroomer_size){ if (ev->type == GDK_2BUTTON_PRESS) { - _view.set_visibility_note_range (MidiStreamView::ContentsRange, false); + _view->set_visibility_note_range (MidiStreamView::ContentsRange, false); return true; } @@ -730,7 +753,7 @@ PianoRollHeader::button_press_handler (GdkEventButton* ev) return true; } else { - int note = _view.midi_context().y_to_note(evd.y); + int note = _midi_context.y_to_note(evd.y); bool tertiary = Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier); bool primary = Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier); @@ -777,7 +800,7 @@ PianoRollHeader::button_release_handler (GdkEventButton* ev) _scroomer_drag = false; - int note = _view.midi_context().y_to_note(evd.y); + int note = _midi_context.y_to_note(evd.y); if (false /*editor().current_mouse_mode() == Editing::MouseRange*/) { //Todo: this mode is buggy, and of questionable utility anyway @@ -829,7 +852,7 @@ bool PianoRollHeader::enter_handler (GdkEventCrossing* ev) { Duple evd (canvas_to_item (Duple (ev->x, ev->y))); - set_note_highlight (_view.midi_context().y_to_note (evd.y)); + set_note_highlight (_midi_context.y_to_note (evd.y)); entered = true; redraw (); return true; @@ -839,7 +862,9 @@ bool PianoRollHeader::leave_handler (GdkEventCrossing*) { if (!_scroomer_drag){ - _view.editing_context().pop_canvas_cursor (); + if (_view) { + _view->editing_context().pop_canvas_cursor (); + } } invalidate_note_range(_highlighted_note, _highlighted_note); @@ -863,11 +888,11 @@ PianoRollHeader::note_range_changed () void PianoRollHeader::invalidate_note_range (int lowest, int highest) { - lowest = max((int) _view.midi_context().lowest_note(), lowest - 1); - highest = min((int) _view.midi_context().highest_note(), highest + 2); + lowest = max((int) _midi_context.lowest_note(), lowest - 1); + highest = min((int) _midi_context.highest_note(), highest + 2); - double y = _view.midi_context().note_to_y (highest); - double height = _view.midi_context().note_to_y (lowest - 1) - y; + double y = _midi_context.note_to_y (highest); + double height = _midi_context.note_to_y (lowest - 1) - y; dynamic_cast(_canvas)->queue_draw_area (0., floor (y), get().width(), floor (height)); } @@ -875,13 +900,17 @@ PianoRollHeader::invalidate_note_range (int lowest, int highest) bool PianoRollHeader::show_scroomer () const { + if (!_view) { + return false; + } + Editing::NoteNameDisplay nnd = UIConfiguration::instance().get_note_name_display(); if (nnd == Editing::Never) { return false; } - switch (_view.editing_context().current_mouse_mode()) { + switch (_view->editing_context().current_mouse_mode()) { case Editing::MouseDraw: case Editing::MouseContent: if (nnd == Editing::WithMIDNAM) { @@ -898,12 +927,16 @@ PianoRollHeader::show_scroomer () const void PianoRollHeader::send_note_on (uint8_t note) { - std::shared_ptr track = _view.midi_track (); + if (!_view) { + return; + } + + std::shared_ptr track = _view->midi_track (); //cerr << "note on: " << (int) note << endl; if (track) { - _event[0] = (MIDI_CMD_NOTE_ON | _view.midi_context().get_preferred_midi_channel ()); + _event[0] = (MIDI_CMD_NOTE_ON | _midi_context.get_preferred_midi_channel ()); _event[1] = note; _event[2] = 100; @@ -914,10 +947,14 @@ PianoRollHeader::send_note_on (uint8_t note) void PianoRollHeader::send_note_off (uint8_t note) { - std::shared_ptr track = _view.midi_track (); + if (!_view) { + return; + } + + std::shared_ptr track = _view->midi_track (); if (track) { - _event[0] = (MIDI_CMD_NOTE_OFF | _view.midi_context().get_preferred_midi_channel ()); + _event[0] = (MIDI_CMD_NOTE_OFF | _midi_context.get_preferred_midi_channel ()); _event[1] = note; _event[2] = 100; diff --git a/gtk2_ardour/prh.h b/gtk2_ardour/prh.h index 7724296a0a..49f0508a09 100644 --- a/gtk2_ardour/prh.h +++ b/gtk2_ardour/prh.h @@ -39,12 +39,10 @@ namespace ArdourCanvas { class PianoRollHeader : public ArdourCanvas::Rectangle { public: - PianoRollHeader (ArdourCanvas::Item* parent, MidiView&); + PianoRollHeader (ArdourCanvas::Item* parent, MidiViewBackground&); void size_request (double& w, double& h) const; - void render (ArdourCanvas::Rect const & area, Cairo::RefPtr) const; - void size_allocate (ArdourCanvas::Rect const &); void instrument_info_change (); @@ -56,55 +54,14 @@ public: sigc::signal ToggleNoteSelection; sigc::signal ExtendNoteSelection; + void set_view (MidiView&); + private: + MidiViewBackground& _midi_context; + Gtk::Adjustment& _adj; + MidiView* _view; - bool event_handler (GdkEvent*); - bool motion_handler (GdkEventMotion*); - bool button_press_handler (GdkEventButton*); - bool button_release_handler (GdkEventButton*); - bool scroll_handler (GdkEventScroll*); - bool enter_handler (GdkEventCrossing*); - bool leave_handler (GdkEventCrossing*); - - // void on_size_request(Gtk::Requisition*); - - struct NoteName { - std::string name; - bool from_midnam; - }; - NoteName note_names[128]; - bool have_note_names; - void set_min_page_size(double page_size); - void render_scroomer(Cairo::RefPtr) const; - NoteName get_note_name (int note); - - Gtk::Adjustment& _adj; - - PianoRollHeader(const PianoRollHeader&); - - enum ItemType { - BLACK_SEPARATOR, - BLACK_MIDDLE_SEPARATOR, - BLACK, - WHITE_SEPARATOR, - WHITE_RECT, - WHITE_CF, - WHITE_EB, - WHITE_DGA - }; - - void invalidate_note_range(int lowest, int highest); - - void get_path(int note, double x[], double y[]) const; - - void send_note_on(uint8_t note); - void send_note_off(uint8_t note); - - void reset_clicked_note(uint8_t, bool invalidate = true); - - MidiView& _view; - - uint8_t _event[3]; + uint8_t _event[3]; mutable Glib::RefPtr _layout; mutable Glib::RefPtr _big_c_layout; @@ -117,7 +74,7 @@ private: uint8_t _clicked_note; double _grab_y; bool _dragging; - double _scroomer_size; + mutable double _scroomer_size; bool _scroomer_drag; double _old_y; double _fract; @@ -131,9 +88,46 @@ private: mutable bool _mini_map_display; bool entered; - bool show_scroomer () const; + // void on_size_request(Gtk::Requisition*); - ArdourCanvas::Rect _alloc; + struct NoteName { + std::string name; + bool from_midnam; + }; + NoteName note_names[128]; + bool have_note_names; + PBD::ScopedConnection height_connection; + + void set_min_page_size (double page_size); + void render_scroomer (Cairo::RefPtr) const; + NoteName get_note_name (int note); + + bool event_handler (GdkEvent*); + bool motion_handler (GdkEventMotion*); + bool button_press_handler (GdkEventButton*); + bool button_release_handler (GdkEventButton*); + bool scroll_handler (GdkEventScroll*); + bool enter_handler (GdkEventCrossing*); + bool leave_handler (GdkEventCrossing*); + + enum ItemType { + BLACK_SEPARATOR, + BLACK_MIDDLE_SEPARATOR, + BLACK, + WHITE_SEPARATOR, + WHITE_RECT, + WHITE_CF, + WHITE_EB, + WHITE_DGA + }; + + void invalidate_note_range (int lowest, int highest); + void get_path (int note, double x[], double y[]) const; + void send_note_on (uint8_t note); + void send_note_off (uint8_t note); + void reset_clicked_note (uint8_t, bool invalidate = true); + bool show_scroomer () const; + void resize (); }; } diff --git a/libs/canvas/ruler.cc b/libs/canvas/ruler.cc index 57f9f5d696..96f8d9f6d0 100644 --- a/libs/canvas/ruler.cc +++ b/libs/canvas/ruler.cc @@ -111,7 +111,7 @@ Ruler::set_second_font_description (Pango::FontDescription fd) void Ruler::render (Rect const & area, Cairo::RefPtr cr) const { - std::cerr << whoami() << " ruler render " << _lower << " .. " << _upper << "\n"; + // std::cerr << whoami() << " ruler render " << _lower << " .. " << _upper << "\n"; if (_lower == _upper) { /* nothing to draw */