From a7b346518f96b9eea2f16cf0e72313d8f9fef901 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 17 Aug 2011 12:46:42 +0000 Subject: [PATCH] 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: http://subversion.ardour.org/svn/ardour2/ardour2/branches/3.0@10000 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/midi_region_view.cc | 96 +++++++++++++++++++++---------------- gtk2_ardour/midi_region_view.h | 6 +-- gtk2_ardour/utils.cc | 40 ++++++++-------- libs/gtkmm2ext/gtkmm2ext/keyboard.h | 4 ++ 4 files changed, 82 insertions(+), 64 deletions(-) diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index f82f309c8..dd9f68656 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -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 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 ()); diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 69cddd2fc..29a5d648d 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -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*); diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 90f792391..8177e7fac 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -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-. change the keyval back to what it would be without - the alt key. this way, we see -v rather than -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-. change the keyval back to what it would be without + the alt key. this way, we see -v rather than -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 { diff --git a/libs/gtkmm2ext/gtkmm2ext/keyboard.h b/libs/gtkmm2ext/gtkmm2ext/keyboard.h index db5f9ef3d..db8100c08 100644 --- a/libs/gtkmm2ext/gtkmm2ext/keyboard.h +++ b/libs/gtkmm2ext/gtkmm2ext/keyboard.h @@ -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*); -- 2.11.4.GIT