Allow dragging of program change flags in MIDI regions.
authorCarl Hetherington <carl@carlh.net>
Mon, 20 Dec 2010 03:42:59 +0000 (03:42 +0000)
committerCarl Hetherington <carl@carlh.net>
Mon, 20 Dec 2010 03:42:59 +0000 (03:42 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8303 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/canvas-program-change.cc
gtk2_ardour/canvas-program-change.h
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h

index d87b164f4070d9bed4261fa5d2b14d19b39d2609..b48d7b33baf6266c0f849b6556302abc1f5a125d 100644 (file)
@@ -6,11 +6,16 @@
 #include "ardour_ui.h"
 #include "midi_region_view.h"
 #include "canvas-program-change.h"
+#include "editor.h"
+#include "editor_drag.h"
 
 using namespace Gnome::Canvas;
 using namespace MIDI::Name;
 using namespace std;
 
+/** @param x x position in pixels.
+ *  @param event_time PC time in beats, with respect to the start of the source.
+ */
 CanvasProgramChange::CanvasProgramChange(
                MidiRegionView& region,
                Group&          parent,
@@ -107,7 +112,17 @@ CanvasProgramChange::on_event(GdkEvent* ev)
 {
        switch (ev->type) {
        case GDK_BUTTON_PRESS:
-               if (ev->button.button == 3) {
+               switch (ev->button.button) {
+               case 1:
+               {
+                       /* XXX: icky dcast */
+                       Editor* e = dynamic_cast<Editor*> (&_region.get_time_axis_view().editor());
+                       if (e->current_mouse_mode() == Editing::MouseObject && e->internal_editing()) {
+                               e->drags()->set (new ProgramChangeDrag (e, this, &_region), ev);
+                               return true;
+                       }
+               }
+               case 3:
                        // lazy init
                        if (!_popup_initialized) {
                                initialize_popup_menus();
index 40939845557b97b6f38bfde56321563af17bee1f..51a7d427e4c13652194883e35d0964e9354800d1 100644 (file)
@@ -35,20 +35,11 @@ public:
 
        virtual bool on_event(GdkEvent* ev);
 
-       string model_name() const { return _model_name; }
-       void set_model_name(string model_name) { _model_name = model_name; }
-
-       string custom_device_mode() const { return _custom_device_mode; }
-       void set_custom_device_mode(string custom_device_mode) { _custom_device_mode = custom_device_mode; }
-
-       double event_time() const { return _event_time; }
-       void set_event_time(double new_time) { _event_time = new_time; };
-
-       uint8_t program() const { return _program; }
-       void set_program(uint8_t new_program) { _program = new_program; };
-
-       uint8_t channel() const { return _channel; }
-       void set_channel(uint8_t new_channel) { _channel = new_channel; };
+       string model_name () const { return _model_name; }
+       string custom_device_mode () const { return _custom_device_mode; }
+       double event_time () const { return _event_time; }
+       uint8_t program () const { return _program; }
+       uint8_t channel () const { return _channel; }
 
        void initialize_popup_menus();
 
index af6969118976ddadbf5dde711f670564d46ef987..4845e8c918b8e75328ab0dcd8a432a1a5244b726 100644 (file)
@@ -220,6 +220,7 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
        }
 
        _raw_grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
+       setup_pointer_frame_offset ();
        _grab_frame = adjusted_frame (_raw_grab_frame, event);
        _last_pointer_frame = _grab_frame;
        _last_pointer_x = _grab_x;
@@ -1181,10 +1182,8 @@ RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p,
 }
 
 void
-RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
+RegionMoveDrag::setup_pointer_frame_offset ()
 {
-       RegionMotionDrag::start_grab (event, c);
-
        _pointer_frame_offset = raw_grab_frame() - _last_frame_position;
 }
 
@@ -1800,11 +1799,15 @@ MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        Drag::start_grab (event, cursor);
 
-       _pointer_frame_offset = raw_grab_frame() - _marker->meter().frame();
-
        _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
 }
 
+void
+MeterMarkerDrag::setup_pointer_frame_offset ()
+{
+       _pointer_frame_offset = raw_grab_frame() - _marker->meter().frame();
+}
+
 void
 MeterMarkerDrag::motion (GdkEvent* event, bool)
 {
@@ -1892,10 +1895,15 @@ TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        Drag::start_grab (event, cursor);
 
-       _pointer_frame_offset = raw_grab_frame() - _marker->tempo().frame();
        _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
 }
 
+void
+TempoMarkerDrag::setup_pointer_frame_offset ()
+{
+       _pointer_frame_offset = raw_grab_frame() - _marker->tempo().frame();
+}      
+
 void
 TempoMarkerDrag::motion (GdkEvent* event, bool)
 {
@@ -1993,11 +2001,15 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
                }
        }
 
-       _pointer_frame_offset = raw_grab_frame() - _cursor->current_frame;
-
        _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
 }
 
+void
+CursorDrag::setup_pointer_frame_offset ()
+{
+       _pointer_frame_offset = raw_grab_frame() - _cursor->current_frame;
+}      
+
 void
 CursorDrag::motion (GdkEvent* event, bool)
 {
@@ -2071,12 +2083,19 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
        boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
 
-       _pointer_frame_offset = raw_grab_frame() - ((framecnt_t) r->fade_in()->back()->when + r->position());
        _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
        
        arv->show_fade_line((framepos_t) r->fade_in()->back()->when);
 }
 
+void
+FadeInDrag::setup_pointer_frame_offset ()
+{
+       AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
+       boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
+       _pointer_frame_offset = raw_grab_frame() - ((framecnt_t) r->fade_in()->back()->when + r->position());
+}
+
 void
 FadeInDrag::motion (GdkEvent* event, bool)
 {
@@ -2183,12 +2202,19 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
        boost::shared_ptr<AudioRegion> r = arv->audio_region ();
 
-       _pointer_frame_offset = raw_grab_frame() - (r->length() - (framecnt_t) r->fade_out()->back()->when + r->position());
        _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
        
        arv->show_fade_line(r->length() - r->fade_out()->back()->when);
 }
 
+void
+FadeOutDrag::setup_pointer_frame_offset ()
+{
+       AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
+       boost::shared_ptr<AudioRegion> r = arv->audio_region ();
+       _pointer_frame_offset = raw_grab_frame() - (r->length() - (framecnt_t) r->fade_out()->back()->when + r->position());
+}      
+
 void
 FadeOutDrag::motion (GdkEvent* event, bool)
 {
@@ -2321,8 +2347,6 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        Location *location = _editor->find_location_from_marker (_marker, is_start);
        _editor->_dragging_edit_point = true;
 
-       _pointer_frame_offset = raw_grab_frame() - (is_start ? location->start() : location->end());
-
        update_item (location);
 
        // _drag_line->show();
@@ -2388,6 +2412,14 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        }
 }
 
+void
+MarkerDrag::setup_pointer_frame_offset ()
+{
+       bool is_start;
+       Location *location = _editor->find_location_from_marker (_marker, is_start);
+       _pointer_frame_offset = raw_grab_frame() - (is_start ? location->start() : location->end());
+}
+
 void
 MarkerDrag::motion (GdkEvent* event, bool)
 {
@@ -3141,9 +3173,6 @@ SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
 void
 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
 {
-       framepos_t start = 0;
-       framepos_t end = 0;
-
        if (_editor->session() == 0) {
                return;
        }
@@ -3166,8 +3195,6 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
                        _editor->clicked_axisview->order_selection_trims (_item, true);
                }
                Drag::start_grab (event, _editor->cursors()->left_side_trim);
-               start = _editor->selection->time[_editor->clicked_selection].start;
-               _pointer_frame_offset = raw_grab_frame() - start;
                break;
 
        case SelectionEndTrim:
@@ -3175,19 +3202,15 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
                        _editor->clicked_axisview->order_selection_trims (_item, false);
                }
                Drag::start_grab (event, _editor->cursors()->right_side_trim);
-               end = _editor->selection->time[_editor->clicked_selection].end;
-               _pointer_frame_offset = raw_grab_frame() - end;
                break;
 
        case SelectionMove:
-               start = _editor->selection->time[_editor->clicked_selection].start;
                Drag::start_grab (event, cursor);
-               _pointer_frame_offset = raw_grab_frame() - start;
                break;
        }
 
        if (_operation == SelectionMove) {
-               _editor->show_verbose_time_cursor (start, 10);
+               _editor->show_verbose_time_cursor (_editor->selection->time[_editor->clicked_selection].start, 10);
        } else {
                _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
        }
