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',