X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fghostregion.cc;h=06946ec7ec8f45bc6333697384bea3f13ce19453;hb=154f9825ff72d691ba550de573948424b81a09a6;hp=f75982cc768fa0930e8a8f2651ebaa1cf490ef78;hpb=36c233fe6ce570ce85224626ce7aba4a2607537f;p=ardour.git diff --git a/gtk2_ardour/ghostregion.cc b/gtk2_ardour/ghostregion.cc index f75982cc76..06946ec7ec 100644 --- a/gtk2_ardour/ghostregion.cc +++ b/gtk2_ardour/ghostregion.cc @@ -18,40 +18,51 @@ */ #include "evoral/Note.hpp" -#include "canvas/group.h" + +#include "ardour/parameter_descriptor.h" + +#include "canvas/container.h" +#include "canvas/polygon.h" #include "canvas/rectangle.h" -#include "canvas/wave_view.h" #include "canvas/debug.h" -#include "ardour_ui.h" +#include "waveview/wave_view.h" + #include "automation_time_axis.h" #include "ghostregion.h" #include "midi_streamview.h" #include "midi_time_axis.h" +#include "region_view.h" +#include "midi_region_view.h" #include "rgb_macros.h" #include "note.h" +#include "hit.h" +#include "ui_config.h" using namespace std; using namespace Editing; -using namespace ArdourCanvas; using namespace ARDOUR; - -PBD::Signal1 GhostRegion::CatchDeletion; - -GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxisView& source_tv, double initial_pos) - : trackview (tv) - , source_trackview (source_tv) +using ArdourCanvas::Duple; + +GhostRegion::GhostRegion(RegionView& rv, + ArdourCanvas::Container* parent, + TimeAxisView& tv, + TimeAxisView& source_tv, + double initial_pos) + : parent_rv(rv) + , trackview(tv) + , source_trackview(source_tv) { - group = new ArdourCanvas::Group (parent); + group = new ArdourCanvas::Container (parent); CANVAS_DEBUG_NAME (group, "ghost region"); group->set_position (ArdourCanvas::Duple (initial_pos, 0)); base_rect = new ArdourCanvas::Rectangle (group); CANVAS_DEBUG_NAME (base_rect, "ghost region rect"); base_rect->set_x0 (0); - base_rect->set_y0 (0); + base_rect->set_y0 (1.0); base_rect->set_y1 (trackview.current_height()); - base_rect->set_outline_what (0); + base_rect->set_outline (false); if (!is_automation_ghost()) { base_rect->hide(); @@ -66,7 +77,8 @@ GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxi GhostRegion::~GhostRegion () { - CatchDeletion (this); + parent_rv.remove_ghost(this); + trackview.erase_ghost(this); delete base_rect; delete group; } @@ -87,8 +99,7 @@ void GhostRegion::set_colors () { if (is_automation_ghost()) { - base_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackBase()); - base_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackBase()); + base_rect->set_fill_color (UIConfiguration::instance().color_mod ("ghost track base", "ghost track base")); } } @@ -105,8 +116,11 @@ GhostRegion::is_automation_ghost() return (dynamic_cast(&trackview)) != 0; } -AudioGhostRegion::AudioGhostRegion(TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos) - : GhostRegion(tv.ghost_group(), tv, source_tv, initial_unit_pos) +AudioGhostRegion::AudioGhostRegion(RegionView& rv, + TimeAxisView& tv, + TimeAxisView& source_tv, + double initial_unit_pos) + : GhostRegion(rv, tv.ghost_group(), tv, source_tv, initial_unit_pos) { } @@ -114,7 +128,7 @@ AudioGhostRegion::AudioGhostRegion(TimeAxisView& tv, TimeAxisView& source_tv, do void AudioGhostRegion::set_samples_per_pixel (double fpp) { - for (vector::iterator i = waves.begin(); i != waves.end(); ++i) { + for (vector::iterator i = waves.begin(); i != waves.end(); ++i) { (*i)->set_samples_per_pixel (fpp); } } @@ -122,7 +136,7 @@ AudioGhostRegion::set_samples_per_pixel (double fpp) void AudioGhostRegion::set_height () { - vector::iterator i; + vector::iterator i; uint32_t n; GhostRegion::set_height(); @@ -142,66 +156,97 @@ AudioGhostRegion::set_colors () guint fill_color; if (is_automation_ghost()) { - fill_color = ARDOUR_UI::config()->get_canvasvar_GhostTrackWaveFill(); + fill_color = UIConfiguration::instance().color ("ghost track wave fill"); } else { fill_color = source_track_color(200); } for (uint32_t n=0; n < waves.size(); ++n) { - waves[n]->set_outline_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackWave()); + waves[n]->set_outline_color (UIConfiguration::instance().color ("ghost track wave")); waves[n]->set_fill_color (fill_color); - waves[n]->set_clip_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackWaveClip()); - waves[n]->set_zero_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackZeroLine()); + waves[n]->set_clip_color (UIConfiguration::instance().color ("ghost track wave clip")); + waves[n]->set_zero_color (UIConfiguration::instance().color ("ghost track zero line")); } } /** The general constructor; called when the destination timeaxisview doesn't have * a midistreamview. * + * @param rv The parent RegionView that is being ghosted. * @param tv TimeAxisView that this ghost region is on. * @param source_tv TimeAxisView that we are the ghost for. */ -MidiGhostRegion::MidiGhostRegion(TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos) - : GhostRegion(tv.ghost_group(), tv, source_tv, initial_unit_pos) - , _optimization_iterator (events.end ()) +MidiGhostRegion::MidiGhostRegion(MidiRegionView& rv, + TimeAxisView& tv, + TimeAxisView& source_tv, + double initial_unit_pos) + : GhostRegion(rv, tv.ghost_group(), tv, source_tv, initial_unit_pos) + , _note_group (new ArdourCanvas::Container (group)) + , parent_mrv (rv) + , _optimization_iterator(events.end()) { - base_rect->lower_to_bottom(); - update_range (); + _outline = UIConfiguration::instance().color ("ghost track midi outline"); - midi_view()->NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiGhostRegion::update_range)); + base_rect->lower_to_bottom(); } /** + * @param rv The parent RegionView being ghosted. * @param msv MidiStreamView that this ghost region is on. * @param source_tv TimeAxisView that we are the ghost for. */ -MidiGhostRegion::MidiGhostRegion(MidiStreamView& msv, TimeAxisView& source_tv, double initial_unit_pos) - : GhostRegion(msv.midi_underlay_group, msv.trackview(), source_tv, initial_unit_pos) - , _optimization_iterator (events.end ()) +MidiGhostRegion::MidiGhostRegion(MidiRegionView& rv, + MidiStreamView& msv, + TimeAxisView& source_tv, + double initial_unit_pos) + : GhostRegion(rv, + msv.midi_underlay_group, + msv.trackview(), + source_tv, + initial_unit_pos) + , _note_group (new ArdourCanvas::Container (group)) + , parent_mrv (rv) + , _optimization_iterator(events.end()) { - base_rect->lower_to_bottom(); - update_range (); + _outline = UIConfiguration::instance().color ("ghost track midi outline"); - midi_view()->NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiGhostRegion::update_range)); + base_rect->lower_to_bottom(); } MidiGhostRegion::~MidiGhostRegion() { clear_events (); + delete _note_group; } -MidiGhostRegion::GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Group* g) +MidiGhostRegion::GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g) : event (e) { - rect = new ArdourCanvas::Rectangle (g, ArdourCanvas::Rect (e->x0(), e->y0(), e->x1(), e->y1())); - CANVAS_DEBUG_NAME (rect, "ghost note rect"); + + if (dynamic_cast(e)) { + item = new ArdourCanvas::Rectangle( + g, ArdourCanvas::Rect(e->x0(), e->y0(), e->x1(), e->y1())); + is_hit = false; + } else { + Hit* hit = dynamic_cast(e); + if (!hit) { + return; + } + ArdourCanvas::Polygon* poly = new ArdourCanvas::Polygon(g); + poly->set(Hit::points(e->y1() - e->y0())); + poly->set_position(hit->position()); + item = poly; + is_hit = true; + } + + CANVAS_DEBUG_NAME (item, "ghost note item"); } MidiGhostRegion::GhostEvent::~GhostEvent () { /* event is not ours to delete */ - delete rect; + delete item; } void @@ -225,24 +270,42 @@ void MidiGhostRegion::set_height () { GhostRegion::set_height(); - update_range(); + update_contents_height (); } void MidiGhostRegion::set_colors() { - guint fill = source_track_color(200); - GhostRegion::set_colors(); + _outline = UIConfiguration::instance().color ("ghost track midi outline"); for (EventList::iterator it = events.begin(); it != events.end(); ++it) { - (*it)->rect->set_fill_color (fill); - (*it)->rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackMidiOutline()); + it->second->item->set_fill_color (UIConfiguration::instance().color_mod((*it).second->event->base_color(), "ghost track midi fill")); + it->second->item->set_outline_color (_outline); } } +static double +note_height(TimeAxisView& trackview, MidiStreamView* mv) +{ + const double tv_height = trackview.current_height(); + const double note_range = mv->contents_note_range(); + + return std::max(1.0, floor(tv_height / note_range - 1.0)); +} + +static double +note_y(TimeAxisView& trackview, MidiStreamView* mv, uint8_t note_num) +{ + const double tv_height = trackview.current_height(); + const double note_range = mv->contents_note_range(); + const double s = tv_height / note_range; + + return tv_height - (note_num + 1 - mv->lowest_note()) * s; +} + void -MidiGhostRegion::update_range () +MidiGhostRegion::update_contents_height () { MidiStreamView* mv = midi_view(); @@ -250,18 +313,22 @@ MidiGhostRegion::update_range () return; } - double const h = trackview.current_height() / double (mv->contents_note_range ()); + double const h = note_height(trackview, mv); for (EventList::iterator it = events.begin(); it != events.end(); ++it) { - uint8_t const note_num = (*it)->event->note()->note(); + uint8_t const note_num = it->second->event->note()->note(); + + double const y = note_y(trackview, mv, note_num); - if (note_num < mv->lowest_note() || note_num > mv->highest_note()) { - (*it)->rect->hide(); + if (!it->second->is_hit) { + _tmp_rect = static_cast(it->second->item); + _tmp_rect->set (ArdourCanvas::Rect (_tmp_rect->x0(), y, _tmp_rect->x1(), y + h)); } else { - (*it)->rect->show(); - double const y = trackview.current_height() - (note_num + 1 - mv->lowest_note()) * h + 1; - (*it)->rect->set_y0 (y); - (*it)->rect->set_y1 (y + h); + _tmp_poly = static_cast(it->second->item); + ArdourCanvas::Duple position = _tmp_poly->position(); + position.y = y; + _tmp_poly->set_position(position); + _tmp_poly->set(Hit::points(h)); } } } @@ -269,23 +336,32 @@ MidiGhostRegion::update_range () void MidiGhostRegion::add_note (NoteBase* n) { - GhostEvent* event = new GhostEvent (n, group); - events.push_back (event); + GhostEvent* event = new GhostEvent (n, _note_group); + events.insert (make_pair (n->note(), event)); - event->rect->set_fill_color (source_track_color(200)); - event->rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_GhostTrackMidiOutline()); + event->item->set_fill_color (UIConfiguration::instance().color_mod(n->base_color(), "ghost track midi fill")); + event->item->set_outline_color (_outline); MidiStreamView* mv = midi_view(); if (mv) { - const uint8_t note_num = n->note()->note(); - if (note_num < mv->lowest_note() || note_num > mv->highest_note()) { - event->rect->hide(); + if (!n->item()->visible()) { + event->item->hide(); } else { - const double y = mv->note_to_y(note_num); - event->rect->set_y0 (y); - event->rect->set_y1 (y + mv->note_height()); + uint8_t const note_num = n->note()->note(); + double const h = note_height(trackview, mv); + double const y = note_y(trackview, mv, note_num); + if (!event->is_hit) { + _tmp_rect = static_cast(event->item); + _tmp_rect->set (ArdourCanvas::Rect (_tmp_rect->x0(), y, _tmp_rect->x1(), y + h)); + } else { + _tmp_poly = static_cast(event->item); + Duple position = _tmp_poly->position(); + position.y = y; + _tmp_poly->set_position(position); + _tmp_poly->set(Hit::points(h)); + } } } } @@ -293,43 +369,97 @@ MidiGhostRegion::add_note (NoteBase* n) void MidiGhostRegion::clear_events() { - for (EventList::iterator it = events.begin(); it != events.end(); ++it) { - delete *it; + _note_group->clear (true); + events.clear (); + _optimization_iterator = events.end(); +} + +/** Update the positions of our representation of a note. + * @param ev The GhostEvent from the parent MidiRegionView. + */ +void +MidiGhostRegion::update_note (GhostEvent* ev) +{ + MidiStreamView* mv = midi_view(); + + if (!mv) { + return; } - events.clear(); - _optimization_iterator = events.end (); + _tmp_rect = static_cast(ev->item); + + uint8_t const note_num = ev->event->note()->note(); + double const y = note_y(trackview, mv, note_num); + double const h = note_height(trackview, mv); + + _tmp_rect->set (ArdourCanvas::Rect (ev->event->x0(), y, ev->event->x1(), y + h)); } -/** Update the x positions of our representation of a parent's note. - * @param parent The CanvasNote from the parent MidiRegionView. +/** Update the positions of our representation of a parent's hit. + * @param ev The GhostEvent from the parent MidiRegionView. */ void -MidiGhostRegion::update_note (NoteBase* parent) +MidiGhostRegion::update_hit (GhostEvent* ev) { - GhostEvent* ev = find_event (parent); - if (!ev) { + MidiStreamView* mv = midi_view(); + + if (!mv) { return; } - double const x1 = parent->x0 (); - double const x2 = parent->x1 (); - ev->rect->set_x0 (x1); - ev->rect->set_x1 (x2); + _tmp_poly = static_cast(ev->item); + + uint8_t const note_num = ev->event->note()->note(); + double const h = note_height(trackview, mv); + double const y = note_y(trackview, mv, note_num); + + ArdourCanvas::Duple ppos = ev->item->position(); + ArdourCanvas::Duple gpos = _tmp_poly->position(); + gpos.x = ppos.x; + gpos.y = y; + + _tmp_poly->set_position(gpos); + _tmp_poly->set(Hit::points(h)); } void MidiGhostRegion::remove_note (NoteBase* note) { - GhostEvent* ev = find_event (note); - if (!ev) { + EventList::iterator f = events.find (note->note()); + if (f == events.end()) { return; } - events.remove (ev); - delete ev; + delete f->second; + events.erase (f); + _optimization_iterator = events.end (); } +void +MidiGhostRegion::redisplay_model () +{ + /* we rely on the parent MRV having removed notes not in the model */ + for (EventList::iterator i = events.begin(); i != events.end(); ) { + + boost::shared_ptr note = i->first; + GhostEvent* cne = i->second; + const bool visible = (note->note() >= parent_mrv._current_range_min) && + (note->note() <= parent_mrv._current_range_max); + + if (visible) { + if (cne->is_hit) { + update_hit (cne); + } else { + update_note (cne); + } + cne->item->show (); + } else { + cne->item->hide (); + } + + ++i; + } +} /** Given a note in our parent region (ie the actual MidiRegionView), find our * representation of it. @@ -337,7 +467,7 @@ MidiGhostRegion::remove_note (NoteBase* note) */ MidiGhostRegion::GhostEvent * -MidiGhostRegion::find_event (NoteBase* parent) +MidiGhostRegion::find_event (boost::shared_ptr parent) { /* we are using _optimization_iterator to speed up the common case where a caller is going through our notes in order. @@ -345,16 +475,14 @@ MidiGhostRegion::find_event (NoteBase* parent) if (_optimization_iterator != events.end()) { ++_optimization_iterator; + if (_optimization_iterator != events.end() && _optimization_iterator->first == parent) { + return _optimization_iterator->second; + } } - if (_optimization_iterator != events.end() && (*_optimization_iterator)->event == parent) { - return *_optimization_iterator; - } - - for (_optimization_iterator = events.begin(); _optimization_iterator != events.end(); ++_optimization_iterator) { - if ((*_optimization_iterator)->event == parent) { - return *_optimization_iterator; - } + _optimization_iterator = events.find (parent); + if (_optimization_iterator != events.end()) { + return _optimization_iterator->second; } return 0;