From ad24d397f5439a2761dac58a391f09350bef7eb4 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 24 Sep 2023 14:08:05 +0200 Subject: [PATCH] Fix various MIDI List editor issues (#9457) * Fix crash when inserting note to empty region * Consistently use fine-grained modifier * Don't allow to edit BBT as text field This is currently not supported. * Fix GTK_IS_CELL_EDITABLE assertions (Tab to next) --- gtk2_ardour/midi_list_editor.cc | 55 ++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/gtk2_ardour/midi_list_editor.cc b/gtk2_ardour/midi_list_editor.cc index 249015636a..98bc07d78f 100644 --- a/gtk2_ardour/midi_list_editor.cc +++ b/gtk2_ardour/midi_list_editor.cc @@ -1,7 +1,7 @@ /* * Copyright (C) 2009-2015 David Robillard * Copyright (C) 2009-2017 Paul Davis - * Copyright (C) 2014-2016 Robin Gareus + * Copyright (C) 2014-2023 Robin Gareus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -129,7 +129,9 @@ MidiListEditor::MidiListEditor (Session* s, std::shared_ptr r, std:: view.get_selection()->set_mode (SELECTION_MULTIPLE); view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &MidiListEditor::selection_changed)); - for (int i = 0; i < 6; ++i) { + /* Editing the first column (BBT) as text is currently not supported + * -> use editable AudioClock, implement parse_as_bbt */ + for (int i = 1; i < 6; ++i) { CellRendererText* renderer = dynamic_cast(view.get_column_cell_renderer (i)); TreeViewColumn* col = view.get_column (i); @@ -207,7 +209,10 @@ MidiListEditor::scroll_event (GdkEventScroll* ev) switch (colnum) { case 0: - if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) { + /* This is dangerous. Changing position with the mouse-wheel can reorder + * notes. The mouse-position does not change and then affect different notes. + */ + if (Keyboard::modifier_state_equals (ev->state, Keyboard::GainFineScaleModifier)) { beat_delta = Temporal::Beats::ticks (Temporal::ticks_per_beat / 64); } else { beat_delta = Temporal::Beats (1, 0); @@ -250,7 +255,7 @@ MidiListEditor::scroll_event (GdkEventScroll* ev) break; case 5: - if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) { + if (Keyboard::modifier_state_equals (ev->state, Keyboard::GainFineScaleModifier)) { beat_delta = Temporal::Beats::ticks (Temporal::ticks_per_beat / 64); } else { beat_delta = Temporal::Beats (1, 0); @@ -397,13 +402,18 @@ MidiListEditor::key_press (GdkEventKey* ev) } if (colnum >= 5) { /* wrap to next line */ + /* XXX never reached. Editing Length shows a dropdown menu, + * which returns edit focus to the dialog. + */ colnum = 0; path.next(); } else { colnum++; } - col = view.get_column (colnum); - view.set_cursor (path, *col, true); + if (!path.empty ()) { + col = view.get_column (colnum); + view.set_cursor (path, *col, true); + } ret = true; } break; @@ -417,8 +427,10 @@ MidiListEditor::key_press (GdkEventKey* ev) editing_editable->editing_done (); } path.prev (); - col = view.get_column (colnum); - view.set_cursor (path, *col, true); + if (!path.empty ()) { + col = view.get_column (colnum); + view.set_cursor (path, *col, true); + } ret = true; } break; @@ -432,8 +444,10 @@ MidiListEditor::key_press (GdkEventKey* ev) editing_editable->editing_done (); } path.next (); - col = view.get_column (colnum); - view.set_cursor (path, *col, true); + if (!path.empty ()) { + col = view.get_column (colnum); + view.set_cursor (path, *col, true); + } ret = true; } break; @@ -461,21 +475,26 @@ MidiListEditor::key_release (GdkEventKey* ev) switch (ev->keyval) { case GDK_Insert: - /* add a new note to the model, based on the note at the cursor - * pos - */ + /* add a new note to the model, based on the note at the cursor pos */ view.get_cursor (path, col); iter = model->get_iter (path); cmd = m->new_note_diff_command (_("insert new note")); - note = (*iter)[columns._note]; - copy.reset (new NoteType (*note.get())); + if (iter) { + note = (*iter)[columns._note]; + copy.reset (new NoteType (*note.get())); + } else { + Temporal::Beats pos = Temporal::TempoMap::use()->quarters_at_sample (region->start().samples()); + copy.reset (new NoteType (0, pos, Temporal::Beats (1, 0), 60, 100)); + } cmd->add (copy); m->apply_diff_command_as_commit (*_session, cmd); /* model has been redisplayed by now */ path.next (); - /* select, start editing column 2 (note) */ - col = view.get_column (2); - view.set_cursor (path, *col, true); + if (!path.empty ()) { + /* select, start editing column 2 (note) */ + col = view.get_column (2); + view.set_cursor (path, *col, true); + } break; case GDK_Delete: