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/machine/ags_pattern_box.h>
21 #include <ags/X/machine/ags_pattern_box_callbacks.h>
22
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 #include <ags/X/ags_machine.h>
26 #include <ags/X/ags_pad.h>
27 #include <ags/X/ags_line.h>
28
29 #include <gdk/gdkkeysyms.h>
30
31 #include <atk/atk.h>
32
33 #include <ags/i18n.h>
34
35 static GType ags_accessible_pattern_box_get_type(void);
36 void ags_pattern_box_class_init(AgsPatternBoxClass *pattern_box);
37 void ags_accessible_pattern_box_class_init(AtkObject *object);
38 void ags_accessible_pattern_box_action_interface_init(AtkActionIface *action);
39 void ags_pattern_box_connectable_interface_init(AgsConnectableInterface *connectable);
40 void ags_pattern_box_init(AgsPatternBox *pattern_box);
41 void ags_pattern_box_finalize(GObject *gobject);
42
43 void ags_pattern_box_connect(AgsConnectable *connectable);
44 void ags_pattern_box_disconnect(AgsConnectable *connectable);
45
46 AtkObject* ags_pattern_box_get_accessible(GtkWidget *widget);
47 void ags_pattern_box_realize(GtkWidget *widget);
48 void ags_pattern_box_show(GtkWidget *widget);
49 void ags_pattern_box_show_all(GtkWidget *widget);
50
51 gboolean ags_accessible_pattern_box_do_action(AtkAction *action,
52 gint i);
53 gint ags_accessible_pattern_box_get_n_actions(AtkAction *action);
54 const gchar* ags_accessible_pattern_box_get_description(AtkAction *action,
55 gint i);
56 const gchar* ags_accessible_pattern_box_get_name(AtkAction *action,
57 gint i);
58 const gchar* ags_accessible_pattern_box_get_keybinding(AtkAction *action,
59 gint i);
60 gboolean ags_accessible_pattern_box_set_description(AtkAction *action,
61 gint i);
62 gchar* ags_accessible_pattern_box_get_localized_name(AtkAction *action,
63 gint i);
64
65 /**
66 * SECTION:ags_pattern_box
67 * @short_description: pattern box sequencer
68 * @title: AgsPatternBox
69 * @section_id:
70 * @include: ags/X/machine/ags_pattern_box.h
71 *
72 * The #AgsPatternBox is a composite widget to act as pattern box sequencer.
73 */
74
75 static gpointer ags_pattern_box_parent_class = NULL;
76 static GQuark quark_accessible_object = 0;
77
78 GtkStyle *pattern_box_style = NULL;
79 GHashTable *ags_pattern_box_led_queue_draw = NULL;
80
81 GType
ags_pattern_box_get_type(void)82 ags_pattern_box_get_type(void)
83 {
84 static volatile gsize g_define_type_id__volatile = 0;
85
86 if(g_once_init_enter (&g_define_type_id__volatile)){
87 GType ags_type_pattern_box = 0;
88
89 static const GTypeInfo ags_pattern_box_info = {
90 sizeof(AgsPatternBoxClass),
91 NULL, /* base_init */
92 NULL, /* base_finalize */
93 (GClassInitFunc) ags_pattern_box_class_init,
94 NULL, /* class_finalize */
95 NULL, /* class_data */
96 sizeof(AgsPatternBox),
97 0, /* n_preallocs */
98 (GInstanceInitFunc) ags_pattern_box_init,
99 };
100
101 static const GInterfaceInfo ags_connectable_interface_info = {
102 (GInterfaceInitFunc) ags_pattern_box_connectable_interface_init,
103 NULL, /* interface_finalize */
104 NULL, /* interface_data */
105 };
106
107 ags_type_pattern_box = g_type_register_static(GTK_TYPE_GRID,
108 "AgsPatternBox", &ags_pattern_box_info,
109 0);
110
111 g_type_add_interface_static(ags_type_pattern_box,
112 AGS_TYPE_CONNECTABLE,
113 &ags_connectable_interface_info);
114
115 g_once_init_leave(&g_define_type_id__volatile, ags_type_pattern_box);
116 }
117
118 return g_define_type_id__volatile;
119 }
120
121 static GType
ags_accessible_pattern_box_get_type(void)122 ags_accessible_pattern_box_get_type(void)
123 {
124 static GType ags_type_accessible_pattern_box = 0;
125
126 if(!ags_type_accessible_pattern_box){
127 const GTypeInfo ags_accesssible_pattern_box_info = {
128 sizeof(GtkAccessibleClass),
129 NULL, /* base_init */
130 NULL, /* base_finalize */
131 (GClassInitFunc) ags_accessible_pattern_box_class_init,
132 NULL, /* class_finalize */
133 NULL, /* class_data */
134 sizeof(GtkAccessible),
135 0, /* n_preallocs */
136 NULL, NULL
137 };
138
139 static const GInterfaceInfo atk_action_interface_info = {
140 (GInterfaceInitFunc) ags_accessible_pattern_box_action_interface_init,
141 NULL, /* interface_finalize */
142 NULL, /* interface_data */
143 };
144
145 ags_type_accessible_pattern_box = g_type_register_static(GTK_TYPE_ACCESSIBLE,
146 "AgsAccessiblePatternBox", &ags_accesssible_pattern_box_info,
147 0);
148
149 g_type_add_interface_static(ags_type_accessible_pattern_box,
150 ATK_TYPE_ACTION,
151 &atk_action_interface_info);
152 }
153
154 return(ags_type_accessible_pattern_box);
155 }
156
157 void
ags_pattern_box_class_init(AgsPatternBoxClass * pattern_box)158 ags_pattern_box_class_init(AgsPatternBoxClass *pattern_box)
159 {
160 GObjectClass *gobject;
161 GtkWidgetClass *widget;
162
163 ags_pattern_box_parent_class = g_type_class_peek_parent(pattern_box);
164
165 quark_accessible_object = g_quark_from_static_string("ags-accessible-object");
166
167 /* GObjectClass */
168 gobject = (GObjectClass *) pattern_box;
169
170 gobject->finalize = ags_pattern_box_finalize;
171
172 /* GtkWidget */
173 widget = (GtkWidgetClass *) pattern_box;
174
175 widget->realize = ags_pattern_box_realize;
176 widget->show = ags_pattern_box_show;
177 widget->show_all = ags_pattern_box_show_all;
178 }
179
180 void
ags_accessible_pattern_box_class_init(AtkObject * object)181 ags_accessible_pattern_box_class_init(AtkObject *object)
182 {
183 /* empty */
184 }
185
186 void
ags_accessible_pattern_box_action_interface_init(AtkActionIface * action)187 ags_accessible_pattern_box_action_interface_init(AtkActionIface *action)
188 {
189 action->do_action = ags_accessible_pattern_box_do_action;
190 action->get_n_actions = ags_accessible_pattern_box_get_n_actions;
191 action->get_description = ags_accessible_pattern_box_get_description;
192 action->get_name = ags_accessible_pattern_box_get_name;
193 action->get_keybinding = ags_accessible_pattern_box_get_keybinding;
194 action->set_description = ags_accessible_pattern_box_set_description;
195 action->get_localized_name = ags_accessible_pattern_box_get_localized_name;
196 }
197
198 void
ags_pattern_box_connectable_interface_init(AgsConnectableInterface * connectable)199 ags_pattern_box_connectable_interface_init(AgsConnectableInterface *connectable)
200 {
201 connectable->connect = ags_pattern_box_connect;
202 connectable->disconnect = ags_pattern_box_disconnect;
203 }
204
205 void
ags_pattern_box_init(AgsPatternBox * pattern_box)206 ags_pattern_box_init(AgsPatternBox *pattern_box)
207 {
208 GtkToggleButton *toggle_button;
209 GtkRadioButton *radio_button;
210
211 AgsApplicationContext *application_context;
212
213 gchar *str;
214
215 gdouble gui_scale_factor;
216 guint i;
217
218 application_context = ags_application_context_get_instance();
219
220 g_object_set(pattern_box,
221 "can-focus", TRUE,
222 NULL);
223
224 gtk_widget_set_events((GtkWidget *) pattern_box,
225 (GDK_CONTROL_MASK
226 | GDK_KEY_PRESS_MASK
227 | GDK_KEY_RELEASE_MASK));
228
229 pattern_box->flags = 0;
230
231 pattern_box->key_mask = 0;
232
233 pattern_box->n_controls = AGS_PATTERN_BOX_N_CONTROLS;
234 pattern_box->n_indices = AGS_PATTERN_BOX_N_INDICES;
235
236 /* led */
237 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
238
239 pattern_box->active_led = 0;
240 pattern_box->hled_array = (AgsHLedArray *) ags_hled_array_new();
241 g_object_set(pattern_box->hled_array,
242 "led-count", pattern_box->n_controls,
243 "led-width", (guint) (gui_scale_factor * AGS_PATTERN_BOX_LED_DEFAULT_WIDTH),
244 "led-height", (guint) (gui_scale_factor * AGS_PATTERN_BOX_LED_DEFAULT_HEIGHT),
245 NULL);
246 gtk_widget_set_size_request((GtkWidget *) pattern_box->hled_array,
247 (guint) (gui_scale_factor * pattern_box->n_controls * AGS_PATTERN_BOX_DEFAULT_PAD_WIDTH), (guint) (gui_scale_factor * AGS_PATTERN_BOX_LED_DEFAULT_HEIGHT));
248
249 gtk_widget_set_valign((GtkWidget *) pattern_box->hled_array,
250 GTK_ALIGN_CENTER);
251 gtk_widget_set_vexpand((GtkWidget *) pattern_box->hled_array,
252 TRUE);
253
254 gtk_grid_attach((GtkGrid *) pattern_box,
255 (GtkWidget *) pattern_box->hled_array,
256 0, 0,
257 1, 1);
258 gtk_widget_show_all((GtkWidget *) pattern_box->hled_array);
259
260 if(ags_pattern_box_led_queue_draw == NULL){
261 ags_pattern_box_led_queue_draw = g_hash_table_new_full(g_direct_hash, g_direct_equal,
262 NULL,
263 NULL);
264 }
265
266 g_hash_table_insert(ags_pattern_box_led_queue_draw,
267 pattern_box, ags_pattern_box_led_queue_draw_timeout);
268 g_timeout_add((guint) floor(AGS_UI_PROVIDER_DEFAULT_TIMEOUT * 1000.0), (GSourceFunc) ags_pattern_box_led_queue_draw_timeout, (gpointer) pattern_box);
269
270 /* pattern */
271 pattern_box->pattern = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
272 0);
273
274 gtk_widget_set_valign((GtkWidget *) pattern_box->pattern,
275 GTK_ALIGN_CENTER);
276 gtk_widget_set_vexpand((GtkWidget *) pattern_box->pattern,
277 TRUE);
278
279 gtk_grid_attach((GtkGrid *) pattern_box,
280 (GtkWidget *) pattern_box->pattern,
281 0, 1,
282 1, 1);
283
284 for(i = 0; i < pattern_box->n_controls; i++){
285 toggle_button = (GtkToggleButton *) gtk_toggle_button_new();
286 gtk_widget_set_size_request((GtkWidget *) toggle_button,
287 gui_scale_factor * AGS_PATTERN_BOX_DEFAULT_PAD_WIDTH, gui_scale_factor * AGS_PATTERN_BOX_DEFAULT_PAD_HEIGHT);
288 gtk_box_pack_start(pattern_box->pattern,
289 (GtkWidget *) toggle_button,
290 FALSE, FALSE,
291 0);
292 }
293
294 /* page / offset */
295 pattern_box->offset = (GtkBox *) gtk_box_new(GTK_ORIENTATION_VERTICAL,
296 0);
297 gtk_grid_attach((GtkGrid *) pattern_box,
298 (GtkWidget *) pattern_box->offset,
299 1, 0,
300 1, 2);
301 radio_button = NULL;
302
303 for(i = 0; i < pattern_box->n_indices; i++){
304 if(radio_button == NULL){
305 str = g_strdup_printf("%d-%d",
306 i * pattern_box->n_controls + 1, (i + 1) * pattern_box->n_controls);
307 radio_button = (GtkRadioButton *) gtk_radio_button_new_with_label(NULL,
308 str);
309 gtk_box_pack_start(pattern_box->offset,
310 (GtkWidget *) radio_button,
311 FALSE, FALSE,
312 0);
313
314 g_free(str);
315 }else{
316 str = g_strdup_printf("%d-%d",
317 i * pattern_box->n_controls + 1, (i + 1) * pattern_box->n_controls);
318 gtk_box_pack_start(pattern_box->offset,
319 (GtkWidget *) gtk_radio_button_new_with_label(gtk_radio_button_get_group(radio_button),
320 str),
321 FALSE, FALSE,
322 0);
323
324 g_free(str);
325 }
326 }
327 }
328
329 void
ags_pattern_box_finalize(GObject * gobject)330 ags_pattern_box_finalize(GObject *gobject)
331 {
332 g_hash_table_remove(ags_pattern_box_led_queue_draw,
333 gobject);
334
335 G_OBJECT_CLASS(ags_pattern_box_parent_class)->finalize(gobject);
336 }
337
338 void
ags_pattern_box_connect(AgsConnectable * connectable)339 ags_pattern_box_connect(AgsConnectable *connectable)
340 {
341 AgsPatternBox *pattern_box;
342
343 GList *list, *list_start;
344
345 if((AGS_PATTERN_BOX_CONNECTED & (AGS_PATTERN_BOX(connectable)->flags)) != 0){
346 return;
347 }
348
349 /* AgsPatternBox */
350 pattern_box = AGS_PATTERN_BOX(connectable);
351
352 pattern_box->flags |= AGS_PATTERN_BOX_CONNECTED;
353
354 g_signal_connect_after(G_OBJECT(pattern_box), "focus_in_event",
355 G_CALLBACK(ags_pattern_box_focus_in_callback), (gpointer) pattern_box);
356
357 g_signal_connect_after(G_OBJECT(pattern_box), "focus_out_event",
358 G_CALLBACK(ags_pattern_box_focus_out_callback), (gpointer) pattern_box);
359
360 g_signal_connect(G_OBJECT(pattern_box), "key_press_event",
361 G_CALLBACK(ags_pattern_box_key_press_event), (gpointer) pattern_box);
362
363 g_signal_connect(G_OBJECT(pattern_box), "key_release_event",
364 G_CALLBACK(ags_pattern_box_key_release_event), (gpointer) pattern_box);
365
366 /* connect pattern */
367 list_start =
368 list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
369
370 while(list != NULL){
371 g_signal_connect(G_OBJECT(list->data), "clicked",
372 G_CALLBACK(ags_pattern_box_pad_callback), (gpointer) pattern_box);
373
374 list = list->next;
375 }
376
377 g_list_free(list_start);
378
379 /* connect pattern offset range */
380 list_start =
381 list = gtk_container_get_children((GtkContainer *) pattern_box->offset);
382
383 while(list != NULL){
384 g_signal_connect_after(G_OBJECT(list->data), "clicked",
385 G_CALLBACK(ags_pattern_box_offset_callback), (gpointer) pattern_box);
386
387 list = list->next;
388 }
389
390 g_list_free(list_start);
391 }
392
393 void
ags_pattern_box_disconnect(AgsConnectable * connectable)394 ags_pattern_box_disconnect(AgsConnectable *connectable)
395 {
396 AgsPatternBox *pattern_box;
397
398 GList *list, *list_start;
399
400 if((AGS_PATTERN_BOX_CONNECTED & (AGS_PATTERN_BOX(connectable)->flags)) == 0){
401 return;
402 }
403
404 /* AgsPatternBox */
405 pattern_box = AGS_PATTERN_BOX(connectable);
406
407 pattern_box->flags &= (~AGS_PATTERN_BOX_CONNECTED);
408
409 g_object_disconnect(G_OBJECT(pattern_box),
410 "any_signal::focus_in_event",
411 G_CALLBACK(ags_pattern_box_focus_in_callback),
412 (gpointer) pattern_box,
413 "any_signal::focus_out_event",
414 G_CALLBACK(ags_pattern_box_focus_out_callback),
415 (gpointer) pattern_box,
416 "any_signal::key_press_event",
417 G_CALLBACK(ags_pattern_box_key_press_event),
418 (gpointer) pattern_box,
419 "any_signal::key_release_event",
420 G_CALLBACK(ags_pattern_box_key_release_event),
421 (gpointer) pattern_box,
422 NULL);
423
424 /* connect pattern */
425 list_start =
426 list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
427
428 while(list != NULL){
429 g_object_disconnect(G_OBJECT(list->data),
430 "any_signal::clicked",
431 G_CALLBACK(ags_pattern_box_pad_callback),
432 (gpointer) pattern_box,
433 NULL);
434
435 list = list->next;
436 }
437
438 g_list_free(list_start);
439
440 /* connect pattern offset range */
441 list_start =
442 list = gtk_container_get_children((GtkContainer *) pattern_box->offset);
443
444 while(list != NULL){
445 g_object_disconnect(G_OBJECT(list->data),
446 "any_signal::clicked",
447 G_CALLBACK(ags_pattern_box_offset_callback),
448 (gpointer) pattern_box,
449 NULL);
450
451 list = list->next;
452 }
453
454 g_list_free(list_start);
455 }
456
457 AtkObject*
ags_pattern_box_get_accessible(GtkWidget * widget)458 ags_pattern_box_get_accessible(GtkWidget *widget)
459 {
460 AtkObject* accessible;
461
462 accessible = g_object_get_qdata(G_OBJECT(widget),
463 quark_accessible_object);
464
465 if(!accessible){
466 accessible = g_object_new(ags_accessible_pattern_box_get_type(),
467 NULL);
468
469 g_object_set_qdata(G_OBJECT(widget),
470 quark_accessible_object,
471 accessible);
472 gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible),
473 widget);
474 }
475
476 return(accessible);
477 }
478
479 void
ags_pattern_box_realize(GtkWidget * widget)480 ags_pattern_box_realize(GtkWidget *widget)
481 {
482 /* call parent */
483 GTK_WIDGET_CLASS(ags_pattern_box_parent_class)->realize(widget);
484 }
485
486 void
ags_pattern_box_show(GtkWidget * widget)487 ags_pattern_box_show(GtkWidget *widget)
488 {
489 GTK_WIDGET_CLASS(ags_pattern_box_parent_class)->show(widget);
490
491 // ags_pattern_box_draw_matrix(AGS_PATTERN_BOX(widget));
492 }
493
494 void
ags_pattern_box_show_all(GtkWidget * widget)495 ags_pattern_box_show_all(GtkWidget *widget)
496 {
497 GTK_WIDGET_CLASS(ags_pattern_box_parent_class)->show_all(widget);
498
499 // ags_pattern_box_draw_matrix(AGS_PATTERN_BOX(widget));
500 }
501
502 gboolean
ags_accessible_pattern_box_do_action(AtkAction * action,gint i)503 ags_accessible_pattern_box_do_action(AtkAction *action,
504 gint i)
505 {
506 AgsPatternBox *pattern_box;
507
508 GdkEventKey *key_press, *key_release;
509 GdkEventKey *modifier_press, *modifier_release;
510
511 if(!(i >= 0 && i < 6)){
512 return(FALSE);
513 }
514
515 pattern_box = (AgsPatternBox *) gtk_accessible_get_widget(GTK_ACCESSIBLE(action));
516
517 key_press = (GdkEventKey *) gdk_event_new(GDK_KEY_PRESS);
518 key_release = (GdkEventKey *) gdk_event_new(GDK_KEY_RELEASE);
519
520 switch(i){
521 case AGS_PATTERN_BOX_MOVE_LEFT:
522 {
523 key_press->keyval =
524 key_release->keyval = GDK_KEY_Left;
525
526 /* send event */
527 gtk_widget_event((GtkWidget *) pattern_box,
528 (GdkEvent *) key_press);
529 gtk_widget_event((GtkWidget *) pattern_box,
530 (GdkEvent *) key_release);
531 }
532 break;
533 case AGS_PATTERN_BOX_MOVE_RIGHT:
534 {
535 key_press->keyval =
536 key_release->keyval = GDK_KEY_Right;
537
538 /* send event */
539 gtk_widget_event((GtkWidget *) pattern_box,
540 (GdkEvent *) key_press);
541 gtk_widget_event((GtkWidget *) pattern_box,
542 (GdkEvent *) key_release);
543 }
544 break;
545 case AGS_PATTERN_BOX_INDEX_DECREMENT:
546 {
547 key_press->keyval =
548 key_release->keyval = GDK_KEY_Up;
549
550 /* send event */
551 gtk_widget_event((GtkWidget *) pattern_box,
552 (GdkEvent *) key_press);
553 gtk_widget_event((GtkWidget *) pattern_box,
554 (GdkEvent *) key_release);
555 }
556 break;
557 case AGS_PATTERN_BOX_INDEX_INCREMENT:
558 {
559 key_press->keyval =
560 key_release->keyval = GDK_KEY_Down;
561
562 /* send event */
563 gtk_widget_event((GtkWidget *) pattern_box,
564 (GdkEvent *) key_press);
565 gtk_widget_event((GtkWidget *) pattern_box,
566 (GdkEvent *) key_release);
567 }
568 break;
569 case AGS_PATTERN_BOX_TOGGLE_PAD:
570 {
571 key_press->keyval =
572 key_release->keyval = GDK_KEY_space;
573
574 /* send event */
575 gtk_widget_event((GtkWidget *) pattern_box,
576 (GdkEvent *) key_press);
577 gtk_widget_event((GtkWidget *) pattern_box,
578 (GdkEvent *) key_release);
579 }
580 break;
581 case AGS_PATTERN_BOX_COPY_PATTERN:
582 {
583 key_press->keyval =
584 key_release->keyval = GDK_KEY_c;
585
586 /* create modifier */
587 modifier_press = (GdkEventKey *) gdk_event_new(GDK_KEY_PRESS);
588 modifier_release = (GdkEventKey *) gdk_event_new(GDK_KEY_RELEASE);
589
590 modifier_press->keyval =
591 modifier_release->keyval = GDK_KEY_Control_R;
592
593 /* send event */
594 gtk_widget_event((GtkWidget *) pattern_box,
595 (GdkEvent *) modifier_press);
596 gtk_widget_event((GtkWidget *) pattern_box,
597 (GdkEvent *) key_press);
598 gtk_widget_event((GtkWidget *) pattern_box,
599 (GdkEvent *) key_release);
600 gtk_widget_event((GtkWidget *) pattern_box,
601 (GdkEvent *) modifier_release);
602 }
603 break;
604 }
605
606 return(TRUE);
607 }
608
609 gint
ags_accessible_pattern_box_get_n_actions(AtkAction * action)610 ags_accessible_pattern_box_get_n_actions(AtkAction *action)
611 {
612 return(6);
613 }
614
615 const gchar*
ags_accessible_pattern_box_get_description(AtkAction * action,gint i)616 ags_accessible_pattern_box_get_description(AtkAction *action,
617 gint i)
618 {
619 static const gchar *actions[] = {
620 "move cursor left",
621 "move cursor right",
622 "decrement pattern index",
623 "increment pattern index",
624 "toggle audio pattern"
625 "copy pattern to clipboard",
626 };
627
628 if(i >= 0 && i < 6){
629 return(actions[i]);
630 }else{
631 return(NULL);
632 }
633 }
634
635 const gchar*
ags_accessible_pattern_box_get_name(AtkAction * action,gint i)636 ags_accessible_pattern_box_get_name(AtkAction *action,
637 gint i)
638 {
639 static const gchar *actions[] = {
640 "left",
641 "right",
642 "up",
643 "down",
644 "toggle",
645 "copy",
646 };
647
648 if(i >= 0 && i < 6){
649 return(actions[i]);
650 }else{
651 return(NULL);
652 }
653 }
654
655 const gchar*
ags_accessible_pattern_box_get_keybinding(AtkAction * action,gint i)656 ags_accessible_pattern_box_get_keybinding(AtkAction *action,
657 gint i)
658 {
659 static const gchar *actions[] = {
660 "left",
661 "right",
662 "up",
663 "down",
664 "space",
665 "Ctrl+c",
666 };
667
668 if(i >= 0 && i < 6){
669 return(actions[i]);
670 }else{
671 return(NULL);
672 }
673 }
674
675 gboolean
ags_accessible_pattern_box_set_description(AtkAction * action,gint i)676 ags_accessible_pattern_box_set_description(AtkAction *action,
677 gint i)
678 {
679 //TODO:JK: implement me
680
681 return(FALSE);
682 }
683
684 gchar*
ags_accessible_pattern_box_get_localized_name(AtkAction * action,gint i)685 ags_accessible_pattern_box_get_localized_name(AtkAction *action,
686 gint i)
687 {
688 //TODO:JK: implement me
689
690 return(NULL);
691 }
692
693 /**
694 * ags_pattern_box_set_pattern:
695 * @pattern_box: the #AgsPatternBox
696 *
697 * Resets the pattern on @pattern_box.
698 *
699 * since: 2.0.0
700 */
701 void
ags_pattern_box_set_pattern(AgsPatternBox * pattern_box)702 ags_pattern_box_set_pattern(AgsPatternBox *pattern_box)
703 {
704 AgsMachine *machine;
705 AgsLine *selected_line;
706
707 GList *list, *list_start;
708 GList *line, *line_start;
709
710 guint index0, index1, offset;
711 gboolean is_active;
712 gboolean set_active;
713 guint i;
714
715 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) pattern_box,
716 AGS_TYPE_MACHINE);
717
718 if(machine->selected_input_pad == NULL){
719 return;
720 }
721
722 index0 = machine->bank_0;
723 index1 = machine->bank_1;
724
725 /* read boundaries */
726 list = gtk_container_get_children((GtkContainer *) pattern_box->offset);
727
728 for(i = 0; i < pattern_box->n_indices && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(list->data)); i++){
729 list = list->next;
730 }
731
732 offset = i * pattern_box->n_controls;
733
734 /* get pads */
735 list_start =
736 list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
737
738 /* reset */
739 pattern_box->flags |= AGS_PATTERN_BOX_BLOCK_PATTERN;
740
741 for(i = 0; i < pattern_box->n_controls; i++){
742 set_active = TRUE;
743
744 line_start =
745 line = gtk_container_get_children(GTK_CONTAINER(AGS_PAD(machine->selected_input_pad)->expander_set));
746
747 while((line = ags_line_find_next_grouped(line)) != NULL){
748 GList *start_pattern, *pattern;
749
750 selected_line = AGS_LINE(line->data);
751
752 g_object_get(selected_line->channel,
753 "pattern", &start_pattern,
754 NULL);
755
756 /* check active */
757 pattern = start_pattern;
758
759 is_active = ags_pattern_get_bit((AgsPattern *) pattern->data, index0, index1, offset + i);
760
761 g_list_free_full(start_pattern,
762 g_object_unref);
763
764 if(!is_active){
765 set_active = FALSE;
766
767 break;
768 }
769
770 /* iterate */
771 line = line->next;
772 }
773
774 g_list_free(line_start);
775
776 gtk_toggle_button_set_active((GtkToggleButton *) list->data, set_active);
777
778 list = list->next;
779 }
780
781 pattern_box->flags &= (~AGS_PATTERN_BOX_BLOCK_PATTERN);
782
783 g_list_free(list_start);
784 }
785
786 /**
787 * ags_pattern_box_led_queue_draw_timeout:
788 * @pattern_box: the #AgsPatternBox
789 *
790 * Queue draw led.
791 *
792 * Returns: %TRUE if continue timeout, otherwise %FALSE
793 *
794 * Since: 3.0.0
795 */
796 gboolean
ags_pattern_box_led_queue_draw_timeout(AgsPatternBox * pattern_box)797 ags_pattern_box_led_queue_draw_timeout(AgsPatternBox *pattern_box)
798 {
799 if(g_hash_table_lookup(ags_pattern_box_led_queue_draw,
800 pattern_box) != NULL){
801 AgsMachine *machine;
802
803 AgsAudio *audio;
804 AgsRecallID *recall_id;
805
806 AgsFxPatternAudio *play_fx_pattern_audio;
807 AgsFxPatternAudioProcessor *play_fx_pattern_audio_processor;
808
809 GList *start_list, *list;
810 GList *start_recall, *recall;
811
812 guint64 active_led_new;
813 gboolean success;
814
815 GRecMutex *play_fx_pattern_audio_processor_mutex;
816
817 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) pattern_box,
818 AGS_TYPE_MACHINE);
819
820 if(machine == NULL){
821 return(TRUE);
822 }
823
824 audio = machine->audio;
825
826 /* get some recalls */
827 recall_id = NULL;
828 g_object_get(audio,
829 "recall-id", &start_list,
830 NULL);
831
832 list = start_list;
833
834 success = FALSE;
835
836 while(list != NULL && !success){
837 AgsRecyclingContext *parent_recycling_context;
838 AgsRecyclingContext *current_recycling_context;
839
840 parent_recycling_context = NULL;
841 current_recycling_context = NULL;
842
843 g_object_get(list->data,
844 "recycling-context", ¤t_recycling_context,
845 NULL);
846
847 if(current_recycling_context != NULL){
848 g_object_get(current_recycling_context,
849 "parent", &parent_recycling_context,
850 NULL);
851
852 if(parent_recycling_context == NULL &&
853 ags_recall_id_check_sound_scope(list->data, AGS_SOUND_SCOPE_SEQUENCER)){
854 recall_id = list->data;
855
856 g_object_get(audio,
857 "play", &start_recall,
858 NULL);
859
860 play_fx_pattern_audio = NULL;
861 play_fx_pattern_audio_processor = NULL;
862
863 recall = ags_recall_find_type(start_recall,
864 AGS_TYPE_FX_PATTERN_AUDIO);
865
866 if(recall != NULL){
867 play_fx_pattern_audio = AGS_FX_PATTERN_AUDIO(recall->data);
868 }
869
870 recall = ags_recall_find_type_with_recycling_context(start_recall,
871 AGS_TYPE_FX_PATTERN_AUDIO_PROCESSOR,
872 (GObject *) current_recycling_context);
873
874 if(recall != NULL){
875 play_fx_pattern_audio_processor = AGS_FX_PATTERN_AUDIO_PROCESSOR(recall->data);
876 }
877
878
879 g_list_free_full(start_recall,
880 g_object_unref);
881
882 if(play_fx_pattern_audio == NULL ||
883 play_fx_pattern_audio_processor == NULL){
884 recall_id = NULL;
885 }else{
886 success = TRUE;
887 }
888 }
889 }
890
891 if(parent_recycling_context != NULL){
892 g_object_unref(parent_recycling_context);
893 }
894
895 if(current_recycling_context != NULL){
896 g_object_unref(current_recycling_context);
897 }
898
899 list = list->next;
900 }
901
902 g_list_free_full(start_list,
903 g_object_unref);
904
905 if(recall_id == NULL){
906 return(TRUE);
907 }
908
909 /* active led */
910 play_fx_pattern_audio_processor_mutex = AGS_RECALL_GET_OBJ_MUTEX(play_fx_pattern_audio_processor);
911
912 g_rec_mutex_lock(play_fx_pattern_audio_processor_mutex);
913
914 active_led_new = play_fx_pattern_audio_processor->offset_counter;
915
916 g_rec_mutex_unlock(play_fx_pattern_audio_processor_mutex);
917
918 pattern_box->active_led = (guint) (active_led_new % pattern_box->n_controls);
919
920 ags_led_array_unset_all((AgsLedArray *) pattern_box->hled_array);
921 ags_led_array_set_nth((AgsLedArray *) pattern_box->hled_array,
922 pattern_box->active_led);
923
924 return(TRUE);
925 }else{
926 return(FALSE);
927 }
928 }
929
930 /**
931 * ags_pattern_box_new:
932 *
933 * Create a new instance of #AgsPatternBox
934 *
935 * Returns: the new #AgsPatternBox
936 *
937 * Since: 3.0.0
938 */
939 AgsPatternBox*
ags_pattern_box_new()940 ags_pattern_box_new()
941 {
942 AgsPatternBox *pattern_box;
943
944 pattern_box = (AgsPatternBox *) g_object_new(AGS_TYPE_PATTERN_BOX,
945 NULL);
946
947 return(pattern_box);
948 }
949