1 /*
2  * Copyright (C) 2020 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/channel.h"
21 #include "audio/track.h"
22 #include "gui/backend/event.h"
23 #include "gui/backend/event_manager.h"
24 #include "gui/widgets/channel_slot.h"
25 #include "gui/widgets/plugin_strip_expander.h"
26 #include "project.h"
27 #include "settings/settings.h"
28 #include "utils/gtk.h"
29 #include "zrythm_app.h"
30 
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
33 
34 #define PLUGIN_STRIP_EXPANDER_WIDGET_TYPE \
35   (plugin_strip_expander_widget_get_type ())
G_DEFINE_TYPE(PluginStripExpanderWidget,plugin_strip_expander_widget,EXPANDER_BOX_WIDGET_TYPE)36 G_DEFINE_TYPE (
37   PluginStripExpanderWidget,
38   plugin_strip_expander_widget,
39   EXPANDER_BOX_WIDGET_TYPE)
40 
41 /**
42  * Queues a redraw of the given slot.
43  */
44 void
45 plugin_strip_expander_widget_redraw_slot (
46   PluginStripExpanderWidget * self,
47   int                         slot)
48 {
49   switch (self->slot_type)
50     {
51     case PLUGIN_SLOT_INSERT:
52     case PLUGIN_SLOT_MIDI_FX:
53       gtk_widget_queue_draw (
54         GTK_WIDGET (self->slots[slot]));
55       break;
56     default:
57       break;
58     }
59 }
60 
61 /**
62  * Unsets state flags and redraws the widget at the
63  * given slot.
64  *
65  * @param slot Slot, or -1 for all slots.
66  * @param set True to set, false to unset.
67  */
68 void
plugin_strip_expander_widget_set_state_flags(PluginStripExpanderWidget * self,int slot,GtkStateFlags flags,bool set)69 plugin_strip_expander_widget_set_state_flags (
70   PluginStripExpanderWidget * self,
71   int                         slot,
72   GtkStateFlags               flags,
73   bool                        set)
74 {
75   switch (self->slot_type)
76     {
77     case PLUGIN_SLOT_INSERT:
78     case PLUGIN_SLOT_MIDI_FX:
79       if (slot == -1)
80         {
81           for (int i = 0; i < STRIP_SIZE; i++)
82             {
83               plugin_strip_expander_widget_set_state_flags (
84                 self, i, flags, set);
85             }
86         }
87       else
88         {
89           channel_slot_widget_set_state_flags (
90             self->slots[slot], flags, set);
91         }
92       break;
93     default:
94       break;
95     }
96 }
97 
98 /**
99  * Refreshes each field.
100  */
101 void
plugin_strip_expander_widget_refresh(PluginStripExpanderWidget * self)102 plugin_strip_expander_widget_refresh (
103   PluginStripExpanderWidget * self)
104 {
105   for (int i = 0; i < STRIP_SIZE; i++)
106     {
107       switch (self->slot_type)
108         {
109         case PLUGIN_SLOT_INSERT:
110           {
111             Channel * ch =
112               track_get_channel (self->track);
113             Plugin * pl = ch->inserts[i];
114             plugin_strip_expander_widget_set_state_flags (
115               self, i,
116               GTK_STATE_FLAG_SELECTED,
117               pl && plugin_is_selected (pl));
118             gtk_widget_queue_draw (
119               GTK_WIDGET (self->slots[i]));
120           }
121           break;
122         case PLUGIN_SLOT_MIDI_FX:
123           {
124             Channel * ch =
125               track_get_channel (self->track);
126             Plugin * pl = ch->midi_fx[i];
127             plugin_strip_expander_widget_set_state_flags (
128               self, i,
129               GTK_STATE_FLAG_SELECTED,
130               pl && plugin_is_selected (pl));
131             gtk_widget_queue_draw (
132               GTK_WIDGET (self->slots[i]));
133           }
134           break;
135         default:
136           break;
137         }
138     }
139 }
140 
141 static void
on_reveal_changed(ExpanderBoxWidget * expander_box,bool revealed,PluginStripExpanderWidget * self)142 on_reveal_changed (
143   ExpanderBoxWidget *         expander_box,
144   bool                        revealed,
145   PluginStripExpanderWidget * self)
146 {
147   if (self->position == PSE_POSITION_CHANNEL)
148     {
149       Channel * ch =
150         track_get_channel (self->track);
151       if (self->slot_type == PLUGIN_SLOT_INSERT)
152         {
153           g_settings_set_boolean (
154             S_UI_MIXER, "inserts-expanded",
155             revealed);
156           EVENTS_PUSH (
157             ET_MIXER_CHANNEL_INSERTS_EXPANDED_CHANGED,
158             ch);
159         }
160       else if (self->slot_type ==
161                  PLUGIN_SLOT_MIDI_FX)
162         {
163           g_settings_set_boolean (
164             S_UI_MIXER, "midi-fx-expanded",
165             revealed);
166           EVENTS_PUSH (
167             ET_MIXER_CHANNEL_MIDI_FX_EXPANDED_CHANGED,
168             ch);
169         }
170     }
171 }
172 
173 /**
174  * Sets up the PluginStripExpanderWidget.
175  */
176 void
plugin_strip_expander_widget_setup(PluginStripExpanderWidget * self,PluginSlotType slot_type,PluginStripExpanderPosition position,Track * track)177 plugin_strip_expander_widget_setup (
178   PluginStripExpanderWidget * self,
179   PluginSlotType              slot_type,
180   PluginStripExpanderPosition position,
181   Track *                     track)
182 {
183   /* set name and icon */
184   char fullstr[200];
185   bool is_midi = false;
186   switch (slot_type)
187     {
188     case PLUGIN_SLOT_INSERT:
189       strcpy (fullstr, _("Inserts"));
190       is_midi =
191         track &&
192         track->out_signal_type == TYPE_EVENT;
193       break;
194     case PLUGIN_SLOT_MIDI_FX:
195       strcpy (fullstr, "MIDI FX");
196       is_midi = true;
197       break;
198     default:
199       g_return_if_reached ();
200       break;
201     }
202   expander_box_widget_set_label (
203     Z_EXPANDER_BOX_WIDGET (self),
204     fullstr);
205 
206   if (is_midi)
207     {
208       expander_box_widget_set_icon_name (
209         Z_EXPANDER_BOX_WIDGET (self),
210         "midi-insert");
211     }
212   else
213     {
214       expander_box_widget_set_icon_name (
215         Z_EXPANDER_BOX_WIDGET (self),
216         "audio-insert");
217     }
218 
219   if (track != self->track ||
220       slot_type != self->slot_type ||
221       position != self->position)
222     {
223       /* remove children */
224       z_gtk_container_destroy_all_children (
225         GTK_CONTAINER (self->box));
226 
227       Channel * ch = track_get_channel (track);
228       g_return_if_fail (ch);
229       for (int i = 0; i < STRIP_SIZE; i++)
230         {
231           GtkBox * strip_box =
232             GTK_BOX (
233               gtk_box_new (
234                 GTK_ORIENTATION_HORIZONTAL, 0));
235           self->strip_boxes[i] = strip_box;
236 
237           switch (slot_type)
238             {
239             case PLUGIN_SLOT_INSERT:
240             case PLUGIN_SLOT_MIDI_FX:
241               {
242                 ChannelSlotWidget * csw =
243                   channel_slot_widget_new (
244                     i, track, slot_type,
245                     position ==
246                       PSE_POSITION_CHANNEL);
247                 self->slots[i] = csw;
248                 gtk_box_pack_start (
249                   strip_box, GTK_WIDGET (csw), 1, 1, 0);
250               }
251               break;
252             default:
253               g_warn_if_reached ();
254               break;
255             }
256 
257           gtk_box_pack_start (
258             self->box,
259             GTK_WIDGET (strip_box), 0, 1, 0);
260           gtk_widget_show_all (
261             GTK_WIDGET (strip_box));
262         }
263     }
264 
265   self->track = track;
266   self->slot_type = slot_type;
267   self->position = position;
268 
269   switch (position)
270     {
271     case PSE_POSITION_INSPECTOR:
272       gtk_widget_set_size_request (
273         GTK_WIDGET (self->scroll), -1, 124);
274       break;
275     case PSE_POSITION_CHANNEL:
276       gtk_widget_set_size_request (
277         GTK_WIDGET (self->scroll), -1, 68);
278       if (slot_type == PLUGIN_SLOT_INSERT ||
279           slot_type == PLUGIN_SLOT_MIDI_FX)
280         {
281           expander_box_widget_set_reveal_callback (
282             Z_EXPANDER_BOX_WIDGET (self),
283             (ExpanderBoxRevealFunc)
284             on_reveal_changed, self);
285         }
286       break;
287     }
288 
289   plugin_strip_expander_widget_refresh (self);
290 }
291 
292 static void
plugin_strip_expander_widget_class_init(PluginStripExpanderWidgetClass * klass)293 plugin_strip_expander_widget_class_init (
294   PluginStripExpanderWidgetClass * klass)
295 {
296 }
297 
298 static void
plugin_strip_expander_widget_init(PluginStripExpanderWidget * self)299 plugin_strip_expander_widget_init (
300   PluginStripExpanderWidget * self)
301 {
302   self->scroll =
303     GTK_SCROLLED_WINDOW (
304       gtk_scrolled_window_new (
305         NULL, NULL));
306   gtk_widget_set_vexpand (
307     GTK_WIDGET (self->scroll), 1);
308   gtk_widget_set_visible (
309     GTK_WIDGET (self->scroll), 1);
310   gtk_scrolled_window_set_shadow_type (
311     self->scroll, GTK_SHADOW_ETCHED_IN);
312 
313   self->viewport =
314     GTK_VIEWPORT (
315       gtk_viewport_new (NULL, NULL));
316   gtk_widget_set_visible (
317     GTK_WIDGET (self->viewport), 1);
318   gtk_container_add (
319     GTK_CONTAINER (self->scroll),
320     GTK_WIDGET (self->viewport));
321 
322   self->box =
323     GTK_BOX (
324       gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
325   gtk_widget_set_visible (
326     GTK_WIDGET (self->box), 1);
327   gtk_container_add (
328     GTK_CONTAINER (self->viewport),
329     GTK_WIDGET (self->box));
330 
331   expander_box_widget_add_content (
332     Z_EXPANDER_BOX_WIDGET (self),
333     GTK_WIDGET (self->scroll));
334 }
335