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