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
This commit is contained in:
Paul Davis 2012-01-20 02:54:23 +00:00
parent c2a93a9b38
commit 5de9a8f38b
8 changed files with 177 additions and 30 deletions

View 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)
{

View 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
{

View 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)
{

View 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*);

View 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)
{

View 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);

View File

@ -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);
if (editor().current_mouse_mode() == Editing::MouseRange) {
/* select note range */
if (Keyboard::no_modifiers_active (ev->state)) {
AddNoteSelection (note); // EMIT SIGNAL
}
_highlighted_note = note;
}
} else {
/* play notes */
/* 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);
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();
}

View 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__ */