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_composite_editor.h>
21 #include <ags/X/ags_composite_editor_callbacks.h>
22 
23 #include <libxml/tree.h>
24 #include <libxml/xpath.h>
25 
26 #include <ags/i18n.h>
27 
28 void ags_composite_editor_class_init(AgsCompositeEditorClass *composite_editor);
29 void ags_composite_editor_connectable_interface_init(AgsConnectableInterface *connectable);
30 void ags_composite_editor_init(AgsCompositeEditor *composite_editor);
31 
32 AgsUUID* ags_composite_editor_get_uuid(AgsConnectable *connectable);
33 gboolean ags_composite_editor_has_resource(AgsConnectable *connectable);
34 gboolean ags_composite_editor_is_ready(AgsConnectable *connectable);
35 void ags_composite_editor_add_to_registry(AgsConnectable *connectable);
36 void ags_composite_editor_remove_from_registry(AgsConnectable *connectable);
37 xmlNode* ags_composite_editor_list_resource(AgsConnectable *connectable);
38 xmlNode* ags_composite_editor_xml_compose(AgsConnectable *connectable);
39 void ags_composite_editor_xml_parse(AgsConnectable *connectable,
40 				    xmlNode *node);
41 gboolean ags_composite_editor_is_connected(AgsConnectable *connectable);
42 void ags_composite_editor_connect(AgsConnectable *connectable);
43 void ags_composite_editor_disconnect(AgsConnectable *connectable);
44 
45 void ags_composite_editor_real_machine_changed(AgsCompositeEditor *composite_editor,
46 					       AgsMachine *machine);
47 
48 enum{
49   MACHINE_CHANGED,
50   LAST_SIGNAL,
51 };
52 
53 static gpointer ags_composite_editor_parent_class = NULL;
54 static guint composite_editor_signals[LAST_SIGNAL];
55 
56 /**
57  * SECTION:ags_composite_editor
58  * @short_description: composite editor
59  * @title: AgsCompositeEditor
60  * @section_id:
61  * @include: ags/X/ags_composite_editor.h
62  *
63  * The #AgsCompositeEditor is a composite abstraction of edit implementation.
64  */
65 
66 GType
ags_composite_editor_get_type(void)67 ags_composite_editor_get_type(void)
68 {
69   static volatile gsize g_define_type_id__volatile = 0;
70 
71   if(g_once_init_enter (&g_define_type_id__volatile)){
72     GType ags_type_composite_editor = 0;
73 
74     static const GTypeInfo ags_composite_editor_info = {
75       sizeof (AgsCompositeEditorClass),
76       NULL, /* base_init */
77       NULL, /* base_finalize */
78       (GClassInitFunc) ags_composite_editor_class_init,
79       NULL, /* class_finalize */
80       NULL, /* class_data */
81       sizeof (AgsCompositeEditor),
82       0,    /* n_preallocs */
83       (GInstanceInitFunc) ags_composite_editor_init,
84     };
85 
86     static const GInterfaceInfo ags_connectable_interface_info = {
87       (GInterfaceInitFunc) ags_composite_editor_connectable_interface_init,
88       NULL, /* interface_finalize */
89       NULL, /* interface_data */
90     };
91 
92     ags_type_composite_editor = g_type_register_static(GTK_TYPE_BOX,
93 						       "AgsCompositeEditor", &ags_composite_editor_info,
94 						       0);
95 
96     g_type_add_interface_static(ags_type_composite_editor,
97 				AGS_TYPE_CONNECTABLE,
98 				&ags_connectable_interface_info);
99 
100     g_once_init_leave(&g_define_type_id__volatile, ags_type_composite_editor);
101   }
102 
103   return g_define_type_id__volatile;
104 }
105 
106 void
ags_composite_editor_class_init(AgsCompositeEditorClass * composite_editor)107 ags_composite_editor_class_init(AgsCompositeEditorClass *composite_editor)
108 {
109   ags_composite_editor_parent_class = g_type_class_peek_parent(composite_editor);
110 
111   /* AgsCompositeEditorClass */
112   composite_editor->machine_changed = ags_composite_editor_real_machine_changed;
113 
114   /* signals */
115   /**
116    * AgsCompositeEditor::machine-changed:
117    * @editor: the object to change machine.
118    * @machine: the #AgsMachine to set
119    *
120    * The ::machine-changed signal notifies about changed machine.
121    *
122    * Since: 3.8.0
123    */
124   composite_editor_signals[MACHINE_CHANGED] =
125     g_signal_new("machine-changed",
126                  G_TYPE_FROM_CLASS(composite_editor),
127                  G_SIGNAL_RUN_LAST,
128 		 G_STRUCT_OFFSET(AgsCompositeEditorClass, machine_changed),
129                  NULL, NULL,
130                  g_cclosure_marshal_VOID__OBJECT,
131                  G_TYPE_NONE, 1,
132 		 G_TYPE_OBJECT);
133 }
134 
135 void
ags_composite_editor_connectable_interface_init(AgsConnectableInterface * connectable)136 ags_composite_editor_connectable_interface_init(AgsConnectableInterface *connectable)
137 {
138   connectable->get_uuid = ags_composite_editor_get_uuid;
139   connectable->has_resource = ags_composite_editor_has_resource;
140 
141   connectable->is_ready = ags_composite_editor_is_ready;
142   connectable->add_to_registry = ags_composite_editor_add_to_registry;
143   connectable->remove_from_registry = ags_composite_editor_remove_from_registry;
144 
145   connectable->list_resource = ags_composite_editor_list_resource;
146   connectable->xml_compose = ags_composite_editor_xml_compose;
147   connectable->xml_parse = ags_composite_editor_xml_parse;
148 
149   connectable->is_connected = ags_composite_editor_is_connected;
150   connectable->connect = ags_composite_editor_connect;
151   connectable->disconnect = ags_composite_editor_disconnect;
152 
153   connectable->connect_connection = NULL;
154   connectable->disconnect_connection = NULL;
155 }
156 
157 void
ags_composite_editor_init(AgsCompositeEditor * composite_editor)158 ags_composite_editor_init(AgsCompositeEditor *composite_editor)
159 {
160   GtkViewport *viewport;
161   GtkScrolledWindow *scrolled_window;
162 
163   gtk_orientable_set_orientation(GTK_ORIENTABLE(composite_editor),
164 				 GTK_ORIENTATION_VERTICAL);
165 
166   composite_editor->flags = 0;
167   composite_editor->edit = 0;
168 
169   composite_editor->version = g_strdup(AGS_COMPOSITE_EDITOR_DEFAULT_VERSION);
170   composite_editor->build_id = g_strdup(AGS_COMPOSITE_EDITOR_DEFAULT_BUILD_ID);
171 
172   /* uuid */
173   composite_editor->uuid = ags_uuid_alloc();
174   ags_uuid_generate(composite_editor->uuid);
175 
176   /* widgets */
177   composite_editor->toolbar = ags_composite_toolbar_new();
178   gtk_box_pack_start((GtkBox *) composite_editor,
179 		     (GtkWidget *) composite_editor->toolbar,
180 		     FALSE, FALSE,
181 		     0);
182 
183   /* paned */
184   composite_editor->paned = (GtkPaned *) gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
185   gtk_box_pack_start((GtkBox *) composite_editor,
186 		     (GtkWidget *) composite_editor->paned,
187 		     FALSE, FALSE,
188 		     0);
189 
190   /* machine selector */
191   viewport = (GtkViewport *) gtk_viewport_new(NULL,
192 					      NULL);
193   g_object_set(viewport,
194 	       "shadow-type", GTK_SHADOW_NONE,
195 	       NULL);
196   gtk_paned_pack1((GtkPaned *) composite_editor->paned,
197 		  (GtkWidget *) viewport,
198 		  FALSE, TRUE);
199 
200   scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
201   gtk_container_add(GTK_CONTAINER(viewport),
202 		    GTK_WIDGET(scrolled_window));
203 
204   composite_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
205 						    "homogeneous", FALSE,
206 						    "spacing", 0,
207 						    NULL);
208   gtk_label_set_label(composite_editor->machine_selector->label,
209 		      i18n("composite selector"));
210 
211   composite_editor->machine_selector->popup = ags_machine_selector_popup_new(composite_editor->machine_selector);
212   g_object_set(composite_editor->machine_selector->menu_button,
213 	       "menu", composite_editor->machine_selector->popup,
214 	       NULL);
215 
216   gtk_container_add((GtkContainer *) scrolled_window,
217 		    (GtkWidget *) composite_editor->machine_selector);
218 }
219 
220 AgsUUID*
ags_composite_editor_get_uuid(AgsConnectable * connectable)221 ags_composite_editor_get_uuid(AgsConnectable *connectable)
222 {
223   AgsCompositeEditor *composite_editor;
224 
225   AgsUUID *ptr;
226 
227   composite_editor = AGS_COMPOSITE_EDITOR(connectable);
228 
229   ptr = composite_editor->uuid;
230 
231   return(ptr);
232 }
233 
234 gboolean
ags_composite_editor_has_resource(AgsConnectable * connectable)235 ags_composite_editor_has_resource(AgsConnectable *connectable)
236 {
237   return(FALSE);
238 }
239 
240 gboolean
ags_composite_editor_is_ready(AgsConnectable * connectable)241 ags_composite_editor_is_ready(AgsConnectable *connectable)
242 {
243   AgsCompositeEditor *composite_editor;
244 
245   gboolean is_ready;
246 
247   composite_editor = AGS_COMPOSITE_EDITOR(connectable);
248 
249   /* check is added */
250   is_ready = ags_composite_editor_test_flags(composite_editor, AGS_COMPOSITE_EDITOR_ADDED_TO_REGISTRY);
251 
252   return(is_ready);
253 }
254 
255 void
ags_composite_editor_add_to_registry(AgsConnectable * connectable)256 ags_composite_editor_add_to_registry(AgsConnectable *connectable)
257 {
258   AgsCompositeEditor *composite_editor;
259 
260   AgsRegistry *registry;
261   AgsRegistryEntry *entry;
262 
263   AgsApplicationContext *application_context;
264 
265   if(ags_connectable_is_ready(connectable)){
266     return;
267   }
268 
269   composite_editor = AGS_COMPOSITE_EDITOR(connectable);
270 
271   ags_composite_editor_set_flags(composite_editor, AGS_COMPOSITE_EDITOR_ADDED_TO_REGISTRY);
272 
273   application_context = ags_application_context_get_instance();
274 
275   registry = (AgsRegistry *) ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
276 
277   if(registry != NULL){
278     entry = ags_registry_entry_alloc(registry);
279 
280     entry->id = composite_editor->uuid;
281     g_value_set_object(entry->entry,
282 		       (gpointer) composite_editor);
283 
284     ags_registry_add_entry(registry,
285 			   entry);
286   }
287 }
288 
289 void
ags_composite_editor_remove_from_registry(AgsConnectable * connectable)290 ags_composite_editor_remove_from_registry(AgsConnectable *connectable)
291 {
292   if(!ags_connectable_is_ready(connectable)){
293     return;
294   }
295 
296   //TODO:JK: implement me
297 }
298 
299 xmlNode*
ags_composite_editor_list_resource(AgsConnectable * connectable)300 ags_composite_editor_list_resource(AgsConnectable *connectable)
301 {
302   xmlNode *node;
303 
304   node = NULL;
305 
306   //TODO:JK: implement me
307 
308   return(node);
309 }
310 
311 xmlNode*
ags_composite_editor_xml_compose(AgsConnectable * connectable)312 ags_composite_editor_xml_compose(AgsConnectable *connectable)
313 {
314   xmlNode *node;
315 
316   node = NULL;
317 
318   //TODO:JK: implement me
319 
320   return(node);
321 }
322 
323 void
ags_composite_editor_xml_parse(AgsConnectable * connectable,xmlNode * node)324 ags_composite_editor_xml_parse(AgsConnectable *connectable,
325 			       xmlNode *node)
326 {
327   //TODO:JK: implement me
328 }
329 
330 gboolean
ags_composite_editor_is_connected(AgsConnectable * connectable)331 ags_composite_editor_is_connected(AgsConnectable *connectable)
332 {
333   AgsCompositeEditor *composite_editor;
334 
335   gboolean is_connected;
336 
337   composite_editor = AGS_COMPOSITE_EDITOR(connectable);
338 
339   /* check is connected */
340   is_connected = ags_composite_editor_test_flags(composite_editor, AGS_COMPOSITE_EDITOR_CONNECTED);
341 
342   return(is_connected);
343 }
344 
345 void
ags_composite_editor_connect(AgsConnectable * connectable)346 ags_composite_editor_connect(AgsConnectable *connectable)
347 {
348   AgsCompositeEditor *composite_editor;
349 
350   composite_editor = AGS_COMPOSITE_EDITOR(connectable);
351 
352   if((AGS_COMPOSITE_EDITOR_CONNECTED & (composite_editor->flags)) != 0){
353     return;
354   }
355 
356   composite_editor->flags |= AGS_COMPOSITE_EDITOR_CONNECTED;
357 
358   //TODO:JK: implement me
359 }
360 
361 void
ags_composite_editor_disconnect(AgsConnectable * connectable)362 ags_composite_editor_disconnect(AgsConnectable *connectable)
363 {
364   AgsCompositeEditor *composite_editor;
365 
366   composite_editor = AGS_COMPOSITE_EDITOR(connectable);
367 
368   if((AGS_COMPOSITE_EDITOR_CONNECTED & (composite_editor->flags)) == 0){
369     return;
370   }
371 
372   composite_editor->flags &= (~AGS_COMPOSITE_EDITOR_CONNECTED);
373 
374   //TODO:JK: implement me
375 }
376 
377 /**
378  * ags_composite_editor_test_flags:
379  * @composite_editor: the #AgsCompositeEditor
380  * @flags: the flags
381  *
382  * Test @flags to be set on @composite_editor.
383  *
384  * Returns: %TRUE if flags are set, else %FALSE
385  *
386  * Since: 3.8.0
387  */
388 gboolean
ags_composite_editor_test_flags(AgsCompositeEditor * composite_editor,guint flags)389 ags_composite_editor_test_flags(AgsCompositeEditor *composite_editor, guint flags)
390 {
391   gboolean retval;
392 
393   if(!AGS_IS_COMPOSITE_EDITOR(composite_editor)){
394     return(FALSE);
395   }
396 
397   /* test */
398   retval = (flags & (composite_editor->flags)) ? TRUE: FALSE;
399 
400   return(retval);
401 }
402 
403 /**
404  * ags_composite_editor_set_flags:
405  * @composite_editor: the #AgsCompositeEditor
406  * @flags: see enum AgsCompositeEditorFlags
407  *
408  * Enable a feature of #AgsCompositeEditor.
409  *
410  * Since: 3.8.0
411  */
412 void
ags_composite_editor_set_flags(AgsCompositeEditor * composite_editor,guint flags)413 ags_composite_editor_set_flags(AgsCompositeEditor *composite_editor, guint flags)
414 {
415   if(!AGS_IS_COMPOSITE_EDITOR(composite_editor)){
416     return;
417   }
418 
419   /* set flags */
420   composite_editor->flags |= flags;
421 }
422 
423 /**
424  * ags_composite_editor_unset_flags:
425  * @composite_editor: the #AgsCompositeEditor
426  * @flags: see enum AgsCompositeEditorFlags
427  *
428  * Disable a feature of AgsCompositeEditor.
429  *
430  * Since: 3.8.0
431  */
432 void
ags_composite_editor_unset_flags(AgsCompositeEditor * composite_editor,guint flags)433 ags_composite_editor_unset_flags(AgsCompositeEditor *composite_editor, guint flags)
434 {
435   if(!AGS_IS_COMPOSITE_EDITOR(composite_editor)){
436     return;
437   }
438 
439   /* unset flags */
440   composite_editor->flags &= (~flags);
441 }
442 
443 void
ags_composite_editor_real_machine_changed(AgsCompositeEditor * composite_editor,AgsMachine * machine)444 ags_composite_editor_real_machine_changed(AgsCompositeEditor *composite_editor,
445 					  AgsMachine *machine)
446 {
447   //TODO:JK: implement me
448 }
449 
450 /**
451  * ags_composite_editor_machine_changed:
452  * @composite_editor: the #AgsCompositeEditor
453  * @machine: the new #AgsMachine
454  *
455  * Is emitted as machine changed of composite_editor.
456  *
457  * Since: 3.8.0
458  */
459 void
ags_composite_editor_machine_changed(AgsCompositeEditor * composite_editor,AgsMachine * machine)460 ags_composite_editor_machine_changed(AgsCompositeEditor *composite_editor,
461 				     AgsMachine *machine)
462 {
463   g_return_if_fail(AGS_IS_COMPOSITE_EDITOR(composite_editor));
464 
465   g_object_ref((GObject *) composite_editor);
466   g_signal_emit((GObject *) composite_editor,
467 		composite_editor_signals[MACHINE_CHANGED], 0,
468 		machine);
469   g_object_unref((GObject *) composite_editor);
470 }
471 
472 /**
473  * ags_composite_editor_paste:
474  * @composite_editor: the #AgsCompositeEditor
475  *
476  * Paste to @composite_editor from clipboard.
477  *
478  * Since: 3.8.0
479  */
480 void
ags_composite_editor_paste(AgsCompositeEditor * composite_editor)481 ags_composite_editor_paste(AgsCompositeEditor *composite_editor)
482 {
483   //TODO:JK: implement me
484 }
485 
486 /**
487  * ags_composite_editor_copy:
488  * @composite_editor: the #AgsCompositeEditor
489  *
490  * Copy to clipboard from @composite_editor.
491  *
492  * Since: 3.8.0
493  */
494 void
ags_composite_editor_copy(AgsCompositeEditor * composite_editor)495 ags_composite_editor_copy(AgsCompositeEditor *composite_editor)
496 {
497   //TODO:JK: implement me
498 }
499 
500 /**
501  * ags_composite_editor_cut:
502  * @composite_editor: the #AgsCompositeEditor
503  *
504  * Copy to clipboard from @composite_editor.
505  *
506  * Since: 3.8.0
507  */
508 void
ags_composite_editor_cut(AgsCompositeEditor * composite_editor)509 ags_composite_editor_cut(AgsCompositeEditor *composite_editor)
510 {
511   //TODO:JK: implement me
512 }
513 
514 /**
515  * ags_composite_editor_invert:
516  * @composite_editor: the #AgsCompositeEditor
517  *
518  * Invert selected region of @composite_editor.
519  *
520  * Since: 3.8.0
521  */
522 void
ags_composite_editor_invert(AgsCompositeEditor * composite_editor)523 ags_composite_editor_invert(AgsCompositeEditor *composite_editor)
524 {
525   //TODO:JK: implement me
526 }
527 
528 /**
529  * ags_composite_editor_new:
530  *
531  * Create a new #AgsCompositeEditor.
532  *
533  * Returns: a new #AgsCompositeEditor
534  *
535  * Since: 3.8.0
536  */
537 AgsCompositeEditor*
ags_composite_editor_new()538 ags_composite_editor_new()
539 {
540   AgsCompositeEditor *composite_editor;
541 
542   composite_editor = (AgsCompositeEditor *) g_object_new(AGS_TYPE_COMPOSITE_EDITOR,
543 							 NULL);
544 
545   return(composite_editor);
546 }
547