Fix thinkos in cubasish theme
[ardour.git] / gtk2_ardour / plugin_presets_ui.cc
1 /*
2  * Copyright (C) 2018-2019 Robin Gareus <robin@gareus.org>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <gtkmm/box.h>
20 #include <gtkmm/frame.h>
21
22 #include "gtkmm2ext/utils.h"
23
24 #include "ardour/plugin.h"
25 #include "gui_thread.h"
26
27 #include "plugin_presets_ui.h"
28
29 #include "pbd/i18n.h"
30
31 using namespace ARDOUR;
32 using namespace Gtk;
33
34 PluginPresetsUI::PluginPresetsUI (boost::shared_ptr<PluginInsert> insert)
35         : _insert (insert)
36         , _load_button (_("Load"))
37 {
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);
48
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);
59
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);
67
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);
72
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);
79
80         Frame* frame = manage (new Frame);
81         frame->set_label (_("Description"));
82         frame->add (_preset_desc);
83
84         _preset_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
85         _preset_scroller.add (_plugin_preset_display);
86
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);
90
91         Box* filter_box = manage (new VBox ());
92         filter_box->pack_start (_banks_scroller);
93         filter_box->pack_start (_types_scroller);
94
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);
99
100         boost::shared_ptr<Plugin> plugin (_insert->plugin ());
101
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 ());
104
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 ());
107
108         update_preset_list ();
109 }
110
111 void
112 PluginPresetsUI::update_preset_list ()
113 {
114         boost::shared_ptr<Plugin> plugin (_insert->plugin ());
115         std::vector<Plugin::PresetRecord> presets = plugin->get_presets ();
116
117         _pps.clear ();
118         std::map<std::string, size_t> banks; // or vendors
119         std::map<std::string, size_t> types; // or categories
120
121         for (std::vector<Plugin::PresetRecord>::const_iterator i = presets.begin (); i != presets.end (); ++i) {
122                 ++banks[_("-All-")];
123                 ++types[_("-All-")];
124                 if (i->user) {
125                         ++banks[_("-User-")];
126                         _pps.push_back (PluginPreset(*i, _("-User-")));
127                         continue;
128                 }
129
130                 std::string l (i->label);
131                 std::vector<std::string> cat;
132                 size_t pos = 0;
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) {
137                                 break;
138                         }
139                 }
140                 if (cat.size() > 1) {
141                         ++banks[cat.at (0)];
142                         ++types[cat.at (1)];
143                         _pps.push_back (PluginPreset(*i, cat.at (0), cat.at (1)));
144                 } else if (cat.size() > 0) {
145                         ++banks[cat.at (0)];
146                         _pps.push_back (PluginPreset(*i, cat.at (0)));
147                 } else {
148                         _pps.push_back (PluginPreset(*i));
149                 }
150         }
151
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];
157                 } else {
158                         selected_type = Gtkmm2ext::markup_escape_text(_("-All-"));
159                 }
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;
165                 }
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);
171                                 break;
172                         }
173                 }
174                 _filter_types_display.show_all ();
175                 _types_scroller.show ();
176         } else {
177                 _filter_types_model->clear ();
178                 _types_scroller.hide ();
179         }
180
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];
186                 }
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;
192                 }
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);
198                                 break;
199                         }
200                 }
201                 _filter_banks_display.show_all ();
202                 _banks_scroller.show ();
203         } else {
204                 _filter_banks_model->clear ();
205                 _banks_scroller.hide ();
206         }
207
208         std::sort (_pps.begin(), _pps.end());
209
210         filter_presets ();
211 }
212
213 void
214 PluginPresetsUI::filter_presets ()
215 {
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) {
222                         selected_bank = "";
223                 }
224                 if (_("-User-") == selected_bank) {
225                         selected_bank = "";
226                         user_only = true;
227                 }
228         }
229
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) {
235                         selected_type = "";
236                 }
237         }
238
239         boost::shared_ptr<Plugin> plugin (_insert->plugin ());
240         Plugin::PresetRecord const& p = plugin->last_preset ();
241
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;
247         }
248
249         _plugin_preset_model->clear ();
250         bool const modified = plugin->parameter_changed_since_last_preset ();
251
252         for (std::vector<PluginPreset>::const_iterator i = _pps.begin (); i != _pps.end (); ++i) {
253                 if (!selected_type.empty() && i->_type != selected_type) {
254                         continue;
255                 }
256                 if (!selected_bank.empty() && i->_bank != selected_bank) {
257                         continue;
258                 }
259
260                 ARDOUR::Plugin::PresetRecord const& ppr (i->_preset_record);
261
262                 if (user_only && !ppr.user) {
263                         continue;
264                 }
265
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));
269                 } else {
270                         row[_plugin_preset_columns.name] = Gtkmm2ext::markup_escape_text (ppr.label);
271                 }
272                 row[_plugin_preset_columns.description] = ppr.description;
273                 row[_plugin_preset_columns.plugin_preset] = ppr;
274         }
275
276         int path = 0;
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);
282                         char row_path[21];
283                         snprintf(row_path, 21, "%d", path);
284                         _plugin_preset_display.scroll_to_row (Gtk::TreePath(row_path));
285                         break;
286                 }
287         }
288 }
289
290 void
291 PluginPresetsUI::preset_selected ()
292 {
293         if (_plugin_preset_display.get_selection ()->count_selected_rows () != 1) {
294                 _preset_desc.get_buffer ()->set_text ("");
295                 _load_button.set_sensitive (false);
296                 return;
297         }
298
299         TreeIter iter = _plugin_preset_display.get_selection ()->get_selected ();
300         assert (iter);
301         ARDOUR::Plugin::PresetRecord const& ppr ((*iter)[_plugin_preset_columns.plugin_preset]);
302
303         std::string d;
304         if (!ppr.valid) {
305                 d = "-";
306         } else if (ppr.user) {
307                 d = _("(user preset)");
308         } else {
309                 d = (*iter)[_plugin_preset_columns.description];
310         }
311         _preset_desc.get_buffer ()->set_text (d);
312
313         Plugin::PresetRecord const& p = _insert->plugin ()->last_preset ();
314         _load_button.set_sensitive (ppr.valid && !(p.valid && p.uri == ppr.uri));
315 }
316
317 void
318 PluginPresetsUI::preset_row_activated (Gtk::TreeModel::Path, Gtk::TreeViewColumn*)
319 {
320         if (_load_button.get_sensitive ()) {
321                 load_preset ();
322         }
323 }
324
325 void
326 PluginPresetsUI::load_preset ()
327 {
328         if (_plugin_preset_display.get_selection ()->count_selected_rows () != 1) {
329                 return;
330         }
331
332         TreeIter iter = _plugin_preset_display.get_selection ()->get_selected ();
333         ARDOUR::Plugin::PresetRecord const& ppr ((*iter)[_plugin_preset_columns.plugin_preset]);
334         if (ppr.valid) {
335                 _insert->load_preset (ppr);
336         }
337 }