X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fghostregion.cc;h=31e6de390ba23186068c8510da2bcfd80e249853;hb=149085ba160cf58cda46ada78f11fd5a3b4f6221;hp=e57e3b637534ead01637b9f972cdfb45fc9d4064;hpb=1b657585572298d1a69a7b43e611f59b7e185df3;p=ardour.git diff --git a/gtk2_ardour/ghostregion.cc b/gtk2_ardour/ghostregion.cc index e57e3b6375..31e6de390b 100644 --- a/gtk2_ardour/ghostregion.cc +++ b/gtk2_ardour/ghostregion.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2007 Paul Davis + Copyright (C) 2000-2007 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,21 +17,24 @@ */ -#include "simplerect.h" -#include "waveview.h" -#include "ghostregion.h" -#include "midi_time_axis.h" +#include "evoral/Note.hpp" +#include "ardour_ui.h" #include "automation_time_axis.h" +#include "canvas-note.h" +#include "ghostregion.h" #include "midi_streamview.h" +#include "midi_time_axis.h" #include "rgb_macros.h" -#include "ardour_ui.h" -#include "canvas-hit.h" -#include "canvas-note.h" +#include "simplerect.h" +#include "waveview.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) @@ -43,10 +46,10 @@ GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxi base_rect = new ArdourCanvas::SimpleRect (*group); base_rect->property_x1() = (double) 0.0; base_rect->property_y1() = (double) 0.0; - base_rect->property_y2() = (double) trackview.height; + base_rect->property_y2() = (double) trackview.current_height(); base_rect->property_outline_what() = (guint32) 0; - if(!is_automation_ghost()) { + if (!is_automation_ghost()) { base_rect->hide(); } @@ -59,7 +62,7 @@ GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxi GhostRegion::~GhostRegion () { - GoingAway (this); + CatchDeletion (this); delete base_rect; delete group; } @@ -67,41 +70,41 @@ GhostRegion::~GhostRegion () void GhostRegion::set_duration (double units) { - base_rect->property_x2() = units; + base_rect->property_x2() = units; } void GhostRegion::set_height () { - base_rect->property_y2() = (double) trackview.height; + base_rect->property_y2() = (double) trackview.current_height(); } void GhostRegion::set_colors () { - if(is_automation_ghost()) { + if (is_automation_ghost()) { base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackBase.get(); base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackBase.get(); } } guint -GhostRegion::source_track_color(unsigned char alpha) { +GhostRegion::source_track_color(unsigned char alpha) +{ Gdk::Color color = source_trackview.color(); - unsigned char r,g,b ; - r = color.get_red()/256; - g = color.get_green()/256; - b = color.get_blue()/256; - return RGBA_TO_UINT(r, g, b, alpha); + return RGBA_TO_UINT (color.get_red() / 256, color.get_green() / 256, color.get_blue() / 256, alpha); } bool -GhostRegion::is_automation_ghost() { +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) { + : GhostRegion(tv.ghost_group(), tv, source_tv, initial_unit_pos) +{ + } void @@ -109,7 +112,7 @@ AudioGhostRegion::set_samples_per_unit (double spu) { for (vector::iterator i = waves.begin(); i != waves.end(); ++i) { (*i)->property_samples_per_unit() = spu; - } + } } void @@ -121,8 +124,8 @@ AudioGhostRegion::set_height () GhostRegion::set_height(); - ht = ((trackview.height) / (double) waves.size()); - + ht = ((trackview.current_height()) / (double) waves.size()); + for (n = 0, i = waves.begin(); i != waves.end(); ++i, ++n) { gdouble yoff = n * ht; (*i)->property_height() = ht; @@ -136,7 +139,7 @@ AudioGhostRegion::set_colors () GhostRegion::set_colors(); guint fill_color; - if(is_automation_ghost()) { + if (is_automation_ghost()) { fill_color = ARDOUR_UI::config()->canvasvar_GhostTrackWaveFill.get(); } else { @@ -151,157 +154,205 @@ AudioGhostRegion::set_colors () } } -/* - * This is the general constructor, and is called when the destination timeaxisview doesn't have - * a midistreamview. But what to do when positioning the midi ghost here? For example, there is - * no range controller in these tracks. maybe show the whole range. +/** The general constructor; called when the destination timeaxisview doesn't have + * a midistreamview. + * + * @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) { - + : GhostRegion(tv.ghost_group(), tv, source_tv, initial_unit_pos) + , _optimization_iterator (events.end ()) +{ base_rect->lower_to_bottom(); + update_range (); + + midi_view()->NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiGhostRegion::update_range)); } +/** + * @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) { + : GhostRegion(msv.midi_underlay_group, msv.trackview(), source_tv, initial_unit_pos) + , _optimization_iterator (events.end ()) +{ + base_rect->lower_to_bottom(); + update_range (); - base_rect->lower_to_bottom(); + midi_view()->NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiGhostRegion::update_range)); } -MidiGhostRegion::Event::Event(ArdourCanvas::CanvasMidiEvent* e) - : event(e) { +MidiGhostRegion::~MidiGhostRegion() +{ + clear_events (); } -MidiGhostRegion::Note::Note(ArdourCanvas::CanvasNote* n, ArdourCanvas::Group* g) - : Event(n) { - - rect = new ArdourCanvas::SimpleRect(*g, n->x1(), n->y1(), n->x2(), n->y2()); +MidiGhostRegion::Event::Event (ArdourCanvas::CanvasNoteEvent* e, ArdourCanvas::Group* g) + : event (e) +{ + rect = new ArdourCanvas::SimpleRect (*g, e->x1(), e->y1(), e->x2(), e->y2()); } -MidiGhostRegion::Note::~Note() { +MidiGhostRegion::Event::~Event () +{ + /* event is not ours to delete */ delete rect; } void -MidiGhostRegion::Note::x_changed() { - rect->property_x1() = event->x1(); - rect->property_x2() = event->x2(); -} - -MidiGhostRegion::Hit::Hit(ArdourCanvas::CanvasHit* h, ArdourCanvas::Group*) - : Event(h) { - cerr << "Hit ghost item does not work yet" << endl; -} - -MidiGhostRegion::Hit::~Hit() { -} - -void -MidiGhostRegion::Hit::x_changed() { -} - -void -MidiGhostRegion::set_samples_per_unit (double spu) +MidiGhostRegion::set_samples_per_unit (double /*spu*/) { } +/** @return MidiStreamView that we are providing a ghost for */ MidiStreamView* -MidiGhostRegion::midi_view() { - MidiTimeAxisView* mtv; +MidiGhostRegion::midi_view () +{ + StreamView* sv = source_trackview.view (); + assert (sv); + MidiStreamView* msv = dynamic_cast (sv); + assert (msv); - if((mtv = dynamic_cast(&trackview)) != 0) { - return mtv->midi_view(); - } - else { - return 0; - } + return msv; } void -MidiGhostRegion::set_height() { +MidiGhostRegion::set_height () +{ GhostRegion::set_height(); update_range(); } void -MidiGhostRegion::set_colors() { - MidiGhostRegion::Note* note; +MidiGhostRegion::set_colors() +{ guint fill = source_track_color(200); GhostRegion::set_colors(); - for(EventList::iterator it = events.begin(); it != events.end(); ++it) { - if((note = dynamic_cast(*it)) != 0) { - note->rect->property_fill_color_rgba() = fill; - note->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackMidiOutline.get(); - } + for (EventList::iterator it = events.begin(); it != events.end(); ++it) { + (*it)->rect->property_fill_color_rgba() = fill; + (*it)->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackMidiOutline.get(); } } void -MidiGhostRegion::update_range() { +MidiGhostRegion::update_range () +{ MidiStreamView* mv = midi_view(); - if(!mv) { + if (!mv) { return; } - MidiGhostRegion::Note* note; - uint8_t note_num; - double y; - - for(EventList::iterator it = events.begin(); it != events.end(); ++it) { - if((note = dynamic_cast(*it)) != 0) { - note_num = note->event->note()->note(); - - if(note_num < mv->lowest_note() || note_num > mv->highest_note()) { - note->rect->hide(); - } - else { - note->rect->show(); - y = mv->note_to_y(note_num); - note->rect->property_y1() = y; - note->rect->property_y2() = y + mv->note_height(); - } + double const h = trackview.current_height() / double (mv->contents_note_range ()); + + for (EventList::iterator it = events.begin(); it != events.end(); ++it) { + uint8_t const note_num = (*it)->event->note()->note(); + + if (note_num < mv->lowest_note() || note_num > mv->highest_note()) { + (*it)->rect->hide(); + } else { + (*it)->rect->show(); + double const y = trackview.current_height() - (note_num + 1 - mv->lowest_note()) * h + 1; + (*it)->rect->property_y1() = y; + (*it)->rect->property_y2() = y + h; } } } void -MidiGhostRegion::add_note(ArdourCanvas::CanvasNote* n) { - Note* note = new Note(n, group); - events.push_back(note); +MidiGhostRegion::add_note(ArdourCanvas::CanvasNote* n) +{ + Event* event = new Event (n, group); + events.push_back (event); - note->rect->property_fill_color_rgba() = source_track_color(200); - note->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackMidiOutline.get(); + event->rect->property_fill_color_rgba() = source_track_color(200); + event->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_GhostTrackMidiOutline.get(); MidiStreamView* mv = midi_view(); - if(mv) { - uint8_t note_num = n->note()->note(); - double y; + if (mv) { + const uint8_t note_num = n->note()->note(); - if(note_num < mv->lowest_note() || note_num > mv->highest_note()) { - note->rect->hide(); - } - else { - y = mv->note_to_y(note_num); - note->rect->property_y1() = y; - note->rect->property_y2() = y + mv->note_height(); + if (note_num < mv->lowest_note() || note_num > mv->highest_note()) { + event->rect->hide(); + } else { + const double y = mv->note_to_y(note_num); + event->rect->property_y1() = y; + event->rect->property_y2() = y + mv->note_height(); } } } void -MidiGhostRegion::add_hit(ArdourCanvas::CanvasHit* h) { - //events.push_back(new Hit(h, group)); +MidiGhostRegion::clear_events() +{ + for (EventList::iterator it = events.begin(); it != events.end(); ++it) { + delete *it; + } + + events.clear(); + _optimization_iterator = events.end (); } +/** Update the x positions of our representation of a parent's note. + * @param parent The CanvasNote from the parent MidiRegionView. + */ void -MidiGhostRegion::clear_events() { - for(EventList::iterator it = events.begin(); it != events.end(); ++it) { - delete *it; +MidiGhostRegion::update_note (ArdourCanvas::CanvasNote* parent) +{ + Event* ev = find_event (parent); + if (!ev) { + return; } - events.clear(); + double const x1 = parent->property_x1 (); + double const x2 = parent->property_x2 (); + ev->rect->property_x1 () = x1; + ev->rect->property_x2 () = x2; +} + +void +MidiGhostRegion::remove_note (ArdourCanvas::CanvasNoteEvent* note) +{ + Event* ev = find_event (note); + if (!ev) { + return; + } + + events.remove (ev); + delete ev; + _optimization_iterator = events.end (); +} + +/** Given a note in our parent region (ie the actual MidiRegionView), find our + * representation of it. + * @return Our Event, or 0 if not found. + */ + +MidiGhostRegion::Event * +MidiGhostRegion::find_event (ArdourCanvas::CanvasNoteEvent* parent) +{ + /* we are using _optimization_iterator to speed up the common case where a caller + is going through our notes in order. + */ + + if (_optimization_iterator != events.end()) { + ++_optimization_iterator; + } + + 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; + } + } + + return 0; }