From c4534cc9c4844286d60f0c55cef0aa939d227adb Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 29 Jun 2024 16:47:42 -0600 Subject: [PATCH] undo history for MidiCueEditor redo not operational yet for some unknown reason --- gtk2_ardour/cue_editor.cc | 1 + gtk2_ardour/cue_editor.h | 8 +++ gtk2_ardour/editing_context.cc | 96 ++++++++++++++++------------------ gtk2_ardour/editing_context.h | 31 +++++++++-- gtk2_ardour/editor.h | 16 +++--- gtk2_ardour/editor_actions.cc | 35 ++----------- gtk2_ardour/editor_ops.cc | 65 +++++++++++++++++++++++ gtk2_ardour/midi_cue_editor.cc | 10 ++++ gtk2_ardour/midi_cue_editor.h | 1 + gtk2_ardour/midi_view.cc | 19 ++++--- 10 files changed, 179 insertions(+), 103 deletions(-) diff --git a/gtk2_ardour/cue_editor.cc b/gtk2_ardour/cue_editor.cc index 26dd5307ec..383ad8dda6 100644 --- a/gtk2_ardour/cue_editor.cc +++ b/gtk2_ardour/cue_editor.cc @@ -8,6 +8,7 @@ CueEditor::CueEditor (std::string const & name) , HistoryOwner (X_("cue-editor")) { } + CueEditor::~CueEditor () { } diff --git a/gtk2_ardour/cue_editor.h b/gtk2_ardour/cue_editor.h index ca4b840821..0bc1471874 100644 --- a/gtk2_ardour/cue_editor.h +++ b/gtk2_ardour/cue_editor.h @@ -66,6 +66,14 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner void undo_selection_op (); void redo_selection_op (); + PBD::HistoryOwner& history() { return *this; } + + void add_command (PBD::Command * cmd) { HistoryOwner::add_command (cmd); } + void begin_reversible_command (std::string cmd_name) { HistoryOwner::begin_reversible_command (cmd_name); } + void begin_reversible_command (GQuark gq) { HistoryOwner::begin_reversible_command (gq); } + void abort_reversible_command () { HistoryOwner::abort_reversible_command (); } + void commit_reversible_command () { HistoryOwner::commit_reversible_command (); } + double get_y_origin () const; void set_zoom_focus (Editing::ZoomFocus); diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 1f8cbd98b0..de35d337ab 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -64,6 +64,7 @@ using std::string; sigc::signal EditingContext::DropDownKeys; Gtkmm2ext::Bindings* EditingContext::button_bindings = nullptr; Glib::RefPtr EditingContext::_midi_actions; +Glib::RefPtr EditingContext::_common_actions; std::stack EditingContext::ec_stack; std::vector EditingContext::grid_type_strings; MouseCursors* EditingContext::_cursors = nullptr; @@ -100,6 +101,11 @@ sigc::signal EditingContext::DrawLengthChanged; sigc::signal EditingContext::DrawVelocityChanged; sigc::signal EditingContext::DrawChannelChanged; +Glib::RefPtr EditingContext::undo_action; +Glib::RefPtr EditingContext::redo_action; +Glib::RefPtr EditingContext::alternate_redo_action; +Glib::RefPtr EditingContext::alternate_alternate_redo_action; + EditingContext::EditingContext (std::string const & name) : rubberband_rect (0) , _name (name) @@ -129,6 +135,7 @@ EditingContext::EditingContext (std::string const & name) , quantize_dialog (nullptr) , vertical_adjustment (0.0, 0.0, 10.0, 400.0) , horizontal_adjustment (0.0, 0.0, 1e16) + , bindings (nullptr) , mouse_mode (MouseObject) , visual_change_queued (false) , autoscroll_horizontal_allowed (false) @@ -199,6 +206,21 @@ EditingContext::set_selected_midi_region_view (MidiRegionView& mrv) get_selection().set (&mrv); } +void +EditingContext::register_common_actions (Bindings* common_bindings) +{ + if (_common_actions) { + return; + } + + _common_actions = ActionManager::create_action_group (common_bindings, X_("Editing")); + + undo_action = reg_sens (_common_actions, "undo", S_("Command|Undo"), []() { current_editing_context()->undo(1U) ; }); + redo_action = reg_sens (_common_actions, "redo", _("Redo"), []() { current_editing_context()->redo(1U) ; }); + alternate_redo_action = reg_sens (_common_actions, "alternate-redo", _("Redo"), []() { current_editing_context()->redo(1U) ; }); + alternate_alternate_redo_action = reg_sens (_common_actions, "alternate-alternate-redo", _("Redo"), []() { current_editing_context()->redo(1U) ; }); +} + void EditingContext::register_midi_actions (Bindings* midi_bindings) { @@ -1248,56 +1270,6 @@ EditingContext::set_follow_playhead (bool yn, bool catch_up) } } -void -EditingContext::begin_reversible_command (string name) -{ - if (_session) { - before.push_back (&_selection_memento->get_state ()); - _session->begin_reversible_command (name); - } -} - -void -EditingContext::begin_reversible_command (GQuark q) -{ - if (_session) { - before.push_back (&_selection_memento->get_state ()); - _session->begin_reversible_command (q); - } -} - -void -EditingContext::abort_reversible_command () -{ - if (_session) { - while(!before.empty()) { - delete before.front(); - before.pop_front(); - } - _session->abort_reversible_command (); - } -} - -void -EditingContext::commit_reversible_command () -{ - if (_session) { - if (before.size() == 1) { - _session->add_command (new MementoCommand(*(_selection_memento), before.front(), &_selection_memento->get_state ())); - begin_selection_op_history (); - } - - if (before.empty()) { - PBD::stacktrace (std::cerr, 30); - std::cerr << "Please call begin_reversible_command() before commit_reversible_command()." << std::endl; - } else { - before.pop_back(); - } - - _session->commit_reversible_command (); - } -} - double EditingContext::time_to_pixel (timepos_t const & pos) const { @@ -2494,3 +2466,27 @@ EditingContext::pre_render () } } +/* Convenience functions to slightly reduce verbosity when registering actions */ + +RefPtr +EditingContext::reg_sens (RefPtr group, char const * name, char const * label, sigc::slot slot) +{ + RefPtr act = ActionManager::register_action (group, name, label, slot); + ActionManager::session_sensitive_actions.push_back (act); + return act; +} + +void +EditingContext::toggle_reg_sens (RefPtr group, char const * name, char const * label, sigc::slot slot) +{ + RefPtr act = ActionManager::register_toggle_action (group, name, label, slot); + ActionManager::session_sensitive_actions.push_back (act); +} + +void +EditingContext::radio_reg_sens (RefPtr action_group, RadioAction::Group& radio_group, char const * name, char const * label, sigc::slot slot) +{ + RefPtr act = ActionManager::register_radio_action (action_group, radio_group, name, label, slot); + ActionManager::session_sensitive_actions.push_back (act); +} + diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index 2e6558ccfd..3be030f6bc 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -167,10 +167,20 @@ public: virtual void undo_selection_op () = 0; virtual void redo_selection_op () = 0; - virtual void begin_reversible_command (std::string cmd_name); - virtual void begin_reversible_command (GQuark); - virtual void abort_reversible_command (); - virtual void commit_reversible_command (); + /* Some EditingContexts may defer to the Session, which IS-A + * HistoryOwner (Editor does this). + * + * Others may themselves have the IS-A HistoryOwner inheritance, and so + * they just proxy back to their base class (CueEditor does this). + */ + + virtual PBD::HistoryOwner& history() = 0; + + virtual void add_command (PBD::Command *) = 0; + virtual void begin_reversible_command (std::string cmd_name) = 0; + virtual void begin_reversible_command (GQuark) = 0; + virtual void abort_reversible_command () = 0; + virtual void commit_reversible_command () = 0; virtual void set_selected_midi_region_view (MidiRegionView&); @@ -350,6 +360,7 @@ public: void transpose_region (); static void register_midi_actions (Gtkmm2ext::Bindings*); + static void register_common_actions (Gtkmm2ext::Bindings*); ArdourCanvas::Rectangle* rubberband_rect; @@ -391,6 +402,7 @@ public: std::string _name; static Glib::RefPtr _midi_actions; + static Glib::RefPtr _common_actions; /* Cursor stuff. Do not use directly, use via CursorContext. */ friend class CursorContext; @@ -644,6 +656,17 @@ public: virtual void do_undo (uint32_t n) = 0; virtual void do_redo (uint32_t n) = 0; + static Glib::RefPtr undo_action; + static Glib::RefPtr redo_action; + static Glib::RefPtr alternate_redo_action; + static Glib::RefPtr alternate_alternate_redo_action; + + /* protected helper functions to help with registering actions */ + + static Glib::RefPtr reg_sens (Glib::RefPtr group, char const* name, char const* label, sigc::slot slot); + static void toggle_reg_sens (Glib::RefPtr group, char const* name, char const* label, sigc::slot slot); + static void radio_reg_sens (Glib::RefPtr action_group, Gtk::RadioAction::Group& radio_group, char const* name, char const* label, sigc::slot slot); + private: static std::stack ec_stack; diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 9f59b6a0d4..e2d142a20c 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -431,6 +431,14 @@ public: void abort_reversible_selection_op (); void undo_selection_op (); void redo_selection_op (); + void add_command (PBD::Command * cmd); + + PBD::HistoryOwner& history(); + + void begin_reversible_command (std::string cmd_name); + void begin_reversible_command (GQuark); + void abort_reversible_command (); + void commit_reversible_command (); MixerStrip* get_current_mixer_strip () const { return current_mixer_strip; @@ -2092,10 +2100,6 @@ private: void session_state_saved (std::string); - Glib::RefPtr undo_action; - Glib::RefPtr redo_action; - Glib::RefPtr alternate_redo_action; - Glib::RefPtr alternate_alternate_redo_action; Glib::RefPtr selection_undo_action; Glib::RefPtr selection_redo_action; @@ -2265,10 +2269,6 @@ private: Glib::RefPtr register_region_action (Glib::RefPtr group, Editing::RegionActionTarget, char const* name, char const* label, sigc::slot slot); void register_toggle_region_action (Glib::RefPtr group, Editing::RegionActionTarget, char const* name, char const* label, sigc::slot slot); - Glib::RefPtr reg_sens (Glib::RefPtr group, char const* name, char const* label, sigc::slot slot); - void toggle_reg_sens (Glib::RefPtr group, char const* name, char const* label, sigc::slot slot); - void radio_reg_sens (Glib::RefPtr action_group, Gtk::RadioAction::Group& radio_group, char const* name, char const* label, sigc::slot slot); - void remove_gap_marker_callback (Temporal::timepos_t at, Temporal::timecnt_t distance); Editing::GridType determine_mapping_grid_snap (Temporal::timepos_t t); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index c275437487..a12c7d14a4 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -71,9 +71,6 @@ using namespace Editing; using Gtkmm2ext::Bindings; -/* Convenience functions to slightly reduce verbosity below */ - - RefPtr Editor::register_region_action (RefPtr group, RegionActionTarget tgt, char const * name, char const * label, sigc::slot slot) { @@ -91,28 +88,6 @@ Editor::register_toggle_region_action (RefPtr group, RegionActionTa region_action_map.insert (make_pair (name, RegionAction (act,tgt))); } -RefPtr -Editor::reg_sens (RefPtr group, char const * name, char const * label, sigc::slot slot) -{ - RefPtr act = ActionManager::register_action (group, name, label, slot); - ActionManager::session_sensitive_actions.push_back (act); - return act; -} - -void -Editor::toggle_reg_sens (RefPtr group, char const * name, char const * label, sigc::slot slot) -{ - RefPtr act = ActionManager::register_toggle_action (group, name, label, slot); - ActionManager::session_sensitive_actions.push_back (act); -} - -void -Editor::radio_reg_sens (RefPtr action_group, RadioAction::Group& radio_group, char const * name, char const * label, sigc::slot slot) -{ - RefPtr act = ActionManager::register_radio_action (action_group, radio_group, name, label, slot); - ActionManager::session_sensitive_actions.push_back (act); -} - void Editor::register_actions () { @@ -401,11 +376,6 @@ Editor::register_actions () sigc::bind (sigc::mem_fun (*this, &Editor::duplicate_range), true)); - undo_action = reg_sens (editor_actions, "undo", S_("Command|Undo"), []() { current_editing_context()->undo(1U) ; }); - redo_action = reg_sens (editor_actions, "redo", _("Redo"), []() { current_editing_context()->redo(1U) ; }); - alternate_redo_action = reg_sens (editor_actions, "alternate-redo", _("Redo"), []() { current_editing_context()->redo(1U) ; }); - alternate_alternate_redo_action = reg_sens (editor_actions, "alternate-alternate-redo", _("Redo"), []() { current_editing_context()->redo(1U) ; }); - selection_undo_action = reg_sens (editor_actions, "undo-last-selection-op", _("Undo Selection Change"), sigc::mem_fun(*this, &Editor::undo_selection_op)); selection_redo_action = reg_sens (editor_actions, "redo-last-selection-op", _("Redo Selection Change"), sigc::mem_fun(*this, &Editor::redo_selection_op)); @@ -793,10 +763,13 @@ Editor::load_bindings () */ Bindings* midi_bindings = Bindings::get_bindings (X_("MIDI")); - register_midi_actions (midi_bindings); + Bindings* shared_bindings = Bindings::get_bindings (X_("Editing")); + register_common_actions (shared_bindings); + _track_canvas_viewport->canvas()->set_data ("ardour-bindings", midi_bindings); + global_hpacker.set_data ("ardour-bindings-shared", shared_bindings); } void diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index ef91495a37..d9c0f5d9f4 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -144,6 +144,71 @@ using Gtkmm2ext::Keyboard; Editor operations ***********************************************************************/ +HistoryOwner& +Editor::history() +{ + assert (_session); + return *_session; +} + +void +Editor::add_command (PBD::Command * cmd) +{ + if (_session) { + _session->add_command (cmd); + } +} + +void +Editor::begin_reversible_command (string name) +{ + if (_session) { + before.push_back (&_selection_memento->get_state ()); + _session->begin_reversible_command (name); + } +} + +void +Editor::begin_reversible_command (GQuark q) +{ + if (_session) { + before.push_back (&_selection_memento->get_state ()); + _session->begin_reversible_command (q); + } +} + +void +Editor::abort_reversible_command () +{ + if (_session) { + while(!before.empty()) { + delete before.front(); + before.pop_front(); + } + _session->abort_reversible_command (); + } +} + +void +Editor::commit_reversible_command () +{ + if (_session) { + if (before.size() == 1) { + _session->add_command (new MementoCommand(*(_selection_memento), before.front(), &_selection_memento->get_state ())); + begin_selection_op_history (); + } + + if (before.empty()) { + PBD::stacktrace (std::cerr, 30); + std::cerr << "Please call begin_reversible_command() before commit_reversible_command()." << std::endl; + } else { + before.pop_back(); + } + + _session->commit_reversible_command (); + } +} + void Editor::do_undo (uint32_t n) { diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index c68884f271..0707699184 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -87,6 +87,7 @@ MidiCueEditor::MidiCueEditor() MidiCueEditor::~MidiCueEditor () { + delete bindings; } void @@ -283,7 +284,16 @@ MidiCueEditor::build_canvas () _canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); _canvas->set_can_focus (); + bindings_changed (); +} + +void +MidiCueEditor::bindings_changed () +{ Bindings* midi_bindings = Bindings::get_bindings (X_("MIDI")); + Bindings* shared_bindings = Bindings::get_bindings (X_("Editing")); + + _canvas_viewport->set_data (X_("ardour-bindings"), shared_bindings); _canvas->set_data (X_("ardour-bindings"), midi_bindings); } diff --git a/gtk2_ardour/midi_cue_editor.h b/gtk2_ardour/midi_cue_editor.h index bdee7c842a..88da627404 100644 --- a/gtk2_ardour/midi_cue_editor.h +++ b/gtk2_ardour/midi_cue_editor.h @@ -193,6 +193,7 @@ class MidiCueEditor : public CueEditor void stop_canvas_autoscroll (); void visual_changer (const VisualChange&); + void bindings_changed (); }; diff --git a/gtk2_ardour/midi_view.cc b/gtk2_ardour/midi_view.cc index 58dd8e5005..9b31d8d284 100644 --- a/gtk2_ardour/midi_view.cc +++ b/gtk2_ardour/midi_view.cc @@ -844,7 +844,6 @@ MidiView::start_note_diff_command (string name) { if (!_note_diff_command) { _editing_context.begin_reversible_command (name); - std::cerr << "start note diff on " << _model << " uc " << _model.use_count() << std::endl; _note_diff_command = _model->new_note_diff_command (name); } else { std::cerr << "ERROR: start_note_diff_command command called, but a note_diff_command was already underway" << std::endl; @@ -912,7 +911,7 @@ MidiView::apply_note_diff (bool as_subcommand, bool was_copy) { PBD::Unwinder puw (_select_all_notes_after_add, true); /*note that we don't use as_commit here, because that would BEGIN a new undo record; we already have one underway*/ - _model->apply_diff_command_as_subcommand (*_editing_context.session(), _note_diff_command); + _model->apply_diff_command_as_subcommand (_editing_context.history(), _note_diff_command); } if (!as_subcommand) { @@ -1911,7 +1910,7 @@ MidiView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPrimaryKe c->change_bank (pc.patch (), new_bank); } - _model->apply_diff_command_as_commit (*_editing_context.session(), c); + _model->apply_diff_command_as_commit (_editing_context.history(), c); remove_canvas_patch_change (&pc); display_patch_changes (); @@ -1940,7 +1939,7 @@ MidiView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evora c->change_bank (old_change, new_change.bank()); } - _model->apply_diff_command_as_commit (*_editing_context.session(), c); + _model->apply_diff_command_as_commit (_editing_context.history(), c); for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) { if (x->second->patch() == old_change) { @@ -1969,7 +1968,7 @@ MidiView::add_patch_change (timecnt_t const & t, Evoral::PatchChangesource_relative_position (_midi_region->position() + t).beats(), patch.channel(), patch.program(), patch.bank()))); - _model->apply_diff_command_as_commit (*_editing_context.session(), c); + _model->apply_diff_command_as_commit (_editing_context.history(), c); display_patch_changes (); } @@ -1979,7 +1978,7 @@ MidiView::move_patch_change (PatchChange& pc, Temporal::Beats t) { MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change")); c->change_time (pc.patch (), t); - _model->apply_diff_command_as_commit (*_editing_context.session(), c); + _model->apply_diff_command_as_commit (_editing_context.history(), c); display_patch_changes (); } @@ -1989,7 +1988,7 @@ MidiView::delete_patch_change (PatchChange* pc) { MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("delete patch change")); c->remove (pc->patch ()); - _model->apply_diff_command_as_commit (*_editing_context.session(), c); + _model->apply_diff_command_as_commit (_editing_context.history(), c); remove_canvas_patch_change (pc); display_patch_changes (); @@ -3839,13 +3838,13 @@ MidiView::paste_internal (timepos_t const & pos, unsigned paste_count, float tim // XXXX _midi_region->clear_changes (); /* we probably need to get the snap modifier somehow to make this correct for non-musical use */ _midi_region->set_length (_midi_region->position().distance (end)); - _editing_context.session()->add_command (new StatefulDiffCommand (_midi_region)); + _editing_context.add_command (new StatefulDiffCommand (_midi_region)); } _marked_for_selection.clear (); _pending_note_selection.clear (); - _model->apply_diff_command_as_subcommand (*_editing_context.session(), _note_diff_command); + _model->apply_diff_command_as_subcommand (_editing_context.history(), _note_diff_command); _note_diff_command = nullptr; } @@ -4485,7 +4484,7 @@ MidiView::quantize_selected_notes () if (cmd) { _editing_context.begin_reversible_command (quant->name ()); (*cmd)(); - _editing_context.session()->add_command (cmd); + _editing_context.add_command (cmd); _editing_context.commit_reversible_command (); _editing_context.session()->set_dirty (); }