Fix my name :)
[ardour.git] / gtk2_ardour / midi_region_view.cc
index af79a4f2b8f892b9d29121f7ab1b24357bff992e..af3b624eebbf72620ce60842fced64c355860b8e 100644 (file)
@@ -1,6 +1,6 @@
 /*
     Copyright (C) 2001-2007 Paul Davis
-    Author: Dave Robillard
+    Author: David Robillard
 
     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
@@ -49,6 +49,7 @@
 #include "canvas-hit.h"
 #include "canvas-note.h"
 #include "canvas_patch_change.h"
+#include "debug.h"
 #include "editor.h"
 #include "ghostregion.h"
 #include "gui_thread.h"
@@ -293,10 +294,6 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                return false;
        }
 
-       /* XXX: note that until version 2.30, the GnomeCanvas did not propagate scroll events
-          to its items, which means that ev->type == GDK_SCROLL will never be seen
-       */
-
        switch (ev->type) {
        case GDK_SCROLL:
                 return scroll (&ev->scroll);
@@ -380,16 +377,20 @@ MidiRegionView::mouse_mode_changed ()
 bool
 MidiRegionView::button_press (GdkEventButton* ev)
 {
+        if (ev->button != 1) {
+                return false;
+        }
+
         _last_x = ev->x;
         _last_y = ev->y;
-       
+        
         group->w2i (_last_x, _last_y);
         
         if (_mouse_state != SelectTouchDragging) {
-         
+                
                 _pressed_button = ev->button;
                 _mouse_state = Pressed;
-
+                
                 return true;
         }
         
@@ -404,6 +405,10 @@ MidiRegionView::button_release (GdkEventButton* ev)
        double event_x, event_y;
        framepos_t event_frame = 0;
 
+        if (ev->button != 1) {
+                return false;
+        }
+
         event_x = ev->x;
         event_y = ev->y;
        
@@ -924,7 +929,7 @@ MidiRegionView::note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
 }
 
 void
-MidiRegionView::apply_diff ()
+MidiRegionView::apply_diff (bool as_subcommand)
 {
         bool add_or_remove;
 
@@ -939,7 +944,12 @@ MidiRegionView::apply_diff ()
                 }
         }
 
-       _model->apply_command(*trackview.session(), _note_diff_command);
+       if (as_subcommand) {
+               _model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
+       } else {
+               _model->apply_command (*trackview.session(), _note_diff_command);
+       }
+       
        _note_diff_command = 0;
        midi_view()->midi_track()->playlist_modified();
         
@@ -950,33 +960,6 @@ MidiRegionView::apply_diff ()
        _marked_for_velocity.clear();
 }
 
-void
-MidiRegionView::apply_diff_as_subcommand ()
-{
-        bool add_or_remove;
-
-       if (!_note_diff_command) {
-               return;
-       }
-
-        if ((add_or_remove = _note_diff_command->adds_or_removes())) {
-                // Mark all selected notes for selection when model reloads
-                for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
-                        _marked_for_selection.insert((*i)->note());
-                }
-        }
-
-       _model->apply_command_as_subcommand(*trackview.session(), _note_diff_command);
-       _note_diff_command = 0;
-       midi_view()->midi_track()->playlist_modified();
-
-        if (add_or_remove) {
-                _marked_for_selection.clear();
-        }
-       _marked_for_velocity.clear();
-}
-
-
 void
 MidiRegionView::abort_command()
 {
@@ -1028,7 +1011,6 @@ MidiRegionView::redisplay_model()
        }
 
        if (!_model) {
-               cerr << "MidiRegionView::redisplay_model called without a model" << endmsg;
                return;
        }
 
@@ -1327,16 +1309,16 @@ MidiRegionView::add_ghost (TimeAxisView& tv)
                ghost = new MidiGhostRegion (tv, trackview, unit_position);
        }
 
-       ghost->set_height ();
-       ghost->set_duration (_region->length() / samples_per_unit);
-       ghosts.push_back (ghost);
-
        for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
                if ((note = dynamic_cast<CanvasNote*>(*i)) != 0) {
                        ghost->add_note(note);
                }
        }
 
+       ghost->set_height ();
+       ghost->set_duration (_region->length() / samples_per_unit);
+       ghosts.push_back (ghost);
+
        GhostRegion::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&RegionView::remove_ghost, this, _1), gui_context());
 
        return ghost;
@@ -1460,8 +1442,12 @@ MidiRegionView::note_in_region_range(const boost::shared_ptr<NoteType> note, boo
        return !outside;
 }
 
+/** Update a canvas note's size from its model note.
+ *  @param ev Canvas note to update.
+ *  @param update_ghost_regions true to update the note in any ghost regions that we have, otherwise false.
+ */
 void
