make mouse range mode do something interesting when in internal/note edit mode. not...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 20 Jan 2012 02:54:23 +0000 (02:54 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 20 Jan 2012 02:54:23 +0000 (02:54 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@11273 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/midi_time_axis.h
gtk2_ardour/piano_roll_header.cc
gtk2_ardour/piano_roll_header.h

index 25d1c878b812b1496118f339cc9ea0af602366c8..5201d3346df98d3bae2661067ea0a1b6b9f79439 100644 (file)
@@ -3112,6 +3112,7 @@ FeatureLineDrag::aborted (bool)
 
 RubberbandSelectDrag::RubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
+       , _vertical_only (false)
 {
        DEBUG_TRACE (DEBUG::Drags, "New RubberbandSelectDrag\n");
 }
@@ -3163,8 +3164,14 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool)
                double x2 = _editor->frame_to_pixel (end);
 
                _editor->rubberband_rect->property_x1() = x1;
+               if (_vertical_only) {
+                       /* fixed 10 pixel width */
+                       _editor->rubberband_rect->property_x2() = x1 + 10;
+               } else {
+                       _editor->rubberband_rect->property_x2() = x2;
+               } 
+
                _editor->rubberband_rect->property_y1() = y1;
-               _editor->rubberband_rect->property_x2() = x2;
                _editor->rubberband_rect->property_y2() = y2;
 
                _editor->rubberband_rect->show();
@@ -4337,6 +4344,34 @@ MidiRubberbandSelectDrag::deselect_things ()
        /* XXX */
 }
 
+MidiVerticalSelectDrag::MidiVerticalSelectDrag (Editor* e, MidiRegionView* rv)
+       : RubberbandSelectDrag (e, rv->get_canvas_frame ())
+       , _region_view (rv)
+{
+       _vertical_only = true;
+}
+
+void
+MidiVerticalSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress)
+{
+       double const y = _region_view->midi_view()->y_position ();
+
+       y1 = max (0.0, y1 - y);
+       y2 = max (0.0, y2 - y);
+       
+       _region_view->update_vertical_drag_selection (
+               y1,
+               y2,
+               Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier)
+               );
+}
+
+void
+MidiVerticalSelectDrag::deselect_things ()
+{
+       /* XXX */
+}
+
 EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
        : RubberbandSelectDrag (e, i)
 {
index 6e055a6344a4c612d318bbe46c5e4c9f592a1584..e4270b9d9d8f24e3aaccc2874f0bf269578ed2b9 100644 (file)
@@ -800,6 +800,9 @@ public:
        virtual void select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) = 0;
        
        virtual void deselect_things () = 0;
+
+  protected:
+       bool _vertical_only;
 };
 
 /** A general editor RubberbandSelectDrag (for regions, automation points etc.) */
@@ -825,6 +828,19 @@ private:
        MidiRegionView* _region_view;
 };
 
+/** A RubberbandSelectDrag for selecting MIDI notes but with no horizonal component */
+class MidiVerticalSelectDrag : public RubberbandSelectDrag
+{
+public:
+       MidiVerticalSelectDrag (Editor *, MidiRegionView *);
+
+       void select_things (int, framepos_t, framepos_t, double, double, bool);
+       void deselect_things ();
+
+private:
+       MidiRegionView* _region_view;
+};
+
 /** Region drag in time-FX mode */
 class TimeFXDrag : public RegionDrag
 {
index 196f0f09603e7a80079892c252095967fc92a08f..dcd760484cec2f6432bd043d272f91c0d5ebf165 100644 (file)
@@ -435,7 +435,7 @@ MidiRegionView::button_press (GdkEventButton* ev)
 
        Editor* editor = dynamic_cast<Editor *> (&trackview.editor());
        MouseMode m = editor->current_mouse_mode();
-       
+
        if (m == MouseObject && Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
                pre_press_cursor = editor->get_canvas_cursor ();
                editor->set_canvas_cursor (editor->cursors()->midi_pencil);
@@ -480,6 +480,11 @@ MidiRegionView::button_release (GdkEventButton* ev)
        case Pressed: // Clicked
 
                switch (editor.current_mouse_mode()) {
+               case MouseRange:
+                       /* no motion occured - simple click */
+                       clear_selection ();
+                       break;
+
                case MouseObject:
                case MouseTimeFX:
                        {
@@ -595,20 +600,23 @@ MidiRegionView::motion (GdkEventMotion* ev)
                                _mouse_state = AddDragging;
                                remove_ghost_note ();
                                editor.verbose_cursor()->hide ();
-                               cerr << "starting note create drag\n";
-
                                return true;
-                       } else {
+                       } else if (m == MouseObject) {
                                
                                editor.drags()->set (new MidiRubberbandSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev);
                                _mouse_state = SelectRectDragging;
                                return true;
+                       } else if (m == MouseRange) {
+                               editor.drags()->set (new MidiVerticalSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev);
+                               _mouse_state = SelectVerticalDragging;
+                               return true;
                        }
                }
 
                return false;
 
        case SelectRectDragging:
+       case SelectVerticalDragging:
        case AddDragging:
                editor.drags()->motion_handler ((GdkEvent *) ev, false);
                break;
@@ -2208,6 +2216,38 @@ MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2
        }
 }
 
