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