1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 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_machine_editor.h>
21 #include <ags/X/ags_machine_editor_callbacks.h>
22 
23 #include <ags/X/ags_listing_editor.h>
24 #include <ags/X/ags_property_collection_editor.h>
25 #include <ags/X/ags_link_collection_editor.h>
26 #include <ags/X/ags_resize_editor.h>
27 
28 #include <ags/i18n.h>
29 
30 void ags_machine_editor_class_init(AgsMachineEditorClass *machine_editor);
31 void ags_machine_editor_connectable_interface_init(AgsConnectableInterface *connectable);
32 void ags_machine_editor_applicable_interface_init(AgsApplicableInterface *applicable);
33 void ags_machine_editor_init(AgsMachineEditor *machine_editor);
34 void ags_machine_editor_set_property(GObject *gobject,
35 				     guint prop_id,
36 				     const GValue *value,
37 				     GParamSpec *param_spec);
38 void ags_machine_editor_get_property(GObject *gobject,
39 				     guint prop_id,
40 				     GValue *value,
41 				     GParamSpec *param_spec);
42 
43 void ags_machine_editor_connect(AgsConnectable *connectable);
44 void ags_machine_editor_disconnect(AgsConnectable *connectable);
45 
46 void ags_machine_editor_set_update(AgsApplicable *applicable, gboolean update);
47 void ags_machine_editor_apply(AgsApplicable *applicable);
48 void ags_machine_editor_reset(AgsApplicable *applicable);
49 
50 void ags_machine_editor_real_set_machine(AgsMachineEditor *machine_editor,
51 					 AgsMachine *machine);
52 
53 /**
54  * SECTION:ags_machine_editor
55  * @short_description: Edit audio related aspects
56  * @title: AgsMachineEditor
57  * @section_id:
58  * @include: ags/X/ags_machine_editor.h
59  *
60  * #AgsMachineEditor is a composite widget to edit all aspects of #AgsAudio.
61  * It consists of multiple child editors.
62  */
63 
64 enum{
65   SET_MACHINE,
66   LAST_SIGNAL,
67 };
68 
69 enum{
70   PROP_0,
71   PROP_MACHINE,
72 };
73 
74 static guint machine_editor_signals[LAST_SIGNAL];
75 
76 GType
ags_machine_editor_get_type(void)77 ags_machine_editor_get_type(void)
78 {
79   static volatile gsize g_define_type_id__volatile = 0;
80 
81   if(g_once_init_enter (&g_define_type_id__volatile)){
82     GType ags_type_machine_editor = 0;
83 
84     static const GTypeInfo ags_machine_editor_info = {
85       sizeof (AgsMachineEditorClass),
86       NULL, /* base_init */
87       NULL, /* base_finalize */
88       (GClassInitFunc) ags_machine_editor_class_init,
89       NULL, /* class_finalize */
90       NULL, /* class_data */
91       sizeof (AgsMachineEditor),
92       0,    /* n_preallocs */
93       (GInstanceInitFunc) ags_machine_editor_init,
94     };
95 
96     static const GInterfaceInfo ags_connectable_interface_info = {
97       (GInterfaceInitFunc) ags_machine_editor_connectable_interface_init,
98       NULL, /* interface_finalize */
99       NULL, /* interface_data */
100     };
101 
102     static const GInterfaceInfo ags_applicable_interface_info = {
103       (GInterfaceInitFunc) ags_machine_editor_applicable_interface_init,
104       NULL, /* interface_finalize */
105       NULL, /* interface_data */
106     };
107 
108     ags_type_machine_editor = g_type_register_static(GTK_TYPE_DIALOG,
109 						     "AgsMachineEditor", &ags_machine_editor_info,
110 						     0);
111 
112     g_type_add_interface_static(ags_type_machine_editor,
113 				AGS_TYPE_CONNECTABLE,
114 				&ags_connectable_interface_info);
115 
116     g_type_add_interface_static(ags_type_machine_editor,
117 				AGS_TYPE_APPLICABLE,
118 				&ags_applicable_interface_info);
119 
120     g_once_init_leave(&g_define_type_id__volatile, ags_type_machine_editor);
121   }
122 
123   return g_define_type_id__volatile;
124 }
125 
126 void
ags_machine_editor_class_init(AgsMachineEditorClass * machine_editor)127 ags_machine_editor_class_init(AgsMachineEditorClass *machine_editor)
128 {
129   GObjectClass *gobject;
130   GParamSpec *param_spec;
131 
132   /* GObjectClass */
133   gobject = (GObjectClass *) machine_editor;
134 
135   gobject->set_property = ags_machine_editor_set_property;
136   gobject->get_property = ags_machine_editor_get_property;
137 
138   /* properties */
139   /**
140    * AgsMachineEditor:machine:
141    *
142    * The #AgsMachine to edit.
143    *
144    * Since: 3.0.0
145    */
146   param_spec = g_param_spec_object("machine",
147 				   i18n_pspec("assigned machine"),
148 				   i18n_pspec("The machine which this machine editor is assigned with"),
149 				   AGS_TYPE_MACHINE,
150 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
151   g_object_class_install_property(gobject,
152 				  PROP_MACHINE,
153 				  param_spec);
154 
155   /* AgsMachineEditorClass */
156   machine_editor->set_machine = ags_machine_editor_real_set_machine;
157 
158   /* signals */
159   /**
160    * AgsMachineEditor::set-machine:
161    * @machine_editor: the #AgsMachineEditor
162    * @machine: the #AgsMachine to set
163    *
164    * The ::set-machine notify about modified machine.
165    *
166    * Since: 3.0.0
167    */
168   machine_editor_signals[SET_MACHINE] =
169     g_signal_new("set-machine",
170 		 G_TYPE_FROM_CLASS (machine_editor),
171 		 G_SIGNAL_RUN_LAST,
172 		 G_STRUCT_OFFSET (AgsMachineEditorClass, set_machine),
173 		 NULL, NULL,
174 		 g_cclosure_marshal_VOID__OBJECT,
175 		 G_TYPE_NONE, 1,
176 		 G_TYPE_OBJECT);
177 }
178 
179 void
ags_machine_editor_connectable_interface_init(AgsConnectableInterface * connectable)180 ags_machine_editor_connectable_interface_init(AgsConnectableInterface *connectable)
181 {
182   connectable->is_ready = NULL;
183   connectable->is_connected = NULL;
184   connectable->connect = ags_machine_editor_connect;
185   connectable->disconnect = ags_machine_editor_disconnect;
186 }
187 
188 void
ags_machine_editor_applicable_interface_init(AgsApplicableInterface * applicable)189 ags_machine_editor_applicable_interface_init(AgsApplicableInterface *applicable)
190 {
191   applicable->set_update = ags_machine_editor_set_update;
192   applicable->apply = ags_machine_editor_apply;
193   applicable->reset = ags_machine_editor_reset;
194 }
195 
196 void
ags_machine_editor_init(AgsMachineEditor * machine_editor)197 ags_machine_editor_init(AgsMachineEditor *machine_editor)
198 {
199   GtkNotebook *notebook;
200   GtkScrolledWindow *scrolled_window;
201 
202   gtk_window_set_title((GtkWindow *) machine_editor,
203 		       i18n("properties"));
204 
205   machine_editor->flags = 0;
206 
207   machine_editor->version = AGS_MACHINE_EDITOR_DEFAULT_VERSION;
208   machine_editor->build_id = AGS_MACHINE_EDITOR_DEFAULT_BUILD_ID;
209 
210   machine_editor->machine = NULL;
211 
212   machine_editor->notebook =
213     notebook = (GtkNotebook *) gtk_notebook_new();
214   gtk_box_pack_start((GtkBox *) gtk_dialog_get_content_area((GtkDialog *) machine_editor),
215 		     (GtkWidget *) notebook,
216 		     TRUE, TRUE,
217 		     0);
218 
219   /* AgsOutput */
220   machine_editor->output_scrolled_window =
221     scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
222   gtk_notebook_append_page(notebook,
223 			   (GtkWidget *) scrolled_window,
224 			   (GtkWidget *) gtk_label_new(i18n("output")));
225 
226   /* AgsInput */
227   machine_editor->input_scrolled_window =
228     scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
229   gtk_notebook_append_page(notebook,
230 			   (GtkWidget *) scrolled_window,
231 			   (GtkWidget *) gtk_label_new(i18n("input")));
232 
233 
234   /* AgsOutput link editor */
235   machine_editor->output_link_editor_scrolled_window =
236     scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
237   gtk_notebook_append_page(notebook,
238 			   (GtkWidget *) scrolled_window,
239 			   (GtkWidget *) gtk_label_new(i18n("link output")));
240 
241   /* AgsInput link editor */
242   machine_editor->input_link_editor_scrolled_window =
243     scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
244   gtk_notebook_append_page(notebook,
245 			   (GtkWidget *) scrolled_window,
246 			   (GtkWidget *) gtk_label_new(i18n("link input")));
247 
248   /* resize editor */
249   machine_editor->resize_editor_scrolled_window =
250     scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
251   gtk_notebook_append_page(notebook, (GtkWidget *) scrolled_window,
252 			   (GtkWidget *) gtk_label_new(i18n("resize channels")));
253 
254   /* GtkButton's in GtkDialog->action_area  */
255   machine_editor->apply = (GtkButton *) gtk_button_new_with_mnemonic(i18n("_Apply"));
256   gtk_dialog_add_action_widget((GtkDialog *) machine_editor,
257 			       (GtkWidget *) machine_editor->apply,
258 			       GTK_RESPONSE_NONE);
259 
260   machine_editor->ok = (GtkButton *) gtk_button_new_with_mnemonic(i18n("_OK"));
261   gtk_dialog_add_action_widget((GtkDialog *) machine_editor,
262 			       (GtkWidget *) machine_editor->ok,
263 			       GTK_RESPONSE_NONE);
264 
265   machine_editor->cancel = (GtkButton *) gtk_button_new_with_mnemonic("_Cancel");
266   gtk_dialog_add_action_widget((GtkDialog *) machine_editor,
267 			       (GtkWidget *) machine_editor->cancel,
268 			       GTK_RESPONSE_NONE);
269 }
270 
271 void
ags_machine_editor_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)272 ags_machine_editor_set_property(GObject *gobject,
273 				guint prop_id,
274 				const GValue *value,
275 				GParamSpec *param_spec)
276 {
277   AgsMachineEditor *machine_editor;
278 
279   machine_editor = AGS_MACHINE_EDITOR(gobject);
280 
281   switch(prop_id){
282   case PROP_MACHINE:
283   {
284     AgsMachine *machine;
285 
286     machine = (AgsMachine *) g_value_get_object(value);
287 
288     ags_machine_editor_set_machine(machine_editor, machine);
289   }
290   break;
291   default:
292     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
293     break;
294   }
295 }
296 
297 void
ags_machine_editor_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)298 ags_machine_editor_get_property(GObject *gobject,
299 				guint prop_id,
300 				GValue *value,
301 				GParamSpec *param_spec)
302 {
303   AgsMachineEditor *machine_editor;
304 
305   machine_editor = AGS_MACHINE_EDITOR(gobject);
306 
307   switch(prop_id){
308   case PROP_MACHINE:
309     g_value_set_object(value, machine_editor->machine);
310     break;
311   default:
312     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
313     break;
314   }
315 }
316 
317 void
ags_machine_editor_connect(AgsConnectable * connectable)318 ags_machine_editor_connect(AgsConnectable *connectable)
319 {
320   AgsMachineEditor *machine_editor;
321 
322   machine_editor = AGS_MACHINE_EDITOR(connectable);
323 
324   if((AGS_MACHINE_EDITOR_CONNECTED & (machine_editor->flags)) != 0){
325     return;
326   }
327 
328   machine_editor->flags |= AGS_MACHINE_EDITOR_CONNECTED;
329 
330   /* AgsMachineEditor tabs */
331   ags_connectable_connect(AGS_CONNECTABLE(machine_editor->output_editor));
332   ags_connectable_connect(AGS_CONNECTABLE(machine_editor->input_editor));
333 
334   ags_connectable_connect(AGS_CONNECTABLE(machine_editor->output_link_editor));
335   ags_connectable_connect(AGS_CONNECTABLE(machine_editor->input_link_editor));
336 
337   ags_connectable_connect(AGS_CONNECTABLE(machine_editor->resize_editor));
338 
339   /* AgsMachineEditor buttons */
340   g_signal_connect((GObject *) machine_editor->apply, "clicked",
341 		   G_CALLBACK(ags_machine_editor_apply_callback), (gpointer) machine_editor);
342 
343   g_signal_connect((GObject *) machine_editor->ok, "clicked",
344 		   G_CALLBACK(ags_machine_editor_ok_callback), (gpointer) machine_editor);
345 
346   g_signal_connect((GObject *) machine_editor->cancel, "clicked",
347 		   G_CALLBACK(ags_machine_editor_cancel_callback), (gpointer) machine_editor);
348 }
349 
350 void
ags_machine_editor_disconnect(AgsConnectable * connectable)351 ags_machine_editor_disconnect(AgsConnectable *connectable)
352 {
353   AgsMachineEditor *machine_editor;
354 
355   machine_editor = AGS_MACHINE_EDITOR(connectable);
356 
357   if((AGS_MACHINE_EDITOR_CONNECTED & (machine_editor->flags)) == 0){
358     return;
359   }
360 
361   machine_editor->flags &= (~AGS_MACHINE_EDITOR_CONNECTED);
362 
363   /* AgsMachineEditor tabs */
364   ags_connectable_disconnect(AGS_CONNECTABLE(machine_editor->output_editor));
365   ags_connectable_disconnect(AGS_CONNECTABLE(machine_editor->input_editor));
366 
367   ags_connectable_disconnect(AGS_CONNECTABLE(machine_editor->output_link_editor));
368   ags_connectable_disconnect(AGS_CONNECTABLE(machine_editor->input_link_editor));
369 
370   ags_connectable_disconnect(AGS_CONNECTABLE(machine_editor->resize_editor));
371 }
372 
373 void
ags_machine_editor_set_update(AgsApplicable * applicable,gboolean update)374 ags_machine_editor_set_update(AgsApplicable *applicable, gboolean update)
375 {
376   AgsMachineEditor *machine_editor;
377 
378   machine_editor = AGS_MACHINE_EDITOR(applicable);
379 
380   ags_applicable_set_update(AGS_APPLICABLE(machine_editor->output_editor), update);
381   ags_applicable_set_update(AGS_APPLICABLE(machine_editor->input_editor), update);
382 
383   ags_applicable_set_update(AGS_APPLICABLE(machine_editor->output_link_editor), update);
384   ags_applicable_set_update(AGS_APPLICABLE(machine_editor->input_link_editor), update);
385 
386   ags_applicable_set_update(AGS_APPLICABLE(machine_editor->resize_editor), update);
387 }
388 
389 void
ags_machine_editor_apply(AgsApplicable * applicable)390 ags_machine_editor_apply(AgsApplicable *applicable)
391 {
392   AgsMachineEditor *machine_editor;
393 
394   machine_editor = AGS_MACHINE_EDITOR(applicable);
395 
396   ags_applicable_apply(AGS_APPLICABLE(machine_editor->output_editor));
397   ags_applicable_apply(AGS_APPLICABLE(machine_editor->input_editor));
398 
399   ags_applicable_apply(AGS_APPLICABLE(machine_editor->output_link_editor));
400   ags_applicable_apply(AGS_APPLICABLE(machine_editor->input_link_editor));
401 
402   ags_applicable_apply(AGS_APPLICABLE(machine_editor->resize_editor));
403 }
404 
405 void
ags_machine_editor_reset(AgsApplicable * applicable)406 ags_machine_editor_reset(AgsApplicable *applicable)
407 {
408   AgsMachineEditor *machine_editor;
409 
410   machine_editor = AGS_MACHINE_EDITOR(applicable);
411 
412   ags_applicable_reset(AGS_APPLICABLE(machine_editor->output_editor));
413   ags_applicable_reset(AGS_APPLICABLE(machine_editor->input_editor));
414 
415   ags_applicable_reset(AGS_APPLICABLE(machine_editor->output_link_editor));
416   ags_applicable_reset(AGS_APPLICABLE(machine_editor->input_link_editor));
417 
418   ags_applicable_reset(AGS_APPLICABLE(machine_editor->resize_editor));
419 }
420 
421 /**
422  * ags_machine_editor_add_children:
423  * @machine_editor: the #AgsMachineEditor
424  *
425  * Add all child editors.
426  *
427  * Since: 3.0.0
428  */
429 void
ags_machine_editor_add_children(AgsMachineEditor * machine_editor)430 ags_machine_editor_add_children(AgsMachineEditor *machine_editor)
431 {
432   gchar **output_link_editor_child_strv;
433   gchar **input_link_editor_child_strv;
434 
435   GValue *output_link_editor_child_value;
436   GValue *input_link_editor_child_value;
437 
438   /* output */
439   output_link_editor_child_strv = (gchar **) g_malloc(2 * sizeof(gchar *));
440 
441   output_link_editor_child_strv[0] = g_strdup("channel-type");
442   output_link_editor_child_strv[1] = NULL;
443 
444   output_link_editor_child_value = g_new0(GValue,
445 					  1);
446 
447   g_value_init(output_link_editor_child_value, G_TYPE_GTYPE);
448   g_value_set_gtype(output_link_editor_child_value,
449 		    AGS_TYPE_OUTPUT);
450 
451   /* input */
452   input_link_editor_child_strv = (gchar **) g_malloc(2 * sizeof(gchar *));
453 
454   input_link_editor_child_strv[0] = g_strdup("channel-type");
455   input_link_editor_child_strv[1] = NULL;
456 
457   input_link_editor_child_value = g_new0(GValue,
458 					 1);
459 
460   g_value_init(input_link_editor_child_value, G_TYPE_GTYPE);
461   g_value_set_gtype(input_link_editor_child_value,
462 		    AGS_TYPE_INPUT);
463 
464   /* AgsOutput */
465   machine_editor->output_editor = ags_listing_editor_new(AGS_TYPE_OUTPUT);
466   gtk_container_add((GtkContainer *) machine_editor->output_scrolled_window,
467 		    (GtkWidget *) machine_editor->output_editor);
468 
469   ags_listing_editor_add_children(machine_editor->output_editor,
470 				  machine_editor->machine->audio, 0,
471 				  FALSE);
472 
473   /* AgsInput */
474   machine_editor->input_editor = ags_listing_editor_new(AGS_TYPE_INPUT);
475   gtk_container_add((GtkContainer *) machine_editor->input_scrolled_window,
476 		    (GtkWidget *) machine_editor->input_editor);
477 
478   ags_listing_editor_add_children(machine_editor->input_editor,
479 				  machine_editor->machine->audio, 0,
480 				  FALSE);
481 
482   /* AgsOutput link editor */
483   machine_editor->output_link_editor = ags_property_collection_editor_new(AGS_TYPE_LINK_COLLECTION_EDITOR,
484 									  output_link_editor_child_strv,
485 									  output_link_editor_child_value);
486   gtk_container_add((GtkContainer *) machine_editor->output_link_editor_scrolled_window,
487 		    (GtkWidget *) machine_editor->output_link_editor);
488 
489   /* AgsInput link editor */
490   machine_editor->input_link_editor = ags_property_collection_editor_new(AGS_TYPE_LINK_COLLECTION_EDITOR,
491 									 input_link_editor_child_strv,
492 									 input_link_editor_child_value);
493   gtk_container_add((GtkContainer *) machine_editor->input_link_editor_scrolled_window,
494 		    (GtkWidget *) machine_editor->input_link_editor);
495 
496   /* resize editor */
497   machine_editor->resize_editor = ags_resize_editor_new();
498   gtk_container_add((GtkContainer *) machine_editor->resize_editor_scrolled_window,
499 		    (GtkWidget *) machine_editor->resize_editor);
500 }
501 
502 void
ags_machine_editor_real_set_machine(AgsMachineEditor * machine_editor,AgsMachine * machine)503 ags_machine_editor_real_set_machine(AgsMachineEditor *machine_editor, AgsMachine *machine)
504 {
505   if(machine_editor->machine != NULL){
506     gtk_widget_destroy(GTK_WIDGET(machine_editor->output_editor));
507     gtk_widget_destroy(GTK_WIDGET(machine_editor->input_editor));
508     gtk_widget_destroy(GTK_WIDGET(machine_editor->output_link_editor));
509     gtk_widget_destroy(GTK_WIDGET(machine_editor->input_link_editor));
510     gtk_widget_destroy(GTK_WIDGET(machine_editor->resize_editor));
511   }
512 
513   machine_editor->machine = machine;
514 
515   if(machine != NULL){
516     ags_machine_editor_add_children(machine_editor);
517   }
518 }
519 
520 /**
521  * ags_machine_editor_set_machine:
522  * @machine_editor: an #AgsMachineEditor
523  * @machine: the new #AgsMachine
524  *
525  * Is emitted as machine gets modified.
526  *
527  * Since: 3.0.0
528  */
529 void
ags_machine_editor_set_machine(AgsMachineEditor * machine_editor,AgsMachine * machine)530 ags_machine_editor_set_machine(AgsMachineEditor *machine_editor, AgsMachine *machine)
531 {
532   g_return_if_fail(AGS_IS_MACHINE_EDITOR(machine_editor));
533 
534   g_object_ref((GObject *) machine_editor);
535   g_signal_emit(G_OBJECT(machine_editor),
536 		machine_editor_signals[SET_MACHINE], 0,
537 		machine);
538   g_object_unref((GObject *) machine_editor);
539 }
540 
541 /**
542  * ags_machine_editor_new:
543  * @machine: the assigned machine.
544  *
545  * Creates an #AgsMachineEditor
546  *
547  * Returns: a new #AgsMachineEditor
548  *
549  * Since: 3.0.0
550  */
551 AgsMachineEditor*
ags_machine_editor_new(AgsMachine * machine)552 ags_machine_editor_new(AgsMachine *machine)
553 {
554   AgsMachineEditor *machine_editor;
555 
556   machine_editor = (AgsMachineEditor *) g_object_new(AGS_TYPE_MACHINE_EDITOR,
557 						     "machine", machine,
558 						     NULL);
559 
560   return(machine_editor);
561 }
562