@@ -3195,6 +3218,25 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
        _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
 }
 
+void
+SelectionDrag::setup_pointer_frame_offset ()
+{
+       switch (_operation) {
+       case CreateSelection:
+               _pointer_frame_offset = 0;
+               break;
+
+       case SelectionStartTrim:
+       case SelectionMove:
+               _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].start;
+               break;
+
+       case SelectionEndTrim:
+               _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end;
+               break;
+       }
+}
+
 void
 SelectionDrag::motion (GdkEvent* event, bool first_move)
 {
@@ -4038,3 +4080,59 @@ DraggingView::DraggingView (RegionView* v, RegionDrag* parent)
        initial_position = v->region()->position ();
        initial_end = v->region()->position () + v->region()->length ();
 }
+
+ProgramChangeDrag::ProgramChangeDrag (Editor* e, CanvasProgramChange* i, MidiRegionView* r)
+       : Drag (e, i)
+       , _region_view (r)
+       , _program_change (i)
+       , _cumulative_dx (0)
+{
+       DEBUG_TRACE (DEBUG::Drags, "New ProgramChangeDrag\n");
+}
+
+void
+ProgramChangeDrag::motion (GdkEvent* ev, bool)
+{
+       framepos_t f = adjusted_current_frame (ev);
+       boost::shared_ptr<Region> r = _region_view->region ();
+       f = max (f, r->position ());
+       f = min (f, r->last_frame ());
+       
+       framecnt_t const dxf = f - grab_frame();
+       double const dxu = _editor->frame_to_unit (dxf);
+       _program_change->move (dxu - _cumulative_dx, 0);
+       _cumulative_dx = dxu;
+}
+
+void
+ProgramChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
+{
+       if (!movement_occurred) {
+               return;
+       }
+
+       boost::shared_ptr<Region> r (_region_view->region ());
+       
+       framepos_t f = adjusted_current_frame (ev);
+       f = max (f, r->position ());
+       f = min (f, r->last_frame ());
+       
+       _region_view->move_program_change (
+               MidiRegionView::PCEvent (_program_change->event_time(), _program_change->program(), _program_change->channel()),
+               _region_view->frames_to_beats (f - r->position() - r->start())
+               );
+}
+
+void
+ProgramChangeDrag::aborted ()
+{
+       _program_change->move (-_cumulative_dx, 0);
+}
+
+void
+ProgramChangeDrag::setup_pointer_frame_offset ()
+{
+       boost::shared_ptr<Region> region = _region_view->region ();
+       _pointer_frame_offset = raw_grab_frame() - _region_view->beats_to_frames (_program_change->event_time()) - region->position() + region->start();
+}
+
index e0d3d91ee86f6a99775e0dbe2992a491905a6595..a3d3919fed3b0ba512746f8d03bbcde9fb11a86d 100644 (file)
@@ -42,6 +42,7 @@ namespace PBD {
 namespace Gnome {
        namespace Canvas {
                class CanvasNoteEvent;
+               class CanvasProgramChange;
        }
 }
 
@@ -175,6 +176,11 @@ public:
                return true;
        }
 
