2 * Copyright (C) 2018-2019 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <gtkmm/box.h>
20 #include <gtkmm/frame.h>
22 #include "gtkmm2ext/utils.h"
24 #include "ardour/plugin.h"
25 #include "gui_thread.h"
27 #include "plugin_presets_ui.h"
31 using namespace ARDOUR;
34 PluginPresetsUI::PluginPresetsUI (boost::shared_ptr<PluginInsert> insert)
36 , _load_button (_("Load"))
38 _filter_banks_model = TreeStore::create (_filter_banks_columns);
39 _filter_banks_display.set_model (_filter_banks_model);
40 _filter_banks_display.set_headers_visible (true);
41 _filter_banks_display.get_selection ()->set_mode (SELECTION_BROWSE);
42 _filter_banks_display.get_selection ()->signal_changed ().connect (sigc::mem_fun (*this, &PluginPresetsUI::filter_presets));
43 _filter_banks_display.set_sensitive (true);
44 _filter_banks_display.append_column (_("Bank/Vendor"), _filter_banks_columns.name);
45 _banks_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
46 _banks_scroller.add (_filter_banks_display);
47 _banks_scroller.set_no_show_all (true);
49 _filter_types_model = TreeStore::create (_filter_types_columns);
50 _filter_types_display.set_model (_filter_types_model);
51 _filter_types_display.set_headers_visible (true);
52 _filter_types_display.get_selection ()->set_mode (SELECTION_BROWSE);
53 _filter_types_display.get_selection ()->signal_changed ().connect (sigc::mem_fun (*this, &PluginPresetsUI::filter_presets));
54 _filter_types_display.set_sensitive (true);
55 _filter_types_display.append_column (_("Type/Category"), _filter_types_columns.name);
56 _types_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
57 _types_scroller.add (_filter_types_display);
58 _types_scroller.set_no_show_all (true);
60 _plugin_preset_model = TreeStore::create (_plugin_preset_columns);
61 _plugin_preset_display.set_model (_plugin_preset_model);
62 _plugin_preset_display.set_headers_visible (true);
63 _plugin_preset_display.get_selection ()->set_mode (SELECTION_BROWSE);
64 _plugin_preset_display.get_selection ()->signal_changed ().connect (sigc::mem_fun (*this, &PluginPresetsUI::preset_selected));
65 _plugin_preset_display.signal_row_activated ().connect (sigc::mem_fun (*this, &PluginPresetsUI::preset_row_activated));
66 _plugin_preset_display.set_sensitive (true);
68 CellRendererText* label_render = manage (new CellRendererText());
69 TreeView::Column* label_col = manage (new TreeView::Column (_("Preset"), *label_render));
70 label_col->add_attribute (label_render->property_markup(), _plugin_preset_columns.name);
71 _plugin_preset_display.append_column (*label_col);
73 _preset_desc.set_editable (false);
74 _preset_desc.set_can_focus (false);
75 _preset_desc.set_wrap_mode (WRAP_WORD);
76 _preset_desc.set_size_request (300,200);
77 _preset_desc.set_name (X_("TextOnBackground"));
78 _preset_desc.set_border_width (15);
80 Frame* frame = manage (new Frame);
81 frame->set_label (_("Description"));
82 frame->add (_preset_desc);
84 _preset_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
85 _preset_scroller.add (_plugin_preset_display);
87 _load_button.set_name ("generic button");
88 _load_button.signal_clicked.connect (sigc::mem_fun (*this, &PluginPresetsUI::load_preset));
89 _load_button.set_sensitive (false);
91 Box* filter_box = manage (new VBox ());
92 filter_box->pack_start (_banks_scroller);
93 filter_box->pack_start (_types_scroller);
95 attach (*filter_box, 0, 1, 0, 2, FILL, EXPAND|FILL, 2, 0);
96 attach (_preset_scroller, 1, 2, 0, 2, FILL, EXPAND|FILL, 2, 0);
97 attach (*frame, 2, 3, 0, 1, EXPAND|FILL, EXPAND|FILL, 2, 4);
98 attach (_load_button, 2, 3, 1, 2, FILL, SHRINK, 2, 0);
100 boost::shared_ptr<Plugin> plugin (_insert->plugin ());
102 plugin->PresetAdded.connect (_preset_connections, invalidator (*this), boost::bind (&PluginPresetsUI::update_preset_list, this), gui_context ());
103 plugin->PresetRemoved.connect (_preset_connections, invalidator (*this), boost::bind (&PluginPresetsUI::update_preset_list, this), gui_context ());
105 plugin->PresetLoaded.connect (_preset_connections, invalidator (*this), boost::bind (&PluginPresetsUI::filter_presets, this), gui_context ());
106 plugin->PresetDirty.connect (_preset_connections, invalidator (*this), boost::bind (&PluginPresetsUI::filter_presets, this), gui_context ());
108 update_preset_list ();
112 PluginPresetsUI::update_preset_list ()
114 boost::shared_ptr<Plugin> plugin (_insert->plugin ());
115 std::vector<Plugin::PresetRecord> presets = plugin->get_presets ();
118 std::map<std::string, size_t> banks; // or vendors
119 std::map<std::string, size_t> types; // or categories
121 for (std::vector<Plugin::PresetRecord>::const_iterator i = presets.begin (); i != presets.end (); ++i) {
125 ++banks[_("-User-")];
126 _pps.push_back (PluginPreset(*i, _("-User-")));
130 std::string l (i->label);
131 std::vector<std::string> cat;
133 while ((pos = l.find(" - ")) != std::string::npos) {
134 cat.push_back (l.substr (0, pos));
135 l.erase (0, pos + 3);
136 if (cat.size() > 1) {
140 if (cat.size() > 1) {
143 _pps.push_back (PluginPreset(*i, cat.at (0), cat.at (1)));
144 } else if (cat.size() > 0) {
146 _pps.push_back (PluginPreset(*i, cat.at (0)));
148 _pps.push_back (PluginPreset(*i));
152 if (types.size() > 2) {
153 std::string selected_type;
154 if (_filter_types_display.get_selection ()->count_selected_rows () == 1) {
155 TreeIter iter = _filter_types_display.get_selection ()->get_selected ();
156 selected_type = (*iter)[_filter_types_columns.name];
158 selected_type = Gtkmm2ext::markup_escape_text(_("-All-"));
160 _filter_types_model->clear ();
161 for (std::map<std::string, size_t>::const_iterator i = types.begin (); i != types.end(); ++i) {
162 TreeModel::Row row = *(_filter_types_model->append ());
163 row[_filter_types_columns.name] = Gtkmm2ext::markup_escape_text (i->first);
164 row[_filter_types_columns.count] = i->second;
166 TreeModel::Children rows = _filter_types_model->children ();
167 for (TreeModel::Children::iterator i = rows.begin (); i != rows.end (); ++i) {
168 std::string const& name ((*i)[_filter_types_columns.name]);
169 if (selected_type == name) {
170 _filter_types_display.get_selection ()->select (*i);
174 _filter_types_display.show_all ();
175 _types_scroller.show ();
177 _filter_types_model->clear ();
178 _types_scroller.hide ();
181 if (banks.size() > 2) {
182 std::string selected_bank = Gtkmm2ext::markup_escape_text(_("-All-"));
183 if (_filter_banks_display.get_selection ()->count_selected_rows () == 1) {
184 TreeIter iter = _filter_banks_display.get_selection ()->get_selected ();
185 selected_bank = (*iter)[_filter_banks_columns.name];
187 _filter_banks_model->clear ();
188 for (std::map<std::string, size_t>::const_iterator i = banks.begin (); i != banks.end(); ++i) {
189 TreeModel::Row row = *(_filter_banks_model->append ());
190 row[_filter_banks_columns.name] = Gtkmm2ext::markup_escape_text (i->first);
191 row[_filter_banks_columns.count] = i->second;
193 TreeModel::Children rows = _filter_banks_model->children ();
194 for (TreeModel::Children::iterator i = rows.begin (); i != rows.end (); ++i) {
195 std::string const& name ((*i)[_filter_banks_columns.name]);
196 if (selected_bank == name) {
197 _filter_banks_display.get_selection ()->select (*i);
201 _filter_banks_display.show_all ();
202 _banks_scroller.show ();
204 _filter_banks_model->clear ();
205 _banks_scroller.hide ();
208 std::sort (_pps.begin(), _pps.end());
214 PluginPresetsUI::filter_presets ()
216 bool user_only = false;
217 std::string selected_bank;
218 if (_filter_banks_display.get_selection ()->count_selected_rows () == 1) {
219 TreeIter iter = _filter_banks_display.get_selection ()->get_selected ();
220 selected_bank = (*iter)[_filter_banks_columns.name];
221 if (_("-All-") == selected_bank) {
224 if (_("-User-") == selected_bank) {
230 std::string selected_type;
231 if (_filter_types_display.get_selection ()->count_selected_rows () == 1) {
232 TreeIter iter = _filter_types_display.get_selection ()->get_selected ();
233 selected_type = (*iter)[_filter_types_columns.name];
234 if (_("-All-") == selected_type) {
239 boost::shared_ptr<Plugin> plugin (_insert->plugin ());
240 Plugin::PresetRecord const& p = plugin->last_preset ();
242 std::string selected_uri = p.valid ? p.uri : "";
243 if (_plugin_preset_display.get_selection ()->count_selected_rows () == 1) {
244 TreeIter iter = _plugin_preset_display.get_selection ()->get_selected ();
245 ARDOUR::Plugin::PresetRecord const& ppr ((*iter)[_plugin_preset_columns.plugin_preset]);
246 selected_uri = ppr.uri;
249 _plugin_preset_model->clear ();
250 bool const modified = plugin->parameter_changed_since_last_preset ();
252 for (std::vector<PluginPreset>::const_iterator i = _pps.begin (); i != _pps.end (); ++i) {
253 if (!selected_type.empty() && i->_type != selected_type) {
256 if (!selected_bank.empty() && i->_bank != selected_bank) {
260 ARDOUR::Plugin::PresetRecord const& ppr (i->_preset_record);
262 if (user_only && !ppr.user) {
266 TreeModel::Row row = *(_plugin_preset_model->append ());
267 if (p.uri == ppr.uri && !modified) {
268 row[_plugin_preset_columns.name] = string_compose ("<span weight=\"bold\" background=\"green\">%1</span>", Gtkmm2ext::markup_escape_text (ppr.label));
270 row[_plugin_preset_columns.name] = Gtkmm2ext::markup_escape_text (ppr.label);
272 row[_plugin_preset_columns.description] = ppr.description;
273 row[_plugin_preset_columns.plugin_preset] = ppr;
277 TreeModel::Children rows = _plugin_preset_model->children ();
278 for (TreeModel::Children::iterator i = rows.begin (); i != rows.end (); ++i, ++path) {
279 ARDOUR::Plugin::PresetRecord const& ppr ((*i)[_plugin_preset_columns.plugin_preset]);
280 if (ppr.uri == selected_uri) {
281 _plugin_preset_display.get_selection ()->select (*i);
283 snprintf(row_path, 21, "%d", path);
284 _plugin_preset_display.scroll_to_row (Gtk::TreePath(row_path));
291 PluginPresetsUI::preset_selected ()
293 if (_plugin_preset_display.get_selection ()->count_selected_rows () != 1) {
294 _preset_desc.get_buffer ()->set_text ("");
295 _load_button.set_sensitive (false);
299 TreeIter iter = _plugin_preset_display.get_selection ()->get_selected ();
301 ARDOUR::Plugin::PresetRecord const& ppr ((*iter)[_plugin_preset_columns.plugin_preset]);
306 } else if (ppr.user) {
307 d = _("(user preset)");
309 d = (*iter)[_plugin_preset_columns.description];
311 _preset_desc.get_buffer ()->set_text (d);
313 Plugin::PresetRecord const& p = _insert->plugin ()->last_preset ();
314 _load_button.set_sensitive (ppr.valid && !(p.valid && p.uri == ppr.uri));
318 PluginPresetsUI::preset_row_activated (Gtk::TreeModel::Path, Gtk::TreeViewColumn*)
320 if (_load_button.get_sensitive ()) {
326 PluginPresetsUI::load_preset ()
328 if (_plugin_preset_display.get_selection ()->count_selected_rows () != 1) {
332 TreeIter iter = _plugin_preset_display.get_selection ()->get_selected ();
333 ARDOUR::Plugin::PresetRecord const& ppr ((*iter)[_plugin_preset_columns.plugin_preset]);
335 _insert->load_preset (ppr);