+void
+MidiRegionView::update_vertical_drag_selection (double y1, double y2, bool extend)
+{
+       if (y1 > y2) {
+               swap (y1, y2);
+       }
+
+       // TODO: Make this faster by storing the last updated selection rect, and only
+       // adjusting things that are in the area that appears/disappeared.
+       // We probably need a tree to be able to find events in O(log(n)) time.
+
+       for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+
+               /* check if any corner of the note is inside the rect
+
+                  Notes:
+                  1) this is computing "touched by", not "contained by" the rect.
+                  2) this does not require that events be sorted in time.
+               */
+
+               if (((*i)->y1() >= y1 && (*i)->y1() <= y2)) {
+                       // within y- (note-) range
+                       if (!(*i)->selected()) {
+                               add_to_selection (*i);
+                       }
+               } else if ((*i)->selected() && !extend) {
+                       // Not inside rectangle
+                       remove_from_selection (*i);
+               }
+       }
+}
+
 void
 MidiRegionView::remove_from_selection (CanvasNoteEvent* ev)
 {
index d1c1fb7c94a7791221426d981f57ebe62105aba8..120d571725f10ca7440a5f8445e9cfeb1eb819f1 100644 (file)
@@ -230,6 +230,7 @@ public:
                Pressed,
                SelectTouchDragging,
                SelectRectDragging,
+               SelectVerticalDragging,
                AddDragging
        };
 
@@ -315,6 +316,7 @@ protected:
 private:
 
        friend class MidiRubberbandSelectDrag;
+       friend class MidiVerticalSelectDrag;
 
        /** Emitted when the selection has been cleared in one MidiRegionView */
        static PBD::Signal1<void, MidiRegionView*> SelectionCleared;
@@ -353,6 +355,7 @@ private:
        void clear_selection_except (ArdourCanvas::CanvasNoteEvent* ev, bool signal = true);
        void clear_selection (bool signal = true) { clear_selection_except (0, signal); }
        void update_drag_selection (double last_x, double x, double last_y, double y, bool extend);
+       void update_vertical_drag_selection (double last_y, double y, bool extend);
 
        void add_to_selection (ArdourCanvas::CanvasNoteEvent*);
        void remove_from_selection (ArdourCanvas::CanvasNoteEvent*);
index c3df55a43985a6e1d611674d4bdafd991df75ff3..922b5ab031f6e3aa3baeda5851e79a9acd45be62 100644 (file)
@@ -164,6 +164,7 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
        _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
 
        if (is_track()) {
+               _piano_roll_header->SetNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
                _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
                _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
                _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
@@ -964,7 +965,21 @@ MidiTimeAxisView::route_active_changed ()
        }
 }
 
+void
+MidiTimeAxisView::set_note_selection (uint8_t note)
+{
+       if (!_editor.internal_editing()) {
+               return;
+       }
 
+       uint16_t chn_mask = _channel_selector.get_selected_channels();
+
+       if (_view->num_selected_regionviews() == 0) {
+               _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view), note, chn_mask));
+       } else {
+               _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view), note, chn_mask));
+       }
+}
 
 void
 MidiTimeAxisView::add_note_selection (uint8_t note)
@@ -1015,11 +1030,17 @@ MidiTimeAxisView::toggle_note_selection (uint8_t note)
 }
 
 void
-MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
+MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
 {
        dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
 }
 
+void
+MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
+{
+       dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
+}
+
 void
 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
 {
index b3c916ea697fd2739ebd4fa81cf728caaf131b34..8207792f830e892ff702150bef0441f00829ad15 100644 (file)
@@ -153,9 +153,11 @@ class MidiTimeAxisView : public RouteTimeAxisView
        void build_controller_menu ();
        void set_channel_mode (ARDOUR::ChannelMode, uint16_t);
 
+       void set_note_selection (uint8_t note);
        void add_note_selection (uint8_t note);
        void extend_note_selection (uint8_t note);
        void toggle_note_selection (uint8_t note);
+       void set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask);
        void add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask);
        void extend_note_selection_region_view (RegionView*, uint8_t note, uint16_t chn_mask);
        void toggle_note_selection_region_view (RegionView*, uint8_t note, uint16_t chn_mask);
index b041bb3a89aaeb31d00f4498219ba129145d2aa5..3243f893c7622a9d27dfcf6b38c263e1b4000b29 100644 (file)
 
 #include "gtkmm2ext/keyboard.h"
 
+#include "editing.h"
 #include "piano_roll_header.h"
 #include "midi_time_axis.h"
 #include "midi_streamview.h"
