1 /* figure.c
2  *
3  * Functions for the manipulations of figured basses
4  *
5  * for Denemo, a gtk+ frontend for GNU Lilypond
6  * (c) 2003-2006 Richard Shann
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "command/chord.h"
13 #include "display/calculatepositions.h"
14 #include "command/commandfuncs.h"
15 #include "command/contexts.h"
16 #include "command/figure.h"
17 #include "ui/dialogs.h"
18 #include "display/draw.h"
19 #include "command/object.h"
20 #include "command/staff.h"
21 #include "core/utils.h"
22 
23 struct callbackdata
24 {
25   DenemoProject *gui;
26   gchar *string;
27 };
28 
29 
30 
31 
32 /**
33  * Function to actually insert a figure to an object
34  *
35  */
36 static void
insertfigure(gboolean filter,gpointer data)37 insertfigure (gboolean filter, gpointer data)
38 {
39   struct callbackdata *cbdata = (struct callbackdata *) data;
40   DenemoProject *gui = cbdata->gui;
41   DenemoMovement *si = gui->movement;
42   gchar filter_sep = filter ? '/' : '|';
43   gchar filter_spc = filter ? '*' : ' ';
44   if (si->measurewidth == DENEMO_INITIAL_MEASURE_WIDTH)
45     si->measurewidth = DENEMO_INITIAL_MEASURE_WIDTH * 2;
46 
47   if (si->currentobject != NULL)
48     {
49       DenemoObject *curObj = (DenemoObject *) si->currentobject ? (DenemoObject *) si->currentobject->data : NULL;
50       gchar *figure = (cbdata->string);
51       if (strlen (figure) < 1)
52         figure = "_";           /* in case user deleted the figure to yield <> */
53       /* translate the input somewhat */
54       GString *f = g_string_new ("");
55       gchar *c = figure;
56       for (c = figure; *c; c++)
57         {
58           if (*c == '+')
59             {
60               if (c == figure || *(c - 1) == ' ' || *(c - 1) == filter_spc || *(c - 1) == '|' || *(c - 1) == filter_sep)
61                 g_string_append (f, "_+");
62               else
63                 g_string_append (f, "+");
64             }
65           else if (*c == '-')
66             {
67               if (c == figure || *(c - 1) == ' ' || *(c - 1) == filter_spc || *(c - 1) == '|' || *(c - 1) == filter_sep)
68                 g_string_append (f, "_-");
69               else
70                 g_string_append (f, "-");
71             }
72           else if (*c == filter_sep)
73             g_string_append (f, "|");
74           else
75             {
76               if (*c == filter_spc)
77                 g_string_append (f, " ");
78               else
79                 g_string_append_c (f, *c);
80             }
81         }
82 
83       if (curObj && curObj->type == CHORD)
84         ((chord *) curObj->object)->is_figure = TRUE;
85             if(((chord *) curObj->object)->figure)
86                 g_string_free (((chord *) curObj->object)->figure, TRUE);
87       ((chord *) curObj->object)->figure = g_string_new (f->str);
88       g_string_free (f, TRUE);
89       do
90         {
91           if (si->currentobject->next)
92             movecursorright (NULL, NULL);
93           else if (gui->movement->currentmeasure->next)
94             movetomeasureright (NULL, NULL);
95           else
96             break;
97           curObj = si->currentobject ? (DenemoObject *) si->currentobject->data : NULL;
98         }
99       while ((curObj != NULL) && (curObj->type != CHORD));
100 
101 
102       si->has_figures = (gpointer) TRUE;        //&null_info;
103       score_status (gui, TRUE);
104     }                           // if currentobject not null
105   else
106     {
107       warningdialog (_("No current object to attach a figure to"));
108     }
109 }
110 
111 
112 
113 
114 void
delete_figured_bass(GtkAction * action,DenemoScriptParam * param)115 delete_figured_bass (GtkAction * action, DenemoScriptParam * param)
116 {
117   DenemoProject *gui = Denemo.project;
118   DenemoStaff *thestaff = (DenemoStaff *) gui->movement->currentstaff->data;
119   if (confirm ("Figured Bass Deletion", "Delete all figured bass markings from this staff?"))
120     {
121       thestaff->hasfigures = FALSE;
122       gui->movement->has_figures = FALSE;
123       score_status (gui, TRUE);
124       measurenode *curmeasure;
125       for (curmeasure = thestaff->themeasures; curmeasure; curmeasure = curmeasure->next)
126         {
127           objnode *curobj;
128           for (curobj = ((DenemoMeasure*)curmeasure->data)->objects; curobj; curobj = curobj->next)
129             {
130               DenemoObject *curObj = (DenemoObject *) curobj->data;
131               if (curObj && curObj->type == CHORD)
132                 {
133                   GString *s = ((chord *) curObj->object)->figure;
134                   if (s)
135                     g_string_free (s, TRUE);
136                   ((chord *) curObj->object)->figure = NULL;
137                 }
138             }
139         }
140     }
141 }
142 
143 void
hide_figured_bass(GtkAction * action,DenemoScriptParam * param)144 hide_figured_bass (GtkAction * action, DenemoScriptParam * param)
145 {
146   DenemoProject *gui = Denemo.project;
147   DenemoStaff *thestaff = (DenemoStaff *) gui->movement->currentstaff->data;
148   thestaff->hasfigures = FALSE;
149 }
150 
151 /* turn on figured bass if any figures are present */
152 void
show_figured_bass(GtkAction * action,DenemoScriptParam * param)153 show_figured_bass (GtkAction * action, DenemoScriptParam * param)
154 {
155   DenemoProject *gui = Denemo.project;
156   DenemoStaff *thestaff = (DenemoStaff *) gui->movement->currentstaff->data;
157   measurenode *curmeasure;
158   for (curmeasure = thestaff->themeasures; curmeasure; curmeasure = curmeasure->next)
159     {
160       objnode *curobj;
161       for (curobj = ((DenemoMeasure*)curmeasure->data)->objects; curobj; curobj = curobj->next)
162         {
163           DenemoObject *curObj = (DenemoObject *) curobj->data;
164           if (curObj && curObj->type == CHORD)
165             {
166               GString *s = ((chord *) curObj->object)->figure;
167               if (s)
168                 thestaff->hasfigures = TRUE;
169             }
170         }
171     }
172 }
173 
174 /**
175  * Creates figured bass entry dialog
176  *
177  */
178 void
figure_insert(GtkAction * action,DenemoScriptParam * param)179 figure_insert (GtkAction * action, DenemoScriptParam * param)
180 {
181   DenemoProject *gui = Denemo.project;
182   gchar *string = NULL;
183   gchar *PreValue = NULL;
184   DenemoMovement *si = gui->movement;
185   static struct callbackdata cbdata;
186   DenemoObject *curObj = (DenemoObject *) si->currentobject ? (DenemoObject *) si->currentobject->data : NULL;
187   if (curObj==NULL) return;
188   if (curObj->type != CHORD) return;
189   if (curObj && curObj->type == CHORD && ((chord *) curObj->object)->figure)
190     PreValue = ((GString *) ((chord *) curObj->object)->figure)->str;
191 
192   if (!action && param && param->string)
193     {                           //Called from scheme, could be "query" or setting the values
194       GString *values = param->string;
195       gchar *str;
196       gint i;
197       if (!strcmp (values->str, "query"))
198         {
199           if (PreValue && *PreValue && strcmp (PreValue, "_"))
200             {                   //there is a figure, other than the "no figure" sign
201               param->status = TRUE;
202               g_string_assign (param->string, PreValue);
203             }
204           else                  //the no figure case leave status FALSE and return NULL
205             g_string_assign (param->string, "");
206         }
207       else                      //detect the string "figures" followed by a separator character and then the figures
208         for (i = 0; i < values->len; i += strlen (values->str + i) + 1)
209           {
210             if ((str = g_strstr_len (values->str + i, strlen (values->str + i), "figures")))
211               {
212                 string = g_strdup (str + strlen ("figures") + 1);
213                 break;
214               }
215           }
216     }
217   else
218     {                           //interactive
219       string = string_dialog_entry (gui, "Insert/Edit Figure", "Give figures followed by Enter key", PreValue);
220     }
221   cbdata.gui = gui;
222   cbdata.string = string;
223 
224   if (string)
225     {
226       insertfigure (action != NULL, &cbdata);
227       //also \set Staff.useBassFigureExtenders = ##t
228       if (!((DenemoStaff *) si->currentstaff->data)->hasfigures)
229         {
230           signal_structural_change (gui);
231           ((DenemoStaff *) si->currentstaff->data)->hasfigures = TRUE;
232         }
233       displayhelper (gui);
234     }
235   g_free (string);
236 }
237