-MidiRegionView::update_note (CanvasNote* ev)
+MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
 {
        boost::shared_ptr<NoteType> note = ev->note();
 
@@ -1504,6 +1490,15 @@ MidiRegionView::update_note (CanvasNote* ev)
                /* outline all edges */
                ev->property_outline_what() = (guint32) 0xF;
        }
+
+       if (update_ghost_regions) {
+               for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
+                       MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
+                       if (gr) {
+                               gr->update_note (ev);
+                       }
+               }
+       }
 }
 
 double
@@ -2853,7 +2848,7 @@ void
 MidiRegionView::note_mouse_position (float x_fraction, float /*y_fraction*/, bool can_set_cursor)
 {
        Editor* editor = dynamic_cast<Editor*>(&trackview.editor());
-
+        
         if (x_fraction > 0.0 && x_fraction < 0.25) {
                 editor->set_canvas_cursor (editor->cursors()->left_side_trim);
         } else if (x_fraction >= 0.75 && x_fraction < 1.0) {
@@ -2868,13 +2863,27 @@ MidiRegionView::note_mouse_position (float x_fraction, float /*y_fraction*/, boo
 void
 MidiRegionView::set_frame_color()
 {
-       if (frame) {
-               if (_selected && should_show_selection) {
-                       frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get();
-               } else {
-                       frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiFrameBase.get();
-               }
+        uint32_t f;
+
+        TimeAxisViewItem::set_frame_color ();
+
+       if (!frame) {
+               return;
        }
+
+       if (_selected) {
+               f = ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get();
+       } else if (high_enough_for_name) {
+               f= ARDOUR_UI::config()->canvasvar_MidiFrameBase.get();
+       } else {
+               f = fill_color;
+       }
+        
+        if (!rect_visible) {
+                f = UINT_RGBA_CHANGE_A (f, 0);
+        }
+
+        frame->property_fill_color_rgba() = f;
 }
 
 void
@@ -2962,6 +2971,7 @@ MidiRegionView::selection_as_cut_buffer () const
        return cb;
 }
 
+/** This method handles undo */
 void
 MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
 {
@@ -2969,6 +2979,10 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
                return;
        }
 
+        DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("MIDI paste @ %1 times %2\n", pos, times));
+
+       trackview.session()->begin_reversible_command (_("paste"));
+
        start_note_diff_command (_("paste"));
 
        Evoral::MusicalTime beat_delta;
@@ -2981,6 +2995,12 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
        beat_delta = (*mcb.notes().begin())->time() - paste_pos_beats;
        paste_pos_beats = 0;
 
+        DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6 ; beat delta = %7\n",
+                                                       (*mcb.notes().begin())->time(),
+                                                       (*mcb.notes().rbegin())->end_time(),
+                                                       duration, pos, _region->position(),
+                                                       paste_pos_beats, beat_delta));
+                                                       
         clear_selection ();
 
        for (int n = 0; n < (int) times; ++n) {
@@ -3006,14 +3026,16 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
 
        if (end_frame > region_end) {
 
-               trackview.session()->begin_reversible_command (_("paste"));
+                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame));
 
                 _region->clear_changes ();
                _region->set_length (end_frame, this);
                trackview.session()->add_command (new StatefulDiffCommand (_region));
        }
 
-       apply_diff ();
+       apply_diff (true);
+       
+       trackview.session()->commit_reversible_command ();
 }
 
 struct EventNoteTimeEarlyFirstComparator {
@@ -3137,7 +3159,8 @@ MidiRegionView::update_ghost_note (double x, double y)
        _ghost_note->note()->set_length (length);
        _ghost_note->note()->set_note (midi_stream_view()->y_to_note (y));
 
-       update_note (_ghost_note);
+       /* the ghost note does not appear in ghost regions, so pass false in here */
+       update_note (_ghost_note, false);
 
        show_verbose_canvas_cursor (_ghost_note->note ());
 }
@@ -3150,6 +3173,7 @@ MidiRegionView::create_ghost_note (double x, double y)
 
        boost::shared_ptr<NoteType> g (new NoteType);
        _ghost_note = new NoEventCanvasNote (*this, *_note_group, g);
+       _ghost_note->property_outline_color_rgba() = 0x000000aa;
        update_ghost_note (x, y);
        _ghost_note->show ();
 
@@ -3320,8 +3344,8 @@ MidiRegionView::data_recorded (boost::shared_ptr<MidiBuffer> buf, boost::weak_pt
 
                if (ev.type() == MIDI_CMD_NOTE_ON) {
 
-                       boost::shared_ptr<Evoral::Note<Evoral::MusicalTime> > note (
-                               new Evoral::Note<Evoral::MusicalTime> (ev.channel(), time_beats, 0, ev.note(), ev.velocity())
+                       boost::shared_ptr<NoteType> note (
+                               new NoteType (ev.channel(), time_beats, 0, ev.note(), ev.velocity())
                                );
 
                        add_note (note, true);