summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2012-01-20 02:54:23 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2012-01-20 02:54:23 +0000
commit5de9a8f38b0e18317b2b23c5b8698d0d29eba12b (patch)
tree2068d91f2e1af148386e855cee397d332709f4c6
parentc2a93a9b3855f85830a715757b8c131113bc9a3e (diff)
make mouse range mode do something interesting when in internal/note edit mode. not entirely finished because the usual modifiers to add/extend the selection don't work correctly. note that this works both on the scroomer (where the modifiers do work correctly) and in the track (where they do not)
git-svn-id: svn://localhost/ardour2/branches/3.0@11273 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/editor_drag.cc37
-rw-r--r--gtk2_ardour/editor_drag.h16
-rw-r--r--gtk2_ardour/midi_region_view.cc48
-rw-r--r--gtk2_ardour/midi_region_view.h3
-rw-r--r--gtk2_ardour/midi_time_axis.cc23
-rw-r--r--gtk2_ardour/midi_time_axis.h2
-rw-r--r--gtk2_ardour/piano_roll_header.cc74
-rw-r--r--gtk2_ardour/piano_roll_header.h4
8 files changed, 177 insertions, 30 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 25d1c878b8..5201d3346d 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -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)
{
diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h
index 6e055a6344..e4270b9d9d 100644
--- a/gtk2_ardour/editor_drag.h
+++ b/gtk2_ardour/editor_drag.h
@@ -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
{
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 196f0f0960..dcd760484c 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -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;
@@ -2209,6 +2217,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)
{
Selection::iterator i = _selection.find (ev);
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index d1c1fb7c94..120d571725 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -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*);
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index c3df55a439..922b5ab031 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -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,12 +1030,18 @@ 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)
{
dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index b3c916ea69..8207792f83 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -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);
diff --git a/gtk2_ardour/piano_roll_header.cc b/gtk2_ardour/piano_roll_header.cc
index b041bb3a89..3243f893c7 100644
--- a/gtk2_ardour/piano_roll_header.cc
+++ b/gtk2_ardour/piano_roll_header.cc
@@ -22,9 +22,11 @@
#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();
+}
diff --git a/gtk2_ardour/piano_roll_header.h b/gtk2_ardour/piano_roll_header.h
index 7f469aebce..bb87d36e4d 100644
--- a/gtk2_ardour/piano_roll_header.h
+++ b/gtk2_ardour/piano_roll_header.h
@@ -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__ */