make shift-click for extend-selection sort-of work for MIDI

git-svn-id: svn://localhost/ardour2/branches/3.0@5541 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-08-18 02:37:57 +00:00
parent 3162ffb4f4
commit b116282bbb
5 changed files with 133 additions and 55 deletions

View File

@ -325,22 +325,21 @@ CanvasNoteEvent::on_event(GdkEvent* ev)
case Pressed: // Clicked
if (editor.current_mouse_mode() == Editing::MouseRange) {
_state = None;
if (_selected && !select_mod && _region.selection_size() > 1) {
_region.unique_select(this);
} else if (_selected) {
if (_selected) {
_region.note_deselected(this, select_mod);
} else {
_region.note_selected(this, select_mod);
}
#if 0
} else if (midi_edit_mode == Editing::MidiEditErase) {
_region.start_delta_command();
_region.command_remove_note(this);
_region.apply_command();
#endif
}
bool extend = Keyboard::modifier_state_equals (ev->motion.state, Keyboard::TertiaryModifier);
bool add = Keyboard::modifier_state_equals (ev->motion.state, Keyboard::PrimaryModifier);
if (!extend && !add && _region.selection_size() > 1) {
_region.unique_select(this);
} else {
_region.note_selected (this, (extend ? true : add), extend);
}
}
}
return true;
case Dragging: // Dropped
_item->ungrab(ev->button.time);
_state = None;

View File

@ -331,6 +331,8 @@ class Editor : public PublicEditor
/* nudge is initiated by transport controls owned by ARDOUR_UI */
nframes64_t get_nudge_distance (nframes64_t pos, nframes64_t& next);
void nudge_forward (bool next, bool force_playhead);
void nudge_backward (bool next, bool force_playhead);
@ -1901,8 +1903,6 @@ public:
Gtk::VBox nudge_vbox;
AudioClock nudge_clock;
nframes64_t get_nudge_distance (nframes64_t pos, nframes64_t& next);
bool nudge_forward_release (GdkEventButton*);
bool nudge_backward_release (GdkEventButton*);

View File

