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_callbacks.h>
21
22 #include <ags/X/ags_window.h>
23 #include <ags/X/ags_machine.h>
24 #include <ags/X/ags_pad.h>
25 #include <ags/X/ags_line.h>
26
27 #include <gdk/gdkkeysyms.h>
28
29 gboolean
ags_pattern_box_focus_in_callback(GtkWidget * widget,GdkEvent * event,AgsPatternBox * pattern_box)30 ags_pattern_box_focus_in_callback(GtkWidget *widget, GdkEvent *event, AgsPatternBox *pattern_box)
31 {
32 GList *start_list;
33
34 start_list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
35 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
36 pattern_box->cursor_x),
37 GTK_STATE_FLAG_PRELIGHT,
38 FALSE);
39 g_list_free(start_list);
40
41 return(TRUE);
42 }
43
44 gboolean
ags_pattern_box_focus_out_callback(GtkWidget * widget,GdkEvent * event,AgsPatternBox * pattern_box)45 ags_pattern_box_focus_out_callback(GtkWidget *widget, GdkEvent *event, AgsPatternBox *pattern_box)
46 {
47 GList *start_list;
48
49 start_list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
50
51 if(!gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_list,
52 pattern_box->cursor_x - 1))){
53 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
54 pattern_box->cursor_x),
55 GTK_STATE_FLAG_NORMAL,
56 FALSE);
57 }else{
58 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
59 pattern_box->cursor_x),
60 GTK_STATE_FLAG_ACTIVE,
61 FALSE);
62 }
63
64 g_list_free(start_list);
65
66 return(TRUE);
67 }
68
69 void
ags_pattern_box_pad_callback(GtkWidget * toggle_button,AgsPatternBox * pattern_box)70 ags_pattern_box_pad_callback(GtkWidget *toggle_button, AgsPatternBox *pattern_box)
71 {
72 AgsMachine *machine;
73 AgsLine *selected_line;
74
75 GList *list, *list_start;
76 GList *line, *line_start;
77 guint i, index0, index1, offset;
78
79 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) pattern_box,
80 AGS_TYPE_MACHINE);
81
82 if(machine->selected_input_pad == NULL){
83 return;
84 }
85
86 /* */
87 if((AGS_PATTERN_BOX_BLOCK_PATTERN & (pattern_box->flags)) != 0){
88 #ifdef AGS_DEBUG
89 g_message("AgsPatternBox pattern is blocked\n");
90 #endif
91
92 return;
93 }
94
95 /* calculate offset */
96 list_start =
97 list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
98
99 for(i = 0; i < pattern_box->n_controls && toggle_button != list->data; i++){
100 list = list->next;
101 }
102
103 offset = i;
104 g_list_free(list_start);
105
106 /* retrieve indices */
107 index0 = machine->bank_0;
108 index1 = machine->bank_1;
109
110 /* calculate offset / page */
111 list_start =
112 list = gtk_container_get_children((GtkContainer *) pattern_box->offset);
113
114 for(i = 0; i < 4 && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(list->data)); i++){
115 list = list->next;
116 }
117
118 offset += (i * pattern_box->n_controls);
119
120 g_list_free(list_start);
121
122 /**/
123 line_start =
124 line = gtk_container_get_children(GTK_CONTAINER(AGS_PAD(machine->selected_input_pad)->expander_set));
125
126 while((line = ags_line_find_next_grouped(line)) != NULL){
127 GList *start_pattern, *pattern;
128
129 selected_line = AGS_LINE(line->data);
130
131 g_object_get(selected_line->channel,
132 "pattern", &start_pattern,
133 NULL);
134
135 /* toggle */
136 pattern = start_pattern;
137
138 ags_pattern_toggle_bit(pattern->data,
139 index0, index1,
140 offset);
141
142 g_list_free_full(start_pattern,
143 g_object_unref);
144
145 /* iterate */
146 line = line->next;
147 }
148
149 g_list_free(line_start);
150 }
151
152 void
ags_pattern_box_offset_callback(GtkWidget * widget,AgsPatternBox * pattern_box)153 ags_pattern_box_offset_callback(GtkWidget *widget, AgsPatternBox *pattern_box)
154 {
155 ags_pattern_box_set_pattern(pattern_box);
156 }
157
158 gboolean
ags_pattern_box_key_press_event(GtkWidget * widget,GdkEventKey * event,AgsPatternBox * pattern_box)159 ags_pattern_box_key_press_event(GtkWidget *widget, GdkEventKey *event, AgsPatternBox *pattern_box)
160 {
161 if(event->keyval == GDK_KEY_Tab){
162 return(FALSE);
163 }
164
165 switch(event->keyval){
166 case GDK_KEY_Control_L:
167 {
168 pattern_box->key_mask |= AGS_PATTERN_BOX_KEY_L_CONTROL;
169 }
170 break;
171 case GDK_KEY_Control_R:
172 {
173 pattern_box->key_mask |= AGS_PATTERN_BOX_KEY_R_CONTROL;
174 }
175 break;
176 case GDK_KEY_c:
177 {
178 /* copy notes */
179 if((AGS_PATTERN_BOX_KEY_L_CONTROL & (pattern_box->key_mask)) != 0 || (AGS_PATTERN_BOX_KEY_R_CONTROL & (pattern_box->key_mask)) != 0){
180 AgsMachine *machine;
181
182 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) pattern_box,
183 AGS_TYPE_MACHINE);
184
185 ags_machine_copy_pattern(machine);
186 }
187 }
188 break;
189 }
190
191 return(TRUE);
192 }
193
194 gboolean
ags_pattern_box_key_release_event(GtkWidget * widget,GdkEventKey * event,AgsPatternBox * pattern_box)195 ags_pattern_box_key_release_event(GtkWidget *widget, GdkEventKey *event, AgsPatternBox *pattern_box)
196 {
197 AgsMachine *machine;
198
199 if(event->keyval == GDK_KEY_Tab){
200 return(FALSE);
201 }
202
203 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) pattern_box,
204 AGS_TYPE_MACHINE);
205
206 switch(event->keyval){
207 case GDK_KEY_Control_L:
208 {
209 pattern_box->key_mask &= (~AGS_PATTERN_BOX_KEY_L_CONTROL);
210 }
211 break;
212 case GDK_KEY_Control_R:
213 {
214 pattern_box->key_mask &= (~AGS_PATTERN_BOX_KEY_R_CONTROL);
215 }
216 break;
217 case GDK_KEY_Left:
218 case GDK_KEY_leftarrow:
219 {
220 if(pattern_box->cursor_x > 0){
221 GList *start_list;
222
223 pattern_box->cursor_x -= 1;
224
225 start_list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
226
227 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
228 pattern_box->cursor_x),
229 GTK_STATE_FLAG_PRELIGHT,
230 FALSE);
231
232 if(!gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_list,
233 pattern_box->cursor_x + 1))){
234 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
235 pattern_box->cursor_x + 1),
236 GTK_STATE_FLAG_NORMAL,
237 FALSE);
238 }else{
239 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
240 pattern_box->cursor_x + 1),
241 GTK_STATE_FLAG_ACTIVE,
242 FALSE);
243 }
244
245 if(gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_list,
246 pattern_box->cursor_y * pattern_box->n_controls + pattern_box->cursor_x))){
247 /* give audible feedback */
248 ags_pad_play((AgsPad *) machine->selected_input_pad);
249 }
250
251 g_list_free(start_list);
252 }
253 }
254 break;
255 case GDK_KEY_Right:
256 case GDK_KEY_rightarrow:
257 {
258 if(pattern_box->cursor_x + 1 < pattern_box->n_controls){
259 GList *start_list;
260
261 pattern_box->cursor_x += 1;
262
263 start_list = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
264
265 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
266 pattern_box->cursor_x),
267 GTK_STATE_FLAG_PRELIGHT,
268 FALSE);
269
270 if(!gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_list,
271 pattern_box->cursor_x - 1))){
272 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
273 pattern_box->cursor_x - 1),
274 GTK_STATE_FLAG_NORMAL,
275 FALSE);
276 }else{
277 gtk_widget_set_state_flags((GtkWidget *) g_list_nth_data(start_list,
278 pattern_box->cursor_x - 1),
279 GTK_STATE_FLAG_ACTIVE,
280 FALSE);
281 }
282
283 if(gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_list,
284 pattern_box->cursor_y * pattern_box->n_controls + pattern_box->cursor_x))){
285 /* give audible feedback */
286 ags_pad_play((AgsPad *) machine->selected_input_pad);
287 }
288
289 g_list_free(start_list);
290 }
291 }
292 break;
293 case GDK_KEY_Up:
294 case GDK_KEY_uparrow:
295 {
296 if(pattern_box->cursor_y > 0){
297 GList *start_pad;
298 GList *start_list;
299
300 pattern_box->cursor_y -= 1;
301
302 start_list = gtk_container_get_children((GtkContainer *) pattern_box->offset);
303
304 gtk_button_clicked(g_list_nth_data(start_list,
305 pattern_box->cursor_y));
306
307 g_list_free(start_list);
308
309 /* give audible feedback */
310 start_pad = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
311
312 if(gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_pad,
313 pattern_box->cursor_y * pattern_box->n_controls + pattern_box->cursor_x))){
314 ags_pad_play((AgsPad *) machine->selected_input_pad);
315 }
316
317 g_list_free(start_pad);
318 }
319 }
320 break;
321 case GDK_KEY_Down:
322 case GDK_KEY_downarrow:
323 {
324 if(pattern_box->cursor_y + 1 < pattern_box->n_indices){
325 GList *start_pad;
326 GList *start_list;
327
328 start_list = gtk_container_get_children((GtkContainer *) pattern_box->offset);
329 pattern_box->cursor_y += 1;
330
331 gtk_button_clicked(g_list_nth_data(start_list,
332 pattern_box->cursor_y));
333
334 g_list_free(start_list);
335
336 /* give audible feedback */
337 start_pad = gtk_container_get_children((GtkContainer *) pattern_box->pattern);
338
339 if(gtk_toggle_button_get_active((GtkToggleButton *) g_list_nth_data(start_pad,
340 pattern_box->cursor_y * pattern_box->n_controls + pattern_box->cursor_x))){
341 ags_pad_play((AgsPad *) machine->selected_input_pad);
342 }
343
344 g_list_free(start_pad);
345 }
346 }
347 break;
348 case GDK_KEY_space:
349 {
350 AgsLine *selected_line;
351
352 AgsChannel *channel;
353
354 GList *line, *line_start;
355
356 guint i, j;
357 guint offset;
358 guint index0, index1;
359
360 i = pattern_box->cursor_y;
361 j = pattern_box->cursor_x;
362
363 offset = (i * pattern_box->n_controls) + j;
364
365 index0 = machine->bank_0;
366 index1 = machine->bank_1;
367
368 line_start =
369 line = gtk_container_get_children(GTK_CONTAINER(AGS_PAD(machine->selected_input_pad)->expander_set));
370
371 while((line = ags_line_find_next_grouped(line)) != NULL){
372 GList *start_pattern, *pattern;
373
374 selected_line = AGS_LINE(line->data);
375
376 channel = selected_line->channel;
377
378 g_object_get(channel,
379 "pattern", &start_pattern,
380 NULL);
381
382 /* toggle pattern */
383 pattern = start_pattern;
384
385 ags_pattern_toggle_bit(pattern->data,
386 index0, index1,
387 offset);
388
389 g_list_free_full(start_pattern,
390 g_object_unref);
391
392 /* iterate */
393 line = line->next;
394 }
395
396 g_list_free(line_start);
397
398 /* give audible feedback */
399 ags_pad_play((AgsPad *) machine->selected_input_pad);
400 }
401 break;
402 }
403
404 return(TRUE);
405 }
406