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