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