various fixes to MidiRegionView selection handling, key handling, drawing of ghost notes (contains a fix for #4263); shift-drag selections in MidiRegionViews now correctly add to the selection rather than replacing any existing one.

git-svn-id: svn://localhost/ardour2/branches/3.0@10000 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-08-17 12:46:42 +00:00
parent 4aa84f0513
commit 45d51d3aee
4 changed files with 82 additions and 64 deletions

View file

@ -363,25 +363,30 @@ MidiRegionView::enter_notify (GdkEventCrossing* ev)
{
trackview.editor().MouseModeChanged.connect (
_mouse_mode_connection, invalidator (*this), ui_bind (&MidiRegionView::mouse_mode_changed, this), gui_context ()
);
Keyboard::magic_widget_grab_focus();
group->grab_focus();
);
if (trackview.editor().current_mouse_mode() == MouseRange) {
create_ghost_note (ev->x, ev->y);
}
if (!trackview.editor().internal_editing()) {
Keyboard::magic_widget_drop_focus();
} else {
Keyboard::magic_widget_grab_focus();
group->grab_focus();
}
return false;
}
bool
MidiRegionView::leave_notify (GdkEventCrossing*)
MidiRegionView::leave_notify (GdkEventCrossing* ev)
{
_mouse_mode_connection.disconnect ();
trackview.editor().verbose_cursor()->hide ();
remove_ghost_note ();
return false;
}
@ -394,6 +399,13 @@ MidiRegionView::mouse_mode_changed ()
remove_ghost_note ();
trackview.editor().verbose_cursor()->hide ();
}
if (!trackview.editor().internal_editing()) {
Keyboard::magic_widget_drop_focus();
} else {
Keyboard::magic_widget_grab_focus();
group->grab_focus();
}
}
bool
@ -661,7 +673,7 @@ MidiRegionView::motion (GdkEventMotion* ev)
_drag_rect->property_y1() = event_y;
}
update_drag_selection(_drag_start_x, event_x, _drag_start_y, event_y);
update_drag_selection(_drag_start_x, event_x, _drag_start_y, event_y, Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
}
_last_x = event_x;
@ -705,15 +717,17 @@ MidiRegionView::key_press (GdkEventKey* ev)
repeated presses, carry out key actions at key press, not release.
*/
if (ev->keyval == GDK_Alt_L || ev->keyval == GDK_Alt_R) {
bool unmodified = Keyboard::no_modifier_keys_pressed (ev);
if (unmodified && (ev->keyval == GDK_Alt_L || ev->keyval == GDK_Alt_R)) {
_mouse_state = SelectTouchDragging;
return true;
} else if (ev->keyval == GDK_Escape) {
} else if (ev->keyval == GDK_Escape && unmodified) {
clear_selection();
_mouse_state = None;
} else if (ev->keyval == GDK_comma || ev->keyval == GDK_period) {
} else if (unmodified && (ev->keyval == GDK_comma || ev->keyval == GDK_period)) {
bool start = (ev->keyval == GDK_comma);
bool end = (ev->keyval == GDK_period);
@ -724,7 +738,7 @@ MidiRegionView::key_press (GdkEventKey* ev)
return true;
} else if (ev->keyval == GDK_Delete) {
} else if (ev->keyval == GDK_Delete && unmodified) {
delete_selection();
return true;
@ -775,20 +789,17 @@ MidiRegionView::key_press (GdkEventKey* ev)
}
return true;
} else if (ev->keyval == GDK_Left) {
} else if (ev->keyval == GDK_Left && unmodified) {
nudge_notes (false);
return true;
} else if (ev->keyval == GDK_Right) {
} else if (ev->keyval == GDK_Right && unmodified) {
nudge_notes (true);
return true;
} else if (ev->keyval == GDK_Control_L) {
return true;
} else if (ev->keyval == GDK_c) {
} else if (ev->keyval == GDK_c && unmodified) {
channel_edit ();
return true;
}
@ -799,7 +810,7 @@ MidiRegionView::key_press (GdkEventKey* ev)
bool
MidiRegionView::key_release (GdkEventKey* ev)
{
if (ev->keyval == GDK_Alt_L || ev->keyval == GDK_Alt_R) {
if ((_mouse_state == SelectTouchDragging) && (ev->keyval == GDK_Alt_L || ev->keyval == GDK_Alt_R)) {
_mouse_state = None;
return true;
}
@ -1930,40 +1941,37 @@ MidiRegionView::delete_note (boost::shared_ptr<NoteType> n)
}
void
MidiRegionView::clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev)
{
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->selected() && (*i) != ev) {
(*i)->set_selected(false);
(*i)->hide_velocity();
}
}
_selection.clear();
}
void
MidiRegionView::unique_select(ArdourCanvas::CanvasNoteEvent* ev)
MidiRegionView::clear_selection_except (ArdourCanvas::CanvasNoteEvent* ev)
{
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
if ((*i) != ev) {
Selection::iterator tmp = i;
++tmp;
(*i)->set_selected (false);
(*i)->hide_velocity ();
_selection.erase (i);
i = tmp;
} else {
++i;
}
}
/* don't bother with removing this regionview from the editor selection,
since we're about to add another note, and thus put/keep this
regionview in the editor selection.
/* this does not change the status of this regionview w.r.t the editor
selection.
*/
}
void
MidiRegionView::unique_select(ArdourCanvas::CanvasNoteEvent* ev)
{
clear_selection_except (ev);
/* don't bother with checking to see if we should remove this
regionview from the editor selection, since we're about to add
another note, and thus put/keep this regionview in the editor
selection anyway.
*/
if (!ev->selected()) {
@ -2071,10 +2079,14 @@ MidiRegionView::toggle_matching_notes (uint8_t notenum, uint16_t channel_mask)
}
void
MidiRegionView::note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend)
MidiRegionView::note_selected (ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend)
{
if (!add) {
clear_selection_except(ev);
clear_selection_except (ev);
if (!_selection.empty()) {
PublicEditor& editor (trackview.editor());
editor.get_selection().add (this);
}
}
if (!extend) {
@ -2126,7 +2138,7 @@ MidiRegionView::note_deselected(ArdourCanvas::CanvasNoteEvent* ev)
}
void
MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2)
MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2, bool extend)
{
if (x1 > x2) {
swap (x1, x2);
@ -2163,7 +2175,7 @@ MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2
if (!(*i)->selected()) {
add_to_selection (*i);
}
} else if ((*i)->selected()) {
} else if ((*i)->selected() && !extend) {
// Not inside rectangle
remove_from_selection (*i);
}
@ -3333,7 +3345,7 @@ MidiRegionView::update_ghost_note (double x, double y)
/* note that this sets the time of the ghost note in beats relative to
the start of the region.
*/
_ghost_note->note()->set_time (region_frames_to_region_beats (f - _region->position()));
_ghost_note->note()->set_time (region_frames_to_region_beats (f));
_ghost_note->note()->set_length (length);
_ghost_note->note()->set_note (midi_stream_view()->y_to_note (y));
_ghost_note->note()->set_channel (mtv->get_channel_for_add ());

View file

@ -344,9 +344,9 @@ private:
void trim_note(ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::MidiModel::TimeType start_delta,
ARDOUR::MidiModel::TimeType end_delta);
void clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev);
void clear_selection() { clear_selection_except(NULL); }
void update_drag_selection(double last_x, double x, double last_y, double y);
void clear_selection_except (ArdourCanvas::CanvasNoteEvent* ev);
void clear_selection() { clear_selection_except (0); }
void update_drag_selection (double last_x, double x, double last_y, double y, bool extend);
void add_to_selection (ArdourCanvas::CanvasNoteEvent*);
void remove_from_selection (ArdourCanvas::CanvasNoteEvent*);