+       /** Set up the _pointer_frame_offset */
+       virtual void setup_pointer_frame_offset () {
+               _pointer_frame_offset = 0;
+       }
+
 protected:
 
        double grab_x () const {
@@ -312,7 +318,6 @@ public:
        RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
        virtual ~RegionMoveDrag () {}
 
-       virtual void start_grab (GdkEvent *, Gdk::Cursor *);
        void motion (GdkEvent *, bool);
        void finished (GdkEvent *, bool);
        void aborted ();
@@ -325,6 +330,8 @@ public:
                return std::make_pair (4, 4);
        }
 
+       void setup_pointer_frame_offset ();
+
 private:
        typedef std::set<boost::shared_ptr<ARDOUR::Playlist> > PlaylistSet;
 
@@ -444,6 +451,28 @@ class NoteDrag : public Drag
        double _note_height;
 };
 
+/** Drag to move MIDI program changes */
+class ProgramChangeDrag : public Drag
+{
+public:
+       ProgramChangeDrag (Editor *, ArdourCanvas::CanvasProgramChange *, MidiRegionView *);
+
+       void motion (GdkEvent *, bool);
+       void finished (GdkEvent *, bool);
+       void aborted ();
+
+       bool y_movement_matters () const {
+               return false;
+       }
+
+       void setup_pointer_frame_offset ();
+
+private:
+       MidiRegionView* _region_view;
+       ArdourCanvas::CanvasProgramChange* _program_change;
+       double _cumulative_dx;
+};
+
 /** Drag of region gain */
 class RegionGainDrag : public Drag
 {
@@ -504,6 +533,8 @@ public:
        bool y_movement_matters () const {
                return false;
        }
+
+       void setup_pointer_frame_offset ();
        
 private:
        MeterMarker* _marker;
@@ -529,6 +560,8 @@ public:
                return false;
        }
 
