1 /* score.cpp
2  * functions dealing with the whole score
3 
4  * for Denemo, a gtk+ frontend to GNU Lilypond
5  * (c) 2000-2005 Matthew Hiller, Adam Tee*/
6 
7 #include <denemo/denemo.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include "config.h"
11 #include "command/staff.h"
12 #include "command/score.h"
13 #include "core/prefops.h"
14 #include "command/select.h"
15 #include "command/object.h"
16 #include "command/lyric.h"
17 #include "audio/audiointerface.h"
18 #include "source/sourceaudio.h"
19 #include "core/cache.h"
20 #include "core/utils.h"
21 #include "core/view.h"
22 #include "command/commandfuncs.h"
23 #include "ui/moveviewport.h"
24 #include "command/contexts.h"
25 #include "audio/midi.h"
26 #include "display/displayanimation.h"
27 #include "command/lilydirectives.h"
28 #include "export/exportmidi.h"
29 #include "display/calculatepositions.h"
30 #include "command/measure.h"
31 
32 #define MOVEMENT_WIDTH (10)
33 
34 
35 /**
36  * Create new DenemoMovement with no staff
37  * set it as gui->movement but do not add it to the movements list.
38  */
39 void
point_to_empty_movement(DenemoProject * gui)40 point_to_empty_movement (DenemoProject * gui)
41 {
42   DenemoMovement *newscore = (DenemoMovement *) g_malloc0 (sizeof (DenemoMovement));
43   init_score (newscore, gui);
44   if (!Denemo.non_interactive && gui->movement && gui->movement->buttonbox)
45         gtk_widget_hide (gui->movement->buttonbox);
46 
47   if (!Denemo.non_interactive && (gui->movement) && gui->movement->lyricsbox)
48         gtk_widget_hide (gui->movement->lyricsbox);
49   g_static_mutex_lock (&smfmutex);
50   gui->movement = newscore;
51   g_static_mutex_unlock (&smfmutex);
52   if(!Denemo.non_interactive)
53     gtk_widget_show (gui->movement->buttonbox);
54 
55 }
56 
57 /**
58  * Create new DenemoMovement with one empty staff
59  * set it as gui->movement but do not add it to the movements list.
60  */
61 void
point_to_new_movement(DenemoProject * gui)62 point_to_new_movement (DenemoProject * gui)
63 {
64   point_to_empty_movement (gui);
65   staff_new (gui, INITIAL, DENEMO_NONE);
66   cache_all ();
67   gui->movement->undo_guard = Denemo.prefs.disable_undo;
68 }
69 
select_movement(gint movementnum)70 static void select_movement (gint movementnum) {
71    gboolean ok = goto_movement_staff_obj (NULL, movementnum, 1, 1, 0, 0);// this was moving to the movement but failing on the staff num g_print ("ok is %d\n", ok);
72     set_movement_selector (Denemo.project);
73     displayhelper (Denemo.project);
74     write_status (Denemo.project);
75 }
76 
77 #define NUM_MOVEMENTS_TO_SHOW (2*5)
set_movement_selector(DenemoProject * gui)78 void set_movement_selector (DenemoProject *gui)
79 {
80   GtkWidget *button;
81   GList *g;
82   gint i;
83 
84   if(Denemo.non_interactive)
85     return;
86 
87 
88   reset_movement_numbers (gui);
89   if(gui->movements_selector)
90       gtk_widget_destroy (gui->movements_selector);
91   gui->movements_selector = (GtkWidget*)gtk_hbox_new(FALSE,1);
92   gtk_box_pack_start(GTK_BOX(gui->buttonbox), gui->movements_selector,  FALSE, TRUE, 0);
93   gtk_widget_show (gui->movements_selector);
94   gint num_movements = 1;
95   gint last = 1;
96   gint first = 1;
97   if(gui->movements) {
98       gint current = g_list_index (gui->movements, gui->movement) + 1;
99       num_movements = g_list_length(gui->movements);
100       first = current - NUM_MOVEMENTS_TO_SHOW/2;
101       if(first<1) first = 1;
102       last = first + NUM_MOVEMENTS_TO_SHOW -1;
103 
104       if(last>num_movements)
105       {
106           last = num_movements;
107           first = num_movements - NUM_MOVEMENTS_TO_SHOW;
108           if(first<1) first = 1;
109         }
110   }
111   for (g=gui->movements, i=1;g;g=g->next, i++)
112     {
113       if(i<first)
114           continue;
115       if(i>last)
116           continue;
117       button = gtk_button_new_with_label("");
118       if (g->data == gui->movement)
119         {
120             gchar *text = g_strdup_printf("<span foreground=\"%s\"><i><b>%d</b></i></span>", movementcontrol_directive_get_tag ("HideMovement")?"red":"blue", i);
121             GtkWidget *label_widget = gtk_bin_get_child(GTK_BIN(button));
122             gtk_label_set_use_markup (GTK_LABEL(label_widget), TRUE);
123             gtk_label_set_markup (GTK_LABEL (label_widget), text);
124             g_free(text);
125             text = g_strdup_printf(_("This is the current movement number %d\nClick on another button to change movements"), i);
126             gtk_widget_set_tooltip_text (button, text);
127             g_free(text);
128         }
129       else
130         {
131             gchar *more = "";
132             if((last<num_movements) && (i==last))
133                 more = "+...";
134             gchar *text = g_strdup_printf("%d%s", i, more);
135             gtk_button_set_label (GTK_BUTTON (button), text);
136             g_free(text);
137             text = g_strdup_printf(_("Click to switch to movement number %d"), i);
138             gtk_widget_set_tooltip_text (GTK_WIDGET (button), text);
139             g_free(text);
140         }
141 
142 
143         gtk_widget_set_can_focus (button, FALSE);
144         gtk_widget_show(button);
145         g_signal_connect_swapped (G_OBJECT(button), "clicked", G_CALLBACK (select_movement), GINT_TO_POINTER(i));
146         gtk_box_pack_start (GTK_BOX(gui->movements_selector), button,  FALSE, TRUE, 0);
147     }
148     if(i==2)
149         gtk_widget_hide (gui->movements_selector);
150     if(gui->movement)
151         set_master_tempo (gui->movement, 1.0);
152 
153 
154     if ((gui->movement) && gui->movement->lyricsbox && Denemo.prefs.lyrics_pane)
155       gtk_widget_show (gui->movement->lyricsbox), show_lyrics ();
156 
157 
158 }
159 
160 static void
new_movement(GtkAction * action,DenemoScriptParam * param,gboolean before)161 new_movement (GtkAction * action, DenemoScriptParam * param, gboolean before)
162 {
163   DenemoProject *gui = Denemo.project;
164   gint pos = g_list_index (gui->movements, gui->movement);
165   append_new_movement (action, param);
166   DenemoMovement *newsi = g_list_last (gui->movements)->data;
167   gui->movements = g_list_delete_link (gui->movements, g_list_last (gui->movements));
168   gui->movements = g_list_insert (gui->movements, newsi, before ? pos : pos + 1);
169   //newsi->currentmovementnum = 1 + g_list_index (gui->movements, newsi); done in set_movement_selector()
170   staff_set_current_primary (gui->movement);
171   //gui->movements_selector = NULL;
172   set_movement_selector (gui);
173   goto_movement_staff_obj (NULL, -1, 1, 0, 0, 0);
174   rewind_audio ();
175   write_status (gui);
176 }
177 
178 
179 static void
append_movement(GtkAction * action,gpointer param,gboolean populate)180 append_movement (GtkAction * action, gpointer param, gboolean populate)
181 {
182   DenemoProject *gui = Denemo.project;
183   DenemoMovement *source_movement = gui->movement;
184   GList *g;
185   (void) signal_structural_change (gui);
186 
187   if (gui->movement->lyricsbox)
188     gtk_widget_hide (gui->movement->lyricsbox);
189   point_to_empty_movement (gui);
190   for (g = source_movement->thescore; g; g = g->next)
191     {
192       DenemoStaff *source_staff = g->data;
193       staff_new (gui, LAST, DENEMO_NONE);
194       if (!populate)
195         break;
196       GList *dest = g_list_last (gui->movement->thescore);
197       DenemoStaff *dest_staff = dest->data;
198       staff_copy (source_staff, dest_staff);
199     }
200   gui->movements = g_list_append (gui->movements, gui->movement);
201   //gui->movement->currentmovementnum = 1 + g_list_index (gui->movements, gui->movement);
202   set_movement_selector (gui);
203   gui->movement->undo_guard = Denemo.prefs.disable_undo;
204   call_out_to_guile ("(d-DirectivePut-header-postfix \"SuppressTitleRepeats\" \"title = ##f\ninstrument = ##f\n\")");
205   set_width_to_work_with (gui);
206   //FIXME duplicate code
207   set_rightmeasurenum (gui->movement);
208   find_leftmost_allcontexts (gui->movement);
209   set_bottom_staff (gui);
210   if(!Denemo.non_interactive){
211     update_hscrollbar (gui);
212     update_vscrollbar (gui);
213     draw_score_area();
214     g_signal_emit_by_name (G_OBJECT (Denemo.hadjustment), "changed");
215     g_signal_emit_by_name (G_OBJECT (Denemo.vadjustment), "changed");
216   }
217   displayhelper (gui);
218   score_status (gui, TRUE);
219 }
220 
221 //copies staff structure to new movement
222 void
append_new_movement(GtkAction * action,DenemoScriptParam * param)223 append_new_movement (GtkAction * action, DenemoScriptParam * param)
224 {
225   append_movement (action, param, TRUE);
226 }
227 
228 //does not copy staff structure to new movement
229 void
append_blank_movement(void)230 append_blank_movement (void)
231 {
232   append_movement (NULL, NULL, FALSE);
233 }
234 
235 
236 
237 
238 void
insert_movement_before(GtkAction * action,DenemoScriptParam * param)239 insert_movement_before (GtkAction * action, DenemoScriptParam * param)
240 {
241   new_movement (action, param, TRUE);
242 }
243 
244 void
insert_movement_after(GtkAction * action,DenemoScriptParam * param)245 insert_movement_after (GtkAction * action, DenemoScriptParam * param)
246 {
247   new_movement (action, param, FALSE);
248 }
249 
250 static void
terminate_playback(void)251 terminate_playback (void)
252 {
253   if (is_playing ())
254     midi_stop ();
255   g_thread_yield ();            //FIXME find a better way of ensuring playing is finished - in principle the user could start playing again
256   if (is_playing ())
257     terminate_playback ();
258   //g_debug("Terminated %d\n", is_playing());
259 }
260 
261 void
reset_movement_numbers(DenemoProject * gui)262 reset_movement_numbers (DenemoProject * gui)
263 {
264   GList *g;
265   gint i;
266   for (i = 1, g = gui->movements; g; g = g->next, i++)
267     {
268       DenemoMovement *si = g->data;
269       si->currentmovementnum = i;
270     }
271 }
272 
273 void
delete_movement(GtkAction * action,DenemoScriptParam * param)274 delete_movement (GtkAction * action, DenemoScriptParam* param)
275 {
276   DenemoProject *gui = Denemo.project;
277   terminate_playback ();
278   (void) signal_structural_change (gui);
279 
280   GString *primary = g_string_new (""), *secondary = g_string_new ("");
281   if (gui->movements == NULL || (g_list_length (gui->movements) == 1))
282     {
283       g_string_assign (primary, _("This is the only movement"));
284       g_string_assign (secondary, _("Delete it and start over?"));
285       if (confirm (primary->str, secondary->str))
286         {
287           gchar *name = g_strdup (gui->filename->str);
288           gui->movement->undo_guard = 1;  //no undo as that is per movement
289           deletescore (NULL, gui);
290           g_string_assign (gui->filename, name);
291           g_free (name);
292         }
293     }
294   else
295     {                           // more than one movement
296       gint num = g_list_index (gui->movements, gui->movement);
297       g_string_printf (primary, _("This is movement #%d"), num + 1);
298       g_string_assign (secondary, _("Delete entire movement?"));
299       if (confirm (primary->str, secondary->str))
300         {
301           gui->movement->undo_guard = 1;  //no undo as that is per movement
302           free_score (gui);
303           DenemoMovement *si = gui->movement;
304           GList *g = g_list_find (gui->movements, si)->next;
305           if (g == NULL)
306             g = g_list_find (gui->movements, si)->prev;
307           gui->movement = g->data;
308           gui->movements = g_list_remove (gui->movements, (gpointer) si);
309         }
310     }
311   reset_movement_numbers (gui);
312   g_string_free (primary, TRUE);
313   g_string_free (secondary, TRUE);
314   set_movement_selector (gui);
315   set_movement_transition (-MOVEMENT_WIDTH);
316   displayhelper (gui);
317   score_status (gui, TRUE);
318 }
319 
320 /* go to the movement voice measure staff and object numbers (starting from 1)
321  movementnum<=0 means current movement
322  * objnum 0 finds first object if any
323 possible_gui is really a flag interactive or not
324 */
325 gboolean
goto_movement_staff_obj(DenemoProject * possible_gui,gint movementnum,gint staffnum,gint measurenum,gint objnum,gint leftmeasurenum)326 goto_movement_staff_obj (DenemoProject * possible_gui, gint movementnum, gint staffnum, gint measurenum, gint objnum, gint leftmeasurenum)
327 {
328   DenemoProject *gui;
329   terminate_playback ();
330   if (possible_gui == NULL)
331     gui = Denemo.project;
332   else
333     gui = possible_gui;
334   if (movementnum > 0 && (movementnum != gui->movement->currentmovementnum))
335     {
336       GList *this = g_list_nth (gui->movements, movementnum - 1);
337       if (this == NULL)
338         {
339           if (possible_gui)
340             warningdialog (_("No such movement"));
341           return FALSE;
342         }
343       panic_all (); //g_print ("Reset synth\n");
344       if(!Denemo.non_interactive)
345         {
346         gtk_widget_hide (gui->movement->buttonbox);
347         if ((gui->movement) && gui->movement->lyricsbox && Denemo.prefs.lyrics_pane)
348             gtk_widget_hide (gui->movement->lyricsbox);
349         }
350       gui->movement = this->data;
351       if(!Denemo.non_interactive)
352         gtk_widget_show (gui->movement->buttonbox);
353     set_movement_selector (gui);
354    }
355 
356   if (!moveto_currentstaffnum (gui, staffnum))
357     {
358       if (possible_gui)
359         warningdialog (_("No such voice"));
360       return FALSE;
361     }
362   if (!moveto_currentmeasurenum (gui, measurenum, leftmeasurenum))
363     {
364       if (possible_gui)
365         warningdialog (_("No such measure"));
366       return FALSE;
367     }
368   //cursor_x is zero and we are on the first, if any, object
369   if (gui->movement->currentobject == NULL && objnum)
370     return FALSE;               //asking for an object in an empty measure
371 
372   while (--objnum > 0 && gui->movement->currentobject && gui->movement->currentobject->next)
373     {
374       gui->movement->currentobject = gui->movement->currentobject->next;
375       gui->movement->cursor_x++;
376     }
377   //g_debug("objnum %d\n",objnum);
378   if (objnum > 0)
379     {
380       gui->movement->cursor_x++;      // objnum;
381       if (!gui->movement->currentobject)
382         return FALSE;
383       gui->movement->cursor_appending = TRUE;
384     }
385   if(leftmeasurenum)
386     {
387       gui->movement->leftmeasurenum = leftmeasurenum;
388       set_rightmeasurenum (gui->movement);
389     }
390   write_status (gui);
391   move_viewport_up (gui);
392   move_viewport_down (gui);
393   draw_score_area();
394   return TRUE;
395 }
396 
397 
398 /* get the object specified or NULL if there is none.
399 */
400 DenemoObject *
get_object_by_position(gint movementnum,gint staffnum,gint measurenum,gint objnum)401 get_object_by_position (gint movementnum, gint staffnum, gint measurenum, gint objnum)
402 {
403   DenemoProject *gui = Denemo.project;
404   GList *this = g_list_nth (gui->movements, movementnum - 1);
405   if (this == NULL) return NULL;
406   DenemoMovement *movement = this->data;
407   this = g_list_nth (movement->thescore, staffnum - 1);
408   if (this == NULL) return NULL;
409   DenemoStaff *thestaff = (DenemoStaff*)this->data;
410   this = g_list_nth (thestaff->themeasures, measurenum -1);
411   if (this==NULL) return NULL;
412   this = g_list_nth (((DenemoMeasure*)this->data)->objects, objnum-1);
413   if (this==NULL) return NULL;
414    return this->data;
415 }
416 
417 void
PopPosition(GtkAction * action,DenemoScriptParam * param)418 PopPosition (GtkAction * action, DenemoScriptParam * param)
419 {
420   DenemoPosition *pos = pop_position ();
421   DenemoScriptParam dummy;
422   if (action || !param)
423     param = &dummy;
424   if (pos == NULL)
425     {
426       param->status = FALSE;
427       return;
428     }
429   param->status = goto_movement_staff_obj (NULL, pos->movement, pos->staff, pos->measure, pos->object, pos->leftmeasurenum);
430   if (param->status)
431     {
432       Denemo.project->movement->cursor_appending = pos->appending;
433       Denemo.project->movement->cursoroffend = pos->offend;
434     }
435   g_free (pos);
436 }
437 
438 void
PushPosition(GtkAction * action,DenemoScriptParam * param)439 PushPosition (GtkAction * action, DenemoScriptParam * param)
440 {
441   push_position ();
442 }
443 
444 void
PopPushPosition(GtkAction * action,DenemoScriptParam * param)445 PopPushPosition (GtkAction * action, DenemoScriptParam * param)
446 {
447   DenemoPosition *pos = pop_position ();
448   DenemoScriptParam dummy;
449   if (action || !param)
450     param = &dummy;
451   if (pos)
452     {
453       push_position ();
454       param->status = goto_movement_staff_obj (NULL, pos->movement, pos->staff, pos->measure, pos->object, pos->leftmeasurenum);
455       if (param->status)
456         {
457           Denemo.project->movement->cursor_appending = pos->appending;
458           Denemo.project->movement->cursoroffend = pos->offend;
459         }
460     }
461   else
462     param->status = FALSE;
463 }
464 
465 
466 /**
467  * Move to the next movement
468  * @param action - Gtk Action event
469  * @param gui - pointer to the DenemoProject structure
470  * @return none
471 */
472 void
next_movement(GtkAction * action,DenemoScriptParam * param)473 next_movement (GtkAction * action, DenemoScriptParam * param)
474 {
475   DenemoProject *gui = Denemo.project;
476   terminate_playback ();
477   GList *this = g_list_find (gui->movements, gui->movement);
478   this = this->next;
479   if (param)
480     param->status = TRUE;
481   if (this == NULL)
482     {
483       if (param)
484         param->status = FALSE;
485       else
486         warningmessage (_("This is the last movement"));
487       return;
488     }
489 
490   if(!Denemo.non_interactive){
491     gtk_widget_hide (gui->movement->buttonbox);
492     if (gui->movement->lyricsbox)
493       gtk_widget_hide (gui->movement->lyricsbox);
494   }
495   gui->movement = this->data;
496 
497   if(!Denemo.non_interactive){
498     if (gui->movement->lyricsbox && Denemo.prefs.lyrics_pane)
499       gtk_widget_show (gui->movement->lyricsbox);       //toggle_lyrics_view(NULL, NULL);
500     gtk_widget_show (gui->movement->buttonbox);
501   }
502   set_movement_selector (gui);
503   //!!!!!!!!updatescoreinfo (gui);
504   //FIXME duplicate code
505   set_rightmeasurenum (gui->movement);
506   find_leftmost_allcontexts (gui->movement);
507   set_bottom_staff (gui);
508 
509   if(!Denemo.non_interactive){
510     update_hscrollbar (gui);
511     update_vscrollbar (gui);
512     g_signal_emit_by_name (G_OBJECT (Denemo.hadjustment), "changed");
513     g_signal_emit_by_name (G_OBJECT (Denemo.vadjustment), "changed");
514     write_status (gui);
515     //gtk_widget_draw (Denemo.scorearea, NULL);//KLUDGE FIXME see staffup/down
516     set_movement_transition (-MOVEMENT_WIDTH);
517     draw_score_area();
518     draw_score (NULL);
519   }
520 }
521 
522 /**
523  * Move to the previous movement
524  * @param action - Gtk Action event
525  * @param gui - pointer to the DenemoProject structure
526  * @return none
527 */
528 void
prev_movement(GtkAction * action,DenemoScriptParam * param)529 prev_movement (GtkAction * action, DenemoScriptParam * param)
530 {
531   DenemoProject *gui = Denemo.project;
532   terminate_playback ();
533   GList *this = g_list_find (gui->movements, gui->movement);
534   this = this->prev;
535   if (param)
536     param->status = TRUE;
537   if (this == NULL)
538     {
539       if (param)
540         param->status = FALSE;
541       else
542         warningmessage (_("This is the first movement"));
543       return;
544     }
545   if(!Denemo.non_interactive){
546     gtk_widget_hide (gui->movement->buttonbox);
547     if (gui->movement->lyricsbox)
548       gtk_widget_hide (gui->movement->lyricsbox);
549   }
550 
551   gui->movement = this->data;
552 
553   if(!Denemo.non_interactive){
554     gtk_widget_show (gui->movement->buttonbox);
555   }
556   set_movement_selector (gui);
557   //!!!!!!!!!!!!!updatescoreinfo (gui);
558   //FIXME duplicate code
559   set_rightmeasurenum (gui->movement);
560   set_bottom_staff (gui);
561 
562   if(!Denemo.non_interactive){
563     update_hscrollbar (gui);
564     update_vscrollbar (gui);
565     draw_score_area();
566     g_signal_emit_by_name (G_OBJECT (Denemo.hadjustment), "changed");
567     g_signal_emit_by_name (G_OBJECT (Denemo.vadjustment), "changed");
568   }
569   write_status (gui);
570   //gtk_widget_draw (Denemo.scorearea, NULL);//KLUDGE FIXME see staffup/down
571   set_movement_transition (MOVEMENT_WIDTH);
572 
573   if(!Denemo.non_interactive){
574     draw_score_area();
575     draw_score (NULL);
576   }
577 }
578 
579 /**
580  * Initialise scoreinfo structure
581  *
582  * @param si pointer to the scoreinfo structure to initialise
583  */
584 void
init_score(DenemoMovement * si,DenemoProject * gui)585 init_score (DenemoMovement * si, DenemoProject * gui)
586 {
587   gchar *dir = (gchar *) get_user_data_dir (TRUE);
588 
589   si->readonly = 0;
590   si->leftmeasurenum = si->rightmeasurenum = 1;
591   si->top_staff = si->bottom_staff = 1;
592   si->measurewidth = DENEMO_INITIAL_MEASURE_WIDTH;
593   si->measurewidths = NULL;
594   si->staffspace = DENEMO_INITIAL_STAFF_HEIGHT;
595   si->thescore = NULL;
596   si->currentstaffnum = 1;
597   si->currentmeasurenum = 1;
598   si->currentobject = NULL;
599   si->cursor_x = 0;
600   si->cursor_y = 0;
601   si->staffletter_y = 0;
602   si->cursor_appending = TRUE;
603   si->zoom = Denemo.prefs.zoom > 0 ? Denemo.prefs.zoom / 100.0 : 1.0;
604   si->preview_zoom = 1.0;
605   si->system_height = Denemo.prefs.system_height > 0 ? Denemo.prefs.system_height / 100.0 : 1.0;
606 
607   si->cursoroffend = FALSE;
608   //si->cursortime1 = si->cursortime2 = 4;
609   si->markstaffnum = 0;
610   si->markmeasurenum = 0;
611   si->markcursor_x = 0;
612   si->maxkeywidth = 0;
613   si->has_figures = FALSE;
614   si->has_fakechords = FALSE;
615   /*playback purposes */
616   si->tempo = 120;
617   si->start = 0;
618   si->end = 0;
619   si->stafftoplay = 0;
620   si->start_time = 0;
621   si->end_time = -1.0;          //ie unset
622   if (Denemo.project->movement)
623     set_master_volume (si, 1.0);
624   else
625     si->master_volume = 1.0;
626 
627 
628   si->tempo_change_time = 0.0;
629   if (Denemo.project->movement)
630     set_master_tempo (si, 1.0);
631   else
632     si->master_tempo = 1.0;
633   si->savebuffer = NULL;
634   si->smfsync = G_MAXINT;
635   if (gui->filename == NULL)
636       gui->filename = g_string_new ("");
637   gui->autosavename = g_string_new (g_build_filename (dir, "autosave.denemo", NULL));
638   if (gui->tabname == NULL)
639     gui->tabname = g_string_new ("");
640 
641   /* Undo/redo initialisation */
642   si->undodata = g_queue_new ();
643   si->redodata = g_queue_new ();
644   si->undo_guard = 1;           //do not collect undo information until file is loaded
645 
646   if(!Denemo.non_interactive){
647     si->buttonbox = gtk_hbox_new (FALSE, 1);
648     set_movement_selector (gui);
649     gtk_widget_set_tooltip_text (si->buttonbox, _("A button bar that can be populated by Movement titles and other user generated buttons.\nGenerally by clicking the button you can edit the title or value or execute the action of the button"));
650     gtk_box_pack_end (GTK_BOX (gui->buttonboxes), si->buttonbox, FALSE, TRUE, 0);
651     gtk_widget_show (si->buttonbox);
652     gtk_widget_set_can_focus (si->buttonbox, FALSE);
653     //GTK_WIDGET_UNSET_FLAGS(si->buttonbox, GTK_CAN_FOCUS);
654   }
655 }
656 
657 static gboolean
delete_all_staffs(DenemoProject * gui)658 delete_all_staffs (DenemoProject * gui)
659 {
660   DenemoMovement *si = gui->movement;
661   gint i;
662   for (i = g_list_length (si->thescore); i > 0; i--)
663     {
664       si->currentstaffnum = i;
665       si->currentstaff = g_list_nth (si->thescore, i - 1);
666       staff_delete (gui, FALSE);
667     }
668   return TRUE;
669 }
670 
671 
672 
673 
674 /**
675  * FIXME there is a muddle here between DenemoMovement and DenemoProject
676  * frees the data in the passed scoreinfo stucture
677  *
678  * @param si pointer to the scoreinfo structure to free
679  */
680 void
free_score(DenemoProject * gui)681 free_score (DenemoProject * gui)
682 {
683   delete_all_staffs (gui);
684   delete_directives (&gui->movement->layout.directives);
685   delete_directives (&gui->movement->header.directives);
686   free_midi_data (gui->movement);
687   if (gui->movement->buttonbox)
688     {
689       gtk_widget_destroy (gui->movement->buttonbox);
690       gui->movement->buttonbox = NULL;
691     }
692   if (gui->movement->lyricsbox)
693     {
694       gtk_widget_destroy (gui->movement->lyricsbox);
695       gui->movement->lyricsbox = NULL;
696     }
697   reset_lyrics (NULL, 0);
698   g_queue_free (gui->movement->undodata);
699   g_queue_free (gui->movement->redodata);
700 }
701 
702 static GList *
extract_verses(GList * verses)703 extract_verses (GList * verses)
704 {
705   //g_warning("extract_verses not tested!!!!!!!");
706   GList *ret = NULL;
707   GList *g;
708   for (g = verses; g; g = g->next)
709     {
710       GtkTextView *srcVerse = g->data;
711       ret = g_list_append (ret, get_text_from_view (GTK_WIDGET (srcVerse)));
712     }
713   return ret;
714 }
715 
clone_staff(DenemoStaff * srcStaff,DenemoStaff * thestaff)716 static void clone_staff (DenemoStaff *srcStaff, DenemoStaff *thestaff)
717 {
718  //   There are things like
719  //   measurenode *measures; /**< This is a pointer to each measure in the staff */ actually a GList * of measures.
720 // and nummeasures which must be fixed by the caller.
721     memcpy (thestaff, srcStaff, sizeof (DenemoStaff));
722     thestaff->staffmenu = thestaff->voicemenu = NULL;
723     thestaff->sources = NULL;
724     thestaff->denemo_name = g_string_new (srcStaff->denemo_name->str);
725     thestaff->lily_name = g_string_new (srcStaff->lily_name->str);
726     thestaff->midi_instrument = g_string_new (srcStaff->midi_instrument->str);
727     thestaff->device_port= g_string_new (srcStaff->device_port->str);
728 
729 
730     thestaff->clef.directives = clone_directives (srcStaff->clef.directives);
731     thestaff->keysig.directives = clone_directives (srcStaff->keysig.directives);
732     thestaff->timesig.directives = clone_directives (srcStaff->timesig.directives);
733 
734     if (srcStaff->leftmost_clefcontext == &srcStaff->clef)
735     thestaff->leftmost_clefcontext = &thestaff->clef;
736     else{
737     // has to be fixed up after the measures are done..., so do the whole thing after???
738     //                                                         likewise keysig timesig
739     g_warning ("Not doing clef context yet...");
740     thestaff->leftmost_clefcontext = &thestaff->clef;
741     }
742 
743     if (srcStaff->leftmost_timesig == &srcStaff->timesig)
744     thestaff->leftmost_timesig = &thestaff->timesig;
745     else{
746     // has to be fixed up after the measures are done..., so do the whole thing after???
747     //                                                         likewise keysig timesig
748     g_warning ("Not doing timesig context yet...");
749     thestaff->leftmost_timesig = &thestaff->timesig;
750     }
751 
752     if (srcStaff->leftmost_keysig == &srcStaff->keysig)
753     thestaff->leftmost_keysig = &thestaff->keysig;
754     else{
755     // has to be fixed up after the measures are done..., so do the whole thing after???
756     //                                                         likewise keysig timesig
757     g_warning ("Not doing keysig context yet...");
758     thestaff->leftmost_keysig = &thestaff->keysig;
759     }
760 
761 
762     thestaff->denemo_name = g_string_new (srcStaff->denemo_name->str);
763     thestaff->lily_name = g_string_new (srcStaff->lily_name->str);
764 
765     thestaff->staff_directives = clone_directives (srcStaff->staff_directives);
766     {
767     GList *direc;
768     for (direc = thestaff->staff_directives; direc; direc = direc->next)
769       {
770         DenemoDirective *directive = direc->data;
771         directive->widget = NULL;
772         //      widget_for_staff_directive(directive);
773       }
774     }
775     thestaff->voice_directives = clone_directives (srcStaff->voice_directives);
776     {
777     GList *direc;
778     for (direc = thestaff->voice_directives; direc; direc = direc->next)
779       {
780         DenemoDirective *directive = direc->data;
781         directive->widget = NULL;
782         //      widget_for_voice_directive(directive);
783       }
784     }
785 
786 
787     thestaff->verse_views = extract_verses (srcStaff->verse_views);
788     //FIXME: thestaff->verses should probably be cloned too
789     GtkTextView* verse_view = (GtkTextView*) verse_get_current_view (srcStaff);
790     if (verse_view)
791     verse_set_current (thestaff, verse_get_current (srcStaff));
792 }
793 
794 
795 DenemoMovement *
clone_movement(DenemoMovement * si)796 clone_movement (DenemoMovement * si)
797 {
798   DenemoMovement *newscore = (DenemoMovement *) g_malloc0 (sizeof (DenemoMovement));
799   memcpy (newscore, si, sizeof (DenemoMovement));
800 
801   GList *g;
802   newscore->measurewidths = NULL;
803   if (newscore->sources)
804     {
805       g_warning ("Undo will lose source screenshots");
806       newscore->sources = NULL;
807     }
808   for (g = si->measurewidths; g; g = g->next)
809     newscore->measurewidths = g_list_append (newscore->measurewidths, g->data);
810   newscore->playingnow = NULL;
811 
812   for (newscore->thescore = NULL, g = si->thescore; g; g = g->next)
813     {
814 
815       DenemoStaff *srcStaff = (DenemoStaff *) g->data;
816       // staff_copy(srcStaff, thestaff);!!!!!! does not copy e.g. no of lines ... need proper clone code.
817       DenemoStaff *thestaff = (DenemoStaff *)g_malloc(sizeof(DenemoStaff));
818       clone_staff (srcStaff, thestaff);
819       newscore->lyricsbox = NULL;
820       newscore->thescore = g_list_append (newscore->thescore, thestaff);
821       if (g == si->currentprimarystaff)
822         newscore->currentprimarystaff = newscore->thescore;
823       if (g == si->currentstaff)
824         newscore->currentstaff = newscore->thescore;
825       newscore->currentmeasure = newscore->currentobject = thestaff->themeasures = NULL;
826       GList *h;
827       for (h = srcStaff->themeasures; h; h = h->next)
828         {
829           objnode *theobjs = ((DenemoMeasure*)h->data)->objects;
830           DenemoMeasure *newmeasure = (DenemoMeasure*)g_malloc0(sizeof (DenemoMeasure));
831           GList *i;
832           for (i = theobjs; i; i = i->next)
833             {
834               DenemoObject *theobj = (DenemoObject *) i->data;
835               DenemoObject *newobj = dnm_clone_object (theobj);
836               newmeasure->objects = g_list_append (newmeasure->objects, newobj);
837               if (i == si->currentobject)
838                     /*g_print("current object %x\n", g_list_last(newmeasure)), */
839                 newscore->currentobject = g_list_last(newmeasure->objects);
840             }
841           thestaff->themeasures = g_list_append (thestaff->themeasures, newmeasure);
842           if (h == si->currentmeasure)
843                     /*g_print("current measure %x\n", g_list_last(thestaff->measures)), */
844             newscore->currentmeasure = g_list_last (thestaff->themeasures);
845                     //???
846             }
847     }
848 
849 
850 
851   newscore->movementcontrol.directives = clone_directives (si->movementcontrol.directives);
852   newscore->layout.directives = clone_directives (si->layout.directives);
853   newscore->header.directives = clone_directives (si->header.directives);
854 
855 
856 
857 
858 
859      newscore->smfsync = G_MAXINT;
860  /*
861 
862      savebuffer
863      Instruments
864 
865 
866    */
867   newscore->markstaffnum = 0;   //Do not clone the selection
868 
869 
870   return newscore;
871 }
872 
873 
874 
875 
876 /**
877  * Recalculates the stored information about a movement
878  * either gui->movement or if that does exist yet, gui->movements->data, the first movement.(FIXME)
879  *
880  * @param gui pointer to the gui structure
881  */
882 void
updatescoreinfo(DenemoProject * gui)883 updatescoreinfo (DenemoProject * gui)
884 {
885   staffnode *curstaff;
886   DenemoMovement *si;
887   GList *g = gui->movements;
888   if (g)
889     si = g->data;
890   else
891     si = gui->movement;
892   do
893     {
894       for (curstaff = si->thescore; curstaff; curstaff = curstaff->next)
895         {
896           staff_beams_and_stems_dirs ((DenemoStaff *) curstaff->data);
897           staff_show_which_accidentals ((DenemoStaff *) curstaff->data);
898         }
899       find_xes_in_all_measures (si);
900       find_leftmost_allcontexts (si);
901 
902       si->currentstaff = si->thescore;
903       si->currentmeasure = staff_first_measure_node (si->currentstaff);
904       si->currentobject = measure_first_obj_node (si->currentmeasure);
905       if (!si->currentobject)
906         si->cursor_appending = TRUE;
907       else
908         si->cursor_appending = FALSE;
909       si->leftmeasurenum = si->currentstaffnum = si->currentmeasurenum = 1;
910     }
911   while (g && (g = g->next) && (si = g->data));
912   score_status (gui, FALSE);
913 }
914 
915 /**
916  * Delete the movements of the given score and create a new one
917  * with one movement and empty music data, no title
918  * This is the action for the d-New command
919  */
920 void
deletescore(GtkWidget * widget,DenemoProject * gui)921 deletescore (GtkWidget * widget, DenemoProject * gui)
922 {
923 
924   free_movements (gui);
925   score_status (gui, FALSE);
926   if (gui->filename)
927     {
928       g_string_free (gui->filename, TRUE);
929       g_string_free (gui->autosavename, TRUE);
930       gui->filename = NULL;
931       set_title_bar (gui);
932     }
933   if (gui->tabname)
934     {
935       g_string_free (gui->tabname, TRUE);
936       gui->tabname = NULL;
937     }
938   gui->total_edit_time = 0;
939   reset_editing_timer();
940   point_to_new_movement (gui);
941   gui->movements = g_list_append (gui->movements, gui->movement);
942   reset_movement_numbers (gui);
943   set_width_to_work_with (gui);
944   set_rightmeasurenum (gui->movement);
945   if(!Denemo.non_interactive){
946     update_hscrollbar (gui);
947     update_vscrollbar (gui);
948     draw_score_area();
949     g_signal_emit_by_name (G_OBJECT (Denemo.hadjustment), "changed");
950     g_signal_emit_by_name (G_OBJECT (Denemo.vadjustment), "changed");
951     force_lily_refresh (gui);
952   }
953   panic_all (); //g_print ("Reset synth after deletescore()\n");
954 }
955 
956