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