@ -214,6 +214,10 @@ MidiRegionView::canvas_event(GdkEvent* ev)
static ArdourCanvas::SimpleRect* drag_rect = NULL;
/* XXX: note that as of August 2009, the GnomeCanvas does not propagate scroll events
to its items, which means that ev->type == GDK_SCROLL will never be seen
*/
switch (ev->type) {
case GDK_SCROLL:
if (Keyboard::modifier_state_equals (ev->scroll.state, Keyboard::Level4Modifier)) {
@ -273,11 +277,11 @@ MidiRegionView::canvas_event(GdkEvent* ev)
}
} else if (ev->key.keyval == GDK_Left) {
nudge_notes (-1.0);
nudge_notes (false);
} else if (ev->key.keyval == GDK_Right) {
nudge_notes (1.0);
nudge_notes (true);
}
return false;
@ -1233,14 +1237,49 @@ MidiRegionView::unique_select(ArdourCanvas::CanvasNoteEvent* ev)
}
void
MidiRegionView::note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add)
MidiRegionView::note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend)
{
if (!add) {
clear_selection_except(ev);
}
if (!ev->selected()) {
add_to_selection (ev);
if (!extend) {
if (!ev->selected()) {
add_to_selection (ev);
}
} else {
/* find end of latest note selected, select all between that and the start of "ev" */
MidiModel::TimeType earliest = DBL_MAX;
MidiModel::TimeType latest = 0;
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->note()->end_time() > latest) {
latest = (*i)->note()->end_time();
}
if ((*i)->note()->time() < earliest) {
earliest = (*i)->note()->time();
}
}
if (ev->note()->end_time() > latest) {
earliest = latest;
latest = ev->note()->end_time();
} else {
earliest = ev->note()->time();
}
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
if ((*i)->note()->time() >= earliest && (*i)->note()->end_time() <= latest) {
add_to_selection (*i);
}
if ((*i)->note()->end_time() > latest) {
break;
}
}
}
}
@ -1654,29 +1693,13 @@ MidiRegionView::change_note_time (CanvasNoteEvent* event, MidiModel::TimeType de
command_add_note(copy, event->selected(), false);
}
void
MidiRegionView::change_velocity(CanvasNoteEvent* ev, int8_t velocity, bool relative)
{
start_delta_command(_("change velocity"));
change_note_velocity(ev, velocity, relative);
for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
Selection::iterator next = i;
++next;
if ( !(*((*i)->note()) == *(ev->note())) ) {
change_note_velocity(*i, velocity, relative);
}
i = next;
}
apply_command();
}
void
MidiRegionView::change_velocities (int8_t velocity, bool relative)
{
if (_selection.empty()) {
return;
}
start_delta_command(_("change velocities"));
for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
@ -1693,6 +1716,10 @@ MidiRegionView::change_velocities (int8_t velocity, bool relative)
void
MidiRegionView::transpose (bool up, bool fine)
{
if (_selection.empty()) {
return;
}
int8_t delta;
if (fine) {
@ -1718,8 +1745,40 @@ MidiRegionView::transpose (bool up, bool fine)
}
void
MidiRegionView::nudge_notes (MidiModel::TimeType delta)
MidiRegionView::nudge_notes (bool forward)
{
if (_selection.empty()) {
return;
}
/* pick a note as the point along the timeline to get the nudge distance.
its not necessarily the earliest note, so we may want to pull the notes out
into a vector and sort before using the first one.
*/
nframes64_t ref_point = _region->position() + beats_to_frames ((*(_selection.begin()))->note()->time());
nframes64_t next_pos = ref_point;
if (forward) {
next_pos += 1;
} else {
if (next_pos == 0) {
return;
}
next_pos -= 1;
}
trackview.editor().snap_to (next_pos, (forward ? 1 : -1), false);
nframes64_t distance = ref_point - next_pos;
cerr << "ref was " << ref_point << " next is " << next_pos << endl;
MidiModel::TimeType delta = frames_to_beats (fabs (distance));
if (!forward) {
delta = -delta;
}
start_delta_command (_("nudge"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
@ -1897,7 +1956,6 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
copied_note->set_time (paste_pos_beats + copied_note->time() - beat_delta);
/* make all newly added notes selected */
cerr << "\tadd @ " << copied_note->time() << endl;
command_add_note (copied_note, true);
end_point = copied_note->end_time();
@ -1911,15 +1969,12 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
nframes64_t end_frame = _region->position() + beats_to_frames (end_point);
nframes64_t region_end = _region->position() + _region->length() - 1;
cerr << "\tEnd frame = " << end_frame << " from " << end_point << " region end = " << region_end << endl;
if (end_frame > region_end) {
trackview.session().begin_reversible_command (_("paste"));
XMLNode& before (_region->get_state());
_region->set_length (end_frame, this);
cerr << "\textended to " << end_frame << endl;
trackview.session().add_command (new MementoCommand<Region>(*_region, &before, &_region->get_state()));
}
@ -1929,30 +1984,52 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
void
MidiRegionView::goto_next_note ()
{
nframes64_t pos = trackview.session().transport_frame();
// nframes64_t pos = -1;
bool use_next = false;
if (_events.back()->selected()) {
return;
}
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
nframes64_t npos = _region->position() + beats_to_frames ((*i)->note()->time());
if (npos >= pos && !(*i)->selected()) {
if ((*i)->selected()) {
use_next = true;
continue;
} else if (use_next) {
unique_select (*i);
trackview.session().request_locate (npos);
// pos = _region->position() + beats_to_frames ((*i)->note()->time());
return;
}
}
/* use the first one */
unique_select (_events.front());
}
void
MidiRegionView::goto_previous_note ()
{
nframes64_t pos = trackview.session().transport_frame();
// nframes64_t pos = -1;
bool use_next = false;
if (_events.front()->selected()) {
return;
}
for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
nframes64_t npos = _region->position() + beats_to_frames ((*i)->note()->time());
if (npos <= pos && !(*i)->selected()) {
if ((*i)->selected()) {
use_next = true;
continue;
} else if (use_next) {
unique_select (*i);
trackview.session().request_locate (npos);
// pos = _region->position() + beats_to_frames ((*i)->note()->time());
return;
}
}
/* use the last one */
unique_select (*(_events.rbegin()));
}

View File

@ -172,7 +172,7 @@ class MidiRegionView : public RegionView
void note_entered(ArdourCanvas::CanvasNoteEvent* ev);
void unique_select(ArdourCanvas::CanvasNoteEvent* ev);
void note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add);
void note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend=false);
void note_deselected(ArdourCanvas::CanvasNoteEvent* ev, bool add);
void delete_selection();
size_t selection_size() { return _selection.size(); }
@ -265,7 +265,7 @@ class MidiRegionView : public RegionView
void goto_next_note ();
void change_velocities (int8_t velocity, bool relative);
void transpose (bool up, bool fine);
void nudge_notes (ARDOUR::MidiModel::TimeType delta);
void nudge_notes (bool forward);
protected:
/** Allows derived types to specify their visibility requirements

View File

@ -263,6 +263,8 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
virtual void mouse_add_new_marker (nframes64_t where, bool is_cd=false, bool is_xrun=false) = 0;
virtual void foreach_time_axis_view (sigc::slot<void,TimeAxisView&>) = 0;
virtual void add_to_idle_resize (TimeAxisView*, int32_t) = 0;
virtual nframes64_t get_nudge_distance (nframes64_t pos, nframes64_t& next) = 0;
#ifdef WITH_CMT
virtual void add_imageframe_time_axis(const std::string & track_name, void*) = 0;