1 /*
2  * Copyright (C) 2020-2021 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of Zrythm
5  *
6  * Zrythm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Zrythm is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "audio/engine.h"
21 #include "audio/port.h"
22 #include "audio/track.h"
23 #include "gui/backend/event.h"
24 #include "gui/backend/event_manager.h"
25 #include "gui/widgets/editable_label.h"
26 #include "gui/widgets/inspector_port.h"
27 #include "gui/widgets/main_window.h"
28 #include "gui/widgets/plugin_properties_expander.h"
29 #include "plugins/carla_native_plugin.h"
30 #include "plugins/lv2/lv2_state.h"
31 #include "plugins/plugin.h"
32 #include "plugins/plugin_gtk.h"
33 #include "project.h"
34 #include "utils/error.h"
35 #include "utils/gtk.h"
36 #include "zrythm_app.h"
37 
G_DEFINE_TYPE(PianoRollKeysWidget,piano_roll_keys_widget,GTK_TYPE_DRAWING_AREA)38 #include <glib/gi18n.h>
39 
40 G_DEFINE_TYPE (
41   PluginPropertiesExpanderWidget,
42   plugin_properties_expander_widget,
43   TWO_COL_EXPANDER_BOX_WIDGET_TYPE)
44 
45 static void
46 on_bank_changed (
47   GtkComboBox * cb,
48   PluginPropertiesExpanderWidget * self)
49 {
50   if (!self->plugin)
51     return;
52 
53   plugin_set_selected_bank_from_index (
54     self->plugin, gtk_combo_box_get_active (cb));
55 
56   g_signal_handler_block (
57     self->presets, self->pset_changed_handler);
58   plugin_gtk_setup_plugin_presets_list_box (
59     self->presets, self->plugin);
60   g_signal_handler_unblock (
61     self->presets, self->pset_changed_handler);
62 }
63 
64 static void
65 on_preset_changed (
66   GtkListBox *                     box,
67   PluginPropertiesExpanderWidget * self)
68 {
69   if (!self->plugin)
70     return;
71 
72   GtkListBoxRow * row =
73     gtk_list_box_get_selected_row (box);
74   plugin_set_selected_preset_from_index (
75     self->plugin,
76     gtk_list_box_row_get_index (row));
77 }
78 
79 static void
80 on_save_preset_clicked (
81   GtkButton *                      btn,
82   PluginPropertiesExpanderWidget * self)
83 {
84   if (!self->plugin || !self->plugin->instantiated)
85     return;
86 
87   plugin_gtk_on_save_preset_activate (
88     GTK_WIDGET (self), self->plugin);
89 }
90 
91 static void
92 on_load_preset_clicked (
93   GtkButton *                      btn,
94   PluginPropertiesExpanderWidget * self)
95 {
96   if (!self->plugin || !self->plugin->instantiated)
97     return;
98 
99   const PluginSetting * setting =
100     self->plugin->setting;
101 
102   GtkWidget* dialog =
103     gtk_file_chooser_dialog_new (
104     _("Load Preset"),
105     self->plugin->window ?
106       self->plugin->window :
107       GTK_WINDOW (MAIN_WINDOW),
108       GTK_FILE_CHOOSER_ACTION_OPEN,
109     _("_Cancel"), GTK_RESPONSE_REJECT,
110     _("_Load"), GTK_RESPONSE_ACCEPT,
111     NULL);
112   gtk_file_chooser_set_current_folder (
113     GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
114   gtk_widget_show_all (GTK_WIDGET (dialog));
115   gtk_dialog_set_default_response (
116     GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
117   if (gtk_dialog_run (GTK_DIALOG(dialog)) !=
118         GTK_RESPONSE_ACCEPT)
119     {
120       gtk_widget_destroy (GTK_WIDGET (dialog));
121       return;
122     }
123 
124   const char* path =
125     gtk_file_chooser_get_filename (
126       GTK_FILE_CHOOSER (dialog));
127 
128   GError * err = NULL;
129   bool applied = false;
130   if (setting->open_with_carla)
131     {
132 #ifdef HAVE_CARLA
133       applied =
134         carla_native_plugin_load_state (
135           self->plugin->carla, path, &err);
136 #else
137       g_return_if_reached ();
138 #endif
139     }
140   else if (setting->descr->protocol == PROT_LV2)
141     {
142       applied =
143         lv2_state_apply_preset (
144           self->plugin->lv2, NULL, path, &err);
145     }
146 
147   if (applied)
148     {
149       EVENTS_PUSH (
150         ET_PLUGIN_PRESET_LOADED, self->plugin);
151     }
152   else
153     {
154       HANDLE_ERROR (
155         err, "%s", _("Failed to apply preset"));
156     }
157 
158   gtk_widget_destroy (GTK_WIDGET (dialog));
159 }
160 
161 /**
162  * Refreshes each field.
163  */
164 void
165 plugin_properties_expander_widget_refresh (
166   PluginPropertiesExpanderWidget * self,
167   Plugin *                         pl)
168 {
169   if (self->plugin == pl)
170     return;
171 
172   self->plugin = pl;
173 
174   if (pl)
175     {
176       gtk_label_set_text (
177         self->name, pl->setting->descr->name);
178       gtk_label_set_text (
179         self->type,
180         pl->setting->descr->category_str);
181     }
182   else
183     {
184       gtk_label_set_text (
185         self->name, _("None"));
186       gtk_label_set_text (
187         self->type, _("None"));
188     }
189 
190   g_signal_handler_block (
191     self->banks, self->bank_changed_handler);
192   plugin_gtk_setup_plugin_banks_combo_box (
193     self->banks, pl);
194   g_signal_handler_unblock (
195     self->banks, self->bank_changed_handler);
196   g_signal_handler_block (
197     self->presets, self->pset_changed_handler);
198   plugin_gtk_setup_plugin_presets_list_box (
199     self->presets, pl);
200   g_signal_handler_unblock (
201     self->presets, self->pset_changed_handler);
202 }
203 
204 /**
205  * Sets up the PluginPropertiesExpanderWidget for a Plugin.
206  */
207 void
208 plugin_properties_expander_widget_setup (
209   PluginPropertiesExpanderWidget * self,
210   Plugin *      pl)
211 {
212   self->plugin = pl;
213 
214   /* set name and icon */
215   expander_box_widget_set_label (
216     Z_EXPANDER_BOX_WIDGET (self),
217     _("Plugin Properties"));
218 
219   GtkWidget * lbl;
220 
221 #define CREATE_LABEL(x) \
222   lbl = \
223     plugin_gtk_new_label ( \
224       x, true, false, 0.f, 0.5f); \
225   z_gtk_widget_add_style_class ( \
226     lbl, "inspector_label"); \
227   gtk_widget_set_margin_start (lbl, 2); \
228   gtk_widget_set_visible (lbl, 1)
229 
230   CREATE_LABEL (_("Name"));
231   gtk_widget_set_visible (lbl, TRUE);
232   two_col_expander_box_widget_add_single (
233     Z_TWO_COL_EXPANDER_BOX_WIDGET (self), lbl);
234   self->name =
235     GTK_LABEL (gtk_label_new ("dist"));
236   gtk_widget_set_visible (
237     GTK_WIDGET (self->name), TRUE);
238   gtk_label_set_xalign (
239     self->name, 0);
240   gtk_widget_set_margin_start (
241     GTK_WIDGET (self->name), 4);
242   two_col_expander_box_widget_add_single (
243     Z_TWO_COL_EXPANDER_BOX_WIDGET (self),
244     GTK_WIDGET (self->name));
245 
246   CREATE_LABEL (_("Type"));
247   gtk_widget_set_visible (lbl, TRUE);
248   two_col_expander_box_widget_add_single (
249     Z_TWO_COL_EXPANDER_BOX_WIDGET (self), lbl);
250   self->type =
251     GTK_LABEL (gtk_label_new ("Instrument"));
252   gtk_widget_set_visible (
253     GTK_WIDGET (self->type), TRUE);
254   gtk_label_set_xalign (
255     self->type, 0);
256   gtk_widget_set_margin_start (
257     GTK_WIDGET (self->type), 4);
258   two_col_expander_box_widget_add_single (
259     Z_TWO_COL_EXPANDER_BOX_WIDGET (self),
260     GTK_WIDGET (self->type));
261 
262   CREATE_LABEL (_("Banks"));
263   gtk_widget_set_visible (lbl, true);
264   two_col_expander_box_widget_add_single (
265     Z_TWO_COL_EXPANDER_BOX_WIDGET (self), lbl);
266   self->banks =
267     GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new ());
268   gtk_widget_set_visible (
269     GTK_WIDGET (self->banks), true);
270   two_col_expander_box_widget_add_single (
271     Z_TWO_COL_EXPANDER_BOX_WIDGET (self),
272     GTK_WIDGET (self->banks));
273   self->bank_changed_handler =
274     g_signal_connect (
275       G_OBJECT (self->banks), "changed",
276       G_CALLBACK (on_bank_changed), self);
277 
278   CREATE_LABEL (_("Presets"));
279   gtk_widget_set_visible (lbl, true);
280   two_col_expander_box_widget_add_single (
281     Z_TWO_COL_EXPANDER_BOX_WIDGET (self), lbl);
282   self->presets =
283     GTK_LIST_BOX (gtk_list_box_new ());
284   gtk_widget_set_visible (
285     GTK_WIDGET (self->presets), true);
286   GtkScrolledWindow * scroll =
287     GTK_SCROLLED_WINDOW (
288       gtk_scrolled_window_new (NULL, NULL));
289   gtk_scrolled_window_set_min_content_height (
290     scroll, 86);
291   gtk_scrolled_window_set_policy (
292     scroll, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
293   gtk_widget_set_visible (
294     GTK_WIDGET (scroll), true);
295   gtk_container_add (
296     GTK_CONTAINER (scroll),
297     GTK_WIDGET (self->presets));
298   two_col_expander_box_widget_add_single (
299     Z_TWO_COL_EXPANDER_BOX_WIDGET (self),
300     GTK_WIDGET (scroll));
301   self->pset_changed_handler =
302     g_signal_connect (
303       G_OBJECT (self->presets),
304       "selected-rows-changed",
305       G_CALLBACK (on_preset_changed), self);
306 
307   self->save_preset_btn =
308     z_gtk_button_new_with_icon_and_text (
309       "document-save-as", _("Save"), true,
310       GTK_ORIENTATION_HORIZONTAL, 2);
311   gtk_widget_set_tooltip_text (
312     GTK_WIDGET (self->save_preset_btn),
313     _("Save preset"));
314   self->load_preset_btn =
piano_roll_keys_widget_get_key_from_y(PianoRollKeysWidget * self,double y)315     z_gtk_button_new_with_icon_and_text (
316       "document-open", _("Load"), true,
317       GTK_ORIENTATION_HORIZONTAL, 2);
318   gtk_widget_set_tooltip_text (
319     GTK_WIDGET (self->load_preset_btn),
320     _("Load preset"));
321   GtkWidget * box =
322     gtk_button_box_new (
323       GTK_ORIENTATION_HORIZONTAL);
324   gtk_widget_set_visible (box, true);
325   gtk_container_add (
326     GTK_CONTAINER (box),
327     GTK_WIDGET (self->save_preset_btn));
328   gtk_container_add (
329     GTK_CONTAINER (box),
piano_roll_keys_widget_get_font_size(PianoRollKeysWidget * self)330     GTK_WIDGET (self->load_preset_btn));
331   z_gtk_widget_add_style_class (box, "linked");
332   two_col_expander_box_widget_add_single (
333     Z_TWO_COL_EXPANDER_BOX_WIDGET (self), box);
334   g_signal_connect (
335     G_OBJECT (self->save_preset_btn), "clicked",
336     G_CALLBACK (on_save_preset_clicked), self);
337   g_signal_connect (
338     G_OBJECT (self->load_preset_btn), "clicked",
339     G_CALLBACK (on_load_preset_clicked), self);
340 
341   plugin_properties_expander_widget_refresh (
342     self, pl);
343 }
344 
345 static void
346 plugin_properties_expander_widget_class_init (
send_note_event(PianoRollKeysWidget * self,int note,int on)347   PluginPropertiesExpanderWidgetClass * klass)
348 {
349 }
350 
351 static void
352 plugin_properties_expander_widget_init (
353   PluginPropertiesExpanderWidget * self)
354 {
355   /*two_col_expander_box_widget_add_single (*/
356     /*Z_TWO_COL_EXPANDER_BOX_WIDGET (self),*/
357     /*GTK_WIDGET (self->name));*/
358 }
359