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:
parent
c2a93a9b38
commit
5de9a8f38b
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in New Issue
Block a user