+#include "public_editor.h"
 
 const int no_note = 0xff;
 
@@ -465,26 +467,39 @@ PianoRollHeader::on_motion_notify_event (GdkEventMotion* ev)
 
                int note = _view.y_to_note(ev->y);
 
-               if (_highlighted_note != no_note) {
-                       if (note > _highlighted_note) {
-                               invalidate_note_range(_highlighted_note, note);
-                       } else {
-                               invalidate_note_range(note, _highlighted_note);
-                       }
-
-                       _highlighted_note = note;
-               }
+               if (editor().current_mouse_mode() == Editing::MouseRange) {
+                       
+                       /* select note range */
 
-               /* redraw already taken care of above */
-               if (_clicked_note != no_note && _clicked_note != note) {
-                       _active_notes[_clicked_note] = false;
-                       send_note_off(_clicked_note);
+                       if (Keyboard::no_modifiers_active (ev->state)) {
+                               AddNoteSelection (note); // EMIT SIGNAL
+                       }
 
-                       _clicked_note = note;
+               } else {
+                       
+                       /* play notes */
 
-                       if (!_active_notes[note]) {
-                               _active_notes[note] = true;
-                               send_note_on(note);
+                       if (_highlighted_note != no_note) {
+                               if (note > _highlighted_note) {
+                                       invalidate_note_range(_highlighted_note, note);
+                               } else {
+                                       invalidate_note_range(note, _highlighted_note);
+                               }
+                               
+                               _highlighted_note = note;
+                       }
+                       
+                       /* redraw already taken care of above */
+                       if (_clicked_note != no_note && _clicked_note != note) {
+                               _active_notes[_clicked_note] = false;
+                               send_note_off(_clicked_note);
+                               
+                               _clicked_note = note;
+                               
+                               if (!_active_notes[note]) {
+                                       _active_notes[note] = true;
+                                       send_note_on(note);
+                               }
                        }
                }
        }
@@ -499,9 +514,15 @@ PianoRollHeader::on_button_press_event (GdkEventButton* ev)
 {
        int note = _view.y_to_note(ev->y);
 
-       if (ev->button == 2) {
-               send_note_on (note);
-               /* relax till release */
+       if (ev->button != 1) {
+               return false;
+       }
+
+       if (editor().current_mouse_mode() == Editing::MouseRange) {
+               if (Keyboard::no_modifiers_active (ev->state)) {
+                       SetNoteSelection (note); // EMIT SIGNAL
+               }
+               _dragging = true;
        } else {
 
                if (ev->type == GDK_BUTTON_PRESS && note >= 0 && note < 128) {
@@ -529,8 +550,7 @@ PianoRollHeader::on_button_release_event (GdkEventButton* ev)
 {
        int note = _view.y_to_note(ev->y);
 
-       if (ev->button == 2) {
-               send_note_off (note);
+       if (editor().current_mouse_mode() == Editing::MouseRange) {
 
                if (Keyboard::no_modifiers_active (ev->state)) {
                        AddNoteSelection (note); // EMIT SIGNAL
@@ -539,12 +559,11 @@ PianoRollHeader::on_button_release_event (GdkEventButton* ev)
                } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
                        ExtendNoteSelection (note); // EMIT SIGNAL
                }
-
+               
        } else {
 
                if (_dragging) {
                        remove_modal_grab();
-                       _dragging = false;
 
                        if (note == _clicked_note) {
                                reset_clicked_note(note);
@@ -552,6 +571,7 @@ PianoRollHeader::on_button_release_event (GdkEventButton* ev)
                }
        }
 
+       _dragging = false;
        return true;
 }
 
@@ -694,3 +714,9 @@ PianoRollHeader::reset_clicked_note (uint8_t note, bool invalidate)
                invalidate_note_range (note, note);
        }
 }
+
+PublicEditor&
+PianoRollHeader::editor() const
+{
+       return _view.trackview().editor();
+}
index 7f469aebcefe20b49ff7defb4f1a1846c6d9650f..bb87d36e4dd341917dc9b929a5545d18650e1d25 100644 (file)
@@ -30,6 +30,7 @@ namespace ARDOUR {
 
 class MidiTimeAxisView;
 class MidiStreamView;
+class PublicEditor;
 
 class PianoRollHeader : public Gtk::DrawingArea {
 public:
@@ -58,6 +59,7 @@ public:
                double b;
        };
 
+       sigc::signal<void,uint8_t> SetNoteSelection;
        sigc::signal<void,uint8_t> AddNoteSelection;
        sigc::signal<void,uint8_t> ToggleNoteSelection;
        sigc::signal<void,uint8_t> ExtendNoteSelection;
@@ -107,6 +109,8 @@ private:
 
        double _note_height;
        double _black_note_width;
+
+       PublicEditor& editor() const;
 };
 
 #endif /* __ardour_piano_roll_header_h__ */