View file

@ -599,6 +599,8 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
GtkWidget* focus = gtk_window_get_focus (win);
bool special_handling_of_unmodified_accelerators = false;
bool allow_activating = true;
/* consider all relevant modifiers but not LOCK or SHIFT */
const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
if (focus) {
if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
@ -654,42 +656,38 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
*/
#ifdef GTKOSX
if (!special_handling_of_unmodified_accelerators) {
if (ev->state & GDK_MOD1_MASK) {
/* we're not in a text entry or "magic focus" widget so we don't want OS X "special-character"
text-style handling of alt-<key>. change the keyval back to what it would be without
the alt key. this way, we see <alt>-v rather than <alt>-radical and so on.
*/
guint keyval_without_alt = osx_keyval_without_alt (ev->keyval);
if (keyval_without_alt != GDK_VoidSymbol) {
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Remapped %1 to %2\n", gdk_keyval_name (ev->keyval), gdk_keyval_name (keyval_without_alt)));
ev->keyval = keyval_without_alt;
}
if (!special_handling_of_unmodified_accelerators && (ev->state & Keyboard::SecondaryModifier)) {
/* we're not in a text entry or "magic focus" widget so we don't want OS X "special-character"
text-style handling of alt-<key>. change the keyval back to what it would be without
the alt key. this way, we see <alt>-v rather than <alt>-radical and so on.
*/
guint keyval_without_alt = osx_keyval_without_alt (ev->keyval);
if (keyval_without_alt != GDK_VoidSymbol) {
DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Remapped %1 to %2\n", gdk_keyval_name (ev->keyval), gdk_keyval_name (keyval_without_alt)));
ev->keyval = keyval_without_alt;
}
}
#endif
if (!special_handling_of_unmodified_accelerators) {
if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
/* pretend that certain key events that GTK does not allow
to be used as accelerators are actually something that
it does allow.
it does allow. but only where there are no modifiers.
*/
uint32_t fakekey = ev->keyval;
if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
if (allow_activating && gtk_accel_groups_activate(G_OBJECT(win), fakekey, GdkModifierType(ev->state))) {
DEBUG_TRACE (DEBUG::Accelerators, "\taccel group activated by fakekey\n");
return true;
}
}
}
/* consider all relevant modifiers but not LOCK or SHIFT */
guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
/* no special handling or there are modifiers in effect: accelerate first */
@ -700,6 +698,8 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
if (gtk_window_activate_key (win, ev)) {
return true;
}
} else {
DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n");
}
DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
@ -715,6 +715,8 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
if (allow_activating) {
return gtk_window_activate_key (win, ev);
} else {
DEBUG_TRACE (DEBUG::Accelerators, "\tactivation skipped\n");
}
} else {

View file

@ -91,6 +91,10 @@ class Keyboard : public sigc::trackable, PBD::Stateful
return (ev->state & RelevantModifierKeyMask) == 0;
}
static bool no_modifier_keys_pressed(GdkEventKey* ev) {
return (ev->state & RelevantModifierKeyMask) == 0;
}
bool leave_window (GdkEventCrossing *ev, Gtk::Window*);
bool enter_window (GdkEventCrossing *ev, Gtk::Window*);