+       void setup_pointer_frame_offset ();
+       
 private:
        TempoMarker* _marker;
        bool _copy;
@@ -558,6 +591,8 @@ public:
                return false;
        }
 
+       void setup_pointer_frame_offset ();
+       
 private:
        EditorCursor* _cursor; ///< cursor being dragged
        bool _stop; ///< true to stop the transport on starting the drag, otherwise false
@@ -578,6 +613,8 @@ public:
        bool y_movement_matters () const {
                return false;
        }
+
+       void setup_pointer_frame_offset ();
 };
 
 /** Region fade-out drag */
@@ -594,6 +631,8 @@ public:
        bool y_movement_matters () const {
                return false;
        }
+
+       void setup_pointer_frame_offset ();
 };
 
 /** Marker drag */
@@ -615,6 +654,8 @@ public:
        bool y_movement_matters () const {
                return false;
        }
+
+       void setup_pointer_frame_offset ();
        
 private:
        void update_item (ARDOUR::Location *);
@@ -758,6 +799,8 @@ public:
        void finished (GdkEvent *, bool);
        void aborted ();
 
+       void setup_pointer_frame_offset ();
+
 private:
        Operation _operation;
        bool _copy;
index a27d437274f6a182d5dd2f57f41ab109dd732e01..e2298c42ad75b79209952abf214d644db6687819 100644 (file)
@@ -1668,6 +1668,31 @@ MidiRegionView::alter_program_change(PCEvent& old_program, const MIDI::Name::Pat
         display_program_changes (); // XXX would be nice to limit to just old_program.channel
 }
 
+void
+MidiRegionView::move_program_change (PCEvent pc, double t)
+{
+       boost::shared_ptr<Evoral::Control> control = _model->control (Evoral::Parameter (MidiPgmChangeAutomation, pc.channel, 0));
+       assert (control);
+
+       /* XXX: seems that these events should have IDs, or that this code should
+          at least be in ControlList.
+       */
+
+       boost::shared_ptr<Evoral::ControlList> list = control->list ();
+       Evoral::ControlList::iterator i = list->begin ();
+       while (i != list->end() && ((*i)->when != pc.time || (*i)->value != pc.value)) {
+               ++i;
+       }
+
+       assert (i != list->end ());
+
+       list->erase (i);
+       list->add (t, pc.value);
+
+       _pgm_changes.clear ();
+       display_program_changes ();
+}
+
 void
 MidiRegionView::program_selected(CanvasProgramChange& program, const MIDI::Name::PatchPrimaryKey& new_patch)
 {
index 2b07c02382e79e0ba02a2282d3d8bc1384f34dd9..79a8405927598433baf85611da70737e17c9e340 100644 (file)
@@ -149,6 +149,8 @@ class MidiRegionView : public RegionView
         */
        void alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch);
 
+       void move_program_change (PCEvent, double);
+
        /** Alter a given program to the new given one.
         * (Called on context menu select on CanvasProgramChange)
         */