13
0

undo history for MidiCueEditor

redo not operational yet for some unknown reason
This commit is contained in:
Paul Davis 2024-06-29 16:47:42 -06:00
parent 8eb38f1406
commit c4534cc9c4
10 changed files with 179 additions and 103 deletions

View File

@ -8,6 +8,7 @@ CueEditor::CueEditor (std::string const & name)
, HistoryOwner (X_("cue-editor"))
{
}
CueEditor::~CueEditor ()
{
}

View File

@ -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);

View File

@ -64,6 +64,7 @@ using std::string;
sigc::signal<void> EditingContext::DropDownKeys;
Gtkmm2ext::Bindings* EditingContext::button_bindings = nullptr;
Glib::RefPtr<Gtk::ActionGroup> EditingContext::_midi_actions;
Glib::RefPtr<Gtk::ActionGroup> EditingContext::_common_actions;
std::stack<EditingContext*> EditingContext::ec_stack;
std::vector<std::string> EditingContext::grid_type_strings;
MouseCursors* EditingContext::_cursors = nullptr;
@ -100,6 +101,11 @@ sigc::signal<void> EditingContext::DrawLengthChanged;
sigc::signal<void> EditingContext::DrawVelocityChanged;
sigc::signal<void> EditingContext::DrawChannelChanged;
Glib::RefPtr<Gtk::Action> EditingContext::undo_action;
Glib::RefPtr<Gtk::Action> EditingContext::redo_action;
Glib::RefPtr<Gtk::Action> EditingContext::alternate_redo_action;
Glib::RefPtr<Gtk::Action> 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<SelectionMemento>(*(_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<Action>
EditingContext::reg_sens (RefPtr<ActionGroup> group, char const * name, char const * label, sigc::slot<void> slot)
{
RefPtr<Action> act = ActionManager::register_action (group, name, label, slot);
ActionManager::session_sensitive_actions.push_back (act);
return act;
}
void
EditingContext::toggle_reg_sens (RefPtr<ActionGroup> group, char const * name, char const * label, sigc::slot<void> slot)
{
RefPtr<Action> act = ActionManager::register_toggle_action (group, name, label, slot);
ActionManager::session_sensitive_actions.push_back (act);
}
void
EditingContext::radio_reg_sens (RefPtr<ActionGroup> action_group, RadioAction::Group& radio_group, char const * name, char const * label, sigc::slot<void> slot)
{
RefPtr<Action> act = ActionManager::register_radio_action (action_group, radio_group, name, label, slot);
ActionManager::session_sensitive_actions.push_back (act);
}

View File

@ -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<Gtk::ActionGroup> _midi_actions;
static Glib::RefPtr<Gtk::ActionGroup> _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<Gtk::Action> undo_action;
static Glib::RefPtr<Gtk::Action> redo_action;
static Glib::RefPtr<Gtk::Action> alternate_redo_action;
static Glib::RefPtr<Gtk::Action> alternate_alternate_redo_action;
/* protected helper functions to help with registering actions */
static Glib::RefPtr<Gtk::Action> reg_sens (Glib::RefPtr<Gtk::ActionGroup> group, char const* name, char const* label, sigc::slot<void> slot);
static void toggle_reg_sens (Glib::RefPtr<Gtk::ActionGroup> group, char const* name, char const* label, sigc::slot<void> slot);
static void radio_reg_sens (Glib::RefPtr<Gtk::ActionGroup> action_group, Gtk::RadioAction::Group& radio_group, char const* name, char const* label, sigc::slot<void> slot);
private:
static std::stack<EditingContext*> ec_stack;

View File

@ -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<Gtk::Action> undo_action;
Glib::RefPtr<Gtk::Action> redo_action;
Glib::RefPtr<Gtk::Action> alternate_redo_action;
Glib::RefPtr<Gtk::Action> alternate_alternate_redo_action;
Glib::RefPtr<Gtk::Action> selection_undo_action;
Glib::RefPtr<Gtk::Action> selection_redo_action;
@ -2265,10 +2269,6 @@ private:
Glib::RefPtr<Gtk::Action> register_region_action (Glib::RefPtr<Gtk::ActionGroup> group, Editing::RegionActionTarget, char const* name, char const* label, sigc::slot<void> slot);
void register_toggle_region_action (Glib::RefPtr<Gtk::ActionGroup> group, Editing::RegionActionTarget, char const* name, char const* label, sigc::slot<void> slot);
Glib::RefPtr<Gtk::Action> reg_sens (Glib::RefPtr<Gtk::ActionGroup> group, char const* name, char const* label, sigc::slot<void> slot);
void toggle_reg_sens (Glib::RefPtr<Gtk::ActionGroup> group, char const* name, char const* label, sigc::slot<void> slot);
void radio_reg_sens (Glib::RefPtr<Gtk::ActionGroup> action_group, Gtk::RadioAction::Group& radio_group, char const* name, char const* label, sigc::slot<void> slot);
void remove_gap_marker_callback (Temporal::timepos_t at, Temporal::timecnt_t distance);
Editing::GridType determine_mapping_grid_snap (Temporal::timepos_t t);

View File

@ -71,9 +71,6 @@ using namespace Editing;
using Gtkmm2ext::Bindings;
/* Convenience functions to slightly reduce verbosity below */
RefPtr<Action>
Editor::register_region_action (RefPtr<ActionGroup> group, RegionActionTarget tgt, char const * name, char const * label, sigc::slot<void> slot)
{
@ -91,28 +88,6 @@ Editor::register_toggle_region_action (RefPtr<ActionGroup> group, RegionActionTa
region_action_map.insert (make_pair<string,RegionAction> (name, RegionAction (act,tgt)));
}
RefPtr<Action>
Editor::reg_sens (RefPtr<ActionGroup> group, char const * name, char const * label, sigc::slot<void> slot)
{
RefPtr<Action> act = ActionManager::register_action (group, name, label, slot);
ActionManager::session_sensitive_actions.push_back (act);
return act;
}
void
Editor::toggle_reg_sens (RefPtr<ActionGroup> group, char const * name, char const * label, sigc::slot<void> slot)
{
RefPtr<Action> act = ActionManager::register_toggle_action (group, name, label, slot);
ActionManager::session_sensitive_actions.push_back (act);
}
void
Editor::radio_reg_sens (RefPtr<ActionGroup> action_group, RadioAction::Group& radio_group, char const * name, char const * label, sigc::slot<void> slot)
{
RefPtr<Action> 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

View File

@ -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<SelectionMemento>(*(_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)
{

View File

@ -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);
}

View File

@ -193,6 +193,7 @@ class MidiCueEditor : public CueEditor
void stop_canvas_autoscroll ();
void visual_changer (const VisualChange&);
void bindings_changed ();
};

View File

@ -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<bool> 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::PatchChange<Temporal::B
(_midi_region->source_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 ();
}