1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU 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  * GSequencer 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/X/ags_input_listing_editor.h>
21 #include <ags/X/ags_input_listing_editor_callbacks.h>
22 
23 #include <ags/X/ags_connection_editor.h>
24 #include <ags/X/ags_pad_editor.h>
25 #include <ags/X/ags_line_editor.h>
26 #include <ags/X/ags_input_editor.h>
27 
28 void ags_input_listing_editor_class_init(AgsInputListingEditorClass *input_listing_editor);
29 void ags_input_listing_editor_connectable_interface_init(AgsConnectableInterface *connectable);
30 void ags_input_listing_editor_applicable_interface_init(AgsApplicableInterface *applicable);
31 void ags_input_listing_editor_init(AgsInputListingEditor *input_listing_editor);
32 
33 void ags_input_listing_editor_connect(AgsConnectable *connectable);
34 void ags_input_listing_editor_disconnect(AgsConnectable *connectable);
35 
36 void ags_input_listing_editor_set_update(AgsApplicable *applicable, gboolean update);
37 void ags_input_listing_editor_apply(AgsApplicable *applicable);
38 void ags_input_listing_editor_reset(AgsApplicable *applicable);
39 
40 /**
41  * SECTION:ags_input_listing_editor
42  * @short_description: pack input editors
43  * @title: AgsInputListingEditor
44  * @section_id:
45  * @include: ags/X/ags_input_listing_editor.h
46  *
47  * #AgsInputListingEditor is a composite widget to pack #AgsInputEditor.
48  */
49 
50 static gpointer ags_input_listing_editor_parent_class = NULL;
51 static AgsConnectableInterface* ags_input_listing_editor_parent_connectable_interface;
52 
53 GType
ags_input_listing_editor_get_type()54 ags_input_listing_editor_get_type()
55 {
56   static volatile gsize g_define_type_id__volatile = 0;
57 
58   if(g_once_init_enter (&g_define_type_id__volatile)){
59     GType ags_type_input_listing_editor = 0;
60 
61     static const GTypeInfo ags_input_listing_editor_info = {
62       sizeof (AgsInputListingEditorClass),
63       NULL, /* base_init */
64       NULL, /* base_finalize */
65       (GClassInitFunc) ags_input_listing_editor_class_init,
66       NULL, /* class_finalize */
67       NULL, /* class_data */
68       sizeof (AgsInputListingEditor),
69       0,    /* n_preallocs */
70       (GInstanceInitFunc) ags_input_listing_editor_init,
71     };
72 
73     static const GInterfaceInfo ags_connectable_interface_info = {
74       (GInterfaceInitFunc) ags_input_listing_editor_connectable_interface_init,
75       NULL, /* interface_finalize */
76       NULL, /* interface_data */
77     };
78 
79     static const GInterfaceInfo ags_applicable_interface_info = {
80       (GInterfaceInitFunc) ags_input_listing_editor_applicable_interface_init,
81       NULL, /* interface_finalize */
82       NULL, /* interface_data */
83     };
84 
85     ags_type_input_listing_editor = g_type_register_static(AGS_TYPE_PROPERTY_LISTING_EDITOR,
86 							   "AgsInputListingEditor",
87 							   &ags_input_listing_editor_info,
88 							   0);
89 
90     g_type_add_interface_static(ags_type_input_listing_editor,
91 				AGS_TYPE_CONNECTABLE,
92 				&ags_connectable_interface_info);
93 
94     g_type_add_interface_static(ags_type_input_listing_editor,
95 				AGS_TYPE_APPLICABLE,
96 				&ags_applicable_interface_info);
97 
98     g_once_init_leave(&g_define_type_id__volatile, ags_type_input_listing_editor);
99   }
100 
101   return g_define_type_id__volatile;
102 }
103 
104 void
ags_input_listing_editor_class_init(AgsInputListingEditorClass * input_listing_editor)105 ags_input_listing_editor_class_init(AgsInputListingEditorClass *input_listing_editor)
106 {
107   ags_input_listing_editor_parent_class = g_type_class_peek_parent(input_listing_editor);
108 }
109 
110 void
ags_input_listing_editor_connectable_interface_init(AgsConnectableInterface * connectable)111 ags_input_listing_editor_connectable_interface_init(AgsConnectableInterface *connectable)
112 {
113   ags_input_listing_editor_parent_connectable_interface = g_type_interface_peek_parent(connectable);
114 
115   connectable->is_ready = NULL;
116   connectable->is_connected = NULL;
117   connectable->connect = ags_input_listing_editor_connect;
118   connectable->disconnect = ags_input_listing_editor_disconnect;
119 }
120 
121 void
ags_input_listing_editor_applicable_interface_init(AgsApplicableInterface * applicable)122 ags_input_listing_editor_applicable_interface_init(AgsApplicableInterface *applicable)
123 {
124   applicable->set_update = ags_input_listing_editor_set_update;
125   applicable->apply = ags_input_listing_editor_apply;
126   applicable->reset = ags_input_listing_editor_reset;
127 }
128 
129 void
ags_input_listing_editor_init(AgsInputListingEditor * input_listing_editor)130 ags_input_listing_editor_init(AgsInputListingEditor *input_listing_editor)
131 {
132   g_signal_connect_after(G_OBJECT(input_listing_editor), "parent_set",
133 			 G_CALLBACK(ags_input_listing_editor_parent_set_callback), input_listing_editor);
134 
135   input_listing_editor->channel_type = G_TYPE_NONE;
136 
137   input_listing_editor->child = NULL;
138 }
139 
140 void
ags_input_listing_editor_connect(AgsConnectable * connectable)141 ags_input_listing_editor_connect(AgsConnectable *connectable)
142 {
143   AgsConnectionEditor *connection_editor;
144   AgsInputListingEditor *input_listing_editor;
145 
146   GList *pad_editor, *pad_editor_start;
147 
148   input_listing_editor = AGS_INPUT_LISTING_EDITOR(connectable);
149 
150   if((AGS_PROPERTY_EDITOR_CONNECTED & (AGS_PROPERTY_EDITOR(input_listing_editor)->flags)) != 0){
151     return;
152   }
153 
154   ags_input_listing_editor_parent_connectable_interface->connect(connectable);
155 
156   connection_editor = (AgsConnectionEditor *) gtk_widget_get_ancestor(GTK_WIDGET(input_listing_editor),
157 								      AGS_TYPE_CONNECTION_EDITOR);
158 
159   if(connection_editor != NULL &&
160      connection_editor->machine != NULL){
161     g_signal_connect_after(G_OBJECT(connection_editor->machine), "resize-pads",
162 			   G_CALLBACK(ags_input_listing_editor_resize_pads_callback), input_listing_editor);
163   }
164 
165   /* AgsPadEditor */
166   if(input_listing_editor->child != NULL){
167     pad_editor_start =
168       pad_editor = gtk_container_get_children(GTK_CONTAINER(input_listing_editor->child));
169 
170     while(pad_editor != NULL){
171       ags_connectable_connect(AGS_CONNECTABLE(pad_editor->data));
172 
173       pad_editor = pad_editor->next;
174     }
175 
176     g_list_free(pad_editor_start);
177   }
178 }
179 
180 void
ags_input_listing_editor_disconnect(AgsConnectable * connectable)181 ags_input_listing_editor_disconnect(AgsConnectable *connectable)
182 {
183   AgsConnectionEditor *connection_editor;
184   AgsInputListingEditor *input_listing_editor;
185 
186   GList *pad_editor, *pad_editor_start;
187 
188   input_listing_editor = AGS_INPUT_LISTING_EDITOR(connectable);
189 
190   if((AGS_PROPERTY_EDITOR_CONNECTED & (AGS_PROPERTY_EDITOR(input_listing_editor)->flags)) == 0){
191     return;
192   }
193 
194   ags_input_listing_editor_parent_connectable_interface->disconnect(connectable);
195 
196   connection_editor = (AgsConnectionEditor *) gtk_widget_get_ancestor(GTK_WIDGET(input_listing_editor),
197 								      AGS_TYPE_CONNECTION_EDITOR);
198 
199   if(connection_editor != NULL &&
200      connection_editor->machine != NULL){
201     g_object_disconnect(G_OBJECT(connection_editor->machine),
202 			"any_signal::resize-pads",
203 			G_CALLBACK(ags_input_listing_editor_resize_pads_callback),
204 			input_listing_editor,
205 			NULL);
206   }
207 
208   /* AgsPadEditor */
209   if(input_listing_editor->child != NULL){
210     pad_editor_start =
211       pad_editor = gtk_container_get_children(GTK_CONTAINER(input_listing_editor->child));
212 
213     while(pad_editor != NULL){
214       ags_connectable_disconnect(AGS_CONNECTABLE(pad_editor->data));
215 
216       pad_editor = pad_editor->next;
217     }
218 
219     g_list_free(pad_editor_start);
220   }
221 }
222 
223 void
ags_input_listing_editor_set_update(AgsApplicable * applicable,gboolean update)224 ags_input_listing_editor_set_update(AgsApplicable *applicable, gboolean update)
225 {
226   AgsInputListingEditor *input_listing_editor;
227 
228   GList *pad_editor, *pad_editor_start;
229 
230   input_listing_editor = AGS_INPUT_LISTING_EDITOR(applicable);
231 
232   if(input_listing_editor->child != NULL){
233     pad_editor_start =
234       pad_editor = gtk_container_get_children(GTK_CONTAINER(input_listing_editor->child));
235 
236     while(pad_editor != NULL){
237       ags_applicable_set_update(AGS_APPLICABLE(pad_editor->data), update);
238 
239       pad_editor = pad_editor->next;
240     }
241 
242     g_list_free(pad_editor_start);
243   }
244 }
245 
246 void
ags_input_listing_editor_apply(AgsApplicable * applicable)247 ags_input_listing_editor_apply(AgsApplicable *applicable)
248 {
249   AgsInputListingEditor *input_listing_editor;
250 
251   GList *pad_editor, *pad_editor_start;
252 
253   input_listing_editor = AGS_INPUT_LISTING_EDITOR(applicable);
254 
255   if((AGS_PROPERTY_EDITOR_ENABLED & (AGS_PROPERTY_EDITOR(input_listing_editor)->flags)) == 0){
256     return;
257   }
258 
259   if(input_listing_editor->child != NULL){
260     pad_editor_start =
261       pad_editor = gtk_container_get_children(GTK_CONTAINER(input_listing_editor->child));
262 
263     while(pad_editor != NULL){
264       ags_applicable_apply(AGS_APPLICABLE(pad_editor->data));
265 
266       pad_editor = pad_editor->next;
267     }
268 
269     g_list_free(pad_editor_start);
270   }
271 }
272 
273 void
ags_input_listing_editor_reset(AgsApplicable * applicable)274 ags_input_listing_editor_reset(AgsApplicable *applicable)
275 {
276   AgsInputListingEditor *input_listing_editor;
277 
278   GList *pad_editor, *pad_editor_start;
279 
280   input_listing_editor = AGS_INPUT_LISTING_EDITOR(applicable);
281 
282   if(input_listing_editor->child != NULL){
283     pad_editor_start =
284       pad_editor = gtk_container_get_children(GTK_CONTAINER(input_listing_editor->child));
285 
286     while(pad_editor != NULL){
287       ags_applicable_reset(AGS_APPLICABLE(pad_editor->data));
288 
289       pad_editor = pad_editor->next;
290     }
291 
292     g_list_free(pad_editor_start);
293   }
294 }
295 
296 /**
297  * ags_input_listing_editor_add_children:
298  * @input_listing_editor: the #AgsInputListingEditor
299  * @audio: the #AgsAudio to use
300  * @nth: nth channel to start creation until end
301  * @connect: if %TRUE widget is connected and shown
302  *
303  * Creates new pad editors or destroys them.
304  *
305  * Since: 3.0.0
306  */
307 void
ags_input_listing_editor_add_children(AgsInputListingEditor * input_listing_editor,AgsAudio * audio,guint nth,gboolean connect)308 ags_input_listing_editor_add_children(AgsInputListingEditor *input_listing_editor,
309 				      AgsAudio *audio, guint nth,
310 				      gboolean connect)
311 {
312   AgsPadEditor *pad_editor;
313   GtkBox *vbox;
314 
315   AgsChannel *start_channel;
316   AgsChannel *channel, *next_pad, *nth_channel;
317 
318   if(nth == 0 &&
319      input_listing_editor->child != NULL){
320     vbox = input_listing_editor->child;
321     input_listing_editor->child = NULL;
322     gtk_widget_destroy(GTK_WIDGET(vbox));
323   }
324 
325   if(audio == NULL){
326     return;
327   }
328 
329   /* instantiate pad editor vbox */
330   if(nth == 0){
331     input_listing_editor->child = (GtkBox *) gtk_vbox_new(GTK_ORIENTATION_VERTICAL,
332 							  0);
333     gtk_box_pack_start((GtkBox *) input_listing_editor,
334 		       (GtkWidget *) input_listing_editor->child,
335 		       FALSE, FALSE,
336 		       0);
337   }
338 
339   /* get current channel */
340   if(g_type_is_a(input_listing_editor->channel_type, AGS_TYPE_OUTPUT)){
341     g_object_get(audio,
342 		 "output", &start_channel,
343 		 NULL);
344   }else if(g_type_is_a(input_listing_editor->channel_type, AGS_TYPE_INPUT)){
345     g_object_get(audio,
346 		 "input", &start_channel,
347 		 NULL);
348   }else{
349     start_channel = NULL;
350   }
351 
352   nth_channel = ags_channel_nth(start_channel,
353 				nth);
354 
355   channel = nth_channel;
356 
357   next_pad = NULL;
358 
359   while(channel != NULL){
360     /* instantiate pad editor */
361     pad_editor = ags_pad_editor_new(NULL);
362 
363     pad_editor->editor_type_count = 1;
364     pad_editor->editor_type = (GType *) malloc(pad_editor->editor_type_count * sizeof(GType));
365     pad_editor->editor_type[0] = AGS_TYPE_INPUT_EDITOR;
366 
367     g_object_set(pad_editor,
368 		 "channel", channel,
369 		 NULL);
370 
371     gtk_box_pack_start((GtkBox *) input_listing_editor->child,
372 		       (GtkWidget *) pad_editor,
373 		       FALSE, FALSE,
374 		       0);
375 
376     if(connect){
377       ags_connectable_connect(AGS_CONNECTABLE(pad_editor));
378       gtk_widget_show_all(GTK_WIDGET(pad_editor));
379     }
380 
381     /* iterate */
382     next_pad = ags_channel_next_pad(channel);
383 
384     g_object_unref(channel);
385 
386     channel = next_pad;
387   }
388 
389   if(next_pad != NULL){
390     g_object_unref(next_pad);
391   }
392 
393   /* unref */
394   if(start_channel != NULL){
395     g_object_unref(start_channel);
396   }
397 }
398 
399 /**
400  * ags_input_listing_editor_new:
401  * @channel_type: the channel type to represent
402  *
403  * Create a new instance of #AgsInputListingEditor
404  *
405  * Returns: the new #AgsInputListingEditor
406  *
407  * Since: 3.0.0
408  */
409 AgsInputListingEditor*
ags_input_listing_editor_new(GType channel_type)410 ags_input_listing_editor_new(GType channel_type)
411 {
412   AgsInputListingEditor *input_listing_editor;
413 
414   input_listing_editor = (AgsInputListingEditor *) g_object_new(AGS_TYPE_INPUT_LISTING_EDITOR,
415 								NULL);
416 
417   input_listing_editor->channel_type = channel_type;
418 
419   return(input_listing_editor);
420 }
421