mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-30 08:53:08 +01:00
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:
parent
4aa84f0513
commit
45d51d3aee
4 changed files with 82 additions and 64 deletions
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue