1 /* keysigdialog.c
2  * Prompts the user to change the key signature
3  *
4  * for Denemo, a gtk+ frontend to GNU Lilypond
5  * (c) 2000-2005 Matthew Hiller
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "display/calculatepositions.h"
12 #include "command/commandfuncs.h"
13 #include "command/contexts.h"
14 #include <denemo/denemo.h>
15 #include "ui/dialogs.h"
16 #include "display/draw.h"
17 #include "command/object.h"
18 #include "command/staff.h"
19 #include "core/utils.h"
20 #include "core/cache.h"
21 #include "ui/keysigdialog.h"
22 #include "audio/pitchentry.h"
23 
24 #define KEYNAME_ARRAY_OFFSET 7
25 
26 //FIXME: Make those translatable
27 static gchar *majorkeys[15] = { "C flat", "G flat", "D flat", "A flat", "E flat", "B flat", "F",
28   "C", "G", "D", "A", "E", "B", "F sharp", "C sharp"
29 };
30 
31 static gchar *minorkeys[15] = { "A flat", "E flat", "B flat", "F", "C", "G", "D",
32   "A", "E", "B", "F sharp", "C sharp", "G sharp", "D sharp", "A sharp"
33 };
34 
35 static gchar *uminorkeys[15] = { "A FLAT", "E FLAT", "B FLAT", "F", "C", "G", "D",
36   "A", "E", "B", "F SHARP", "C SHARP", "G SHARP", "D SHARP", "A SHARP"
37 };
38 
39 static gchar *umajorkeys[15] = { "C FLAT", "G FLAT", "D FLAT", "A FLAT", "E FLAT", "B FLAT", "F",
40   "C", "G", "D", "A", "E", "B", "F SHARP", "C SHARP"
41 };
42 /* UNUSED
43 static gchar *modes[7] = { "lydian", "ionian", "mixolydian", "dorian", "aeolian", "phrygian",
44   "locrain"
45 };
46 */
47 typedef struct keysig_data
48 {
49   GtkWidget *checkbutton;
50   GtkWidget *majorkeycombo;
51   GtkWidget *minorkeycombo;
52 //  GtkWidget *okbutton;
53   GList *majorlist;
54   GList *minorlist;
55   GtkWidget *radiobutton2;
56   gboolean initial;
57 } keysig_data;
58 
59 
60 /**
61  * Finds key name and returns its numeric value
62  *
63  * Returns G_MININT if keyname cannot be found
64  */
65 
66 gint
findkey(GtkWidget * combobox,GList * list)67 findkey (GtkWidget * combobox, GList * list)
68 {
69 #if GTK_MAJOR_VERSION==3
70   gchar *tokeystring = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combobox));
71 #else
72   gchar *tokeystring = (gchar *) gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (combobox)->entry));
73 #endif
74   gint ret;
75   ret = g_list_position (list, g_list_find_custom (list, tokeystring, (GCompareFunc) strcmp));
76 
77   if (ret != -1)
78     return ret - KEYNAME_ARRAY_OFFSET;
79   else
80     return G_MININT;
81 }
82 
83 /**
84  * Sets the initial key signature on either the current staff or
85  * across the entire score.
86  */
87 static void
set_keysig(keysig_data * cbdata)88 set_keysig (keysig_data * cbdata)
89 {
90   DenemoMovement *si = Denemo.project->movement;
91   staffnode *curstaff;
92   DenemoStaff *curstaffstruct = (DenemoStaff *) Denemo.project->movement->currentstaff->data;
93   gint tokey, mode;
94   tokey = mode = 0;
95 
96   gint isminor = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cbdata->radiobutton2)) ? 1 : 0;
97 
98   if (isminor == 0)
99     tokey = findkey (cbdata->majorkeycombo, cbdata->majorlist);
100   else
101     tokey = findkey (cbdata->minorkeycombo, cbdata->minorlist);
102 
103   if (tokey != G_MININT)
104     {
105       if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cbdata->checkbutton)))
106         {
107           for (curstaff = si->thescore; curstaff; curstaff = curstaff->next)
108             {
109               curstaffstruct = (DenemoStaff *) curstaff->data;
110               dnm_setinitialkeysig (curstaffstruct, tokey - mode, isminor);
111             }
112           find_leftmost_allcontexts (si);
113         }
114       else
115         {
116           dnm_setinitialkeysig (curstaffstruct, tokey - mode, isminor);
117         }
118     }
119   score_status (Denemo.project, TRUE);
120 }
121 
122 /**
123  * Inserts a key signature change either on a single staff or
124  * across the entire score
125  */
126 static void
insert_keysig(keysig_data * kdata)127 insert_keysig (keysig_data * kdata)
128 {
129   staffnode *curstaff;
130   DenemoMovement *si = Denemo.project->movement;
131   measurenode *curmeasure;
132   gint tokey, mode;
133   DenemoObject *newkey = NULL;
134   tokey = mode = 0;
135 
136   gint isminor = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (kdata->radiobutton2)) ? 1 : 0;
137 
138   if (isminor == 0)
139     tokey = findkey (kdata->majorkeycombo, kdata->majorlist);
140   else
141     tokey = findkey (kdata->minorkeycombo, kdata->minorlist);
142 
143   if (tokey != G_MININT)
144     {
145       if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (kdata->checkbutton)))
146         {
147           for (curstaff = si->thescore; curstaff; curstaff = curstaff->next)
148             {
149               curmeasure = g_list_nth (staff_first_measure_node (curstaff), si->currentmeasurenum - 1);
150               if (curmeasure)
151                 {
152                     if (curmeasure == si->currentmeasure)
153                         ((DenemoMeasure*)curmeasure->data)->objects = g_list_insert ((objnode *) ((DenemoMeasure*)curmeasure->data)->objects, newkey = dnm_newkeyobj ((tokey - mode), isminor, mode), si->cursor_x);
154                     else
155                     {
156                         if(si->cursor_x<2)
157                             ((DenemoMeasure*)curmeasure->data)->objects = g_list_prepend ((objnode *) ((DenemoMeasure*)curmeasure->data)->objects, newkey = dnm_newkeyobj ((tokey - mode), isminor, mode));
158                         else
159                             ((DenemoMeasure*)curmeasure->data)->objects = g_list_append ((objnode *) ((DenemoMeasure*)curmeasure->data)->objects, newkey = dnm_newkeyobj ((tokey - mode), isminor, mode));
160                     }
161                     newkey->keysig = newkey->object;
162                     cache_measure (curmeasure); //to give the new keysig cached values
163                     update_keysig_cache (curmeasure, g_list_find (((DenemoMeasure*)curmeasure->data)->objects, newkey));  //to update everything beyond the newkey
164                     if (curmeasure == si->currentmeasure)
165                         si->currentobject = g_list_nth ((objnode *) ((DenemoMeasure*)curmeasure->data)->objects, si->cursor_x);
166                     staff_show_which_accidentals ((DenemoStaff *) curstaff->data);
167                 }
168             }                   /* End for all staffs*/
169         }                       /* End if check button all staffs*/
170       else
171         {
172           object_insert (Denemo.project, newkey = dnm_newkeyobj (tokey - mode, isminor, mode));
173           newkey->keysig = newkey->object;
174           cache_measure (si->currentmeasure); //to give the new keysig cached values
175           update_keysig_cache (si->currentmeasure, g_list_find (((DenemoMeasure*)si->currentmeasure->data)->objects, newkey)); //to update everything beyond the newkey
176           staff_show_which_accidentals ((DenemoStaff *) si->currentstaff->data);
177         }
178       si->cursor_appending = FALSE;
179       if (newkey)
180         {
181             adjust_tonal_center (((keysig *) (newkey->object))->accs);
182         }
183     }                           /* End if valid key*/
184 }
185 //static void sensitize_ok_button (keysig_data *data) {
186   //   gtk_widget_set_sensitive (data->okbutton, TRUE);
187 //}
188 /**
189  * Update the keysig dialogs combobox with the
190  * major keys
191  */
192 void
majorcallback(GtkWidget * widget,struct keysig_data * data)193 majorcallback (GtkWidget * widget, struct keysig_data *data)
194 {
195 //  sensitize_ok_button (data);
196   gtk_widget_hide (data->minorkeycombo);
197   gtk_widget_show (data->majorkeycombo);
198 }
199 
200 /**
201  * Update the keysig dialogs combobox with the
202  * minor keys
203  */
204 void
minorcallback(GtkWidget * widget,struct keysig_data * data)205 minorcallback (GtkWidget * widget, struct keysig_data *data)
206 {
207 //  sensitize_ok_button (data);
208   gtk_widget_hide (data->majorkeycombo);
209   gtk_widget_show (data->minorkeycombo);
210 }
211 
212 /* interprets the scheme_string to set key number and isminor value
213  */
214 static gboolean
key_from_string(GString * scheme_string,gint * tokey,gint * isminor)215 key_from_string (GString * scheme_string, gint * tokey, gint * isminor)
216 {
217 
218   gchar *upper = g_ascii_strup (scheme_string->str, scheme_string->len);
219   gint UNSET = G_MININT;
220   gint length = 0;
221   *isminor = (g_strstr_len (upper, -1, "MINOR")) ? 1 : 0;
222   //g_debug("upper %s, scheme %s\n", upper, scheme_string->str);
223 
224   gchar **keystosearch = (*isminor ? uminorkeys : umajorkeys);
225   gint i;
226   for (*tokey = UNSET, i = 0; i < 15; i++)
227     if (g_strstr_len (upper, -1, keystosearch[i]))
228       {
229         if (strlen (keystosearch[i]) > length)
230           {
231             *tokey = i - KEYNAME_ARRAY_OFFSET;
232             length = strlen (keystosearch[i]);
233           }
234       }
235 
236   g_free (upper);
237   if (*tokey != UNSET)
238     return TRUE;
239   return FALSE;
240 }
241 
242 /**
243  * callback for inserting a keysig change
244  *  calls key_change with the INSERT argument
245  * if called with action==NULL inserts the keychange from the GString param
246  * and returns the key in it
247  */
248 void
key_change_insert(GtkAction * action,DenemoScriptParam * param)249 key_change_insert (GtkAction * action, DenemoScriptParam * param)
250 {
251   GET_1PARAM (action, param, keyname);
252   DenemoProject *gui = Denemo.project;
253   DenemoStaff *curstaffstruct = (DenemoStaff *) gui->movement->currentstaff->data;
254   if (keyname == NULL)
255     key_change (gui, INSERT);
256   else
257     {
258       gint tokey, isminor;
259       GString *scheme_str = g_string_new (keyname);
260       gboolean valid = key_from_string (scheme_str, &tokey, &isminor);
261       g_string_free (scheme_str, TRUE);
262       if (valid)
263         {
264           object_insert (gui, dnm_newkeyobj (tokey, isminor, 0));
265           staff_show_which_accidentals (gui->movement->currentstaff->data);
266           displayhelper (gui);
267         }
268       gchar *key;
269       isminor = 0;
270       gboolean number;
271       // FIXME try to find the previous keysig object, else return initial keysig
272       /* if currentobject is keysig change return the keysig */
273       DenemoObject *curobj = (DenemoObject *) Denemo.project->movement->currentobject->data;
274       if (curobj && curobj->type == KEYSIG)
275         {
276           isminor = ((keysig *) curobj->object)->isminor;
277           number = ((keysig *) curobj->object)->number + KEYNAME_ARRAY_OFFSET;
278         }
279       else
280         {
281           isminor = (curstaffstruct->keysig.isminor == 1);
282           number = curstaffstruct->keysig.number + KEYNAME_ARRAY_OFFSET;
283         }
284       /* return initial key */
285       if (isminor)
286         key = g_strdup_printf ("%s %s", minorkeys[number], "Minor");
287       else
288         key = g_strdup_printf ("%s %s", majorkeys[number], "Major");
289       g_string_assign (param->string, key);
290       g_free (key);
291     }
292 }
293 
294 /**
295  * callback for changing the initial keysig
296  *  calls key_change with the CHANGEINITIAL argument
297  */
298 void
key_change_initial(GtkAction * action,DenemoScriptParam * param)299 key_change_initial (GtkAction * action, DenemoScriptParam * param)
300 {
301   GET_1PARAM (action, param, keyname);
302   DenemoProject *gui = Denemo.project;
303   DenemoStaff *curstaffstruct = (DenemoStaff *) gui->movement->currentstaff->data;
304   if (keyname == NULL)
305     key_change (gui, CHANGEINITIAL);
306   else
307     {
308       gint tokey, isminor;
309       GString *scheme_str = g_string_new (keyname);
310       gboolean valid = key_from_string (scheme_str, &tokey, &isminor);
311       g_string_free (scheme_str, TRUE);
312       if (valid)
313         {
314           dnm_setinitialkeysig (curstaffstruct, tokey, isminor);
315           displayhelper (gui);
316         }
317 
318       gchar *key;
319       if (curstaffstruct->keysig.isminor == 1)
320         key = g_strdup_printf ("%s %s", minorkeys[curstaffstruct->keysig.number + KEYNAME_ARRAY_OFFSET], "Minor");
321       else
322         key = g_strdup_printf ("%s %s", majorkeys[curstaffstruct->keysig.number + KEYNAME_ARRAY_OFFSET], "Major");
323       g_string_assign (param->string, key);
324       g_free (key);
325 
326     }
327 }
328 
329 static void
button_response(GtkWidget * dialog,gint response_id,keysig_data * data)330 button_response (GtkWidget * dialog, gint response_id, keysig_data * data)
331 {
332   DenemoProject *gui = Denemo.project;
333   if (response_id == GTK_RESPONSE_ACCEPT)
334     {
335       if (data->initial)
336         set_keysig (data);
337       else
338         {
339           if (gui->movement->currentobject && ((DenemoObject *) gui->movement->currentobject->data)->type == KEYSIG)
340             deleteobject (NULL, NULL);
341           insert_keysig (data);
342         }
343       score_status (gui, TRUE);
344       displayhelper (gui);
345     }
346   gtk_widget_destroy (dialog);
347   g_free (data);
348 }
349 
350 /**
351  * Key sig change dialog
352  * Allows user to select key from a drop down list
353  *
354  */
355 void
key_change(DenemoProject * gui,actiontype action)356 key_change (DenemoProject * gui, actiontype action)
357 {
358   GtkWidget *dialog;
359   gboolean initial = action == CHANGEINITIAL ? TRUE : FALSE;
360   /* GUI setup */
361   dialog = gtk_dialog_new_with_buttons (_("Key Signature Change"), GTK_WINDOW (Denemo.window), (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), _("_OK"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
362  // GtkWidget *okbutton = gtk_dialog_add_button (GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_ACCEPT);
363   //gtk_widget_set_sensitive (okbutton, FALSE);
364   if (action == CHANGEINITIAL)
365     gtk_window_set_title (GTK_WINDOW (dialog), _("Change initial key signature"));
366   else
367     gtk_window_set_title (GTK_WINDOW (dialog), _("Insert key signature change"));
368 
369   GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
370   GtkWidget *vbox = gtk_vbox_new (FALSE, 1);
371   gtk_container_add (GTK_CONTAINER (content_area), vbox);
372 
373   keysig_data *keysig_widgets = (keysig_data *) g_malloc0 (sizeof (keysig_data));
374 //  keysig_widgets->okbutton = okbutton;
375   GtkWidget *label;
376   GtkWidget *radiobutton1, *radiobutton2;
377   GtkWidget *checkbutton;
378 
379   static GList *majorlist = NULL;
380   static GList *minorlist = NULL;
381 
382   gint i;
383   if (majorlist == NULL)
384     {
385       for (i = 0; i < G_N_ELEMENTS (majorkeys); i++)
386         majorlist = g_list_append (majorlist, majorkeys[i]);
387       for (i = 0; i < G_N_ELEMENTS (minorkeys); i++)
388         minorlist = g_list_append (minorlist, minorkeys[i]);
389     }
390 #if GTK_MAJOR_VERSION==3
391   GtkWidget *majorkeycombo = gtk_combo_box_text_new ();
392   GtkWidget *minorkeycombo = gtk_combo_box_text_new ();
393   for (i = 0; i < G_N_ELEMENTS (majorkeys); i++)
394     gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (majorkeycombo), majorkeys[i]);
395   for (i = 0; i < G_N_ELEMENTS (minorkeys); i++)
396     gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (minorkeycombo), minorkeys[i]);
397 #else
398   GtkWidget *majorkeycombo = gtk_combo_new ();
399   gtk_combo_set_popdown_strings (GTK_COMBO (majorkeycombo), majorlist);
400   GtkWidget *minorkeycombo = gtk_combo_new ();
401   gtk_combo_set_popdown_strings (GTK_COMBO (minorkeycombo), minorlist);
402 #endif
403 //  g_signal_connect_swapped (majorkeycombo, "changed", sensitize_ok_button, keysig_widgets);
404 //  g_signal_connect_swapped (minorkeycombo, "changed", sensitize_ok_button, keysig_widgets);
405   GtkWidget *pack_to_vbox = gtk_vbox_new (FALSE, 1);
406   label = gtk_label_new (_("Select desired key signature"));
407   gtk_container_add (GTK_CONTAINER (pack_to_vbox), label);
408 
409   radiobutton1 = gtk_radio_button_new_with_label (NULL, _("Major"));
410   g_signal_connect (G_OBJECT (radiobutton1), "clicked", G_CALLBACK (majorcallback), keysig_widgets);
411   gtk_container_add (GTK_CONTAINER (pack_to_vbox), radiobutton1);
412 
413   radiobutton2 = gtk_radio_button_new_with_label (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton1)), _("Minor"));
414   g_signal_connect (G_OBJECT (radiobutton2), "clicked", G_CALLBACK (minorcallback), keysig_widgets);
415   gtk_container_add (GTK_CONTAINER (pack_to_vbox), radiobutton2);
416 
417 #if GTK_MAJOR_VERSION==3
418   gtk_combo_box_set_active (GTK_COMBO_BOX (majorkeycombo), 7);
419   gtk_combo_box_set_active (GTK_COMBO_BOX (minorkeycombo), 7);
420 #endif
421 
422   gtk_container_add (GTK_CONTAINER (pack_to_vbox), majorkeycombo);
423   gtk_container_add (GTK_CONTAINER (pack_to_vbox), minorkeycombo);
424 
425   checkbutton = gtk_check_button_new_with_label (_("Current Staff Only?"));
426   gtk_container_add (GTK_CONTAINER (pack_to_vbox), checkbutton);
427 
428   keysig_widgets->checkbutton = checkbutton;
429   keysig_widgets->radiobutton2 = radiobutton2;
430   keysig_widgets->majorkeycombo = majorkeycombo;
431   keysig_widgets->minorkeycombo = minorkeycombo;
432   keysig_widgets->majorlist = majorlist;
433   keysig_widgets->minorlist = minorlist;
434   keysig_widgets->initial = initial;
435 
436   gtk_widget_grab_focus (majorkeycombo);
437   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton1), TRUE);
438   gtk_widget_hide (keysig_widgets->minorkeycombo);
439   gtk_widget_show (keysig_widgets->majorkeycombo);
440 
441   gtk_container_add (GTK_CONTAINER (vbox), pack_to_vbox);
442   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
443   gtk_widget_show_all (dialog);
444   gtk_widget_hide (keysig_widgets->minorkeycombo);
445 
446   g_signal_connect (dialog, "response", G_CALLBACK (button_response), keysig_widgets);
447 }
448