diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index 1be9d6e25c..c4b53821dc 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -13,6 +13,7 @@ #endif + diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 87e16cf778..6441809cd7 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -101,6 +101,7 @@ #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" #include "ardour/automation_watch.h" +#include "ardour/directory_names.h" #include "ardour/disk_reader.h" #include "ardour/disk_writer.h" #include "ardour/filename_extensions.h" diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index ea6e789338..134b063d54 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -307,7 +307,7 @@ public: void start_duplicate_routes (); void save_as_template_dialog_response (int response, SaveTemplateDialog* d); - void save_route_template (); + void save_route_template (bool local); //local route templates are "mixer snapshots" void apply_route_template (); void new_from_route_template (); diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index c62047a702..a72c1c0158 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -189,8 +189,14 @@ ARDOUR_UI::install_actions () ActionManager::write_sensitive_actions.push_back (act); ActionManager::route_selection_sensitive_actions.push_back (act); + act = ActionManager::register_action (main_actions, X_("MixerSnapshot"), _("Mixer Snapshot..."), + sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::save_route_template), true)); + ActionManager::session_sensitive_actions.push_back (act); + ActionManager::write_sensitive_actions.push_back (act); + ActionManager::route_selection_sensitive_actions.push_back (act); + act = ActionManager::register_action (main_actions, X_("save-route-template"), _("Save Selected Tracks as Template..."), - sigc::mem_fun(*this, &ARDOUR_UI::save_route_template)); + sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::save_route_template), false)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::write_sensitive_actions.push_back (act); ActionManager::route_selection_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/mixer_snapshot_dialog.cc b/gtk2_ardour/mixer_snapshot_dialog.cc index 86de3d7915..44f17e5fa8 100644 --- a/gtk2_ardour/mixer_snapshot_dialog.cc +++ b/gtk2_ardour/mixer_snapshot_dialog.cc @@ -519,7 +519,7 @@ void MixerSnapshotDialog::refill_display(bool global) for(vector::iterator i = files.begin(); i != files.end(); i++) { string path = *(i); - MixerSnapshot* snap = new MixerSnapshot(_session, path); + MixerSnapshot* snap = new MixerSnapshot(_session, path); //ToDo: pretty sure this is leaked new_row(model, snap, path); } } diff --git a/gtk2_ardour/mixer_snapshots.cc b/gtk2_ardour/mixer_snapshots.cc new file mode 100644 index 0000000000..431dbd7ce8 --- /dev/null +++ b/gtk2_ardour/mixer_snapshots.cc @@ -0,0 +1,198 @@ +/* + Copyright (C) 2000-2019 Paul Davis + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#include +#include "pbd/file_utils.h" +#include "pbd/gstdio_compat.h" + +#include +#include + +#include + +#include "ardour/directory_names.h" +#include "ardour/filename_extensions.h" +#include "ardour/filesystem_paths.h" +#include "ardour/session.h" +#include "ardour/session_state_utils.h" +#include "ardour/session_directory.h" + +#include "widgets/choice.h" +#include "widgets/prompter.h" + +#include "ardour_ui.h" +#include "utils.h" + +#include "pbd/i18n.h" + +#include "mixer_snapshots.h" + +using namespace std; +using namespace PBD; +using namespace Gtk; +using namespace ARDOUR; +using namespace ARDOUR_UI_UTILS; + +MixerSnapshotList::MixerSnapshotList () +{ + _snapshot_model = ListStore::create (_columns); + _snapshot_display.set_model (_snapshot_model); + _snapshot_display.append_column (_("Mixer Snapshots (double-click to load)"), _columns.name); +// _snapshot_display.append_column (_("Modified Date"), _columns.timestamp); + _snapshot_display.set_size_request (75, -1); + _snapshot_display.set_headers_visible (true); + _snapshot_display.set_reorderable (false); + _scroller.add (_snapshot_display); + _scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + _snapshot_display.get_selection()->signal_changed().connect (sigc::mem_fun(*this, &MixerSnapshotList::selection_changed)); + _snapshot_display.signal_button_press_event().connect (sigc::mem_fun (*this, &MixerSnapshotList::button_press), false); +} + +void +MixerSnapshotList::set_session (Session* s) +{ + SessionHandlePtr::set_session (s); + + redisplay (); +} + +/* A new snapshot has been selected. */ +void +MixerSnapshotList::selection_changed () +{ + if (_snapshot_display.get_selection()->count_selected_rows() == 0) { + return; + } + + TreeModel::iterator i = _snapshot_display.get_selection()->get_selected(); + + //std::string snap_path = (*i)[_columns.snap]; + + _snapshot_display.set_sensitive (false); +// ARDOUR_UI::instance()->load_session (_session->path(), string (snap_name)); + _snapshot_display.set_sensitive (true); +} + +bool +MixerSnapshotList::button_press (GdkEventButton* ev) +{ + if (ev->button == 3) { + return true; + } + return false; +} + + +/** Pop up the snapshot display context menu. + * @param button Button used to open the menu. + * @param time Menu open time. + * @param snapshot_name Name of the snapshot that the menu click was over. + */ +void +MixerSnapshotList::popup_context_menu (int button, int32_t time, std::string snapshot_name) +{ + using namespace Menu_Helpers; + + MenuList& items (_menu.items()); + items.clear (); + + const bool modification_allowed = (_session->snap_name() != snapshot_name && _session->name() != snapshot_name); + +/* add_item_with_sensitivity (items, MenuElem (_("Remove"), sigc::bind (sigc::mem_fun (*this, &MixerSnapshotList::remove), snapshot_name)), modification_allowed); + + add_item_with_sensitivity (items, MenuElem (_("Rename..."), sigc::bind (sigc::mem_fun (*this, &MixerSnapshotList::rename), snapshot_name)), modification_allowed); +*/ + + _menu.popup (button, time); +} + +void +MixerSnapshotList::rename (std::string old_name) +{ + ArdourWidgets::Prompter prompter(true); + + string new_name; + + prompter.set_name ("Prompter"); + prompter.set_title (_("Rename Snapshot")); + prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); + prompter.set_prompt (_("New name of snapshot")); + prompter.set_initial_text (old_name); + + if (prompter.run() == RESPONSE_ACCEPT) { + prompter.get_result (new_name); + if (new_name.length()) { +// _session->rename_state (old_name, new_name); + redisplay (); + } + } +} + + +void +MixerSnapshotList::remove (std::string name) +{ + vector choices; + + std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(which cannot be undone)"), name); + + choices.push_back (_("No, do nothing.")); + choices.push_back (_("Yes, remove it.")); + + ArdourWidgets::Choice prompter (_("Remove snapshot"), prompt, choices); + + if (prompter.run () == 1) { +// _session->remove_state (name); + redisplay (); + } +} + +void +MixerSnapshotList::redisplay () +{ + if (_session == 0) { + return; + } + + std::string local_snap_path = Glib::build_filename(_session->session_directory().root_path(), route_templates_dir_name); + + _snapshot_model->clear(); + + std::string suffix_pattern ("*"); + suffix_pattern = suffix_pattern + template_suffix; // "*.template" + + vector files; + find_files_matching_pattern(files, local_snap_path, suffix_pattern); //assume they are all templates in here? + + if(files.empty()) { + return; + } + + for(vector::iterator i = files.begin(); i != files.end(); i++) { + string path = *(i); + MixerSnapshot* snap = new MixerSnapshot(_session, path); //ToDo: this is leaked; probably need a "template manager" in libardour + + TreeModel::Row row = *(_snapshot_model->append()); + row[_columns.name] = snap->get_label(); + row[_columns.snapshot] = snap; + } +} + diff --git a/gtk2_ardour/mixer_snapshots.h b/gtk2_ardour/mixer_snapshots.h new file mode 100644 index 0000000000..7719461c05 --- /dev/null +++ b/gtk2_ardour/mixer_snapshots.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2000-2019 Paul Davis + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtk_ardour_mixer_snapshots_h__ +#define __gtk_ardour_mixer_snapshots_h__ + +#include +#include +#include +#include + +#include "ardour/mixer_snapshot.h" + +class MixerSnapshotList : public ARDOUR::SessionHandlePtr +{ +public: + MixerSnapshotList (); + + void set_session (ARDOUR::Session *); + + Gtk::Widget& widget () { + return _scroller; + } + + void redisplay (); + +private: + + Gtk::ScrolledWindow _scroller; + + struct Columns : public Gtk::TreeModel::ColumnRecord { + Columns () { + add (name); + add (timestamp); + add (snapshot); + } + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn timestamp; + Gtk::TreeModelColumn snapshot; //ToDo: these are leaked + }; + + Columns _columns; + Glib::RefPtr _snapshot_model; + Gtk::TreeView _snapshot_display; + Gtk::Menu _menu; + + bool button_press (GdkEventButton *); + void selection_changed (); + void popup_context_menu (int, int32_t, std::string); + void remove (std::string); + void rename (std::string); +}; + +#endif // __gtk_ardour_mixer_snapshots_h__ diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index e568a58623..1c92e23963 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -68,6 +68,7 @@ #include "foldback_strip.h" #include "keyboard.h" #include "mixer_ui.h" +#include "mixer_snapshots.h" #include "mixer_strip.h" #include "monitor_section.h" #include "plugin_selector.h" @@ -273,7 +274,12 @@ Mixer_UI::Mixer_UI () rhs_pane2.add (rhs_pane1); rhs_pane2.add (group_display_frame); - list_vpacker.pack_start (rhs_pane2, true, true); + _mix_snaps = new MixerSnapshotList(); + + rhs_pane3.add (rhs_pane2); + rhs_pane3.add (_mix_snaps->widget()); + + list_vpacker.pack_start (rhs_pane3, true, true); vca_label_bar.set_size_request (-1, 16 + 1); /* must match height in GroupTabs::set_size_request() + 1 border px*/ vca_vpacker.pack_start (vca_label_bar, false, false); @@ -325,6 +331,7 @@ Mixer_UI::Mixer_UI () rhs_pane1.set_drag_cursor (*PublicEditor::instance().cursors()->expand_up_down); rhs_pane2.set_drag_cursor (*PublicEditor::instance().cursors()->expand_up_down); + rhs_pane3.set_drag_cursor (*PublicEditor::instance().cursors()->expand_up_down); list_hpane.set_drag_cursor (*PublicEditor::instance().cursors()->expand_left_right); inner_pane.set_drag_cursor (*PublicEditor::instance().cursors()->expand_left_right); @@ -349,6 +356,7 @@ Mixer_UI::Mixer_UI () favorite_plugins_frame.show(); rhs_pane1.show(); rhs_pane2.show(); + rhs_pane3.show(); strip_packer.show(); inner_pane.show(); vca_scroller.show(); @@ -1097,6 +1105,8 @@ Mixer_UI::set_session (Session* sess) _group_tabs->set_session (sess); + _mix_snaps->set_session (sess); + if (!_session) { _selection.clear (); return; diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 7adc79d99e..e86ab38e27 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -70,6 +70,7 @@ class AxisView; class FoldbackStrip; class MixerStrip; class PluginSelector; +class MixerSnapshotList; class MixerGroupTabs; class MonitorSection; class VCAMasterStrip; @@ -187,6 +188,7 @@ private: Gtk::ComboBoxText favorite_plugins_tag_combo; ArdourWidgets::VPane rhs_pane1; ArdourWidgets::VPane rhs_pane2; + ArdourWidgets::VPane rhs_pane3; ArdourWidgets::HPane inner_pane; Gtk::VBox strip_group_box; Gtk::HBox strip_packer; @@ -203,6 +205,8 @@ private: MixerGroupTabs* _group_tabs; + MixerSnapshotList* _mix_snaps; + bool on_scroll_event (GdkEventScroll*); bool on_vca_scroll_event (GdkEventScroll*); diff --git a/gtk2_ardour/save_template_dialog.cc b/gtk2_ardour/save_template_dialog.cc index 5200a36d38..2cfdf5154e 100644 --- a/gtk2_ardour/save_template_dialog.cc +++ b/gtk2_ardour/save_template_dialog.cc @@ -31,9 +31,12 @@ using namespace Gtk; using namespace ARDOUR; -SaveTemplateDialog::SaveTemplateDialog (const std::string& name, const std::string& desc) +SaveTemplateDialog::SaveTemplateDialog (const std::string& name, const std::string& desc, bool local) : ArdourDialog (_("Save as template")) { +printf("saving %s\n", local ? "LOCAL" : "PREFS"); + _local = local; + _name_entry.get_buffer()->set_text (name); _description_editor.get_buffer()->set_text (desc); _description_editor.set_wrap_mode (Gtk::WRAP_WORD); diff --git a/gtk2_ardour/save_template_dialog.h b/gtk2_ardour/save_template_dialog.h index 4e46e8e971..078058f12a 100644 --- a/gtk2_ardour/save_template_dialog.h +++ b/gtk2_ardour/save_template_dialog.h @@ -30,12 +30,14 @@ class SaveTemplateDialog : public ArdourDialog { public: - SaveTemplateDialog (const std::string& name, const std::string& description = ""); + SaveTemplateDialog (const std::string& name, const std::string& description = "", bool local = false); std::string get_template_name () const; std::string get_description () const; - + bool is_local() { return _local; } private: + bool _local; + Gtk::Entry _name_entry; Gtk::TextView _description_editor; }; diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 3a6a14e767..a828b7fe5e 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -166,6 +166,7 @@ gtk2_ardour_sources = [ 'mixer_snapshot_dialog.cc', 'mixer_snapshot_substitution_dialog.cc', 'mixer_group_tabs.cc', + 'mixer_snapshots.cc', 'mixer_strip.cc', 'mixer_ui.cc', 'meterbridge.cc',