1 // scorelayout.c
2 //
3 // Copyright 2012 Richard Shann
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 // MA 02110-1301, USA.
19
20 #include <string.h>
21 #include "command/scorelayout.h"
22 #include "export/exportlilypond.h"
23 #include "core/utils.h"
24 #include "export/print.h"
25 #include "printview/printview.h"
26 #include "command/score.h"
27 #include "command/processstaffname.h"
28 #include "core/view.h"
29
30
31
32 #define LILYPOND_TEXT_EDITOR _("LilyPond text editor")
33 #define DEFAULT_SCORE_LAYOUT _("Default Score Layout")
34 static void set_notebook_page (GtkWidget * w);
35 static void prefix_edit_callback (GtkWidget * widget, GtkWidget * frame);
36 static void create_element (GtkWidget * vbox, GtkWidget * widget, gchar * lilypond);
37 static void create_standard_scoreblock (DenemoScoreblock ** psb, gint movement, gchar * partname);
38 static void recreate_standard_scoreblock (DenemoScoreblock ** psb);
39 static DenemoScoreblock *get_standard_scoreblock (GtkWidget * widget);
40 static GtkWidget *get_options_button (DenemoScoreblock * sb, gboolean custom);
41 static void install_duplicate_movement_callback (DenemoScoreblock *sb);
42 static void reorder_movement_callback (DenemoScoreblock * psb);
43 static gboolean edit_lilypond_prefix (GtkWidget * widget, gchar * oldval, gchar * newval);
44 static void reload_scorewide_block (GtkWidget *frame);
45 static gint layout_sync;
46
47 // Reverses (reflects) bits in a 32-bit word.
48 static guint32
bit_reverse(guint32 x)49 bit_reverse (guint32 x)
50 {
51 x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
52 x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
53 x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
54 x = (x << 24) | ((x & 0xFF00) << 8) | ((x >> 8) & 0xFF00) | (x >> 24);
55 return x;
56 }
57
58 /* This is the basic CRC algorithm with no optimizations. It follows the
59 logic circuit as closely as possible. */
60 //returns a 32 bit crc for the passed string
61 static guint32
crc32(guchar * message)62 crc32 (guchar * message)
63 {
64 int i, j;
65 guint32 byte, crc;
66 i = 0;
67 crc = 0xFFFFFFFF;
68 while (message[i] != 0)
69 {
70 byte = message[i]; // Get next byte.
71 byte = bit_reverse (byte); // 32-bit reversal.
72 for (j = 0; j <= 7; j++)
73 { // Do eight times.
74 if ((int) (crc ^ byte) < 0)
75 crc = (crc << 1) ^ 0x04C11DB7;
76 else
77 crc = crc << 1;
78 byte = byte << 1; // Ready next msg bit.
79 }
80 i = i + 1;
81 }
82 return bit_reverse (~crc);
83 }
84
85 static guint
get_location(guint movementnum,guint voicecount)86 get_location (guint movementnum, guint voicecount)
87 {
88 return (movementnum << 16) | voicecount;
89 }
90
91 static void
navigate_to_location(GtkWidget * w,guint location)92 navigate_to_location (GtkWidget * w, guint location)
93 {
94 guint movementnum = location >> 16;
95 guint staffnum = location & 0xFFFF;
96 goto_movement_staff_obj (NULL, movementnum, staffnum, 1, 0, 0);
97 }
98
99 static void
popup_staff_groups_menu(GtkWidget * button)100 popup_staff_groups_menu (GtkWidget * button)
101 {
102 GtkWidget *menuitem = gtk_ui_manager_get_widget (Denemo.ui_manager, "/ObjectMenu/StaffMenu/StaffGroupings");
103 if (get_standard_scoreblock (button))
104 {
105 if (menuitem)
106 gtk_menu_popup (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem))), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
107 else
108 g_warning ("No such menu path");
109 }
110 else
111 warningdialog (_("This button is for changing the score itself, it will not affect this custom layout"));
112 }
113
114 static void
staff_groups_menu(GtkWidget * w,GdkEvent * event,guint location)115 staff_groups_menu (GtkWidget * w, GdkEvent * event, guint location)
116 {
117 navigate_to_location (NULL, location);
118 popup_staff_groups_menu (w);
119 }
120
121 //callback on destroying widgets that are on the staff_list of a scoreblock.
122 static gboolean
remove_from_staff_list(GtkWidget * widget,GList ** g)123 remove_from_staff_list (GtkWidget * widget, GList ** g)
124 {
125 *g = g_list_remove (*g, widget);
126 return TRUE; //that is go on to destroy the widget
127 }
128
129 //free the passed DenemoScoreblock structure for re-use or disposal
130 static void
free_scoreblock(DenemoScoreblock * sb)131 free_scoreblock (DenemoScoreblock * sb)
132 {
133 if (sb->widget)
134 gtk_widget_destroy (sb->widget); //FIXME free lilypond attached to widgets
135 sb->widget = 0;
136 if (sb->lilypond)
137 g_string_free ((GString *) (sb->lilypond), TRUE);
138 g_free (sb->instrumentation);
139 sb->instrumentation = NULL;
140 sb->lilypond = NULL;
141 }
142
143 void
free_scoreblocks(DenemoProject * gui)144 free_scoreblocks (DenemoProject * gui)
145 {
146 if (gui->standard_scoreblocks)
147 {
148 GList *g;
149 for (g = gui->standard_scoreblocks; g; g = g->next)
150 {
151 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
152 free_scoreblock (sb);
153 }
154 g_list_free (gui->standard_scoreblocks);
155 gui->standard_scoreblocks = NULL;
156 }
157 if (gui->custom_scoreblocks)
158 {
159 GList *g;
160 for (g = gui->custom_scoreblocks; g; g = g->next)
161 {
162 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
163 free_scoreblock (sb);
164 }
165 g_list_free (gui->custom_scoreblocks);
166 gui->custom_scoreblocks = NULL;
167 }
168 }
169
170
171
172 static gboolean
is_in_standard_scoreblock(DenemoScoreblock * sb)173 is_in_standard_scoreblock (DenemoScoreblock * sb)
174 {
175 return (g_list_find (Denemo.project->standard_scoreblocks, sb) != NULL);
176 }
177
178
179 static gboolean
free_prefix_and_postfix(GtkWidget * widget)180 free_prefix_and_postfix (GtkWidget * widget)
181 {
182 // glib 2.28 and greater can use:
183 //g_list_free_full(g_object_get_data(G_OBJECT(widget), "prefix"), (GDestroyNotify)g_free);
184 //g_list_free_full(g_object_get_data(G_OBJECT(widget), "postfix"), (GDestroyNotify)g_free);
185 GList *g = g_object_get_data (G_OBJECT (widget), "prefix");
186 g_list_foreach (g, (GFunc) (g_free), NULL);
187 g_list_free (g);
188 g = g_object_get_data (G_OBJECT (widget), "postfix");
189 g_list_foreach (g, (GFunc) (g_free), NULL);
190 g_list_free (g);
191 return TRUE; //and destroy widget
192 }
193
194 // attaches the two lilypond strings to the prefix and postfix lists of widget
195 // prefix is created in the reverse order to postfix so they can nest
196 // the destroy widget is arranged to free the lists
197 static void
add_lilypond(GtkWidget * w,gchar * prefix,gchar * postfix)198 add_lilypond (GtkWidget * w, gchar * prefix, gchar * postfix)
199 {
200 if (g_object_get_data (G_OBJECT (w), "prefix") == NULL && g_object_get_data (G_OBJECT (w), "postfix") == NULL)
201 g_signal_connect (G_OBJECT (w), "destroy", G_CALLBACK (free_prefix_and_postfix), NULL);
202
203 if (prefix)
204 g_object_set_data (G_OBJECT (w), "prefix", (gpointer) g_list_append (g_object_get_data (G_OBJECT (w), "prefix"), prefix));
205 if (postfix)
206 g_object_set_data (G_OBJECT (w), "postfix", (gpointer) g_list_prepend (g_object_get_data (G_OBJECT (w), "postfix"), postfix));
207 }
208
209 static gchar *
get_voicetag(gint movementnum,gint voice_count)210 get_voicetag (gint movementnum, gint voice_count)
211 {
212 GString *str = g_string_new ("");
213 GString *name = g_string_new ("");
214 g_string_printf (str, "Voice%d Mvmnt%d", voice_count, movementnum);
215 set_lily_name (str, name);
216 g_string_free (str, TRUE);
217 return g_string_free (name, FALSE);
218 }
219
220 static gchar *
get_voicename(gint movementnum,gint voice_count)221 get_voicename (gint movementnum, gint voice_count)
222 {
223 GString *str = g_string_new ("");
224 GString *name = g_string_new ("");
225 g_string_printf (str, "Mvmnt%d Voice%d", movementnum, voice_count);
226 set_lily_name (str, name);
227 g_string_free (str, TRUE);
228 return g_string_free (name, FALSE);
229 }
230
231
232 static gchar *
get_versename(gint movementnum,gint voice_count,gint versenum)233 get_versename (gint movementnum, gint voice_count, gint versenum)
234 {
235 GString *str = g_string_new ("");
236 GString *name = g_string_new ("");
237 g_string_printf (str, "Mvmnt%d Voice%d Verse%d", movementnum, voice_count, versenum);
238 set_lily_name (str, name);
239 g_string_free (str, TRUE);
240 return g_string_free (name, FALSE);
241 }
242
243 //Change the name of the scoreblock to user given value
244 static gboolean
name_scoreblock(DenemoScoreblock * sb,gchar * name)245 name_scoreblock (DenemoScoreblock * sb, gchar * name)
246 {
247 gchar *value;
248 if (name == NULL)
249 value = string_dialog_entry (Denemo.project, _("New Score Layout"), _("Give a name for this new score layout"), _("Custom Layout"));
250 else
251 value = name;
252 if (value)
253 {
254 sb->name = g_strdup (value);
255 gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (get_score_layout_notebook (Denemo.project)), sb->widget, value);
256 //FIXME if name==NULL g_free(value) I think.
257 return TRUE;
258 }
259 else
260 return FALSE;
261 }
262
263 //gets the toplevel standard DenemoScoreblock which contains the passed in widget, or NULL if not in the standard scoreblocks
264 static DenemoScoreblock *
get_standard_scoreblock(GtkWidget * widget)265 get_standard_scoreblock (GtkWidget * widget)
266 {
267 GList *g;
268 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
269 {
270 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
271 if (sb->widget && gtk_widget_is_ancestor (widget, sb->widget))
272 return sb;
273 }
274 return NULL;
275 }
276
277 //gets the toplevel custom DenemoScoreblock which contains the passed in widget, or NULL if not in the custom scoreblocks
278 /* UNUSED
279 static DenemoScoreblock *
280 get_custom_scoreblock (GtkWidget * widget)
281 {
282 GList *g;
283 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
284 {
285 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
286 if (sb->widget && gtk_widget_is_ancestor (widget, sb->widget))
287 return sb;
288 }
289 return NULL;
290 }
291 */
292 static gboolean
is_lilypond_text_layout(DenemoScoreblock * sb)293 is_lilypond_text_layout (DenemoScoreblock * sb)
294 {
295 return sb->text_only;
296 //return sb->widget && GTK_IS_FRAME(sb->widget) && gtk_frame_get_label(GTK_FRAME(sb->widget)) && !strcmp(gtk_frame_get_label(GTK_FRAME(sb->widget)), LILYPOND_TEXT_EDITOR);
297 }
298
299 static void
open_lilypond_window_callback(void)300 open_lilypond_window_callback (void)
301 {
302 if (Denemo.textwindow && !gtk_widget_get_visible (Denemo.textwindow))
303 activate_action ("/MainMenu/ViewMenu/ToggleLilyText");
304 }
305
306 static void
convert_to_lilypond_callback(GtkWidget * widget,DenemoScoreblock * sb)307 convert_to_lilypond_callback (GtkWidget * widget, DenemoScoreblock * sb)
308 {
309 refresh_lilypond (sb);
310 DenemoScoreblock *newsb = get_scoreblock_for_lilypond (sb->lilypond->str);
311 Denemo.project->custom_scoreblocks = g_list_remove (Denemo.project->custom_scoreblocks, sb);
312 Denemo.project->standard_scoreblocks = g_list_remove (Denemo.project->standard_scoreblocks, sb);
313 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
314 GtkWidget *label = gtk_label_new (sb->name);
315 if (sb->widget)
316 gtk_widget_destroy (sb->widget);
317 gtk_widget_show_all (newsb->widget);
318 gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), newsb->widget, label);
319 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
320 Denemo.project->custom_scoreblocks = g_list_append (Denemo.project->custom_scoreblocks, newsb);
321 Denemo.project->layout_id = 0;
322 }
323
324 static void
delete_custom_scoreblock_callback(GtkWidget * dummy,DenemoScoreblock * sb)325 delete_custom_scoreblock_callback (GtkWidget * dummy, DenemoScoreblock * sb)
326 {
327 Denemo.project->custom_scoreblocks = g_list_remove (Denemo.project->custom_scoreblocks, sb);
328 gtk_widget_destroy (sb->widget);
329 if(Denemo.project->standard_scoreblocks==NULL && Denemo.project->custom_scoreblocks==NULL)
330 create_default_scoreblock ();
331 score_status (Denemo.project, TRUE);
332 }
333
334 static void
delete_standard_scoreblock_callback(GtkWidget * widget,DenemoScoreblock * sb)335 delete_standard_scoreblock_callback (GtkWidget * widget, DenemoScoreblock * sb)
336 {
337 Denemo.project->standard_scoreblocks = g_list_remove (Denemo.project->standard_scoreblocks, sb);
338 gtk_widget_destroy (sb->widget);
339 if(Denemo.project->standard_scoreblocks==NULL && Denemo.project->custom_scoreblocks==NULL)
340 create_default_scoreblock ();
341 score_status (Denemo.project, TRUE);
342 }
343
344 static void
recreate_standard_scoreblock_callback(GtkWidget * widget,DenemoScoreblock * psb)345 recreate_standard_scoreblock_callback (GtkWidget * widget, DenemoScoreblock * psb)
346 {
347 recreate_standard_scoreblock (&psb);
348 }
349
350 static gboolean
customize_scoreblock(DenemoScoreblock * sb,gchar * name)351 customize_scoreblock (DenemoScoreblock * sb, gchar * name)
352 {
353 if (is_lilypond_text_layout (sb))
354 {
355 DenemoScoreblock *newsb = get_scoreblock_for_lilypond (sb->lilypond->str);
356 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
357 name_scoreblock (newsb, name);
358 GtkWidget *label = gtk_label_new (newsb->name);
359 gtk_widget_show_all (newsb->widget);
360 gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), newsb->widget, label);
361 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
362 Denemo.project->custom_scoreblocks = g_list_append (Denemo.project->custom_scoreblocks, newsb);
363 Denemo.project->layout_id = 0;
364 gchar *new_name = g_strdup_printf ("%%%s\n", newsb->name);
365 g_string_prepend (newsb->lilypond, new_name);
366 g_free (new_name);
367 g_string_append_printf (newsb->lilypond, "\n\\header {DenemoLayoutName = \"%s\"}\n", newsb->name);
368 score_status (Denemo.project, TRUE);
369 }
370 else if (name_scoreblock (sb, name))
371 {
372 g_free (sb->partname);
373 sb->partname = NULL;
374 sb->movement = 0;
375 if (sb->lilypond)
376 g_string_free (sb->lilypond, TRUE);
377 sb->lilypond = NULL;
378 Denemo.project->standard_scoreblocks = g_list_remove (Denemo.project->standard_scoreblocks, sb);
379 Denemo.project->custom_scoreblocks = g_list_append (Denemo.project->custom_scoreblocks, sb);
380 score_status (Denemo.project, TRUE);
381 }
382 else
383 {
384 return FALSE;
385 }
386 return TRUE;
387 }
388
389 #if 0
390 //having buttons that affect the score itself is confusing
391 /* go through the layout deleting score block elements that are marked standard as they are not needed for a custom scoreblock*/
392 static void
393 prune_layout (GtkWidget * layout)
394 {
395 if (GTK_IS_CONTAINER (layout))
396 {
397 GList *g = gtk_container_get_children (GTK_CONTAINER (layout));
398 if (g)
399 do
400 {
401 prune_layout (g->data);
402 }
403 while ((g = g->next));
404 }
405 if (g_object_get_data (G_OBJECT (layout), "standard"))
406 gtk_widget_destroy (layout);
407 }
408 #endif
409 static DenemoScoreblock *
clone_scoreblock(DenemoScoreblock * sb,gchar * name)410 clone_scoreblock (DenemoScoreblock * sb, gchar * name)
411 {
412 gchar *partname = g_strdup (sb->partname);
413 //prune_layout (sb->widget);
414 GtkWidget *options = get_options_button (sb, TRUE);
415 gtk_widget_show_all (options);
416 GtkWidget *viewport = gtk_bin_get_child (GTK_BIN (sb->widget));
417 GList *children = gtk_container_get_children (GTK_CONTAINER (viewport));
418 GtkWidget *vbox = children->data;
419 GList *grandchildren = gtk_container_get_children (GTK_CONTAINER (vbox));
420 gtk_container_remove (GTK_CONTAINER (vbox), grandchildren->data);
421 gtk_box_pack_start (GTK_BOX (vbox), options, FALSE, FALSE, 0);
422 gtk_box_reorder_child (GTK_BOX (vbox), options, 0);
423 if (customize_scoreblock (sb, name))
424 {
425 #if 0
426 DenemoScoreblock *newsb = g_malloc0 (sizeof (DenemoScoreblock));
427 create_standard_scoreblock (&newsb, movement, partname);
428 Denemo.project->standard_scoreblocks = g_list_prepend (Denemo.project->standard_scoreblocks, newsb);
429 Denemo.project->lilysync = G_MAXUINT;
430 Denemo.project->layout_id = 0;
431 gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (Denemo.project->score_layout))));
432 return newsb;
433 #else
434 g_free (partname);
435 return sb;
436 #endif
437 }
438 else
439 {
440 g_free (partname);
441 return NULL;
442 }
443 }
444
445 static void
customize_standard_scoreblock_callback(GtkWidget * widget,DenemoScoreblock * sb)446 customize_standard_scoreblock_callback (GtkWidget * widget, DenemoScoreblock * sb)
447 {
448 if(confirm (_("Customize Layout"), _("Replace Standard Layout?")))
449 { static gboolean warned;
450 clone_scoreblock (sb, sb->name);
451 if(!warned)
452 infodialog (_("This layout will be used in place of the standard one, unless you delete it.\nAny new staffs added to the score will not appear in it unless you edit it."));
453 warned = TRUE;
454 } else
455 clone_scoreblock (sb, NULL);
456 }
457
458 static void
duplicate_lilypond_scoreblock_callback(GtkWidget * widget,DenemoScoreblock * sb)459 duplicate_lilypond_scoreblock_callback (GtkWidget * widget, DenemoScoreblock * sb)
460 {
461 customize_scoreblock (sb, NULL);
462 }
463 #if 0
464 //having buttons that affect the score itself is confusing
465 //Mark the passed widget as being for standard layouts only
466 static void
467 mark_as_non_custom (GtkWidget * button)
468 {
469 GdkColor color;
470 if (gdk_color_parse ("#B0A090", &color))
471 gtk_widget_modify_bg (button, GTK_STATE_NORMAL, &color);
472 g_object_set_data (G_OBJECT (button), "standard", (gpointer) 1);
473 }
474 #endif
475
476 static GtkWidget *
get_options_button(DenemoScoreblock * sb,gboolean custom)477 get_options_button (DenemoScoreblock * sb, gboolean custom)
478 {
479 GtkWidget *frame = gtk_frame_new (_("Actions for this Layout"));
480 GtkWidget *hbox = gtk_hbox_new (FALSE, 8);
481 gtk_container_add (GTK_CONTAINER (frame), hbox);
482
483 GtkWidget *button = gtk_button_new_with_label (_("Typeset"));
484 gtk_widget_set_tooltip_text (button, _("Typeset the score using this layout to determine which movements, parts, titles, page breaks etc should be used"));
485 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
486 #ifdef USE_EVINCE
487 g_signal_connect (button, "clicked", G_CALLBACK (show_print_view), NULL);
488 #endif
489 if (custom)
490 {
491 if (sb->text_only)
492 {
493 button = gtk_button_new_with_label (_("Edit LilyPond Text of Layout"));
494 gtk_widget_set_tooltip_text (button, _("Opens the LilyPond window for further editing."));
495 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
496 g_signal_connect (button, "clicked", G_CALLBACK (open_lilypond_window_callback), sb);
497 button = gtk_button_new_with_label (_("Duplicate"));
498 gtk_widget_set_tooltip_text (button, _("Create a duplicate of this layout."));
499 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
500 g_signal_connect (button, "clicked", G_CALLBACK (duplicate_lilypond_scoreblock_callback), sb);
501
502
503 }
504 else
505 {
506 button = gtk_button_new_with_label (_("Convert to LilyPond Text"));
507 gtk_widget_set_tooltip_text (button, _("Converts this layout to LilyPond text for further editing."));
508 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
509 g_signal_connect (button, "clicked", G_CALLBACK (convert_to_lilypond_callback), sb);
510
511 }
512 button = gtk_button_new_with_label (_("Delete"));
513 gtk_widget_set_tooltip_text (button, _("Discard this customized score layout."));
514 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
515 g_signal_connect (button, "clicked", G_CALLBACK (delete_custom_scoreblock_callback), sb);
516
517 button = gtk_button_new_with_label (_("Create Default Score Layout"));
518 gtk_widget_set_tooltip_text (button, _("Creates the Default Score Layout"));
519 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
520 g_signal_connect (button, "clicked", G_CALLBACK (create_default_scoreblock), NULL);
521
522 if (!sb->text_only)
523 {
524 button = gtk_button_new_with_label (_("Append Current Movement"));
525 gtk_widget_set_tooltip_text (button, _("Appends the current movement at the end of this layout. Select the movement you wish to append to the layout in the Denemo Display first. The same movement can be placed multiple times in the layout, with individual edits as needed."));
526 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
527 g_signal_connect_swapped (button, "clicked", G_CALLBACK (install_duplicate_movement_callback), sb);
528
529 button = gtk_button_new_with_label (_("Re-order Movement"));
530 gtk_widget_set_tooltip_text (button, _("Moves the first expanded movement in this layout to the end.\nThis does not alter the score, just this layout. To re-order the actual movements of the score see the Movements menu."));
531 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
532 g_signal_connect_swapped (button, "clicked", G_CALLBACK (reorder_movement_callback), sb);
533 }
534 }
535 else
536 {
537 button = gtk_button_new_with_label (_("Refresh"));
538 gtk_widget_set_tooltip_text (button, _("Re-calculate this layout to incorporate changes made to the score structure."));
539 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
540 g_signal_connect (button, "clicked", G_CALLBACK (recreate_standard_scoreblock_callback), sb);
541
542 button = gtk_button_new_with_label (_("Customize"));
543 gtk_widget_set_tooltip_text (button, _("Create a layout from this standard layout that you can then modify."));
544 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
545 g_signal_connect (button, "clicked", G_CALLBACK (customize_standard_scoreblock_callback), sb);
546 button = gtk_button_new_with_label (_("Delete"));
547 gtk_widget_set_tooltip_text (button, _("Discard this standard score layout."));
548 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
549 g_signal_connect (button, "clicked", G_CALLBACK (delete_standard_scoreblock_callback), sb);
550 }
551
552
553 return frame;
554 }
555
556
557
558 //if widget is in a standard scoreblock, clone the scoreblock converting the standard one into a custom one.
559 static gboolean
clone_scoreblock_if_needed(GtkWidget * widget)560 clone_scoreblock_if_needed (GtkWidget * widget)
561 {
562 DenemoScoreblock *default_sb;
563 if ((default_sb = get_standard_scoreblock (widget)))
564 {
565 //the button widget was on the default scoreblock, so we convert this to a custom scoreblock
566 return clone_scoreblock (default_sb, NULL) != NULL;
567 }
568 return TRUE;
569 }
570
571
572 static gboolean
move_parent(GtkWidget * widget,gboolean up)573 move_parent (GtkWidget * widget, gboolean up)
574 {
575 if (!clone_scoreblock_if_needed (widget))
576 return TRUE;
577
578 GtkWidget *parent = gtk_widget_get_parent (widget);
579 GtkWidget *grandparent = gtk_widget_get_parent (parent);
580 GList *children = gtk_container_get_children (GTK_CONTAINER (grandparent));
581 gint position = g_list_index (children, parent);
582 if (up)
583 {
584 if (position > 0)
585 {
586 position--;
587 gtk_box_reorder_child (GTK_BOX (grandparent), parent, position);
588 score_status (Denemo.project, TRUE);
589 }
590 }
591 else
592 {
593 position++;
594 gtk_box_reorder_child (GTK_BOX (grandparent), parent, position);
595 score_status (Denemo.project, TRUE);
596 }
597 return TRUE;
598 }
599
600
601 static gboolean
move_grandparent(GtkWidget * widget,gboolean up)602 move_grandparent (GtkWidget * widget, gboolean up)
603 {
604 if (!clone_scoreblock_if_needed (widget))
605 return TRUE;
606
607 GtkWidget *parent = gtk_widget_get_parent (gtk_widget_get_parent (widget));
608 GtkWidget *grandparent = gtk_widget_get_parent (parent);
609 GList *children = gtk_container_get_children (GTK_CONTAINER (grandparent));
610 gint position = g_list_index (children, parent);
611 if (up)
612 {
613 if (position > 0)
614 {
615 position--;
616 gtk_box_reorder_child (GTK_BOX (grandparent), parent, position);
617 score_status (Denemo.project, TRUE);
618 }
619 }
620 else
621 {
622 position++;
623 gtk_box_reorder_child (GTK_BOX (grandparent), parent, position);
624 score_status (Denemo.project, TRUE);
625 }
626 return TRUE;
627 }
628
629
630 static gboolean
remove_element(GtkWidget * widget)631 remove_element (GtkWidget * widget)
632 {
633 if (!clone_scoreblock_if_needed (widget))
634 return TRUE;
635
636 GtkWidget *parent = gtk_widget_get_parent (widget);
637 gtk_widget_destroy (parent);
638 score_status (Denemo.project, TRUE);
639 return TRUE;
640 }
641
642 static gboolean
remove_parent_element(GtkWidget * widget)643 remove_parent_element (GtkWidget * widget)
644 {
645 if (!clone_scoreblock_if_needed (widget))
646 return TRUE;
647 GtkWidget *parent = gtk_widget_get_parent (gtk_widget_get_parent (widget));
648 gtk_widget_destroy (parent);
649 score_status (Denemo.project, TRUE);
650 return TRUE;
651 }
652
653 static gboolean
remove_lyric_element(GtkWidget * widget,gchar * context_text)654 remove_lyric_element (GtkWidget * widget, gchar * context_text)
655 {
656 if (!clone_scoreblock_if_needed (widget))
657 return TRUE;
658 GtkWidget *parent = gtk_widget_get_parent (widget);
659 GtkWidget *grandparent = gtk_widget_get_parent (parent);
660 gtk_widget_destroy (parent);
661 GList *postfixes = (GList *) g_object_get_data (G_OBJECT (grandparent), "postfix");
662 g_object_set_data (G_OBJECT (grandparent), "postfix", (gpointer) g_list_remove (postfixes, context_text));
663 //free context_text here
664 score_status (Denemo.project, TRUE);
665 return TRUE;
666 }
667
668
substitute_voice_name(GtkWidget * button,GtkWidget * frame)669 static void substitute_voice_name (GtkWidget *button, GtkWidget *frame)
670 {
671 if (!clone_scoreblock_if_needed (frame))
672 return;
673 GList *m;
674 gint mvmnt = 1, staffnum = Denemo.project->movement->currentstaffnum;
675 if (Denemo.project->movements)
676 mvmnt = 1 + g_list_index (Denemo.project->movements, Denemo.project->movement);
677
678 gchar *thename = g_strdup_printf ("\\Mvmnt%dVoice%d", mvmnt, staffnum);
679 GString *initial = g_string_new (thename);
680 g_free (thename);
681 GString *lily = g_string_new ("");
682 set_lily_name (initial, lily);
683 GList *g = g_object_get_data (G_OBJECT (frame), "prefix");
684 if (g)
685 {
686 gchar *oldlily = (gchar *) g->data;
687 edit_lilypond_prefix (frame, oldlily, g_strdup(lily->str));
688 score_status (Denemo.project, TRUE);
689 gchar *text = g_strdup_printf (_("The music for this staff has been replaced by the music from the current staff, i.e. staff where the cursor is, Movement %d, Staff %d."), mvmnt, staffnum);
690 infodialog (text);
691 }
692 g_string_free (lily, TRUE);
693 }
694
695
696 static GtkWidget *
create_voice_widget(DenemoStaff * staff,gchar * voicename,guint location)697 create_voice_widget (DenemoStaff * staff, gchar * voicename, guint location)
698 {
699 gchar *name = staff->denemo_name->str;
700 GtkWidget *ret = gtk_hbox_new (FALSE, 8);
701 GtkWidget *w = gtk_button_new_with_label (_("Edit"));
702 gtk_widget_set_tooltip_text (w, _("Edit the voice directives for this layout"));
703 gtk_box_pack_start (GTK_BOX (ret), w, FALSE, TRUE, 0);
704 g_signal_connect (w, "clicked", G_CALLBACK (prefix_edit_callback), ret);
705
706 w = gtk_button_new_with_label ("X");
707 gtk_widget_set_tooltip_text (w, _("Delete this voice from the score layout\nNote that if it is the first voice the clef time and keysignatures will be deleted too."));
708 g_signal_connect (w, "clicked", G_CALLBACK (remove_element), NULL);
709 gtk_box_pack_end (GTK_BOX (ret), w, FALSE, TRUE, 0);
710
711 gchar *text = g_strdup_printf (" \\%s", voicename);
712 gchar *label_text = _("Initial Signatures");
713 if (staff->voicecontrol == DENEMO_PRIMARY)
714 {
715 GtkWidget *expander = gtk_expander_new (label_text);
716 gtk_widget_set_tooltip_text (expander, _("Click here to view and edit the clef, key and time signatures of this staff"));
717 gtk_box_pack_start (GTK_BOX (ret), expander, FALSE, TRUE, 0);
718 GtkWidget *hbox = gtk_hbox_new (FALSE, 8);
719 gtk_container_add (GTK_CONTAINER (expander), hbox);
720
721 GtkWidget *button = gtk_button_new_with_label (_("Clef"));
722 gtk_widget_set_tooltip_text (button, _("Edit the LilyPond definition of the clef. The editing affects only this layout."));
723 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (prefix_edit_callback), button);
724 add_lilypond (button, get_lilypond_for_clef (&staff->clef), NULL);
725 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
726
727 button = gtk_button_new_with_label (_("Key"));
728 gtk_widget_set_tooltip_text (button, _("Edit the LilyPond definition of the key signature. The editing affects only this layout."));
729 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (prefix_edit_callback), button);
730 add_lilypond (button, get_lilypond_for_keysig (&staff->keysig), NULL);
731 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
732
733 button = gtk_button_new_with_label (_("Time"));
734 gtk_widget_set_tooltip_text (button, _("Edit the LilyPond definition of the time signature. The editing affects only this layout."));
735 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (prefix_edit_callback), button);
736 add_lilypond (button, get_lilypond_for_timesig (&staff->timesig), NULL);
737 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
738 }
739 else
740 { //Make a matching expander so the music aligns with primary voice
741
742 GtkWidget *expander = gtk_expander_new (label_text);
743 gtk_widget_set_sensitive (expander, FALSE);
744 gtk_widget_set_tooltip_text (expander, _("The clef, time and key signatures attached to other voices are ignored, only the primary one has effect"));
745 gtk_box_pack_start (GTK_BOX (ret), expander, FALSE, TRUE, 0);
746 }
747 gchar *music = g_strconcat (_("Music for "), name, NULL);
748 w = gtk_button_new_with_label (music);
749 gtk_widget_set_tooltip_text (w, _("Click here to move the Denemo cursor to the start of this music.\nThe actual notes live here. You can only edit these in the main Denemo display.\nHowever you can place conditional directives that are to be used only when using this layout. For example page breaks just for this layout can be placed at points in the music.\n"));
750 g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (navigate_to_location), GINT_TO_POINTER (location));
751 g_free (music);
752 add_lilypond (w, text, NULL);
753 gtk_box_pack_start (GTK_BOX (ret), w, FALSE, TRUE, 0);
754
755 GtkWidget *button = gtk_button_new_with_label (_("Substitute"));
756 gtk_widget_set_tooltip_text (button, _("Substitute the music of this staff/voice with the music of the current staff/voice.\nYou can click the \"Music for ...\" button to move the cursor in the Denemo Display onto the staff/voice whose music you want to use before clicking this button to substitute the music. The editing affects only this layout."));
757 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (substitute_voice_name), w);//prefix_edit_callback), w);
758 gtk_box_pack_start (GTK_BOX (ret), button, FALSE, TRUE, 0);
759
760 return ret;
761 }
762
763 static GtkWidget *
create_lyric_widget(gchar * context_text,gchar * name)764 create_lyric_widget (gchar * context_text, gchar * name)
765 {
766 GtkWidget *ret = gtk_hbox_new (FALSE, 8);
767
768 GtkWidget *w = gtk_button_new_with_label ("X");
769 gtk_widget_set_tooltip_text (w, _("Drop this lyric part from the score layout"));
770 g_signal_connect (w, "clicked", G_CALLBACK (remove_lyric_element), context_text);
771 gtk_box_pack_end (GTK_BOX (ret), w, FALSE, TRUE, 0);
772 w = gtk_button_new_with_label (name);
773 //FIXME pop up the lyrics here or some info, or navigate??
774 gtk_box_pack_start (GTK_BOX (ret), w, FALSE, TRUE, 0);
775
776 w = gtk_button_new_with_label ("⬆");
777 gtk_widget_set_tooltip_text (w, _("Move this lyric part above the staff for this score layout"));
778 gtk_box_pack_start (GTK_BOX (ret), w, FALSE, TRUE, 0);
779 g_signal_connect (w, "clicked", G_CALLBACK (move_parent), (gpointer) TRUE);
780 w = gtk_button_new_with_label ("⬇");
781 gtk_widget_set_tooltip_text (w, _("Move this lyric part below the staff for this score layout"));
782 gtk_box_pack_start (GTK_BOX (ret), w, FALSE, TRUE, 0);
783 g_signal_connect (w, "clicked", G_CALLBACK (move_parent), (gpointer) FALSE);
784 return ret;
785 }
786
787 static void
install_voice(DenemoStaff * staff,gint movementnum,gint voice_count,GtkWidget * vbox)788 install_voice (DenemoStaff * staff, gint movementnum, gint voice_count, GtkWidget * vbox)
789 {
790
791 gchar *voicetag = get_voicetag (movementnum, voice_count);
792 gchar *voicename = get_voicename (movementnum, voice_count);
793 GtkWidget *voice = create_voice_widget (staff, voicename, get_location (movementnum, voice_count));
794
795 GString *voicetext = g_string_new ("");
796 //That is \new Voice = name prefix { postfix FIXME is prefix any use here????
797 set_voice_definition (voicetext, staff, voicetag);
798 gchar *text = g_strdup_printf (" %s ", voicetext->str);
799 g_string_assign (voicetext, "");
800 set_voice_termination (voicetext, staff); // TAB TAB"} %End of voice" if not overridden
801 add_lilypond (voice, text, g_string_free (voicetext, FALSE));
802
803
804 gtk_box_pack_start (GTK_BOX (vbox), voice, FALSE, TRUE, 0);
805 }
806
807 static void
do_verses(DenemoStaff * staff,GtkWidget * vbox,gint movementnum,gint voice_count)808 do_verses (DenemoStaff * staff, GtkWidget * vbox, gint movementnum, gint voice_count)
809 {
810 //FIXME do text of the verses get_text_from_view(GtkWidget *textview) where staff->verse_views->data is textview widget
811 GList *g = staff->verse_views;
812 gint versenum = 1;
813 if(!staff->hide_lyrics)
814 for (versenum = 1; g; g = g->next, versenum++)
815 {
816 gchar *versename = get_versename (movementnum, voice_count, versenum);
817 gchar *context_text = g_strdup_printf ("\n" TAB "\\%s%s", versename, "Context\n");
818 //gchar *label = g_strconcat("Lyrics:", staff->denemo_name->str, NULL);
819 gchar *label = g_strdup_printf ("Verse %d: %s", versenum, staff->denemo_name->str);
820 GtkWidget *voice = create_lyric_widget (context_text, label);
821 g_free (label);
822 gchar *lyrics = g_strdup_printf ("\n" TAB "\\new Lyrics = %s\n", versename /*e.g. MvmntIVoiceIVerseI */ );
823 add_lilypond (voice, lyrics, NULL); //FIXME the destroy of these widgets should free the string
824 add_lilypond (voice, NULL, context_text);
825
826 gtk_box_pack_start (GTK_BOX (vbox), voice, FALSE, TRUE, 0); //has to go outside the staff
827
828 g_free (versename);
829 }
830 }
831
832
833 //if oldval is in the prefix list attached to widget, replace it with newval and free oldval
834 static gboolean
edit_lilypond_prefix(GtkWidget * widget,gchar * oldval,gchar * newval)835 edit_lilypond_prefix (GtkWidget * widget, gchar * oldval, gchar * newval)
836 {
837 GList *g;
838 for (g = g_object_get_data (G_OBJECT (widget), "prefix"); g; g = g->next)
839 if (!strcmp ((gchar *) g->data, oldval))
840 {
841 g->data = (gpointer) newval;
842 g_free (oldval);
843 return TRUE;
844 }
845 return FALSE;
846 }
847
848
849 static void
prefix_edit_callback(GtkWidget * widget,GtkWidget * frame)850 prefix_edit_callback (GtkWidget * widget, GtkWidget * frame)
851 {
852 if (!clone_scoreblock_if_needed (frame))
853 return;
854 GList *g = g_object_get_data (G_OBJECT (frame), "prefix");
855 if (g)
856 {
857 gchar *lily = (gchar *) g->data;
858 gchar *newval = string_dialog_editor_with_widget (Denemo.project, _("Edit LilyPond"), _("Edit this using LilyPond syntax\nThe editing applies just to this score layout"), lily ? lily : "", NULL, NULL);
859 if (newval)
860 {
861 edit_lilypond_prefix (frame, lily, newval);
862 score_status (Denemo.project, TRUE);
863 }
864 }
865 }
866
867 static void
affixes_delete_callback(GtkWidget * widget,GtkWidget * frame)868 affixes_delete_callback (GtkWidget * widget, GtkWidget * frame)
869 {
870 if (!clone_scoreblock_if_needed (frame))
871 return;
872 GList *g = g_object_get_data (G_OBJECT (frame), "prefix");
873 if (g)
874 g_free (g->data);
875 g_object_set_data (G_OBJECT (frame), "prefix", NULL);
876 g = g_object_get_data (G_OBJECT (frame), "postfix");
877 if (g)
878 g_free (g->data);
879 g_object_set_data (G_OBJECT (frame), "postfix", NULL);
880 gtk_frame_set_label_widget (GTK_FRAME (frame), NULL);
881
882 score_status (Denemo.project, TRUE);
883 }
884
885
886 static gboolean
popup(GtkWidget * button,GtkWidget * menu)887 popup (GtkWidget * button, GtkWidget * menu)
888 {
889 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
890 return FALSE;
891 }
892
893 static void
create_element(GtkWidget * vbox,GtkWidget * widget,gchar * lilypond)894 create_element (GtkWidget * vbox, GtkWidget * widget, gchar * lilypond)
895 {
896 GtkWidget *hbox = gtk_hbox_new (FALSE, 8);
897 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
898 add_lilypond (hbox, lilypond, NULL);
899 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, TRUE, 0);
900 GtkWidget *button = gtk_button_new_with_label (_("Edit"));
901 gtk_widget_set_tooltip_text (button, _("Edit this element for this layout"));
902 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
903 g_signal_connect (button, "clicked", G_CALLBACK (prefix_edit_callback), hbox);
904 button = gtk_button_new_with_label ("⬆");
905 gtk_widget_set_tooltip_text (button, _("Move this element upwards for this score layout"));
906 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
907 g_signal_connect (button, "clicked", G_CALLBACK (move_parent), (gpointer) TRUE);
908 button = gtk_button_new_with_label ("⬇");
909 gtk_widget_set_tooltip_text (button, _("Move this element downwards for this score layout"));
910 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
911 g_signal_connect (button, "clicked", G_CALLBACK (move_parent), (gpointer) FALSE);
912 button = gtk_button_new_with_label ("X");
913 gtk_widget_set_tooltip_text (button, _("Remove this element from this layout"));
914 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
915 g_signal_connect (button, "clicked", G_CALLBACK (remove_element), NULL);
916 gtk_widget_show_all (hbox);
917 }
918
919
920
921 //gtk_expander_set_expanded (expander,gtk_expander_get_expanded (expander));
922 /* UNUSED
923 static void
924 toggle_expand (GtkWidget * item, GtkWidget * expander)
925 {
926 gtk_expander_set_expanded (GTK_EXPANDER (expander), !gtk_expander_get_expanded (GTK_EXPANDER (expander)));
927 }
928 */
929
930 static void
page_break(GtkWidget * item,GtkWidget * vbox)931 page_break (GtkWidget * item, GtkWidget * vbox)
932 {
933 if (!clone_scoreblock_if_needed (vbox))
934 return;
935 GtkWidget *button = gtk_button_new_with_label (_("Page Break"));
936 gtk_widget_set_tooltip_text (button, _("This forces a new page, useful for avoiding page turns\n"));
937 create_element (vbox, button, g_strdup ("\\pageBreak\n"));
938 gtk_box_reorder_child (GTK_BOX (vbox), gtk_widget_get_parent (button), 0);
939 score_status (Denemo.project, TRUE);
940 }
941
942 static void
blank_page(GtkWidget * item,GtkWidget * vbox)943 blank_page (GtkWidget * item, GtkWidget * vbox)
944 {
945 if (!clone_scoreblock_if_needed (vbox))
946 return;
947 GtkWidget *button = gtk_button_new_with_label (_("Blank Page"));
948 gtk_widget_set_tooltip_text (button, _("This prints a page intentionally left blank, useful for avoiding page turns\n"));
949 create_element (vbox, button, g_strdup ("\\pageBreak\n\\markup \\italic \"This page is intentionally left blank\"\n\\pageBreak\n"));
950 gtk_box_reorder_child (GTK_BOX (vbox), gtk_widget_get_parent (button), 0);
951 score_status (Denemo.project, TRUE);
952 }
953
954 static void
custom_lilypond(GtkWidget * item,GtkWidget * vbox)955 custom_lilypond (GtkWidget * item, GtkWidget * vbox)
956 {
957 if (!clone_scoreblock_if_needed (vbox))
958 return;
959 GtkWidget *button = gtk_button_new_with_label ("LilyPond");
960 gtk_widget_set_tooltip_text (button, _("This lets you insert your own titles etc just for this layout.\nFor book titles use \\titledPiece \\markup \"myname\"\nSimple titles are not placed here, but appear in a header block at the end of the movement.\nFor other possible uses, see LilyPond manual."));
961 create_element (vbox, button, g_strdup ("%Enter LilyPond syntax here\n"));
962 gtk_box_reorder_child (GTK_BOX (vbox), gtk_widget_get_parent (button), 0);
963 score_status (Denemo.project, TRUE);
964 }
965
966 static GtkWidget *
get_titles_menu(GtkWidget * vbox)967 get_titles_menu (GtkWidget * vbox)
968 {
969 GtkWidget *menu = gtk_menu_new ();
970 GtkWidget *item;
971
972 item = gtk_menu_item_new_with_label (_("Create Page Break"));
973 gtk_widget_set_tooltip_text (item, _("This inserts a page break, useful for avoiding page turns\nMove it before the title (using the up arrow) once created!"));
974 g_signal_connect (item, "activate", G_CALLBACK (page_break), vbox);
975 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
976
977 item = gtk_menu_item_new_with_label (_("Create Blank Page"));
978 gtk_widget_set_tooltip_text (item, _("This inserts a page intentionally left blank, useful for avoiding page turns when printing on both sides of the paper"));
979 g_signal_connect (item, "activate", G_CALLBACK (blank_page), vbox);
980 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
981
982 item = gtk_menu_item_new_with_label (_("Insert LilyPond"));
983 gtk_widget_set_tooltip_text (item, _(_("This creates a LilyPond comment which you can then edit to give titles etc for this movment, applying just to this layout.")));
984 g_signal_connect (item, "activate", G_CALLBACK (custom_lilypond), vbox);
985 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
986
987 item = gtk_separator_menu_item_new ();
988 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
989
990 gtk_widget_show_all (menu);
991 return menu;
992 }
993
994
995 //return a newly allocated label to hint at the contents of a directive
996 static gchar *
label_for_directive(DenemoDirective * d)997 label_for_directive (DenemoDirective * d)
998 {
999 gchar *text = g_strdup_printf ("%s%s%.25s", d->tag ? d->tag->str : "<Unknown Tag>", d->display ? ": " : "", d->display ? d->display->str : "");
1000 gchar *etext = g_strescape (text, NULL);
1001 g_free (text);
1002 return etext;
1003 }
1004
1005 static void
popup_movement_menu(GtkWidget * w,GtkWidget * vbox)1006 popup_movement_menu (GtkWidget * w, GtkWidget * vbox)
1007 {
1008 gtk_menu_popup (GTK_MENU (get_titles_menu (vbox)), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
1009 }
1010
1011 static void
popup_movement_titles_menu(GtkWidget * button)1012 popup_movement_titles_menu (GtkWidget * button)
1013 {
1014 GtkWidget *menuitem = gtk_ui_manager_get_widget (Denemo.ui_manager, "/ObjectMenu/MovementMenu/Titles/BookTitles");
1015 if (get_standard_scoreblock (button))
1016 {
1017 if (menuitem)
1018 gtk_menu_popup (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem))), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
1019 else
1020 g_warning ("No such menu path");
1021 }
1022 else
1023 warningdialog (_("This button is for changing the score itself, it will not affect this custom layout"));
1024 }
1025
1026 /* installs movement titles, page breaks etc
1027 *
1028 */
1029 static void
install_pre_movement_widgets(GtkWidget * vbox,DenemoMovement * si,gboolean standard)1030 install_pre_movement_widgets (GtkWidget * vbox, DenemoMovement * si, gboolean standard)
1031 {
1032 GtkWidget *frame = gtk_frame_new (NULL);
1033 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
1034 GtkWidget *expander = gtk_expander_new (_("Movement Titles, Page Breaks etc"));
1035 gtk_widget_set_tooltip_text (expander, _("In here are settings for the movement title, page breaks before the movement etc"));
1036 gtk_container_add (GTK_CONTAINER (frame), expander);
1037
1038 GtkWidget *inner_vbox = gtk_vbox_new (FALSE, 8);
1039 gtk_container_add (GTK_CONTAINER (expander), inner_vbox);
1040
1041 GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 8);
1042 gtk_box_pack_start (GTK_BOX (inner_vbox), inner_hbox, FALSE, TRUE, 0);
1043 GtkWidget *button;
1044 #if 0
1045 //having buttons that affect the score itself is confusing
1046 if(standard)
1047 {
1048 button = gtk_button_new_with_label (_("Create Titles for Movement"));
1049 mark_as_non_custom (button);
1050 gtk_widget_set_tooltip_text (button, _("Set book titles for this movement in the score"));
1051 g_signal_connect (button, "clicked", G_CALLBACK (popup_movement_titles_menu), NULL);
1052 gtk_box_pack_start (GTK_BOX (inner_hbox), button, FALSE, TRUE, 0);
1053 }
1054 #endif
1055
1056 button = gtk_button_new_with_label (_("Create for Custom Layout"));
1057 gtk_widget_set_tooltip_text (button, _("Create page breaks, blank pages ...for this layout"));
1058 g_signal_connect (button, "clicked", G_CALLBACK (popup_movement_menu), inner_vbox);
1059 gtk_box_pack_start (GTK_BOX (inner_hbox), button, FALSE, TRUE, 0);
1060
1061 GList *g;
1062 for (g = si->movementcontrol.directives; g; g = g->next)
1063 {
1064 DenemoDirective *d = (DenemoDirective *) g->data;
1065 if (d->override & DENEMO_OVERRIDE_AFFIX)
1066 continue;
1067 if (d->override & DENEMO_OVERRIDE_HIDDEN)
1068 continue;
1069 if (d->prefix)
1070 {
1071 gchar *text = label_for_directive (d);
1072 GtkWidget *label = gtk_label_new (text);
1073 g_free (text);
1074 create_element (inner_vbox, label, g_strdup (d->prefix->str));
1075 }
1076 }
1077 }
1078
1079 static void
popup_score_titles_menu(GtkWidget * button)1080 popup_score_titles_menu (GtkWidget * button)
1081 {
1082 GtkWidget *menuitem = gtk_ui_manager_get_widget (Denemo.ui_manager, "/ObjectMenu/Score/Titles/BookTitles");
1083 if (get_standard_scoreblock (button))
1084 {
1085 if (menuitem)
1086 gtk_menu_popup (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem))), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
1087 else
1088 g_warning ("No such menu path");
1089 }
1090 else
1091 warningdialog (_("This button is for changing the score itself, it will not affect this custom layout"));
1092 }
1093
1094
1095 /* install widgets for the postfix field of score directives (lilycontrol.directives) which are not hidden and which are not OVERRIDE_AFFIX -
1096 * the prefix is done in create_score_directives.
1097 * Ones with OVERRIDE_AFFIX are done in set_default_scoreblock()
1098 */
1099 static GtkWidget *
install_scoreblock_overrides(GtkWidget * vbox,DenemoProject * gui,DenemoMovement * si,gboolean last_movement)1100 install_scoreblock_overrides (GtkWidget * vbox, DenemoProject * gui, DenemoMovement * si, gboolean last_movement)
1101 {
1102
1103 GList *g;
1104 for (g = gui->lilycontrol.directives; g; g = g->next)
1105 {
1106 DenemoDirective *d = g->data;
1107 if (d->override & DENEMO_OVERRIDE_HIDDEN)
1108 continue;
1109 if (d->override & DENEMO_OVERRIDE_AFFIX)
1110 continue;
1111 gchar *start = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
1112 if (start)
1113 {
1114 GtkWidget *frame = gtk_frame_new (NULL);
1115
1116 gchar *text = label_for_directive (d);
1117 GtkWidget *button = gtk_button_new_with_label (text);
1118 g_free (text);
1119 gtk_frame_set_label_widget (GTK_FRAME (frame), button);
1120 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
1121 gchar *lily = g_strdup_printf ("\n<< %s\n<< ", start);
1122 add_lilypond (frame, lily, g_strdup ("\n >>\n>>"));
1123
1124 GtkWidget *menu = gtk_menu_new ();
1125 GtkWidget *menuitem = gtk_menu_item_new_with_label ("Edit");
1126 g_signal_connect (menuitem, "activate", G_CALLBACK (prefix_edit_callback), frame);
1127 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1128 menuitem = gtk_menu_item_new_with_label ("Delete");
1129 g_signal_connect (menuitem, "activate", G_CALLBACK (affixes_delete_callback), frame);
1130 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1131 gtk_widget_show_all (menu);
1132 g_signal_connect (button, "clicked", G_CALLBACK (popup), menu);
1133
1134
1135
1136 vbox = gtk_vbox_new (FALSE, 8);
1137 gtk_container_add (GTK_CONTAINER (frame), vbox);
1138 }
1139 }
1140 return vbox;
1141 }
1142
1143
1144
1145 static gboolean
draw_staff_brace_for_layout(GtkWidget * w,cairo_t * cr,gchar * context)1146 draw_staff_brace_for_layout (GtkWidget * w, cairo_t *cr, gchar * context)
1147 {
1148 GtkAllocation allocation;
1149 gtk_widget_get_allocation (w, &allocation);
1150 gint height = allocation.height;
1151 cairo_set_source_rgb (cr, 0.9, 0.9, 0.9);
1152 cairo_paint (cr);
1153 gboolean curly = !((!strcmp (context, "ChoirStaffStart")) || (!strcmp (context, "GroupStaffStart")));
1154 draw_staff_brace (cr, curly, 5, 8, height*0.9 - 15);
1155 return TRUE;
1156 }
1157 static gboolean
draw_staff_brace_gtk2(GtkWidget * w,GdkEventExpose * event,gchar * context)1158 draw_staff_brace_gtk2 (GtkWidget * w, GdkEventExpose * event, gchar * context)
1159 {
1160 cairo_t *cr = gdk_cairo_create (event->window);
1161 gdk_cairo_region (cr, event->region);
1162 cairo_clip (cr);
1163 draw_staff_brace_for_layout (w, cr, context);
1164 cairo_destroy (cr);
1165 return TRUE;
1166 }
1167
1168 static void
show_type(GtkWidget * widget,gchar * message)1169 show_type (GtkWidget * widget, gchar * message)
1170 {
1171 g_message ("%s%s", message, widget ? g_type_name (G_TYPE_FROM_INSTANCE (widget)) : "NULL widget");
1172 }
1173
delete_brace(gchar * postfix)1174 static void delete_brace (gchar *postfix)
1175 {
1176 gchar *c = g_strrstr (postfix, ">>%");
1177 if(c && c>postfix) {
1178 *c = 0;
1179 return;
1180 }
1181
1182 #if 0
1183 gchar *c = postfix;
1184 while (*(c++));
1185 c--;c--;c--;
1186 if(c != postfix)
1187 while (*(c--) != '\n');
1188 c++;
1189 if(*c=='\n')
1190 *c=0;
1191 #endif
1192 }
remove_brace_end(GtkWidget * vbox)1193 static void remove_brace_end (GtkWidget *vbox)
1194 {
1195 show_type (vbox, "new vbox ??? ") ;
1196 GList *g = g_object_get_data (G_OBJECT(vbox), "postfix");
1197 for ( ;g;g=g->next)
1198 {
1199 g_print ("Next postfix %s\n", (char *) g->data);
1200 delete_brace (g->data);
1201 g_print ("transformed to %s\n", (char *) g->data);
1202 }
1203 }
1204 static gboolean
remove_context(GtkWidget * button,GtkWidget * parent)1205 remove_context (GtkWidget * button, GtkWidget * parent)
1206 {
1207 if (!clone_scoreblock_if_needed (parent))
1208 return TRUE;
1209 show_type (parent, "parent ");
1210 GList *children = gtk_container_get_children (GTK_CONTAINER (parent));
1211 //show_type (g_list_last (children)->data, "vbox type is");
1212 //show_type (gtk_widget_get_parent (gtk_widget_get_parent (parent)), "Reparenting on ");
1213 GtkWidget *vbox = g_list_last (children)->data;
1214 GList *staff_list = gtk_container_get_children (GTK_CONTAINER (vbox));
1215 GList *g;
1216 for (g = staff_list; g; g = g->next)
1217 {
1218 //show_type (g->data, "The staff frame is ");
1219 gtk_widget_reparent (g->data, //frame
1220 gtk_widget_get_parent (gtk_widget_get_parent (parent)));
1221 }
1222
1223 GtkWidget *topw = gtk_widget_get_parent (gtk_widget_get_parent (gtk_widget_get_parent (parent)));
1224 //show_type (topw, "new vbox parent ");g_print ("parent %p, grandparent %p, great-grp %p\n", parent, gtk_widget_get_parent (parent), topw);
1225
1226 if (g_object_get_data (G_OBJECT(parent), "postfix")==NULL)
1227 remove_brace_end (gtk_bin_get_child (g_list_last(staff_list)->data)); // without it deleting a top level brace leaving lower ones fails.
1228 else
1229 for (g=g_object_get_data (G_OBJECT(parent), "postfix");g;g=g->next)
1230 {
1231 delete_brace (g->data);
1232 if (GTK_IS_BOX (topw))
1233 add_lilypond (topw, NULL, g_strdup (g->data));
1234 }
1235 Denemo.project->lilysync = G_MAXUINT;
1236 gtk_widget_destroy (gtk_widget_get_parent (parent));
1237 return TRUE;
1238 }
1239
1240 //Move the frame above into this frame's vbox, unless we are inside it.
1241 /* UNUSED
1242 static gboolean
1243 move_context_up (GtkWidget * button, GtkWidget * parent)
1244 { //!!!! these not working
1245 if (!clone_scoreblock_if_needed (parent))
1246 return TRUE;
1247 DenemoScoreblock *sb = get_custom_scoreblock (parent);
1248 gint index = g_list_index (sb->staff_list, parent);
1249 if (index > 0)
1250 {
1251 GtkWidget *frame = (GtkWidget *) g_list_nth (sb->staff_list, index - 1)->data;
1252 if (!gtk_widget_is_ancestor (parent, frame))
1253 {
1254 GtkWidget *hbox = gtk_bin_get_child (GTK_BIN (parent));
1255 GList *children = gtk_container_get_children (GTK_CONTAINER (hbox));
1256 GtkWidget *vbox = g_list_last (children)->data;
1257 g_list_free (children);
1258 gtk_widget_reparent (frame, vbox);
1259 gtk_box_reorder_child (GTK_BOX (vbox), frame, 0);
1260 //now move the frame on one in the list of frames
1261 sb->staff_list = g_list_remove (sb->staff_list, frame);
1262 sb->staff_list = g_list_insert (sb->staff_list, frame, index);
1263 //layout = ???
1264 }
1265 }
1266 return TRUE;
1267 }
1268 */
1269 //Move the frame below into this frame's vbox, unless we are inside it.
1270 /* UNUSED
1271 static gboolean
1272 move_context_down (GtkWidget * button, GtkWidget * parent)
1273 {
1274 if (!clone_scoreblock_if_needed (parent))
1275 return TRUE;
1276 DenemoScoreblock *sb = get_custom_scoreblock (parent); //!!!!doesn't work see junk.denemo
1277 g_assert (sb);
1278 gint index = g_list_index (sb->staff_list, parent);
1279 if (index < g_list_length (sb->staff_list))
1280 {
1281 GtkWidget *frame = (GtkWidget *) g_list_nth (sb->staff_list, index + 1)->data;
1282 if (!gtk_widget_is_ancestor (parent, frame))
1283 {
1284 GtkWidget *hbox = gtk_bin_get_child (GTK_BIN (parent));
1285 GList *children = gtk_container_get_children (GTK_CONTAINER (hbox));
1286 GtkWidget *vbox = g_list_last (children)->data;
1287 g_list_free (children);
1288 gtk_widget_reparent (frame, vbox);
1289 gtk_box_reorder_child (GTK_BOX (vbox), frame, -1);
1290 //now move the frame on one in the list of frames
1291 //sb->staff_list = g_list_remove(sb->staff_list, frame);
1292 //sb->staff_list = g_list_insert(sb->staff_list, frame, index);
1293 // layout_sync = ???
1294 }
1295 }
1296 return TRUE;
1297 }
1298 */
1299
1300 static GtkWidget *
install_staff_group_start(GList ** pstaffs,GtkWidget * vbox,GList * directives,gint * nesting)1301 install_staff_group_start (GList ** pstaffs, GtkWidget * vbox, GList * directives, gint * nesting)
1302 {
1303 GList *g;
1304 for (g = directives; g; g = g->next)
1305 {
1306 DenemoDirective *directive = g->data;
1307 if (directive->override & DENEMO_OVERRIDE_AFFIX)
1308 {
1309 if (directive->prefix && (directive->prefix->len > 0))
1310 {
1311 GtkWidget *frame = (GtkWidget *) gtk_frame_new (directive->tag->str);
1312 add_lilypond (frame, directive->prefix ? g_strdup (directive->prefix->str) : NULL, directive->postfix ? g_strdup (directive->postfix->str) : NULL);
1313 (*nesting)++;
1314 *pstaffs = g_list_append (*pstaffs, frame);
1315 g_signal_connect (G_OBJECT (frame), "destroy", G_CALLBACK (remove_from_staff_list), pstaffs);
1316 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
1317 GtkWidget *hbox = gtk_hbox_new (FALSE, 8);
1318 gtk_container_add (GTK_CONTAINER (frame), hbox);
1319
1320
1321 GtkWidget *layout = gtk_drawing_area_new ();
1322 gtk_widget_set_tooltip_text (layout, _("This brace connects together several staffs - you can delete it for a customized layout."));
1323
1324 #if GTK_MAJOR_VERSION != 2
1325 g_signal_connect (G_OBJECT (layout), "draw", G_CALLBACK (draw_staff_brace_for_layout), directive->tag->str);
1326 #else
1327 g_signal_connect (G_OBJECT (layout), "expose_event", G_CALLBACK (draw_staff_brace_gtk2), directive->tag->str);
1328 #endif
1329
1330 gint width = 20, height = 100;
1331 gtk_widget_set_size_request (layout, width, height);
1332
1333 gtk_box_pack_start (GTK_BOX (hbox), layout, TRUE, TRUE, 0);
1334
1335
1336 GtkWidget *controls = gtk_vbox_new (FALSE, 8);
1337 gtk_box_pack_start (GTK_BOX (hbox), controls, FALSE, TRUE, 0);
1338
1339 GtkWidget *button = gtk_button_new_with_label ("X");
1340 gtk_widget_set_tooltip_text (button, _("Remove this staff brace from these staffs for a customized layout."));
1341 g_signal_connect (button, "clicked", G_CALLBACK (remove_context), hbox);
1342 gtk_box_pack_start (GTK_BOX (controls), button, FALSE, TRUE, 0);
1343 vbox = gtk_vbox_new (FALSE, 8); //this vbox will be passed back so that the staffs can be put inside this staff group frame.
1344 gtk_box_pack_end (GTK_BOX (hbox), vbox, FALSE, TRUE, 0);
1345 }
1346 }
1347 }
1348 return vbox;
1349 }
1350
1351 static GtkWidget *
install_staff_group_end(GtkWidget * vbox,GList * directives,gint * nesting)1352 install_staff_group_end (GtkWidget * vbox, GList * directives, gint * nesting)
1353 {
1354 GList *g;
1355 for (g = directives; g; g = g->next)
1356 {
1357 DenemoDirective *directive = g->data;
1358 if (directive->override & DENEMO_OVERRIDE_AFFIX)
1359 {
1360 if (directive->postfix && (directive->postfix->len > 0))
1361 {
1362 if (*nesting)
1363 {
1364 //show_type (gtk_widget_get_parent (vbox), "Adding beam ends to type: "); g_print ("Specifically %s to %p\n", directive->postfix->str, gtk_widget_get_parent (vbox));
1365 add_lilypond (gtk_widget_get_parent (vbox), NULL, g_strdup (directive->postfix->str));
1366 gint number_of_ends = 1;
1367 if(directive->data)
1368 number_of_ends = atoi (directive->data->str);
1369 if (number_of_ends<0 || (number_of_ends>10)) number_of_ends = 1;//sanity check on data in directive
1370
1371 (*nesting) -= number_of_ends;
1372 vbox = gtk_widget_get_parent (gtk_widget_get_parent (gtk_widget_get_parent (vbox)));
1373 }
1374 else
1375 g_warning ("Badly placed end of staff group - ignored");
1376 }
1377 }
1378 }
1379 return vbox;
1380 }
1381
1382 static GtkWidget *
get_label(GtkWidget * button)1383 get_label (GtkWidget * button)
1384 {
1385 if (GTK_IS_CONTAINER (button))
1386 {
1387 GList *g = gtk_container_get_children (GTK_CONTAINER (button));
1388 for (; g; g = g->next)
1389 if (GTK_IS_LABEL (g->data))
1390 return GTK_WIDGET (g->data);
1391 }
1392 return NULL;
1393 }
1394
1395 static GtkWidget *
get_large_button(gchar * text)1396 get_large_button (gchar * text)
1397 {
1398 GtkWidget *button = gtk_button_new_with_label ("dummy");
1399 GtkWidget *label = get_label (button);
1400 gchar *markup = g_markup_printf_escaped ("<big>%s</big>", text);
1401 gtk_label_set_markup (GTK_LABEL (label), markup);
1402 g_free (markup);
1403 return button;
1404 }
1405
1406 static GtkWidget *
get_small_button(gchar * text)1407 get_small_button (gchar * text)
1408 {
1409 GtkWidget *button = gtk_button_new_with_label ("dummy");
1410 GtkWidget *label = get_label (button);
1411 gchar *markup = g_markup_printf_escaped ("<small>%s</small>", text);
1412 gtk_label_set_markup (GTK_LABEL (label), markup);
1413 g_free (markup);
1414 return button;
1415 }
1416
1417 static void
add_staff_widget(DenemoStaff * staff,GtkWidget * hbox)1418 add_staff_widget (DenemoStaff * staff, GtkWidget * hbox)
1419 {
1420 gchar *clef_glyph = "\xF0\x9D\x84\x9E ";
1421 switch (staff->clef.type)
1422 {
1423 case DENEMO_FRENCH_CLEF:
1424
1425 case DENEMO_TREBLE_CLEF:
1426 clef_glyph = " ";
1427 break;
1428 case DENEMO_G_8_CLEF:
1429 clef_glyph = " ";
1430 break;
1431
1432 case DENEMO_F_8_CLEF:
1433 clef_glyph = " ";
1434 break;
1435
1436 case DENEMO_BASS_CLEF:
1437 clef_glyph = " ";
1438 break;
1439 case DENEMO_SOPRANO_CLEF:
1440 case DENEMO_ALTO_CLEF:
1441 case DENEMO_TENOR_CLEF:
1442 clef_glyph = " ";
1443 break;
1444 default:
1445 break;
1446 }
1447 GtkWidget *button = get_large_button (clef_glyph);
1448 gtk_widget_set_tooltip_text (button, _("This shows the clef in the Denemo score - the actual clef printed may be modified by Directives attached to it.\nYou can edit the clef for a custom layout - do this on the first voice on the staff."));
1449 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
1450
1451 button = get_small_button ("⬆");
1452 gtk_widget_set_tooltip_text (button, _("Move this staff (with all its voices) above the preceding staff."));
1453 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
1454 g_signal_connect (button, "clicked", G_CALLBACK (move_grandparent), (gpointer) TRUE);
1455 button = get_small_button ("⬇");
1456 gtk_widget_set_tooltip_text (button, _("Move this staff (with all its voices) after the following staff."));
1457 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
1458 g_signal_connect (button, "clicked", G_CALLBACK (move_grandparent), (gpointer) FALSE);
1459
1460 button = gtk_button_new_with_label ("X");
1461 gtk_widget_set_tooltip_text (button, _("Remove this staff (with all its voices) for customized layout."));
1462
1463 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, TRUE, 0);
1464 g_signal_connect_swapped (button, "clicked", G_CALLBACK (remove_parent_element), hbox);
1465 }
1466
1467 /* UNUSED
1468 static void
1469 popup_initial_clef_menu (GtkWidget * button)
1470 {
1471 GtkWidget *menuitem = gtk_ui_manager_get_widget (Denemo.ui_manager, "/ObjectMenu/ClefMenu");
1472 if (menuitem)
1473 gtk_menu_popup (GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem))), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
1474 else
1475 g_warning ("No such menu path");
1476 }
1477 */
1478
1479 static void
install_staff_with_voices(GList ** pstaffs,GtkWidget ** pvbox,gchar * partname,GList ** pstafflist,gint * pvoice_count,gint staff_count,gint movementnum,gint * pstaff_group_nesting,gboolean standard,gboolean append_only)1480 install_staff_with_voices (GList ** pstaffs, GtkWidget **pvbox, gchar *partname, GList **pstafflist,
1481 gint *pvoice_count, gint staff_count, gint movementnum, gint *pstaff_group_nesting, gboolean standard, gboolean append_only)
1482 {
1483 DenemoMovement *si = Denemo.project->movement;
1484 GList *g = *pstafflist;
1485 GtkWidget *vbox = *pvbox;
1486 DenemoStaff *staff = g->data;
1487 DenemoStaff *nextstaff = g->next ? g->next->data : NULL;
1488
1489
1490 //if (partname == NULL) Don't omit staff groups start for single part, since parts can be multi-staff e.g. piano, it will be closed at the end if the part doesn't include the close
1491 if(!append_only)
1492 vbox = install_staff_group_start (pstaffs, vbox, staff->staff_directives, pstaff_group_nesting);
1493
1494 if (staff->hasfakechords)
1495 { //the reason these are outside the staff frame is it makes them appear above the staff
1496 GtkWidget *chords = gtk_label_new (_("Chord Symbols"));
1497 gchar *text = g_strdup_printf ("\n" TAB TAB "\\new ChordNames \\chordmode { \\%sChords }\n",
1498 get_voicename (movementnum, (*pvoice_count)));
1499 add_lilypond (chords, text, NULL);
1500 gtk_box_pack_start (GTK_BOX (vbox), chords, FALSE, TRUE, 0);
1501 *pstaffs = g_list_append (*pstaffs, chords);
1502 g_signal_connect (G_OBJECT (chords), "destroy", G_CALLBACK (remove_from_staff_list), pstaffs);
1503 }
1504
1505 gchar *label_text = (si->thescore->next == NULL) ? g_strdup (_("Staff Menu")) : g_strdup_printf (_("Staff %d Menu"), staff_count);
1506 GtkWidget *frame = gtk_frame_new (NULL);
1507
1508 GtkWidget *staff_hbox = gtk_hbox_new (FALSE, 8);
1509 //gtk_frame_set_label_widget (GTK_FRAME (frame), staff_hbox); !!!!! setting the label widget it's position looks odd because no frame is visible
1510 GtkWidget *button = gtk_button_new_with_label (label_text);
1511 g_free (label_text);
1512 gtk_box_pack_start (GTK_BOX (staff_hbox), button, FALSE, TRUE, 0);
1513 gtk_widget_set_tooltip_text (button, _("Click for a menu to position the Denemo cursor on this staff\nor to alter this staff for a customized layout"));
1514
1515
1516 GtkWidget *menu = gtk_menu_new ();
1517 GtkWidget *menuitem = gtk_menu_item_new_with_label (_("Move Denemo Cursor to this staff"));
1518 gtk_widget_set_tooltip_text (menuitem, _("This will move the Denemo Cursor to the start of this staff in this movement"));
1519 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (navigate_to_location), GINT_TO_POINTER (get_location (movementnum, (*pvoice_count))));
1520 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1521
1522
1523
1524 menuitem = gtk_menu_item_new_with_label (_("Edit Staff Properties"));
1525 gtk_widget_set_tooltip_text (menuitem, _("Edit the properties of the staff to customize this layout\nTake care only alter the obvious bits, such as instrument name etc\nInjudicious deletion of the LilyPond typesetting characters {<<# etc can make the layout unreadable by the LilyPond typesetter. Just delete the layout if you get stuck."));
1526 g_signal_connect (menuitem, "activate", G_CALLBACK (prefix_edit_callback), frame);
1527 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1528
1529 gtk_widget_show_all (menu);
1530 g_signal_connect (button, "clicked", G_CALLBACK (popup), menu);
1531 #if 0
1532 //having buttons that affect the score itself is confusing
1533 if (standard && (si->thescore->next != NULL))
1534 {
1535 button = gtk_button_new_with_label (_("Set Staff Group Start/End"));
1536 mark_as_non_custom (button);
1537 gtk_box_pack_start (GTK_BOX (staff_hbox), button, FALSE, TRUE, 0);
1538 gtk_widget_set_tooltip_text (button, _("The braces { and [ binding staffs together can be set here. Set the start on one staff and the end on a later staff.\nThis is editing the score, not just customizing a layout.\nRefresh the layout view (see under Options for this Layout button at the top) once you have made the changes."));
1539 g_signal_connect (button, "button-press-event", G_CALLBACK (staff_groups_menu), GINT_TO_POINTER (get_location (movementnum, (*pvoice_count))));
1540 }
1541 #endif
1542 *pstaffs = g_list_append (*pstaffs, frame);
1543 g_signal_connect (G_OBJECT (frame), "destroy", G_CALLBACK (remove_from_staff_list), pstaffs);
1544
1545 GString *staffprefix = g_string_new ("");
1546 set_staff_definition (staffprefix, staff);
1547
1548
1549 // if (staff->no_of_lines != 5) now done by a directive
1550 // g_string_append_printf (staffprefix, TAB "\\override Staff.StaffSymbol #'line-count = #%d\n", staff->no_of_lines); //FIXME create_element
1551
1552 GString *stafftext = g_string_new ("");
1553 g_string_assign (stafftext, "");
1554 set_staff_termination (stafftext, staff); // "\n>>\n%End of Staff\n"
1555
1556
1557 add_lilypond (frame, g_string_free (staffprefix, FALSE), g_string_free (stafftext, FALSE));
1558
1559
1560
1561 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
1562
1563 GtkWidget *outer_vbox = gtk_vbox_new (FALSE, 8);
1564 gtk_container_add (GTK_CONTAINER (frame), outer_vbox);
1565
1566
1567 gtk_box_pack_start (GTK_BOX (outer_vbox), staff_hbox, FALSE, TRUE, 0);
1568
1569 GtkWidget *hbox = gtk_hbox_new (FALSE, 8);
1570 gtk_box_pack_end (GTK_BOX (outer_vbox), hbox, FALSE, TRUE, 0);
1571 //gtk_container_add (GTK_CONTAINER (frame), hbox);
1572 add_staff_widget (staff, hbox);
1573
1574 label_text = (nextstaff && nextstaff->voicecontrol & DENEMO_SECONDARY) ? _("Voices") : _("Voice");
1575 GtkWidget *expander = gtk_expander_new (label_text);
1576 gtk_widget_set_tooltip_text (expander, _("This holds the voice(s) of the staff - the clef, time signature, key signature and music are all here"));
1577 //gtk_container_add (GTK_CONTAINER (frame), expander);
1578 gtk_box_pack_end (GTK_BOX (hbox), expander, FALSE, TRUE, 0);
1579 GtkWidget *voices_vbox = gtk_vbox_new (FALSE, 8);
1580 gtk_container_add (GTK_CONTAINER (expander), voices_vbox);
1581
1582 if (staff->hasfigures)
1583 {
1584 GtkWidget *voice = gtk_label_new ("Bass figures");
1585 gchar *text = g_strdup_printf ("\n" TAB TAB "\\context Staff \\with {implicitBassFigures = #'(0) } \\%sBassFiguresLine %%End of bass figures\n",
1586 get_voicename (movementnum, (*pvoice_count)));
1587 add_lilypond (voice, text, NULL);
1588 gtk_box_pack_start (GTK_BOX (voices_vbox), voice, FALSE, TRUE, 0);
1589 }
1590
1591 install_voice (staff, movementnum, (*pvoice_count), voices_vbox); //Primary voice
1592 do_verses (staff, vbox, movementnum, (*pvoice_count));
1593
1594 if (nextstaff && (nextstaff->voicecontrol & DENEMO_SECONDARY))
1595 {
1596 for (g = g->next, (*pvoice_count)++; g && (((DenemoStaff *) g->data)->voicecontrol & DENEMO_SECONDARY); g = g->next, (*pvoice_count)++)
1597 {
1598
1599 DenemoStaff *staff = g->data;
1600 install_voice (staff, movementnum, (*pvoice_count), voices_vbox);
1601 do_verses (staff, vbox, movementnum, (*pvoice_count)); //!!! these need *pstaffs = g_list_append(*pstaffs, voice); treatment too...
1602 if (partname == NULL)
1603 vbox = install_staff_group_end (vbox, staff->staff_directives, pstaff_group_nesting);
1604 }
1605 if (g != NULL)
1606 {
1607 g = g->prev;
1608 (*pvoice_count)--;
1609 }
1610 }
1611 if (partname == NULL) //Have to omit all end braces for part layouts, since the part may not include all the start braces for them.
1612 vbox = install_staff_group_end (vbox, staff->staff_directives, pstaff_group_nesting);
1613 *pstafflist = g;
1614 *pvbox = vbox;
1615 }
1616
1617 static void
append_staff(GtkWidget * widget,GList ** pstaffs)1618 append_staff (GtkWidget *widget, GList ** pstaffs)
1619 {
1620 if (!clone_scoreblock_if_needed (widget))
1621 return;
1622 gint staff_group_nesting = 0;
1623 gint voice_count = Denemo.project->movement->currentstaffnum;
1624 gint movementnum = 1;
1625 if (Denemo.project->movements)
1626 movementnum = 1 + g_list_index (Denemo.project->movements, Denemo.project->movement);
1627 GtkWidget *vbox = gtk_widget_get_parent (widget);
1628 install_staff_with_voices (pstaffs, &vbox, NULL, &Denemo.project->movement->currentstaff,
1629 &voice_count, Denemo.project->movement->currentstaffnum, movementnum, &staff_group_nesting, FALSE, TRUE);
1630 gtk_widget_show_all (vbox);
1631 Denemo.project->lilysync = G_MAXUINT;
1632 }
1633 static GtkWidget *
get_movement_widget(GList ** pstaffs,gchar * partname,DenemoMovement * si,gint movementnum,gboolean last_movement,gboolean standard)1634 get_movement_widget (GList ** pstaffs, gchar * partname, DenemoMovement * si, gint movementnum, gboolean last_movement, gboolean standard)
1635 {
1636 DenemoProject *gui = Denemo.project;
1637 gint staff_group_nesting = 0; //to check on loose staff group markers
1638 gint voice_count; //a count of voices from the very top of the score (ie DenemoStaffs in thescore)
1639 gint staff_count; //a count of staffs excluding voices from top of score
1640 GtkWidget *ret = gtk_frame_new (NULL);
1641 GString *start = g_string_new ("");
1642 set_initiate_scoreblock (si, start); // ie << possibly overridden
1643 add_lilypond (ret, g_string_free (start, FALSE), g_strdup ("\n >>\n"));
1644
1645 GtkWidget *vbox = gtk_vbox_new (FALSE, 8);
1646 gtk_container_add (GTK_CONTAINER (ret), vbox);
1647
1648 vbox = install_scoreblock_overrides (vbox, gui, si, last_movement); //things like transpose whole score etc
1649
1650 gchar *label_text = (si->thescore->next == NULL) ? _("The Staff") : _("The Staffs");
1651 GtkWidget *topexpander = gtk_expander_new (label_text);
1652 gtk_widget_set_tooltip_text (topexpander, _("This holds the staffs below which are the voices with the music."));
1653 gtk_expander_set_expanded (GTK_EXPANDER (topexpander), si == Denemo.project->movement);
1654 gtk_box_pack_start (GTK_BOX (vbox), topexpander, FALSE, TRUE, 0);
1655 vbox = gtk_vbox_new (FALSE, 8);
1656 gtk_container_add (GTK_CONTAINER (topexpander), vbox);
1657 GtkWidget *addbutton = gtk_button_new_with_label (_ ("Append Current Staff"));
1658 gtk_widget_set_tooltip_text (addbutton, _("Appends the current staff (the one where the cursor is in the Denemo Display) to this layout. The same staff can be placed at multiple positions in the layout with individual edits in each."));
1659
1660 gtk_box_pack_start (GTK_BOX(vbox), addbutton, FALSE, TRUE, 0);
1661 g_signal_connect (G_OBJECT(addbutton), "clicked", G_CALLBACK (append_staff), pstaffs);
1662
1663 GList *g;
1664 for (voice_count = 1, staff_count = 1, g = si->thescore; g; g = g->next, voice_count++, staff_count++)
1665 {
1666 DenemoStaff *staff = g->data;
1667 if ( (*(staff->lily_name->str)) && (partname && strcmp (partname, staff->lily_name->str))) // empty partname means include with all parts.
1668 continue;
1669 install_staff_with_voices (pstaffs, &vbox, partname, &g, &voice_count, staff_count/*sic*/, movementnum, &staff_group_nesting, standard, FALSE);
1670
1671 if (g == NULL)
1672 break;
1673 } //for each staff
1674
1675 if (staff_group_nesting < 0)
1676 {
1677 g_critical ("Impossible staff group nesting");
1678 }
1679 else
1680 {
1681
1682 for (; staff_group_nesting; staff_group_nesting--)
1683 {
1684 if (partname == NULL)
1685 {
1686 g_warning ("Staff group start without end - terminating it");
1687 add_lilypond (vbox, NULL, g_strdup (" >>%Missing staff group end inserted here\n"));
1688 } else
1689 add_lilypond (vbox, NULL, g_strdup (" >>%Closing staff group end for part layout\n"));
1690
1691 }
1692 }
1693
1694
1695
1696
1697 return ret;
1698 }
1699
1700 /* append the data labeled with affix on the widget s to the out string */
1701 static void
append_lilypond_for_affix(const gchar * affix,GtkWidget * w,GString * out)1702 append_lilypond_for_affix (const gchar * affix, GtkWidget * w, GString * out)
1703 {
1704 GList *g;
1705 for (g = (GList *) g_object_get_data (G_OBJECT (w), affix); g; g = g->next)
1706 {
1707 gchar *text = (gchar *) g->data;
1708 if (text)
1709 g_string_append (out, text);
1710 }
1711 }
1712
1713 /* go through the layout appending score block elements to the out string */
1714 static void
lilypond_for_layout(GString * out,GtkWidget * layout)1715 lilypond_for_layout (GString * out, GtkWidget * layout)
1716 {
1717 append_lilypond_for_affix ("prefix", layout, out);
1718 if (GTK_IS_CONTAINER (layout))
1719 {
1720 GList *list = gtk_container_get_children (GTK_CONTAINER (layout));
1721 if (list)
1722 {
1723 GList *g = list;
1724 do
1725 {
1726 lilypond_for_layout (out, g->data);
1727 }
1728 while ((g = g->next));
1729 g_list_free (list);
1730 }
1731 }
1732 append_lilypond_for_affix ("postfix", layout, out);
1733 }
1734
1735 //return a newly allocated name for a standard scoreblock
1736 static gchar *
movement_part_name(gint movement,gchar * partname)1737 movement_part_name (gint movement, gchar * partname)
1738 {
1739 if (movement && partname)
1740 return g_strdup_printf ("%s M%d", partname, movement);
1741 if (movement)
1742 return g_strdup_printf (_("Movement %d"), movement);
1743 if (partname)
1744 return g_strdup_printf ("%s", partname);
1745 return g_strdup (DEFAULT_SCORE_LAYOUT);
1746 }
1747
1748 static GtkWidget *
get_colored_event_box(GtkWidget * vbox,gchar * colorstring)1749 get_colored_event_box (GtkWidget * vbox, gchar * colorstring)
1750 {
1751 GtkWidget *event_box = gtk_event_box_new ();
1752 gtk_box_pack_start (GTK_BOX (vbox), event_box, FALSE, TRUE, 0);
1753 GdkColor color;
1754 if (gdk_color_parse (colorstring, &color))
1755 gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
1756 return event_box;
1757 }
1758
1759 static void
create_misc_scorewide(GtkWidget * inner_vbox)1760 create_misc_scorewide (GtkWidget * inner_vbox)
1761 {
1762 DenemoProject *gui = Denemo.project;
1763
1764
1765 gchar *lily = g_strdup_printf ("#(set-default-paper-size \"%s\"%s)\n", gui->lilycontrol.papersize->str, gui->lilycontrol.orientation ? "" : " 'landscape");
1766 create_element (inner_vbox, gtk_button_new_with_label (_("paper size")), lily);
1767 lily = g_strdup_printf ("#(set-global-staff-size %s)\n", gui->lilycontrol.staffsize->str);
1768 create_element (inner_vbox, gtk_button_new_with_label (_("Global staff size")), lily);
1769 GtkWidget *expander = gtk_expander_new (_("Paper Block"));
1770 gtk_widget_set_tooltip_text (expander, _("Settings for whole score: includes overall staff size, paper size ...\n"));
1771 add_lilypond (expander, g_strdup ("\\paper {\n"), g_strdup ("\n }\n"));
1772 gtk_box_pack_start (GTK_BOX (inner_vbox), expander, FALSE, TRUE, 0);
1773 GtkWidget *paper_box = gtk_vbox_new (FALSE, 8);
1774 gtk_container_add (GTK_CONTAINER (expander), paper_box);
1775
1776 create_element (paper_box, gtk_button_new_with_label (_("the paper block contents")), get_lilypond_paper ());
1777
1778 }
1779
1780 static void
create_scoreheader_directives(GtkWidget * vbox)1781 create_scoreheader_directives (GtkWidget * vbox)
1782 {
1783 DenemoProject *gui = Denemo.project;
1784 GtkWidget *frame = gtk_frame_new (NULL);
1785 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
1786 GtkWidget *top_expander = gtk_expander_new (_("Score Titles"));
1787 gtk_expander_set_expanded (GTK_EXPANDER (top_expander), TRUE);
1788 add_lilypond (top_expander, g_strdup ("\n\\header {\n"), g_strdup ("\n }\n"));
1789 gtk_widget_set_tooltip_text (top_expander, _("Titles, layout settings, preferences etc for the whole score.\nIncludes main title, composer, date, instrumentation, tagline"));
1790 gtk_container_add (GTK_CONTAINER (frame), top_expander);
1791 GtkWidget *header_box = gtk_vbox_new (FALSE, 8);
1792 gtk_container_add (GTK_CONTAINER (top_expander), header_box);
1793
1794 gchar *escaped_name = g_strescape (gui->filename->str, NULL);
1795 gchar *default_tagline = g_strdup_printf ("tagline = \\markup {\"%s\" on \\simple #(strftime \"%%x\" (localtime (current-time)))}\n", escaped_name);
1796 g_free (escaped_name);
1797 create_element (header_box, gtk_label_new (_("Default tagline")), default_tagline);
1798
1799 GList *g;
1800 for (g = gui->scoreheader.directives; g; g = g->next)
1801 {
1802 DenemoDirective *directive = (DenemoDirective *) g->data;
1803 if (directive->override & (DENEMO_OVERRIDE_AFFIX | DENEMO_OVERRIDE_HIDDEN))
1804 continue;
1805 if (directive->postfix == NULL)
1806 continue;
1807 create_element (header_box, gtk_label_new (directive->tag->str), g_strdup (directive->postfix->str));
1808 }
1809 }
1810
1811 static void
create_score_directives(GtkWidget * vbox)1812 create_score_directives (GtkWidget * vbox)
1813 {
1814 DenemoProject *gui = Denemo.project;
1815 if (gui->lilycontrol.directives == NULL)
1816 return;
1817 GtkWidget *frame = gtk_frame_new (NULL);
1818 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
1819 GtkWidget *top_expander = gtk_expander_new (_("Score Directives"));
1820 gtk_widget_set_tooltip_text (top_expander, _("Includes the indent before first measure, LilyPond include files ..."));
1821 gtk_container_add (GTK_CONTAINER (frame), top_expander);
1822 GtkWidget *inner_vbox = gtk_vbox_new (FALSE, 8);
1823 gtk_container_add (GTK_CONTAINER (top_expander), inner_vbox);
1824
1825 GList *g = gui->lilycontrol.directives;
1826 for (; g; g = g->next)
1827 {
1828 DenemoDirective *directive = g->data;
1829 if (directive->prefix && !(directive->override & (DENEMO_OVERRIDE_AFFIX)))
1830 {
1831 GtkWidget *label = gtk_label_new (directive->tag->str);
1832 create_element (inner_vbox, label, g_strdup (directive->prefix->str));
1833 }
1834 }
1835 }
1836
fill_scorewide_frame(GtkWidget * frame,GtkWidget * reload_button)1837 static void fill_scorewide_frame (GtkWidget *frame, GtkWidget *reload_button)
1838 {
1839
1840 GtkWidget *expander = gtk_expander_new (_("Score-wide Settings."));
1841 gtk_widget_set_tooltip_text (expander, _("Setting the score title, composer, headers and footers for this layout"));
1842 gtk_container_add (GTK_CONTAINER (frame), expander);
1843
1844 GtkWidget *inner_box = gtk_vbox_new (FALSE, 8);
1845 gtk_container_add (GTK_CONTAINER (expander), inner_box);
1846 gtk_box_pack_start (GTK_BOX (inner_box), reload_button, FALSE, TRUE, 0);
1847 #if 0
1848 //having buttons that affect the score itself is confusing
1849 GtkWidget *button = gtk_button_new_with_label (_("Create Book Titles"));
1850 mark_as_non_custom (button);
1851 gtk_widget_set_tooltip_text (button, _("Set book titles for the score"));
1852 g_signal_connect (button, "clicked", G_CALLBACK (popup_score_titles_menu), NULL);
1853 gtk_box_pack_start (GTK_BOX (inner_box), button, FALSE, TRUE, 0);
1854 #endif
1855
1856 create_scoreheader_directives (inner_box);
1857 create_score_directives (inner_box);
1858 create_misc_scorewide (inner_box);
1859 }
1860
get_reload_button(GtkWidget * frame)1861 static GtkWidget *get_reload_button (GtkWidget *frame)
1862 {
1863 GtkWidget *reload_button = gtk_button_new_with_label (_("Reload Score-Wide Settings"));
1864 gtk_widget_set_tooltip_text (reload_button, _("Reload the score wide settings for this layout from the current values in the score.\nDo this if you have made changes to the score titles etc which you wish to be used for this layout."));
1865 g_signal_connect_swapped (reload_button, "clicked", G_CALLBACK (reload_scorewide_block), frame);
1866 return reload_button;
1867 }
reload_scorewide_block(GtkWidget * frame)1868 static void reload_scorewide_block (GtkWidget *frame)
1869 {
1870 GtkWidget *event_box = gtk_widget_get_parent (frame);
1871 GtkWidget *vbox = gtk_widget_get_parent (event_box);
1872 gtk_widget_destroy (frame);
1873 frame = gtk_frame_new (NULL);
1874 GtkWidget *reload_button = get_reload_button (frame);
1875 gtk_container_add (GTK_CONTAINER (event_box), frame);
1876 fill_scorewide_frame (frame, reload_button);
1877 gtk_widget_show_all (vbox);
1878 Denemo.project->lilysync = G_MAXUINT;
1879
1880 }
1881 static void
create_scorewide_block(GtkWidget * vbox)1882 create_scorewide_block (GtkWidget * vbox)
1883 {
1884 GtkWidget *frame = gtk_frame_new (NULL);
1885 GtkWidget *reload_button = get_reload_button (frame);
1886 GtkWidget *event_box = get_colored_event_box (vbox, "#BBFFCC");// event_box is packed into vbox
1887 gtk_container_add (GTK_CONTAINER (event_box), frame);
1888 fill_scorewide_frame (frame, reload_button);
1889 gtk_widget_show_all (vbox);
1890 }
1891
1892 static
install_movement_widget(DenemoMovement * si,GtkWidget * vbox,DenemoScoreblock ** psb,gchar * partname,gint movement_num,gboolean last,gboolean standard)1893 void install_movement_widget (DenemoMovement *si, GtkWidget *vbox, DenemoScoreblock ** psb, gchar *partname, gint movement_num, gboolean last, gboolean standard)
1894 {
1895 DenemoProject *gui = Denemo.project;
1896 gchar *label_text = gui->movements->next ? g_strdup_printf (_("<b>Movement %d</b>"), movement_num) : g_strdup (_("Movement"));
1897 GtkWidget *movement_frame = gtk_expander_new (label_text);
1898 gtk_label_set_use_markup (GTK_LABEL (gtk_expander_get_label_widget (GTK_EXPANDER(movement_frame))), TRUE);
1899 gtk_widget_set_tooltip_text (movement_frame, _("This contains the layout of the movement- the movement title, and the actual music itself"));
1900 gtk_expander_set_expanded (GTK_EXPANDER (movement_frame), si == gui->movement);
1901 g_free (label_text);
1902 gtk_box_pack_start (GTK_BOX (vbox), movement_frame, FALSE, TRUE, 0);
1903
1904 GtkWidget *frame_box = gtk_vbox_new (FALSE, 8);
1905 gtk_container_add (GTK_CONTAINER (movement_frame), frame_box);
1906 GtkWidget *remove_box = gtk_hbox_new (FALSE, 8);
1907 gtk_box_pack_start (GTK_BOX (frame_box), remove_box, FALSE, FALSE, 0);
1908 GtkWidget *w = gtk_button_new_with_label ("<span foreground=\"red\">Remove Movement</span>");
1909 gtk_label_set_use_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN(w))), TRUE);
1910 gtk_widget_set_tooltip_text (w, _("Remove this movement from the score layout"));
1911 g_signal_connect_swapped (w, "clicked", G_CALLBACK (remove_element), frame_box); //grandparent
1912 gtk_box_pack_start (GTK_BOX (remove_box), w, FALSE, FALSE, 14);
1913 // GtkWidget *dummy = gtk_label_new (" dummy ");
1914 //gtk_box_pack_start (GTK_BOX (frame_box), dummy, TRUE, TRUE, 0);
1915
1916 GtkWidget *outer_hbox = gtk_hbox_new (FALSE, 8);
1917 gtk_box_pack_start (GTK_BOX (frame_box), outer_hbox, FALSE, TRUE, 0);
1918
1919 GtkWidget *movement_vbox = gtk_vbox_new (FALSE, 8);
1920 gtk_box_pack_start (GTK_BOX (outer_hbox), movement_vbox, FALSE, TRUE, 10);
1921 install_pre_movement_widgets (movement_vbox, si, standard);
1922 GtkWidget *frame = gtk_frame_new (NULL);
1923 add_lilypond (frame, g_strdup ("\n\\score { %Start of Movement\n"), g_strdup ("\n } %End of Movement\n"));
1924 gtk_box_pack_start (GTK_BOX (movement_vbox), frame, FALSE, TRUE, 0);
1925 GtkWidget *outer_vbox = gtk_vbox_new (FALSE, 8);
1926 gtk_container_add (GTK_CONTAINER (frame), outer_vbox);
1927 GtkWidget *hbox = gtk_hbox_new (FALSE, 8);
1928
1929 gtk_box_pack_start (GTK_BOX (hbox), get_movement_widget (&(*psb)->staff_list, partname, si, movement_num, last, standard), FALSE, TRUE, 0);
1930 gtk_box_pack_start (GTK_BOX (outer_vbox), hbox, FALSE, TRUE, 0);
1931 if (si->header.directives)
1932 {
1933 GtkWidget *frame = gtk_frame_new (_("Header block"));
1934 gtk_box_pack_start (GTK_BOX (outer_vbox), frame, FALSE, TRUE, 0);
1935 add_lilypond (frame, g_strdup ("\n\\header {\n"), g_strdup ("\n }\n"));
1936 GtkWidget *innerbox = gtk_vbox_new (FALSE, 8);
1937 gtk_container_add (GTK_CONTAINER (frame), innerbox);
1938 GList *g;
1939 for (g = si->header.directives; g; g = g->next)
1940 {
1941 DenemoDirective *d = g->data;
1942 if (d->override & DENEMO_OVERRIDE_HIDDEN)
1943 continue;
1944
1945 gchar *lily = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
1946 if (lily)
1947 {
1948 create_element (innerbox, gtk_button_new_with_label (d->tag->str), g_strdup (lily));
1949 }
1950 }
1951 }
1952 if (si->layout.directives)
1953 {
1954 GtkWidget *frame = gtk_frame_new (_("Layout block"));
1955 gtk_box_pack_start (GTK_BOX (outer_vbox), frame, FALSE, TRUE, 0);
1956 add_lilypond (frame, g_strdup ("\n\\layout {\n"), g_strdup ("\n}\n"));
1957 GtkWidget *innerbox = gtk_vbox_new (FALSE, 8);
1958 gtk_container_add (GTK_CONTAINER (frame), innerbox);
1959 GList *g;
1960 for (g = si->layout.directives; g; g = g->next)
1961 {
1962 DenemoDirective *d = g->data;
1963 if (d->override & DENEMO_OVERRIDE_HIDDEN)
1964 continue;
1965
1966 gchar *lily = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
1967 if (lily)
1968 {
1969 create_element (innerbox, gtk_button_new_with_label (d->tag->str), g_strdup (lily));
1970 }
1971 }
1972 }
1973
1974 if (si->movementcontrol.directives)
1975 {
1976 GtkWidget *frame = gtk_frame_new (_("Movement Block"));
1977 gtk_box_pack_start (GTK_BOX (outer_vbox), frame, FALSE, TRUE, 0);
1978 GtkWidget *innerbox = gtk_vbox_new (FALSE, 8);
1979 gtk_container_add (GTK_CONTAINER (frame), innerbox);
1980 GList *g;
1981 for (g = si->movementcontrol.directives; g; g = g->next)
1982 {
1983 DenemoDirective *d = (DenemoDirective *) g->data;
1984 if (d->override & DENEMO_OVERRIDE_AFFIX && d->postfix)
1985 {
1986 gchar *text = label_for_directive (d);
1987 GtkWidget *label = gtk_label_new (text);
1988 g_free (text);
1989 create_element (innerbox, label, g_strdup (d->postfix->str));
1990 }
1991 }
1992 }
1993
1994
1995
1996 if (si->movementcontrol.directives)
1997 {
1998 GtkWidget *frame = gtk_frame_new (_("Movement Epilog"));
1999 gtk_box_pack_start (GTK_BOX (movement_vbox), frame, FALSE, TRUE, 0);
2000 GtkWidget *innerbox = gtk_vbox_new (FALSE, 8);
2001 gtk_container_add (GTK_CONTAINER (frame), innerbox);
2002 GList *g;
2003 for (g = si->movementcontrol.directives; g; g = g->next)
2004 {
2005 DenemoDirective *d = (DenemoDirective *) g->data;
2006 if (d->override & DENEMO_OVERRIDE_AFFIX)
2007 continue;
2008 if (d->override & DENEMO_OVERRIDE_HIDDEN)
2009 continue;
2010
2011 if (d->postfix)
2012 {
2013 gchar *text = label_for_directive (d);
2014 GtkWidget *label = gtk_label_new (text);
2015 g_free (text);
2016 create_element (innerbox, label, g_strdup (d->postfix->str));
2017 }
2018 }
2019 }
2020 }
install_duplicate_movement(DenemoScoreblock ** psb,gint movement)2021 static void install_duplicate_movement (DenemoScoreblock ** psb, gint movement)
2022 {
2023 gchar *partname = NULL;
2024 //show_type (gtk_bin_get_child (gtk_bin_get_child ((*psb)->widget)), "Type of widget ");
2025 GtkWidget *vbox = gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN ((*psb)->widget))));
2026 DenemoMovement *si = g_list_nth_data (Denemo.project->movements, movement - 1);
2027 if (si)
2028 install_movement_widget (si, vbox, psb, partname, movement, TRUE, FALSE);
2029 }
install_duplicate_movement_callback(DenemoScoreblock * sb)2030 static void install_duplicate_movement_callback (DenemoScoreblock *sb)
2031 {
2032 install_duplicate_movement (&sb, Denemo.project->movement->currentmovementnum);
2033 score_status (Denemo.project, TRUE);
2034 gtk_widget_show_all (sb->widget);
2035 }
2036
reorder_movement(DenemoScoreblock * psb)2037 static void reorder_movement (DenemoScoreblock * psb)
2038 {
2039 //show_type (gtk_bin_get_child (gtk_bin_get_child ((*psb)->widget)), "Type of widget ");
2040 GtkWidget *vbox = gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN (psb->widget))));
2041 GList *children = gtk_container_get_children (GTK_CONTAINER(vbox));
2042 //show_type ( g_list_nth_data (children, movement) , "Type of widget ");
2043 for ( ;children; children=children->next)
2044 {
2045 if( GTK_IS_EXPANDER (children->data) && gtk_expander_get_expanded (children->data))
2046 {
2047 if (children->next == NULL)
2048 warningdialog (_( "The currently expanded movement is already at the end"));
2049 else
2050 gtk_box_reorder_child (GTK_BOX(vbox), children->data, -1);//-1 = to end
2051 g_list_free (children);
2052 return;
2053 }
2054 }
2055 warningdialog (_("No movement is expanded - don't know which movement to move"));
2056 }
2057
reorder_movement_callback(DenemoScoreblock * psb)2058 static void reorder_movement_callback (DenemoScoreblock * psb)
2059 {
2060 reorder_movement (psb);
2061 score_status (Denemo.project, TRUE);
2062
2063 }
2064
2065 //find the one that is expanded FIXME
2066
2067 //populates the scoreblock *psb with the movement or movements for partname from the current score Denemo.project
2068 static void
set_default_scoreblock(DenemoScoreblock ** psb,gint movement,gchar * partname)2069 set_default_scoreblock (DenemoScoreblock ** psb, gint movement, gchar * partname)
2070 {
2071 DenemoProject *gui = Denemo.project;
2072 (*psb)->staff_list = NULL; //list of staff frames in order they appear in scoreblock
2073
2074 (*psb)->widget = gtk_scrolled_window_new (gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0), gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0));
2075
2076 (*psb)->visible = FALSE; //will be set true when/if tab is selected
2077 if (partname)
2078 (*psb)->partname = g_strdup (partname);
2079 (*psb)->movement = movement;
2080 layout_sync = (*psb)->layout_sync = gui->layout_sync;
2081
2082
2083 GtkWidget *vbox = gtk_vbox_new (FALSE, 8);
2084 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW ((*psb)->widget), vbox);
2085 GtkWidget *options = get_options_button (*psb, FALSE);
2086 gtk_box_pack_start (GTK_BOX (vbox), options, FALSE, FALSE, 0);
2087 //now create a hierarchy of widgets representing the score
2088 create_scorewide_block (vbox);
2089
2090 GList *g;
2091 gint movement_num = 1;
2092 for (g = gui->movements; g; g = g->next, movement_num++)
2093 {
2094 if (movement == 0 /*all movements */ || (movement == movement_num) /*this movement */ )
2095 {
2096 DenemoMovement *si = (DenemoMovement *) g->data;
2097 install_movement_widget (si, vbox, psb, partname, movement_num, !(gboolean) GPOINTER_TO_INT (g->next), TRUE);
2098
2099 } //if movement is wanted
2100 } //for all movements
2101
2102 for (g = gui->lilycontrol.directives; g; g = g->next)
2103 {
2104 DenemoDirective *d = g->data;//g_print("def %s %s\n", d->tag->str, d->postfix?d->postfix->str:"No postfix");
2105 if (d->override & DENEMO_OVERRIDE_HIDDEN)
2106 continue;
2107 if (!(d->override & DENEMO_OVERRIDE_AFFIX))
2108 continue;
2109 gchar *post = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
2110 if (post)
2111 {
2112 create_element (vbox, gtk_button_new_with_label (d->tag->str), g_strdup (post));
2113 }
2114 }
2115
2116
2117 }
2118
2119 //recompute a standard scoreblock
2120 static void
recreate_standard_scoreblock(DenemoScoreblock ** psb)2121 recreate_standard_scoreblock (DenemoScoreblock ** psb)
2122 {
2123 gint movement = (*psb)->movement;
2124 gchar *partname = (*psb)->partname ? g_strdup ((*psb)->partname) : NULL;
2125 gchar *instrumentation = (*psb)->instrumentation ? g_strdup ((*psb)->instrumentation) : NULL;
2126 gboolean visible = (*psb)->visible;
2127 GtkNotebook *notebook = GTK_NOTEBOOK (get_score_layout_notebook (Denemo.project));
2128 if((*psb)->widget)
2129 set_notebook_page((*psb)->widget);
2130 gint position = gtk_notebook_get_current_page(notebook);
2131 free_scoreblock ((*psb)); //this changes the page in the notebook if it was selected before. So if sb->visible then re-select this page after reconstruction
2132 create_standard_scoreblock (psb, movement, partname);
2133 (*psb)->instrumentation = instrumentation;
2134 gtk_notebook_reorder_child (notebook, (*psb)->widget, position);
2135 //alternatively pass in desired position to create_standard_scoreblock....
2136
2137
2138 // if (visible)
2139 // gtk_notebook_set_current_page (GTK_NOTEBOOK (get_score_layout_notebook (Denemo.project)), 0);
2140 }
2141
2142 //return value must not be freed
2143 /* UNUSED
2144 static const gchar *
2145 scoreblock_name (DenemoScoreblock * sb)
2146 {
2147 return gtk_notebook_get_tab_label_text (GTK_NOTEBOOK (get_score_layout_notebook (Denemo.project)), sb->widget);
2148 }
2149 */
2150
2151
2152 //refreshes the lilypond field of all the standard scoreblocks after re-computing the standard scoreblocks already present
2153 //returns FALSE if structure has not changed since they were computed.
2154 static gboolean
check_for_update(void)2155 check_for_update (void)
2156 {
2157 DenemoProject *gui = Denemo.project;
2158 if (gui->layout_sync > layout_sync)
2159 {
2160 GList *g;
2161 for (g = gui->standard_scoreblocks; g; g = g->next)
2162 {
2163 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
2164 recreate_standard_scoreblock (&sb);
2165 }
2166 return TRUE;
2167 }
2168 return FALSE;
2169 }
2170
2171 static gboolean
change_tab(GtkNotebook * notebook,GtkWidget * page,gint pagenum)2172 change_tab (GtkNotebook * notebook, GtkWidget * page, gint pagenum)
2173 {
2174 //this is getting called with pagenum 0 when clicking on the lilypond text window...
2175 Denemo.project->lilysync = G_MAXUINT;
2176 page = gtk_notebook_get_nth_page (notebook, pagenum); // value passed in appears to be something else - it is not documented what.
2177
2178 GList *g;
2179 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
2180 {
2181 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2182 sb->visible = (sb->widget == page);
2183 }
2184 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2185 {
2186 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2187 sb->visible = (sb->widget == page);
2188 }
2189 Denemo.project->layout_id = 0;
2190 return TRUE;
2191 }
2192
2193 //takes a DenemoScoreblock that has a valid widget field and recomputes the lilypond field of the scoreblock
2194 //from the widget. It also sets the name field of the scoreblock to the name on the Notebook tab.
2195 // It sets the instrumentation if set in the scoreblock structure.
2196 void
refresh_lilypond(DenemoScoreblock * sb)2197 refresh_lilypond (DenemoScoreblock * sb)
2198 {
2199 if (sb->widget)
2200 {
2201
2202 if ((!is_lilypond_text_layout (sb)))
2203 {
2204 gchar *instrumentation = sb->instrumentation;
2205 gchar *set_instr = instrumentation? g_strdup (instrumentation):
2206 ((!strcmp (sb->name, DEFAULT_SCORE_LAYOUT))?g_strdup (_("Full Score")):
2207 ((g_str_has_prefix (sb->name, _("Movement")))?
2208 g_strdup (sb->name):
2209 NULL));
2210
2211 instrumentation = set_instr? g_strdup_printf (" instrumentation = \\markup { \\with-url #'\"scheme:(d-BookInstrumentation)\" \"%s\"}\n", set_instr):
2212 g_strdup ("");
2213 g_free (set_instr);
2214 set_instr = instrumentation;
2215
2216 sb->id = crc32 ((guchar*) sb->name);
2217 if (sb->lilypond == NULL)
2218 sb->lilypond = g_string_new (sb->name);
2219 else
2220 g_string_assign (sb->lilypond, sb->name);
2221 g_string_prepend (sb->lilypond, "%");
2222 g_string_append_printf (sb->lilypond, "\n\\header{DenemoLayoutName = \"%s\"\n%s }\n",
2223 sb->name,
2224 set_instr);
2225 g_free (set_instr);
2226 lilypond_for_layout (sb->lilypond, sb->widget);
2227 }
2228 }
2229 else
2230 g_warning ("No widget for scoreblock");
2231 }
2232 gboolean
current_scoreblock_is_custom(void)2233 current_scoreblock_is_custom (void)
2234 {
2235 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
2236 gint pagenum = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
2237 GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum);
2238 GList *g;
2239 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
2240 {
2241 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2242 if (sb->widget == page)
2243 return TRUE;
2244 }
2245 return FALSE;
2246 }
2247 DenemoScoreblock *
selected_scoreblock(void)2248 selected_scoreblock (void)
2249 {
2250 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
2251 gint pagenum = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook)); // value passed in appears to be something else - it is not documented what.
2252 GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum);
2253 GList *g;
2254 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
2255 {
2256 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2257 if (sb->widget == page)
2258 {
2259 refresh_lilypond (sb); //!!!! needs sorting out !!!
2260 return sb;
2261 }
2262 }
2263 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2264 {
2265 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2266 if (sb->widget == page)
2267 {
2268 refresh_lilypond (sb);
2269 return sb;
2270 }
2271 }
2272 return NULL;
2273 }
2274
2275 //returns a uri for the pdf output for the current scoreblock. The user must free when done.
2276 gchar *
get_output_uri_from_scoreblock(void)2277 get_output_uri_from_scoreblock (void)
2278 {
2279 DenemoScoreblock *sb = selected_scoreblock ();
2280 if (sb == NULL)
2281 {
2282 g_warning ("No Score Layout");
2283 return g_strdup ("");
2284 }
2285 DenemoProject *gui = Denemo.project;
2286 if (sb->uri)
2287 return g_strdup (sb->uri);
2288 gchar *basename;
2289 gchar *dirname;
2290 if (Denemo.project->filename && Denemo.project->filename->len)
2291 {
2292 gchar *filename = gui->filename->str;
2293 dirname = g_path_get_dirname (filename);
2294 basename = g_path_get_basename (filename);
2295 gchar *suffix = g_strrstr (basename, DENEMO_FILE_SUFFIX);
2296 if (suffix)
2297 *suffix = 0;
2298 }
2299 else
2300 {
2301 basename = g_strdup ("output");
2302 dirname = g_get_current_dir ();
2303 }
2304 gchar *uri = g_strdup_printf ("file://%s", dirname);
2305 g_free (dirname);
2306 gchar *ret;
2307 if (sb)
2308 {
2309 gchar *pdf_name = g_strconcat (basename, "-", sb->name, ".pdf", NULL);
2310 ret = g_build_filename (uri, pdf_name, NULL);
2311 g_free (pdf_name);
2312 }
2313 else
2314 {
2315 ret = g_build_filename (uri, "output.pdf", NULL);
2316 }
2317 g_free (basename);
2318 g_free (uri);
2319 return ret;
2320 }
2321
2322 void
set_current_scoreblock_uri(gchar * uri)2323 set_current_scoreblock_uri (gchar * uri)
2324 {
2325 DenemoScoreblock *sb = selected_scoreblock ();
2326 if (sb)
2327 {
2328 g_free (sb->uri);
2329 sb->uri = uri;
2330 }
2331 }
2332
2333 //Returns the next scoreblock in the score layout notebook, or NULL if it is the last
2334 DenemoScoreblock *
get_next_scoreblock(void)2335 get_next_scoreblock (void)
2336 {
2337 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
2338 gint pagenum = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
2339 GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), pagenum + 1);
2340 if (page)
2341 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), pagenum + 1);
2342 GList *g;
2343 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
2344 {
2345 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2346 if (sb->widget == page)
2347 {
2348 refresh_lilypond (sb); //!!!! needs sorting out !!!
2349 return sb;
2350 }
2351 }
2352 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2353 {
2354 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2355 if (sb->widget == page)
2356 {
2357 refresh_lilypond (sb);
2358 return sb;
2359 }
2360 }
2361 return NULL;
2362 }
2363
2364 //Returns the next scoreblock in the score layout notebook, or NULL if it is the last
2365 DenemoScoreblock *
get_first_scoreblock(void)2366 get_first_scoreblock (void)
2367 {
2368 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
2369 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
2370 GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0);
2371 GList *g;
2372 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
2373 {
2374 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2375 if (sb->widget == page)
2376 {
2377 refresh_lilypond (sb);
2378 return sb;
2379 }
2380 }
2381 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2382 {
2383 DenemoScoreblock *sb = ((DenemoScoreblock *) g->data);
2384 if (sb->widget == page)
2385 {
2386 refresh_lilypond (sb);
2387 return sb;
2388 }
2389 }
2390 return NULL;
2391 }
2392
2393
2394 gboolean
iterate_custom_layout(gboolean init)2395 iterate_custom_layout (gboolean init)
2396 { //!!!!!!!!problem for lilypondized ones is widget NULL????
2397 static gint current;
2398 DenemoScoreblock *sb;
2399 if (Denemo.project->custom_scoreblocks == NULL)
2400 {
2401 return FALSE;
2402 }
2403 if (init)
2404 {
2405 current = 0;
2406 sb = (DenemoScoreblock *) (Denemo.project->custom_scoreblocks->data);
2407 }
2408 else
2409 {
2410 current++;
2411 sb = (DenemoScoreblock *) g_list_nth_data (Denemo.project->custom_scoreblocks, current);
2412 }
2413 if (sb && sb->widget)
2414 {
2415 if(!Denemo.non_interactive){
2416 if (!gtk_widget_get_visible (Denemo.project->score_layout))
2417 activate_action ("/MainMenu/ViewMenu/ToggleScoreLayout");
2418 set_notebook_page (sb->widget);
2419 }
2420 return TRUE;
2421 }
2422 else
2423 {
2424 g_debug ("No custom layout %d sb = %p\n", current, sb);
2425 return FALSE;
2426 }
2427 }
2428
2429 guint
get_layout_id_for_name(gchar * name)2430 get_layout_id_for_name (gchar *name)
2431 {
2432 return crc32(name);
2433 }
2434
2435 guint
selected_layout_id(void)2436 selected_layout_id (void)
2437 {
2438 if (Denemo.project->layout_id == 0)
2439 {
2440 DenemoScoreblock *sb = selected_scoreblock ();
2441 if (sb)
2442 Denemo.project->layout_id = sb->id;
2443 }
2444 return Denemo.project->layout_id;
2445 }
2446
2447 GtkWidget *
get_score_layout_notebook(DenemoProject * gui)2448 get_score_layout_notebook (DenemoProject * gui)
2449 {
2450 GtkWidget *notebook = gtk_bin_get_child (GTK_BIN (gui->score_layout));
2451 if (notebook == NULL)
2452 {
2453 notebook = gtk_notebook_new ();
2454 g_signal_connect (notebook, "switch_page", G_CALLBACK (change_tab), NULL);
2455 g_signal_connect (gui->score_layout, "focus-in-event", G_CALLBACK (check_for_update), NULL);
2456 gtk_container_add (GTK_CONTAINER (gui->score_layout), notebook);
2457 }
2458 return notebook;
2459 }
2460
2461 //create a standard scoreblock in the passed DenemoScoreblock structure and put it in a new tab in the score
2462 //does not add it to the standard scoreblocks list
2463 static void
create_standard_scoreblock(DenemoScoreblock ** psb,gint movement,gchar * partname)2464 create_standard_scoreblock (DenemoScoreblock ** psb, gint movement, gchar * partname)
2465 {
2466 DenemoProject *gui = Denemo.project;
2467 GtkWidget *notebook = get_score_layout_notebook (gui);
2468 set_default_scoreblock (psb, movement, partname);
2469
2470 gchar *label_text = movement_part_name (movement, partname);
2471 (*psb)->name = g_strdup (label_text);
2472 GtkWidget *label = gtk_label_new (label_text);
2473 g_free (label_text);
2474 gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), (*psb)->widget, label);
2475 gtk_widget_set_tooltip_markup ((*psb)->widget,
2476 _
2477 ("This is a score layout - the buttons mostly customize the layout\nYou can have several layouts and use them to print different versions of your score.\nOnce customized e.g. by adding page breaks, deleting certain parts etc the layout will be saved with your score and can be used for printing from even though you may have made corrections to the music.\nStandard layouts are created by invoking the standard print commands - print, print part, print movement etc.\nThese standard layouts provide a convenient starting point for your customized layouts.<b>Note 1</b>Custom layouts are not saved for further graphical editing, only the typesetting commands are saved, so, unless you are familiar with LilyPond do all your work on the layout in one session.<b>Note 2</b>The first comment in the LilyPond text of the layout holds the name of the layout. If you change it any conditional directives that are for the layout will need refreshing"));
2478 gtk_widget_show_all (notebook);
2479 }
2480
2481 static void
set_notebook_page(GtkWidget * w)2482 set_notebook_page (GtkWidget * w)
2483 {
2484 GtkWidget *notebook = get_score_layout_notebook (Denemo.project);
2485 GList *g = gtk_container_get_children (GTK_CONTAINER (notebook));
2486 gint position = g_list_index (g, w); //g_debug("pos %d", position);
2487 g_list_free (g);
2488 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), position);
2489 }
2490
2491 void
create_default_scoreblock(void)2492 create_default_scoreblock (void)
2493 {
2494 DenemoProject *gui = Denemo.project;
2495 if (gui->custom_scoreblocks)
2496 {
2497 GList *g;
2498 for (g = gui->custom_scoreblocks; g; g = g->next)
2499 {
2500 DenemoScoreblock *sb = g->data;
2501 if (!strcmp (sb->name, DEFAULT_SCORE_LAYOUT))
2502 {
2503 set_notebook_page (sb->widget);
2504 return;
2505 }
2506 }
2507 }
2508 if (gui->standard_scoreblocks)
2509 {
2510 GList *g;
2511 for (g = gui->standard_scoreblocks; g; g = g->next)
2512 {
2513 DenemoScoreblock *sb = g->data;
2514 if (!strcmp (sb->name, DEFAULT_SCORE_LAYOUT))
2515 {
2516 set_notebook_page (sb->widget);
2517 return;
2518 }
2519 }
2520 }
2521 DenemoScoreblock *sb = g_malloc0 (sizeof (DenemoScoreblock));
2522 (void) create_standard_scoreblock (&sb, 0, NULL);
2523 gui->standard_scoreblocks = g_list_prepend (gui->standard_scoreblocks, (gpointer) sb);
2524 }
2525
2526 /* select the scoreblock with the standard default scoreblock name, choosing a customized
2527 * version over any standard version. Create one if it does not exist.
2528 */
2529 void
select_default_scoreblock(void)2530 select_default_scoreblock (void)
2531 {
2532 DenemoProject *gui = Denemo.project;
2533 if (gui->custom_scoreblocks)
2534 {
2535 GList *g;
2536 for (g = gui->custom_scoreblocks; g; g = g->next)
2537 {
2538 DenemoScoreblock *sb = g->data;
2539 if (!strcmp (sb->name, DEFAULT_SCORE_LAYOUT))
2540 {
2541 set_notebook_page (sb->widget);
2542 return;
2543 }
2544 }
2545 }
2546 if (gui->standard_scoreblocks)
2547 {
2548 GList *g;
2549 for (g = gui->standard_scoreblocks; g; g = g->next)
2550 {
2551 DenemoScoreblock *sb = g->data;
2552 if (!strcmp (sb->name, DEFAULT_SCORE_LAYOUT))
2553 {
2554 set_notebook_page (sb->widget);
2555 return;
2556 }
2557 }
2558 }
2559 }
2560
2561 static void
selection_install_voice(DenemoStaff * staff,gint movementnum,gint voice_count,GString * lilypond,GString * tail,GString * voice_tail)2562 selection_install_voice (DenemoStaff * staff, gint movementnum, gint voice_count, GString * lilypond, GString * tail, GString * voice_tail)
2563 {
2564 gchar *voicetag = get_voicetag (movementnum, voice_count);
2565 gchar *voicename = get_voicename (movementnum, voice_count);
2566 gchar *text1;
2567
2568
2569 GString *voicetext = g_string_new ("");
2570 set_voice_definition (voicetext, staff, voicetag); //That is \new Voice = name prefix { postfix FIXME is prefix any use here????
2571 gchar *text = g_strdup_printf (" %s ", voicetext->str);
2572 g_string_assign (voicetext, "");
2573
2574 set_voice_termination (voice_tail, staff); // TAB TAB"} %End of voice" if not overridden
2575
2576
2577
2578 g_string_append (lilypond, text);
2579
2580 text1 = g_strdup_printf (" \\%s", voicename);
2581 if (staff->voicecontrol == DENEMO_PRIMARY)
2582 {
2583 g_string_append (lilypond, get_lilypond_for_clef (&staff->clef));
2584 g_string_append (lilypond, get_lilypond_for_keysig (&staff->keysig));
2585 g_string_append (lilypond, get_lilypond_for_timesig (&staff->timesig));
2586 }
2587 g_string_append (lilypond, text1);
2588 g_free (text1);
2589
2590
2591 g_string_prepend (tail, g_string_free (voicetext, FALSE));
2592 }
2593
2594 //returns a layout with no widget whose lilypond is the scoreblock for just the selected staffs
2595 DenemoScoreblock *
selection_layout(void)2596 selection_layout (void)
2597 {
2598 DenemoProject *gui = Denemo.project;
2599 DenemoMovement *si = gui->movement;
2600 GString *movement_tail = g_string_new ("");
2601 gint movementnum = g_list_index (Denemo.project->movements, Denemo.project->movement) + 1;
2602 static DenemoScoreblock *sb;
2603 if (sb == NULL)
2604 {
2605 sb = g_malloc0 (sizeof (DenemoScoreblock));
2606 sb->lilypond = g_string_new ("");
2607 }
2608
2609 g_string_assign (sb->lilypond, "\n\\score\n{ %Start of Selection from current movement\n");
2610 set_initiate_scoreblock (si, sb->lilypond); // ie << possibly overridden
2611
2612 GList *g; //things like transpose whole score etc
2613 for (g = gui->lilycontrol.directives; g; g = g->next)
2614 {
2615 DenemoDirective *d = g->data;
2616 if (d->override & DENEMO_OVERRIDE_HIDDEN)
2617 continue;
2618 if (d->override & DENEMO_OVERRIDE_AFFIX)
2619 continue;
2620 gchar *start = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
2621 if (start)
2622 {
2623 g_string_append_printf (sb->lilypond, "\n << %s\n << ", start);
2624 g_string_prepend (movement_tail, "\n >>\n >>");
2625 }
2626 }
2627 gint voice_count;
2628 for (voice_count = 1, g = gui->movement->thescore; g; g? g = g->next : g, voice_count++)
2629 {
2630 DenemoStaff *staff = g->data;
2631 DenemoStaff *nextstaff = g->next ? g->next->data : NULL;
2632 GString *stafftext = g_string_new ("");
2633 if (!(voice_count >= gui->movement->selection.firststaffmarked && voice_count <= gui->movement->selection.laststaffmarked))
2634 continue;
2635 if (staff->hasfakechords)
2636 { //the reason these are outside the staff frame is it makes them appear above the staff
2637 g_string_append_printf (sb->lilypond, "\n" TAB TAB "\\new ChordNames \\chordmode { \\%sChords }\n", get_voicename (movementnum, voice_count));
2638 }
2639 set_staff_definition (sb->lilypond, staff);
2640
2641
2642
2643
2644 //if (staff->no_of_lines != 5)
2645 // g_string_append_printf (sb->lilypond, TAB "\\override Staff.StaffSymbol #'line-count = #%d\n", staff->no_of_lines); //FIXME create_element
2646 GString *tail = g_string_new ("");
2647 GString *voice_tail = g_string_new ("");
2648 g_string_assign (stafftext, "");
2649 set_staff_termination (stafftext, staff); // "\n>>\n%End of Staff\n"
2650
2651 g_string_prepend (tail, g_string_free (stafftext, FALSE));
2652
2653 if (staff->hasfigures)
2654 {
2655 g_string_append_printf (sb->lilypond, "\n" TAB TAB "\\context Staff \\with {implicitBassFigures = #'(0) } \\%sBassFiguresLine %%End of bass figures\n", get_voicename (movementnum, voice_count));
2656 }
2657
2658 selection_install_voice (staff, movementnum, voice_count, sb->lilypond, tail, voice_tail); //Primary voice
2659
2660 g_string_append (sb->lilypond, voice_tail->str);
2661 g_string_assign(voice_tail, "");
2662 //selection_do_verses(staff, vbox, movementnum, this is repeated below
2663 gboolean voices_intervened;
2664 voices_intervened = FALSE;
2665 if (nextstaff && (nextstaff->voicecontrol & DENEMO_SECONDARY))
2666 {
2667 for (g = g->next, voice_count++; g && (((DenemoStaff *) g->data)->voicecontrol & DENEMO_SECONDARY); g = g->next, voice_count++)
2668 {
2669 GString *voicetail = g_string_new ("");
2670 DenemoStaff *staff = g->data;
2671 selection_install_voice (staff, movementnum, voice_count, sb->lilypond, voicetail, voice_tail);
2672 g_string_append (sb->lilypond, g_string_free (voicetail, FALSE));
2673 g_string_append (sb->lilypond, voice_tail->str);
2674 g_string_assign(voice_tail, "");
2675 voices_intervened = TRUE;
2676 //selection_do_verses(staff, vbox, movementnum, this is repeated above
2677 }
2678 }
2679
2680 g_string_free (voice_tail, TRUE);
2681
2682 if (tail->len)
2683 g_string_append (sb->lilypond, g_string_free (tail, FALSE));
2684 else
2685 g_string_free (tail, FALSE);
2686
2687 if(g && voices_intervened) // we have added voices to the staff, so the for loop has advanced the iterator over staffs and voice count already, so back up
2688 {
2689 g = g->prev;
2690 voice_count--;
2691 }
2692 } // end of for each staff Now loop back for all the staffs in firststaffnum - laststaffnum
2693 g_string_append (sb->lilypond, movement_tail->str);
2694 g_string_free (movement_tail, TRUE);
2695 g_string_append (sb->lilypond, "\n >>\n");
2696 g_string_append_printf (sb->lilypond, "\n\\header {\n");
2697
2698 for (g = si->header.directives; g; g = g->next)
2699 {
2700 DenemoDirective *d = g->data;
2701 if (d->override & DENEMO_OVERRIDE_HIDDEN)
2702 continue;
2703
2704 gchar *lily = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
2705 if (lily)
2706 {
2707 g_string_append (sb->lilypond, lily);
2708 }
2709 }
2710
2711 g_string_append (sb->lilypond, "\n}\n");
2712
2713
2714
2715 if (si->layout.directives)
2716 {
2717 g_string_append (sb->lilypond, "\n\\layout {\n");
2718 for (g = si->layout.directives; g; g = g->next)
2719 {
2720 DenemoDirective *d = g->data;
2721 if (d->override & DENEMO_OVERRIDE_HIDDEN)
2722 continue;
2723
2724 gchar *lily = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
2725 if (lily)
2726 {
2727 g_string_append (sb->lilypond, lily);
2728 }
2729 }
2730 g_string_append (sb->lilypond, ("\n}\n"));
2731 }
2732 #if 0
2733 maybe not this ... for (g = gui->lilycontrol.directives; g; g = g->next)
2734 {
2735 DenemoDirective *d = g->data;
2736 if (d->override & DENEMO_OVERRIDE_HIDDEN)
2737 continue;
2738 if (!(d->override & DENEMO_OVERRIDE_AFFIX))
2739 continue;
2740 gchar *post = (d->postfix && d->postfix->len) ? d->postfix->str : NULL;
2741 if (post)
2742 {
2743 create_element (vbox, gtk_button_new_with_label (d->tag->str), g_strdup (post));
2744 }
2745 }
2746 #endif
2747
2748 g_string_append (sb->lilypond, "\n} %End of Movement\n");
2749
2750
2751 return sb;
2752 }
2753
2754 //if the call is all_movements is current (1) and no partname ie default, then current layout is returned, re-created (if need be) if it is a standard one
2755 //otherwise selects or creates a standard layout for the given spec: all_movements (0=all, 1 = current) and part (NULL is all parts, otherwise parts with partname).
2756 DenemoScoreblock *
select_layout(gboolean all_movements,gchar * partname,gchar * instrumentation)2757 select_layout (gboolean all_movements, gchar * partname, gchar * instrumentation)
2758 {
2759 GList *g;
2760 DenemoScoreblock *sb;
2761 if (Denemo.project->movement->markstaffnum)
2762 return selection_layout ();
2763
2764
2765
2766 if (all_movements && partname == NULL)
2767 {
2768 sb = selected_scoreblock ();
2769 if (sb)
2770 {
2771 if (is_in_standard_scoreblock (sb))
2772 {
2773 recreate_standard_scoreblock (&sb);
2774 refresh_lilypond (sb);
2775 }
2776 set_notebook_page (sb->widget);
2777 return sb;
2778 }
2779 }
2780
2781
2782 //otherwise return a standard scoreblock recreating it - though this should only need doing if changecount has moved on
2783
2784 //make sure at least the default scoreblock has been created, this can now be a custom version named with default scoreblock name
2785 if (Denemo.project->standard_scoreblocks == NULL)
2786 {
2787 create_default_scoreblock ();
2788 if (Denemo.project->standard_scoreblocks)
2789 sb = (DenemoScoreblock *) (Denemo.project->standard_scoreblocks->data);
2790 else if (Denemo.project->custom_scoreblocks)
2791 sb = (DenemoScoreblock *) (Denemo.project->custom_scoreblocks->data);
2792 else
2793 {
2794 g_critical ("No score layout available");
2795 return NULL;
2796 }
2797
2798 refresh_lilypond (sb); //creating a scoreblock does *not* include generating the lilypond from its widgets.
2799 }
2800
2801
2802
2803 //first recreate all the standard scoreblocks and set them not visible
2804 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2805 {
2806 sb = (DenemoScoreblock *) g->data;
2807 // if(sb->layout_sync!=Denemo.project->layout_sync)
2808 recreate_standard_scoreblock (&sb);
2809 sb->visible = FALSE;
2810 }
2811
2812 if (all_movements && partname == NULL)
2813 { //select the one for the whole score
2814 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2815 {
2816 sb = (DenemoScoreblock *) g->data;
2817 if ((sb->movement == 0) && (sb->partname == NULL))
2818 {
2819 sb->visible = TRUE;
2820 refresh_lilypond (sb);
2821 set_notebook_page (sb->widget);
2822 return sb;
2823 }
2824 }
2825 if (Denemo.project->custom_scoreblocks)
2826 {
2827 sb = (DenemoScoreblock *) (Denemo.project->custom_scoreblocks->data);
2828 return sb;
2829 }
2830 g_warning ("Error in logic: the default standard scoreblock should exist or a custom one of that name ");
2831 }
2832 else
2833 { //Not a whole score print
2834 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2835 {
2836 sb = (DenemoScoreblock *) g->data;
2837
2838 //a good match to partname ?
2839 gboolean good = (sb->partname && partname && !strcmp (sb->partname, partname)) || (sb->partname == NULL && partname == NULL);
2840
2841 if (good && (all_movements && (sb->movement == 0)))
2842 { //scoreblock is for good partname and is for all movements - use it
2843 sb->visible = TRUE;
2844 refresh_lilypond (sb);
2845 set_notebook_page (sb->widget);
2846 return sb;
2847 }
2848 }
2849 }
2850
2851 //either just the current movement or just the part named or both. Set up the movement number (1 ...) or 0 for the all movements case
2852 gint movement;
2853 if (all_movements)
2854 {
2855 movement = 0;
2856 }
2857 else
2858 {
2859 movement = g_list_index (Denemo.project->movements, Denemo.project->movement) + 1; //current movement
2860 }
2861
2862
2863 if (movement || partname)
2864 { //a specific movement and/or a specific part
2865 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2866 {
2867 sb = (DenemoScoreblock *) g->data;
2868 if ((movement == sb->movement) && ((partname == sb->partname) || (partname && sb->partname && !strcmp (sb->partname, partname))))
2869 {
2870 sb->visible = TRUE;
2871 refresh_lilypond (sb);
2872 set_notebook_page (sb->widget);
2873 return sb;
2874 }
2875 }
2876 sb = g_malloc0 (sizeof (DenemoScoreblock));
2877 create_standard_scoreblock (&sb, movement, partname);
2878 Denemo.project->standard_scoreblocks = g_list_prepend (Denemo.project->standard_scoreblocks, sb);
2879 sb->visible = TRUE;
2880 sb->instrumentation = g_strdup (instrumentation); g_print ("instrumentation %s\n", sb->instrumentation);
2881 refresh_lilypond (sb);
2882 set_notebook_page (sb->widget);
2883 return sb;
2884 }
2885 //NOT REACHED
2886 g_warning ("Error in logic: the default standard scoreblock should exist and be returned ");
2887 return sb; //this is the last in the list of standard scoreblocks but cannot be reached
2888 }
2889
2890 void
select_standard_layout(DenemoScoreblock * sb)2891 select_standard_layout (DenemoScoreblock * sb)
2892 {
2893 if (Denemo.project->standard_scoreblocks == NULL)
2894 {
2895 create_default_scoreblock ();
2896 //creating a scoreblock does *not* include generating the lilypond from its widgets.
2897 if (Denemo.project->standard_scoreblocks == NULL)
2898 {
2899 DenemoScoreblock *sb = g_malloc0 (sizeof (DenemoScoreblock));
2900 (void) create_standard_scoreblock (&sb, 0, NULL);
2901 Denemo.project->standard_scoreblocks = g_list_prepend (NULL, (gpointer) sb);
2902 }
2903 sb = (DenemoScoreblock *) (Denemo.project->standard_scoreblocks->data);
2904 }
2905 refresh_lilypond (sb);
2906 set_notebook_page (sb->widget);
2907 }
2908
2909 void
select_custom_layout(DenemoScoreblock * sb)2910 select_custom_layout (DenemoScoreblock * sb)
2911 {
2912 if (Denemo.project->custom_scoreblocks == NULL)
2913 {
2914 return;
2915 }
2916 set_notebook_page (sb->widget);
2917 }
2918
2919 gboolean
select_custom_layout_for_name(gchar * name)2920 select_custom_layout_for_name (gchar * name)
2921 {
2922 GList *g = Denemo.project->custom_scoreblocks;
2923 for (; g; g = g->next)
2924 {
2925 DenemoScoreblock *sb = g->data;
2926
2927 if (sb->name && !strcmp (name, sb->name))
2928 return TRUE;
2929 }
2930 return FALSE;
2931 }
2932
2933 gboolean
select_layout_id(gint id)2934 select_layout_id (gint id)
2935 {
2936 GList *g = Denemo.project->custom_scoreblocks;
2937 for (; g; g = g->next)
2938 {
2939 DenemoScoreblock *sb = g->data;
2940 if (sb->id == id)
2941 {
2942 set_notebook_page (sb->widget);
2943 return TRUE;
2944 }
2945 }
2946
2947 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
2948 {
2949 DenemoScoreblock *sb = g->data;
2950 if (sb->id == id)
2951 {
2952 set_notebook_page (sb->widget);
2953 return TRUE;
2954 }
2955 }
2956 return FALSE;
2957 }
2958 /* UNUSED
2959 static void
2960 text_modified (GtkTextBuffer * textbuffer, DenemoScoreblock * sb)
2961 {
2962 GtkTextIter startiter, enditer;
2963 gtk_text_buffer_get_start_iter (textbuffer, &startiter);
2964 gtk_text_buffer_get_end_iter (textbuffer, &enditer);
2965 gchar *text = gtk_text_buffer_get_text (textbuffer, &startiter, &enditer, FALSE);
2966 if (sb->lilypond)
2967 g_string_assign (sb->lilypond, text);
2968 else
2969 sb->lilypond = g_string_new (text);
2970 score_status (Denemo.project, TRUE);
2971 }
2972 */
2973
2974 DenemoScoreblock *
get_scoreblock_for_lilypond(gchar * lily)2975 get_scoreblock_for_lilypond (gchar * lily)
2976 {
2977 gchar *text = _("The LilyPond text for this layout can be edited in the LilyPond view window.\nYou can safely delete this layout if you no longer need it\n(for example if you have made structural changes to the score\nnot reflected in this layout).");
2978 gchar *name = NULL;
2979 DenemoScoreblock *sb = g_malloc0 (sizeof (DenemoScoreblock));
2980 sb->text_only = TRUE;
2981
2982 if(!Denemo.non_interactive){
2983 GtkWidget *frame = gtk_frame_new (LILYPOND_TEXT_EDITOR);
2984 sb->widget = frame;
2985 gtk_widget_set_tooltip_text (frame, _("This is a customized layout, which has been transformed into instructions for the LilyPond music typesetter.\nThis is the form in which customized layouts are stored in a Denemo score on disk - the graphical interface is no longer available. You can, however still edit the layout with care (and some understanding of LilyPond).\nUse the View → LilyPond window to do this.\nOtherwise you can delete it and create a new one from a standard layout."));
2986 GtkWidget *vbox = gtk_vbox_new (FALSE, 8);
2987 gtk_container_add (GTK_CONTAINER (sb->widget), vbox);
2988 GtkWidget *options = get_options_button (sb, TRUE);
2989 gtk_box_pack_start (GTK_BOX (vbox), options, FALSE, FALSE, 0);
2990 GtkWidget *textview = gtk_text_view_new ();
2991 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), TRUE);
2992 GtkTextBuffer *textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
2993 gtk_text_buffer_set_text (textbuffer, text, -1);
2994
2995 GtkWidget *sw = gtk_scrolled_window_new (gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0), gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0));
2996 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2997 gtk_container_add (GTK_CONTAINER (sw), textview);
2998 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
2999 }
3000
3001 gchar *newline = g_strstr_len (lily, -1, "\n");
3002 if (newline)
3003 {
3004 name = g_strndup (lily, newline - lily);
3005 sb->name = g_strdup (name + 1);
3006 sb->id = crc32 ((guchar*) sb->name);
3007 g_free (name);
3008 }
3009 else
3010 sb->name = g_strdup (_("Custom Scoreblock"));
3011 sb->id = crc32 ((guchar*) sb->name);
3012 sb->lilypond = g_string_new (lily);
3013
3014 refresh_lilypond (sb);
3015 return sb;
3016 }
3017
3018 //if the score_layout window is visible and a standard scoreblock is selected, create a custom one cloned from it with the passed name
3019 DenemoScoreblock *
create_custom_scoreblock(gchar * layout_name,gboolean force)3020 create_custom_scoreblock (gchar * layout_name, gboolean force)
3021 {
3022 GList *g;
3023 if (!force && !gtk_widget_get_visible (Denemo.project->score_layout))
3024 return NULL;
3025 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
3026 {
3027 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
3028 if (!strcmp (layout_name, sb->name))
3029 return NULL;
3030 }
3031 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
3032 {
3033 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
3034 if (sb->visible)
3035 {
3036 if (clone_scoreblock (sb, layout_name))
3037 return sb;
3038 }
3039 }
3040 return NULL;
3041 }
3042
3043
delete_custom_scoreblock(gchar * layout_name)3044 gboolean delete_custom_scoreblock (gchar * layout_name)
3045 {
3046 GList *g;
3047
3048 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
3049 {
3050 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
3051 if (!strcmp (layout_name, sb->name))
3052 {
3053 delete_custom_scoreblock_callback (NULL, sb);
3054 return TRUE;
3055 }
3056 }
3057 return FALSE;
3058 }
3059
3060 DenemoScoreblock *
create_custom_lilypond_scoreblock(void)3061 create_custom_lilypond_scoreblock (void)
3062 {
3063 //called for
3064 //make_scoreblock_editable(); in view.c
3065 DenemoScoreblock *sb = NULL;
3066 GList *g;
3067 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
3068 {
3069 sb = (DenemoScoreblock *) g->data;
3070 if (sb->visible)
3071 {
3072 if (!sb->text_only)
3073 convert_to_lilypond_callback (NULL, sb);
3074 return sb;
3075 }
3076 }
3077 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
3078 {
3079 sb = (DenemoScoreblock *) g->data;
3080 if (sb->visible)
3081 {
3082 if (!sb->text_only)
3083 convert_to_lilypond_callback (NULL, sb);
3084 return sb;
3085 }
3086 }
3087 //if none, create the default and convert that to lilypoond.
3088 create_default_scoreblock ();
3089 sb = (DenemoScoreblock *) (Denemo.project->standard_scoreblocks->data);
3090 convert_to_lilypond_callback (NULL, sb);
3091 return sb;
3092 }
3093
3094
3095 static GtkWidget *LayoutMenu; //a menu for the default layout and all created layouts
3096 static void
typeset_layout(DenemoScoreblock * sb)3097 typeset_layout (DenemoScoreblock * sb)
3098 {
3099 #ifndef USE_EVINCE
3100 g_debug("This feature requires denemo to be built with evince");
3101 #else
3102 set_notebook_page (sb->widget);
3103 g_debug ("Switched to %s\n", sb->name);
3104 typeset_current_layout ();
3105 #endif
3106 }
3107
3108 static void
remove_menuitem(GtkWidget * menuitem,GtkContainer * container)3109 remove_menuitem (GtkWidget * menuitem, GtkContainer * container)
3110 {
3111 gtk_container_remove (container, menuitem);
3112 }
3113
3114 static void
attach_item(DenemoScoreblock * sb)3115 attach_item (DenemoScoreblock * sb)
3116 {
3117 GtkWidget *menuitem = gtk_menu_item_new_with_label (sb->name);
3118 gtk_widget_set_tooltip_text (menuitem, _("Typesets this layout"));
3119 g_signal_connect_swapped (menuitem, "activate", G_CALLBACK (typeset_layout), sb);
3120 gtk_menu_shell_append (GTK_MENU_SHELL (LayoutMenu), menuitem);
3121 }
3122
3123 GtkWidget *
GetLayoutMenu(void)3124 GetLayoutMenu (void)
3125 {
3126 GList *g;
3127 if (LayoutMenu == NULL)
3128 {
3129 LayoutMenu = gtk_menu_new ();
3130 }
3131 else
3132 {
3133 gtk_container_foreach (GTK_CONTAINER (LayoutMenu), (GtkCallback) remove_menuitem, LayoutMenu);
3134 }
3135 if (Denemo.project->standard_scoreblocks == NULL)
3136 create_default_scoreblock ();
3137 for (g = Denemo.project->standard_scoreblocks; g; g = g->next)
3138 {
3139 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
3140 attach_item (sb);
3141 }
3142 for (g = Denemo.project->custom_scoreblocks; g; g = g->next)
3143 {
3144 DenemoScoreblock *sb = (DenemoScoreblock *) g->data;
3145 attach_item (sb);
3146 }
3147
3148 gtk_widget_show_all (LayoutMenu);
3149 return LayoutMenu;
3150 }
3151