1 /* draw.c
2  * loop that draws all the items in the presently-displayed part of
3  * the score
4  *
5  * for Denemo, a gtk+ frontend to GNU Lilypond
6  * (c) 1999-2005 Matthew Hiller, Adam Tee
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <math.h>
14 #include "display/calculatepositions.h"
15 #include "command/commandfuncs.h"
16 #include "command/contexts.h"
17 #include "command/lilydirectives.h"
18 #include "display/draw.h"               /* Which includes gtk.h */
19 #include "display/drawingprims.h"
20 #include "display/slurs.h"
21 #include "display/hairpin.h"
22 #include "command/staff.h"
23 #include "core/utils.h"
24 #include "export/exportlilypond.h"     /* to generate lily text for display */
25 #include "audio/pitchentry.h"
26 #include "command/lyric.h"
27 #include "audio/midi.h"
28 #include "display/displayanimation.h"
29 #include "ui/moveviewport.h"
30 #include "audio/audiointerface.h"
31 
32 #define EXCL_WIDTH 3
33 #define EXCL_HEIGHT 13
34 #define SAMPLERATE (44100) /* arbitrary large figure used if no audio */
35 static GdkPixbuf *StaffPixbuf, *StaffPixbufSmall, *StaffGoBack, *StaffGoForward;
36 static DenemoObject *Startobj, *Endobj;
37 static gboolean layout_needed = TRUE;   //Set FALSE when further call to draw_score(NULL) is not needed.
38 static GList *MidiDrawObject;/* a chord used for drawing MIDI recorded notes on the score */
39 
40 
41 void
initialize_playhead(void)42 initialize_playhead (void)
43 {
44 
45   layout_needed = TRUE;
46 }
47 
48 void
region_playhead(void)49 region_playhead (void)
50 {
51   draw_score_area();
52 }
53 
54 
55 void
set_start_and_end_objects_for_draw(void)56 set_start_and_end_objects_for_draw (void)
57 {
58   if (Denemo.project->movement->smf)
59     {
60       gdouble start = Denemo.project->movement->start_time;
61       gdouble end = Denemo.project->movement->end_time;
62       if ((end > 0.0) && (end < start))
63         {
64 #ifdef SWAPPING_ENDS
65             Denemo.project->movement->start_time = end;
66             Denemo.project->movement->end_time = start;
67             start = Denemo.project->movement->start_time;
68             end = Denemo.project->movement->end_time;
69 #else
70             Denemo.project->movement->end_time = -1.0;
71 #endif
72         }
73       Startobj = get_obj_for_end_time (Denemo.project->movement->smf, start/get_playback_speed() + 0.001);
74       Endobj = Denemo.project->movement->end_time < 0.0 ? NULL : get_obj_for_start_time (Denemo.project->movement->smf, end/get_playback_speed() - 0.001);
75     }
76 }
77 
78 static void
create_tool_pixbuf(void)79 create_tool_pixbuf (void)
80 {
81   GtkWidget *widget = gtk_button_new ();
82   StaffPixbuf = gtk_widget_render_icon (widget, GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_BUTTON, "denemo");
83   StaffPixbufSmall = gtk_widget_render_icon (widget, GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU, "denemo");
84   StaffGoBack = gtk_widget_render_icon (widget, GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON, "denemo");
85   StaffGoForward = gtk_widget_render_icon (widget, GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON, "denemo");
86 }
87 
88 
89 /**
90  * scorearea_configure_event
91  *
92  * This function recaculates the number of measures that can be fit into
93  * the display, and returns
94  */
95 gint
scorearea_configure_event(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventConfigure * event)96 scorearea_configure_event (G_GNUC_UNUSED GtkWidget * widget, G_GNUC_UNUSED GdkEventConfigure * event)
97 {
98   DenemoProject *gui = Denemo.project;
99   static gboolean init = FALSE;
100   if (!init)
101     {
102       MidiDrawObject = g_list_append(NULL, newchord (0, 0, 0));
103       chord *thechord = ((DenemoObject*)(MidiDrawObject->data))->object;
104       create_tool_pixbuf ();
105       init = TRUE;
106     }
107 
108   if (gui == NULL)
109     return TRUE;
110   if (gui->movement == NULL)
111     return TRUE;
112 
113   set_width_to_work_with (gui);
114   nudgerightward (gui);
115   nudge_downward (gui);
116   return TRUE;
117 }
118 
119 #define EXTRAFORSELECTRECT 2
120 
121 /**
122  *   Information to pass between the drawing functions
123  */
124 struct infotopass
125 {
126   clef *clef;
127   gint key;
128   gint curaccs[7];
129   gint keyaccs[7];
130   gint stem_directive;
131   gint time1, time2;
132   gint tickspermeasure;
133   gint wholenotewidth;
134   gint objnum;
135   gint measurenum;
136   gint staffnum;
137   gboolean end;                 //if we have drawn the last measure
138   gint top_y;
139   gint last_gap;                //horizontal gap from last object
140   gint markx1, markx2;
141   gint marky1, marky2;
142   gboolean line_end;            //set true when an object is drawn off the right hand edge
143   gint tupletstart;             //x-coordinate where tuplet started, 0 if none
144   gint tuplety;                 //y-coordinate of highest note within tuplet
145   measurenode *curmeasure;
146   GList *mwidthiterator;
147   GSList *slur_stack;
148   GSList *hairpin_stack;
149   GtkWidget *verse;
150   gint space_above;
151   gint highy;                   /*(return) the highest y value drawn */
152   gint lowy;                    /*(return) the lowest y value drawn */
153   gint in_highy;                // FIXME these are passed in so that highy, lowy do not need to be passed back
154   gint in_lowy;
155   gboolean source_displayed;    //if pixbufs (sources) have been displayed for a staff - show no further staff content
156   gboolean mark;                //whether the region is selected
157   gint *left, *right;           //pointer into array, pointing to leftmost/rightmost measurenum for current system(line)
158   gint *scale;                  //pointer into an array of scales - this entry is the percent horizontal scale applied to the current system
159   GList *last_midi;             //last list of midi events for object at right of window
160   DenemoObject *startobj;       //pointer values - if drawing such an object mark as playback start
161   DenemoObject *endobj;         //pointer values - if drawing such an object mark as playback end
162   gint startposition;           //x coordinate where to start playing
163   gint endposition;             //x coordinate where to end playing
164   gint playposition;            //x coordinate of currently played music
165   gdouble leftmosttime;         //MIDI time of left most object on last system line displayed
166   gdouble rightmosttime;        //MIDI time of last object  displayed
167   GList *recordednote;//list of notes when recorded audio or MIDI is present
168   gint currentframe; //current frame of audio being played. (current time converted to frames (at si->recording->samplerate) and slowed down)
169   gboolean highlight_next_note;//the last CHORD was the one before the currently playing one.
170   gboolean allow_duration_error; //do not indicate errors in duration of measure
171   gdouble red, green, blue, alpha; //color of notes
172   gboolean range;
173   gint range_lo, range_hi;
174 };
175 
176 /* count the number of syllables up to staff->leftmeasurenum */
177 static gint
count_syllables(DenemoStaff * staff,gint from)178 count_syllables (DenemoStaff * staff, gint from)
179 {
180   gint count = 0;
181   gint i;
182   GList *curmeasure = staff->themeasures;
183   gboolean in_slur = FALSE;
184   for (i = 1; curmeasure && (i < from); i++, curmeasure = curmeasure->next)
185     {
186       objnode *curobj;
187       for (curobj = ((DenemoMeasure*)curmeasure->data)->objects; curobj; curobj = curobj->next)
188         {
189           DenemoObject *obj = curobj->data;
190 
191           if (obj->type == CHORD)
192             {
193               chord *thechord = ((chord *) obj->object);
194               if (thechord->notes && !in_slur)
195                 count++;
196               if (thechord->slur_begin_p)
197                 in_slur = TRUE;
198               if (thechord->slur_end_p)
199                 in_slur = FALSE;
200               if (thechord->is_tied && (!in_slur))
201                 count--;
202             }
203         }                       //for objs
204     }                           //for measures
205   if (in_slur)
206     return -count;
207   return count;
208 }
209 
draw_note_onset(cairo_t * cr,double x,const gchar * glyph,gboolean mark)210 static void draw_note_onset(cairo_t *cr, double x, const gchar *glyph, gboolean mark)
211 {
212     if(glyph) {
213         drawlargetext_cr (cr, glyph, x, 20);
214     } else
215     {
216                 cairo_move_to (cr, x, 32);
217                 cairo_line_to (cr, x, 0);
218                 cairo_line_to (cr, x + 10, 32);
219                 cairo_fill (cr);
220 
221     }
222    static gboolean on;
223 
224     if(mark)
225         {
226             on = !on;
227             if(on)
228                 {
229                   cairo_set_line_width (cr, 6.0 / Denemo.project->movement->zoom);
230                   cairo_set_source_rgba (cr, 0, 1, 0, 0.40);
231                   cairo_arc (cr, x + 10, 20, 20 / Denemo.project->movement->zoom, 0, 2 * M_PI);
232                   cairo_stroke (cr);
233                 }
234         }
235 }
236 
237 /**
238  *  draw_object
239  *
240  * Draws a single object in a measure within a staff.
241  * @param curobj
242  * @param x
243  * @param y
244  * @param gui
245  * @param itp
246  * @return excess ticks in the measure at this object. (Negative means still space).
247  */
248 static gint
draw_object(cairo_t * cr,objnode * curobj,gint x,gint y,DenemoProject * gui,struct infotopass * itp)249 draw_object (cairo_t * cr, objnode * curobj, gint x, gint y, DenemoProject * gui, struct infotopass *itp)
250 {
251 
252   itp->highy = itp->lowy = 0;
253   DenemoMovement *si = gui->movement;
254   DenemoObject *mudelaitem = (DenemoObject *) curobj->data;
255 
256   //g_debug("draw obj %d %d\n", mudelaitem->x, y);
257   //this is the selection being given a colored background
258   if (cr)
259     if (itp->mark)
260       {
261         cairo_save (cr);
262         cairo_set_source_rgba (cr, 0.8, 0.8, 0.4, 0.7);
263         cairo_rectangle (cr, x + mudelaitem->x, y, mudelaitem->minpixelsalloted, 80);
264         cairo_fill (cr);
265         cairo_restore (cr);
266       }
267 
268 
269 // if (Denemo.project->movement->playingnow)
270  //   g_print("%p %p %f %f %f\n", Denemo.project->movement->playingnow, mudelaitem, Denemo.project->movement->playhead,  mudelaitem->earliest_time, mudelaitem->latest_time );
271 
272   // draw playhead as (yellowish now) blue background
273  //if (Denemo.project->movement->playingnow == mudelaitem)
274 //  if (Denemo.project->movement->playingnow && (Denemo.project->movement->playhead >= mudelaitem->earliest_time) &&
275 //        (Denemo.project->movement->playhead < mudelaitem->latest_time)) falls through a gap!!!!
276 //  if (Denemo.project->movement->playingnow && (Denemo.project->movement->playhead >= mudelaitem->earliest_time))
277     if(Denemo.project->movement->playingnow && itp->highlight_next_note && (((Denemo.project->movement->playhead < mudelaitem->latest_time))))
278         {
279             itp->highlight_next_note = FALSE;
280             if (cr)
281                 {
282                   cairo_save (cr);
283                   cairo_set_source_rgba (cr, 0.0, 0.2, 0.8, 0.5);
284                   cairo_rectangle (cr, x + mudelaitem->x, y, 20, 80);
285                   cairo_fill (cr);
286                   cairo_restore (cr);
287                 }
288         }
289 
290     if (Denemo.project->movement->playingnow && (!((Denemo.project->movement->playhead < mudelaitem->latest_time))))//For an unknown reason, this is the condition that the next note is being played...
291         {
292             itp->highlight_next_note = TRUE;
293         }
294 
295 
296   /* The current note, rest, etc. being painted */
297 
298   if (mudelaitem == Denemo.project->movement->playingnow)
299     itp->playposition = x + mudelaitem->x;
300 
301   if (mudelaitem == itp->startobj) {
302     itp->startposition = x + mudelaitem->x/* + mudelaitem->minpixelsalloted*/;
303     // if(curobj->prev==NULL) g_debug("item %p at %d\n", curobj, x+mudelaitem->x), itp->startposition -= mudelaitem->minpixelsalloted;
304     }
305 
306   if (mudelaitem == itp->endobj)
307     itp->endposition = x + mudelaitem->x/* + mudelaitem->minpixelsalloted*/;
308 
309 
310 
311   if (cr)
312     if (mudelaitem->type == CHORD && ((chord *) mudelaitem->object)->tone_node)
313       cairo_set_source_rgb (cr, 231.0 / 255, 215.0 / 255, 39.0 / 255);  //thecolor = &yellow;
314 
315 
316 
317   switch (mudelaitem->type)
318     {
319     case CHORD:
320       {
321         chord *thechord = ((chord *) mudelaitem->object);
322         if(cr)
323            {
324             cairo_save (cr);
325             //if staff->range and thechord->highesty staff->range_hi ...
326             if (thechord->notes && ((itp->range && ((thechord->highestpitch > itp->range_hi) || (thechord->lowestpitch < itp->range_lo)))))
327                 cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0);
328             else
329                 cairo_set_source_rgba (cr, itp->red, itp->green, itp->blue, itp->alpha);
330            }
331         gint highest = draw_chord (cr, curobj, x + mudelaitem->x, y,
332                                    GPOINTER_TO_INT (itp->mwidthiterator->data),
333                                    itp->curaccs, itp->mark, (si->currentobject == curobj));
334         if(cr)
335            {
336             cairo_restore (cr);
337            }
338         if ((thechord->highesty) < itp->highy)
339           itp->highy = thechord->highesty;
340         itp->highy = MIN (itp->highy, highest);
341         if ((thechord->lowesty) > itp->lowy + STAFF_HEIGHT)
342           itp->lowy = thechord->lowesty - STAFF_HEIGHT;
343 
344  //display note onsets for source audio above relevant notes in top staff
345  // if there are not enough notes to use up all the recorded note onsets only some recorded notes are shown.
346          if(cr && si->recording && itp->recordednote && (itp->staffnum == si->top_staff))
347             {
348              GList *g = itp->recordednote;
349              gint current = mudelaitem->earliest_time*si->recording->samplerate;
350              gint next =  mudelaitem->latest_time*si->recording->samplerate;
351              gint leadin =  si->recording->leadin;
352              gint notewidth = 0;
353              objnode *curobjnext = curobj->next;
354              if(curobjnext){
355                     DenemoObject *nextobj = (DenemoObject*)curobjnext->data;
356                     notewidth = nextobj->x - mudelaitem->x;
357              } else
358              {
359                     notewidth = GPOINTER_TO_INT (itp->mwidthiterator->data) + SPACE_FOR_BARLINE - mudelaitem->x;
360              }
361 
362              /* draw the extent of the note */
363             gint extra_width = (curobj->prev==NULL) ? SPACE_FOR_BARLINE:0; //first note has extra width to leave no gap in timing from end of last bar
364 
365             notewidth += extra_width;
366 
367             cairo_set_source_rgba (cr, 0.0, 0.2, 1.0, 1);
368             cairo_move_to (cr, -extra_width + x + mudelaitem->x, 25);
369             cairo_line_to (cr, -extra_width + x + mudelaitem->x, 20);
370             cairo_line_to (cr, -extra_width + x + mudelaitem->x+ notewidth - 2, 20);
371             cairo_line_to (cr, -extra_width + x + mudelaitem->x+ notewidth, 14);
372             cairo_line_to (cr, -extra_width + x + mudelaitem->x+ notewidth, 22);
373             cairo_line_to (cr, -extra_width + x + mudelaitem->x+2, 22);
374 
375             cairo_fill (cr);
376 
377 
378 
379             cairo_set_source_rgba (cr, 0.3, 0.3, 0.3, 0.5);
380 
381              while( g && (((gint)(((DenemoRecordedNote*)g->data)->timing) - leadin) < current))
382                 {
383                     if(itp->measurenum == 1) {//represent onsets before score starts as single red onset mark 10 pixels before the first note. test g==itp->onset to avoid re-drawing
384                         cairo_save (cr);
385                         cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0);
386                         draw_note_onset (cr, x - 10, NULL, FALSE);
387                         cairo_restore (cr);
388                     }
389                     g=g->next;
390                 }
391             while( g && (((gint)(((DenemoRecordedNote*)g->data)->timing) - leadin) < next))
392                 {
393                 DenemoRecordedNote *midinote = (DenemoRecordedNote*)(g->data);
394                 gdouble fraction = (((gint)(midinote->timing) - leadin) - current) / (double)(next-current);
395                 gint pos;
396                 gchar *glyph;
397                 glyph = NULL;
398                 pos = notewidth * fraction;
399                 pos +=  mudelaitem->x;
400 
401                 if(g==si->marked_onset)
402                 {
403                     cairo_save (cr);
404                     cairo_set_source_rgba (cr, 0, 0.5, 0, 1);//g_debug("marked offset %2.2f seconds ", midinote->timing/(double)si->recording->samplerate);
405                 } else
406                 if (si->playingnow)
407                     {
408                     (itp->currentframe < ((gint)(midinote->timing) - leadin)) ?
409                         cairo_set_source_rgba (cr, 0.0, 0.2, 0.8, 0.8):
410                         cairo_set_source_rgba (cr, 0.8, 0.2, 0.0, 0.8);
411                     }
412 
413 
414                 //if MIDI RECORDING draw the pitch as a headless diamond note.
415                 if(si->recording->type==DENEMO_RECORDING_MIDI)
416                     {
417 
418                         DenemoObject *midiobj = (DenemoObject*)(MidiDrawObject->data);
419                         DenemoMeasure *curmeasure = si->currentmeasure->data;
420                         midiobj->clef = curmeasure->clef;
421                         midiobj->keysig = curmeasure->keysig;
422                         midiobj->stemdir = curmeasure->stemdir;/// FIXME is there anything else
423 
424                         removetone ((DenemoObject*)(MidiDrawObject->data), 0);//there is only one note in the chord so any mid_c_offset will do
425                         addtone (MidiDrawObject->data,  midinote->mid_c_offset + 7 * midinote->octave,  midinote->enshift);
426                         chord *thechord = ((DenemoObject*)(MidiDrawObject->data))->object;
427                         note *thenote = ((note*)(thechord->notes->data));
428                         thenote->noteheadtype = DENEMO_DIAMOND_NOTEHEAD;
429                         if(midinote->enshift)
430                             thenote->showaccidental = TRUE;
431                         thenote->position_of_accidental = 8;
432                         //thechord->baseduration = midinote->duration;
433                         //thechord->numdots = midinote->dots;
434                         //set_basic_numticks (MidiDrawObject->data);
435                         switch (midinote->duration) {
436                             case 0:
437                                 glyph = midinote->dots?"��•":"��";
438                                 break;
439                             case 1:
440                                 glyph = midinote->dots?"��•":"��";
441                                 break;
442                             case 2:
443                                 glyph = midinote->dots?"��•":"��";
444                                 break;
445                             case 3:
446                                 glyph = midinote->dots?"��•":"��";
447                                 break;
448                             case 4:
449                                 glyph = midinote->dots?"��•":"��";
450                                 break;
451                             case 5:
452                                 glyph = midinote->dots?"•��":"��";
453                                 break;
454                             case 6:
455                                 glyph = midinote->dots?"•��":"��";
456                                 break;
457                             case 7:
458                                 glyph = NULL;//we do not have a glyph for this yet
459                                 break;
460 
461 
462 
463                         }
464 
465                         if (g==si->marked_onset)
466                         {
467                             //midinote->measurenum = itp->measurenum;
468                             //midinote->objnum = itp->objnum;
469                         }
470 
471                         cairo_save (cr);
472                         (g==si->marked_onset) ?cairo_set_source_rgba (cr, 0, 0.5, 0, 1):
473                             cairo_set_source_rgba (cr, 0, 0, 0, 1);
474                         draw_chord (cr, MidiDrawObject, pos + x -extra_width, y, 0, itp->curaccs, FALSE, FALSE);
475                         cairo_restore (cr);
476                     }
477 
478                 draw_note_onset(cr, pos + x - extra_width, glyph, (g==si->marked_onset));
479 
480                 if(g==si->marked_onset)
481                     {//g_debug("fraction = %f; notewidth = %d ", fraction, notewidth);
482                         cairo_restore (cr);
483                     }
484                 if(si->marked_onset_position && ABS((gint)(pos + x - si->marked_onset_position))<20)
485                     {
486                     si->marked_onset = g;
487                     si->marked_onset_position = 0; //g_debug("Found selected onset\n\n");
488                     }
489 
490                 //if(g==itp->onset) g_debug("First onset at %d %d %d %d\n", pos, x, si->marked_onset_position, notewidth);
491 
492 
493                 g = g->next;
494                 }
495             itp->recordednote = g;//Search onwards for future onsets. Only notes on top staff are used for display of onsets.
496 
497          } //recording
498 
499 
500         if (itp->tupletstart)
501           itp->tuplety = MAX (0, MAX (itp->tuplety, MAX (-thechord->lowesty, -thechord->highesty)));
502 
503         if (thechord->is_fakechord)
504           if (cr)
505             draw_fakechord (cr, x + mudelaitem->x, y - 45, mudelaitem);
506 
507         if (si->currentstaffnum == itp->staffnum && itp->verse && thechord->notes)
508           {
509             static gboolean last_tied = FALSE;
510             if ((!last_tied) && (!itp->slur_stack) && (!thechord->is_tied) && !find_directive (thechord->directives, "MoveRest"))
511               {
512                 gchar *syllable = (gchar *) next_syllable ();
513                 if (cr)
514                   if (syllable)
515                     draw_lyric (cr, x + mudelaitem->x, y + itp->in_lowy, syllable);
516               }
517             last_tied = thechord->slur_end_p && thechord->is_tied;
518           }
519 
520         if (cr)
521           if (thechord->dynamics)
522             draw_dynamic (cr, x + mudelaitem->x, y, mudelaitem);
523 
524         if (cr)
525           if (thechord->slur_end_p)
526             draw_slur (cr, &(itp->slur_stack), x + mudelaitem->x + 5/*half note head??? */, y, thechord->highesty);
527         if (thechord->slur_begin_p)
528           itp->slur_stack = push_slur_stack (itp->slur_stack, x + mudelaitem->x, thechord->highesty);
529 
530 
531 
532 
533         if (thechord->crescendo_begin_p)
534           {
535            if (thechord->diminuendo_end_p)
536               {
537                if (top_hairpin_stack (itp->hairpin_stack) == -1)
538                     {
539                         itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, -10);
540                     }
541               if (cr) draw_hairpin (cr, &(itp->hairpin_stack), x + mudelaitem->x, y, 0);
542                    //pop stack
543               itp->hairpin_stack = pop_hairpin_stack (itp->hairpin_stack);
544              } else  if (thechord->crescendo_end_p)
545               {
546                 if (top_hairpin_stack (itp->hairpin_stack) == -1)
547                   {
548                         itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, -10);
549                   }
550                 if (cr) draw_hairpin (cr, &(itp->hairpin_stack), x + mudelaitem->x, y, 1);
551                    //pop stack
552                 itp->hairpin_stack = pop_hairpin_stack (itp->hairpin_stack);
553              }
554             itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, x + mudelaitem->x);
555           }
556         else if (thechord->diminuendo_begin_p)
557           {
558             if (thechord->crescendo_end_p)
559               {
560                 if (top_hairpin_stack (itp->hairpin_stack) == -1)
561                   {
562                         itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, -10);
563                   }
564                 if (cr) draw_hairpin (cr, &(itp->hairpin_stack), x + mudelaitem->x, y, 1);
565                    //pop stack
566                 itp->hairpin_stack = pop_hairpin_stack (itp->hairpin_stack);
567              } else if (thechord->diminuendo_end_p)
568               {
569                if (top_hairpin_stack (itp->hairpin_stack) == -1)
570                     {
571                         itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, -10);
572                     }
573               if (cr) draw_hairpin (cr, &(itp->hairpin_stack), x + mudelaitem->x, y, 0);
574                    //pop stack
575               itp->hairpin_stack = pop_hairpin_stack (itp->hairpin_stack);
576              }
577             itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, x + mudelaitem->x);
578           }
579        else
580           {
581             if (thechord->crescendo_end_p)
582               {
583                  if (top_hairpin_stack (itp->hairpin_stack) == -1)
584                   {
585                         itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, -10);
586                   }
587                 if (cr) draw_hairpin (cr, &(itp->hairpin_stack), x + mudelaitem->x, y, 1);
588                    //pop stack
589                 itp->hairpin_stack = pop_hairpin_stack (itp->hairpin_stack);
590               }
591             else if (thechord->diminuendo_end_p)
592               {
593                if (top_hairpin_stack (itp->hairpin_stack) == -1)
594                     {
595                         itp->hairpin_stack = push_hairpin_stack (itp->hairpin_stack, -10);
596                     }
597                if (cr) draw_hairpin (cr, &(itp->hairpin_stack), x + mudelaitem->x, y, 0);
598                    //pop stack
599                itp->hairpin_stack = pop_hairpin_stack (itp->hairpin_stack);
600               }
601           }
602         /* notice the following does not check is_figure but checks if figure is not VOID) */
603         //if (!thechord->is_figure && thechord->figure)
604         if (cr)
605           if (thechord->figure)
606             draw_figure (cr, x + mudelaitem->x, y + (thechord->lowesty / 2), mudelaitem);
607         if (cr)
608           if (!thechord->is_fakechord && thechord->fakechord)
609             draw_fakechord (cr, x + mudelaitem->x, y - 45,
610                             //y + (thechord->highesty / 4),
611                             mudelaitem);
612       }
613       break;
614     case TUPOPEN:
615       itp->tupletstart = x + mudelaitem->x;
616       if (cr)
617         draw_tupbracket (cr, x + mudelaitem->x, y, mudelaitem, 0);
618       break;
619     case TUPCLOSE:
620       if (cr)
621         draw_tupbracket (cr, x + mudelaitem->x, y - itp->tuplety, mudelaitem, itp->tupletstart);
622       itp->tupletstart = itp->tuplety = 0;
623       break;
624     case LILYDIRECTIVE:
625       {
626         DenemoDirective *directive = mudelaitem->object;
627         if (cr)
628           draw_lily_dir (cr, x + mudelaitem->x, y, 0, 0, mudelaitem, itp->mark, (si->currentobject == curobj));
629         if ((directive->ty - 10) < itp->highy)
630           itp->highy = directive->ty - 10 /* for height of text */ ;
631         if ((directive->gy - 10) < itp->highy)
632           itp->highy = directive->gy - 10 /* for height of text */ ;
633           if(directive->tag && *directive->tag->str == '!')
634             itp->allow_duration_error = TRUE;
635       }
636       break;
637     case CLEF:
638       itp->clef = ((clef *) mudelaitem->object);
639       if (cr)
640         {
641           if (mudelaitem->isinvisible)
642             {
643               cairo_save (cr);
644               cairo_set_source_rgb (cr, 231.0 / 255, 215.0 / 255, 39.0 / 255);  //thecolor = &yellow;cairo_  rgb yellow
645             }
646           draw_clef (cr, x + mudelaitem->x, y, itp->clef);
647           if (mudelaitem->isinvisible)
648             {
649               cairo_restore (cr);
650             }
651         }
652 
653       break;
654     case KEYSIG:
655       if (cr)
656         draw_key (cr, x + mudelaitem->x, y, ((keysig *) mudelaitem->object)->number, itp->key, itp->clef->type, TRUE, (keysig *) mudelaitem->object);
657       itp->key = ((keysig *) mudelaitem->object)->number;
658       memcpy (itp->keyaccs, ((keysig *) mudelaitem->object)->accs, SEVENGINTS);
659       memcpy (itp->curaccs, itp->keyaccs, SEVENGINTS);
660 
661       break;
662     case TIMESIG:
663       itp->time1 = ((timesig *) mudelaitem->object)->time1;
664       itp->time2 = ((timesig *) mudelaitem->object)->time2;
665       if (cr)
666         draw_timesig (cr, x + mudelaitem->x, y, itp->time1, itp->time2, (timesig *) mudelaitem->object);
667 
668       /* The following assumes no multiple simultaneous time signatures */
669       itp->tickspermeasure = WHOLE_NUMTICKS * itp->time1 / itp->time2;
670       itp->wholenotewidth = si->measurewidth * itp->time2 / itp->time1;
671       break;
672     case STEMDIRECTIVE:
673       if (cr)
674         draw_stem_directive (cr, x + mudelaitem->x, y, mudelaitem);
675       itp->stem_directive = ((stemdirective *) mudelaitem->object)->type;
676       break;
677     default:
678       /* Nothing */
679       break;
680     }
681 
682   gint extra = MAX (mudelaitem->minpixelsalloted,
683                     space_after (mudelaitem->durinticks,
684                                  itp->wholenotewidth));
685   if (si->currentobject == curobj)
686     {                           /* Draw the cursor */
687       /* Determine if it needs to be red or not */
688       if (si->cursor_appending || mudelaitem->type != CHORD)
689         si->cursoroffend = (mudelaitem->starttickofnextnote >= itp->tickspermeasure);
690       else
691         si->cursoroffend = (mudelaitem->starttickofnextnote > itp->tickspermeasure);
692       if (si->cursor_appending)
693         {
694           draw_cursor (cr, si, x + mudelaitem->x + extra, y, ((itp->curmeasure->next != NULL) && (objnode *) ((DenemoMeasure*)itp->curmeasure->next->data)->objects) ? -1 : 0 /*itp->last_gap */ , 0, mudelaitem->clef->type);
695 
696         }
697       else
698         {
699           draw_cursor (cr, si, x + mudelaitem->x, y, itp->last_gap, mudelaitem->type == CHORD ? 0 : mudelaitem->minpixelsalloted, mudelaitem->clef->type);
700         }
701     }
702   /* End cursor drawing */
703 
704   itp->last_gap = extra;
705   /* Now quite possibly update the mark */
706 
707   if (si->selection.firststaffmarked == itp->staffnum && si->selection.firstmeasuremarked == itp->measurenum && si->selection.firstobjmarked == itp->objnum)
708     itp->markx1 = x + mudelaitem->x - EXTRAFORSELECTRECT;
709 
710   if (si->selection.laststaffmarked == itp->staffnum && si->selection.lastmeasuremarked == itp->measurenum && si->selection.lastobjmarked == itp->objnum)
711     itp->markx2 = x + mudelaitem->x + mudelaitem->minpixelsalloted + EXTRAFORSELECTRECT;
712 
713     //In page view we have to allow the last time to be the last recorded time for any object on the page, but empty measures on the lowest visible staff will cause the rightmost time to be set too early.
714     //FIXME, use smf.c to calculate start and end times for each measure and consult that.
715   if((Denemo.project->view == DENEMO_PAGE_VIEW) || (itp->rightmosttime < mudelaitem->latest_time*get_playback_speed()))
716     {
717       if (!(itp->measurenum == si->rightmeasurenum + 1)) //ignore partially drawn measures for computing whether we need to call page_viewport
718         itp->rightmosttime = mudelaitem->latest_time*get_playback_speed();
719     }
720   return (mudelaitem->starttickofnextnote - itp->tickspermeasure);
721 }                              /* draw_object */
722 
723 /**
724  * Draws a single measure within a staff.
725  * @param curmeasure pointer to the measure to draw
726  * @param x
727  * @param y
728  * @param gui
729  * @param itp
730  * return TRUE if measure has correct number of beats
731  */
732 static gboolean
draw_measure(cairo_t * cr,measurenode * curmeasure,gint x,gint y,DenemoProject * gui,struct infotopass * itp)733 draw_measure (cairo_t * cr, measurenode * curmeasure, gint x, gint y, DenemoProject * gui, struct infotopass *itp)
734 {
735   static GString *mstring;
736   gint last_type = -1;          //type of last object in measure
737   gint extra_ticks = 0;         //number of ticks by which measure is over-full
738   DenemoMovement *si = gui->movement;
739   objnode *curobj;
740   gboolean has_cursor = FALSE;
741   /* initialization */
742   if (!mstring)
743     mstring = g_string_new (NULL);
744   /* Set information about the state at the current measure,
745      if necessary */
746 
747   memcpy (itp->curaccs, itp->keyaccs, SEVENGINTS);
748   itp->wholenotewidth = si->measurewidth * itp->time2 / itp->time1;
749 
750 
751   /*  paint the measure number at the preceding barline
752    */
753 
754   if (cr)
755     {
756 
757      DenemoMeasure *meas = (DenemoMeasure*)curmeasure->data;
758      if (meas->measure_numbering_offset)
759         {
760           cairo_set_source_rgba (cr, 0.2, 0.1, 0.8, 0.7);
761           g_string_sprintf (mstring, "%d", meas->measure_numbering_offset);
762           drawlargetext_cr (cr, mstring->str, x - SPACE_FOR_BARLINE - 5, y + 2 * STAFF_HEIGHT - 10);
763         }
764 
765       if (itp->measurenum > 1)
766         {                       //don't draw first measure number, as it collides and is obvious anyway and is never typeset thus
767           cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
768           g_string_sprintf (mstring, "%d", meas->measure_number);
769           drawnormaltext_cr (cr, mstring->str, x - SPACE_FOR_BARLINE - 5, y - 3);
770         }
771     }
772 
773 
774   // draw the cursor and set the side effects up if this didn't happen when drawing the currentobject because there isn't one - a blank measure
775   if (!si->currentobject && (si->currentstaffnum == itp->staffnum && si->currentmeasurenum == itp->measurenum))
776     {
777       /* That is, the cursor's at the beginning of this blank measure */
778       si->cursoroffend = FALSE;
779       has_cursor = TRUE;
780       draw_cursor (cr, si, x, y, 0, gui->mode, itp->clef->type);
781     }
782 
783   curobj = (objnode *) ((DenemoMeasure*)curmeasure->data)->objects;
784   /* These default values for the markx'es may be necessary down
785    * the road */
786   if (si->selection.firststaffmarked == itp->staffnum && si->selection.firstmeasuremarked == itp->measurenum)
787     {
788       if (!curobj)
789         itp->markx1 = x - EXTRAFORSELECTRECT;
790       else
791         itp->markx1 = x + GPOINTER_TO_INT (itp->mwidthiterator->data);
792     }
793   if (si->selection.laststaffmarked == itp->staffnum && si->selection.lastmeasuremarked == itp->measurenum)
794     {
795       if (!curobj || (si->selection.lastobjmarked >= (gint) (g_list_length ((objnode *) curobj))))
796         itp->markx2 = x + GPOINTER_TO_INT (itp->mwidthiterator->data) + SPACE_FOR_BARLINE + EXTRAFORSELECTRECT;
797       else
798         itp->markx2 = x;
799     }
800 
801 
802 
803   gboolean not_marked = (!si->markstaffnum) || (si->selection.firststaffmarked > itp->staffnum) || (si->selection.laststaffmarked < itp->staffnum) || (si->selection.firstmeasuremarked > itp->measurenum) || (si->selection.lastmeasuremarked < itp->measurenum);
804 
805   gboolean definitely_marked = (!not_marked) && (si->selection.firstmeasuremarked < itp->measurenum) && (si->selection.lastmeasuremarked > itp->measurenum);
806   gboolean in_firstmeas = (si->selection.firstmeasuremarked == itp->measurenum);
807   gboolean in_lastmeas = (si->selection.lastmeasuremarked == itp->measurenum);
808   /* Draw each mudelaitem */
809   for (itp->objnum = 0; curobj; curobj = curobj->next, itp->objnum++)
810     {
811       itp->mark = (definitely_marked) || ((!not_marked) && ((in_firstmeas && !in_lastmeas && (si->selection.firstobjmarked <= itp->objnum)) || (in_lastmeas && !in_firstmeas && (si->selection.lastobjmarked >= itp->objnum)) || (in_lastmeas && in_firstmeas && (si->selection.firstobjmarked <= itp->objnum) && (si->selection.lastobjmarked >= itp->objnum))));
812 
813 
814       if (cr)
815         {
816           //      if(itp->measurenum > si->rightmeasurenum+1)
817           //        g_critical("Please advise the circumstance in which this happened");
818           if (itp->measurenum == si->rightmeasurenum + 1)
819             cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);   //This draws light gray anything that will be repeated at the start of the next page.
820           else
821             cairo_set_source_rgb (cr, 0, 0, 0); //black;
822         }                       // if cr
823 
824       extra_ticks = draw_object (cr, curobj, x, y, gui, itp);
825 
826       {
827         DenemoObject *obj = (DenemoObject *) curobj->data;
828         last_type = obj->type;
829       }
830       //itp->rightmosttime = curobj->latest_time;//we just want this for the rightmost object
831     }                           // for each object
832   if (cr)
833     {
834       cairo_save (cr);
835       //marking the barline if within selection
836       if (si->markstaffnum &&
837 /*        (curmeasure->data==NULL) && */
838           (si->selection.firststaffmarked <= itp->staffnum) && (si->selection.laststaffmarked >= itp->staffnum) && (si->selection.firstmeasuremarked <= itp->measurenum) && (si->selection.lastmeasuremarked > itp->measurenum))
839         {
840           cairo_set_source_rgba (cr, 0.8, 0.8, 0.4, 0.7);
841           cairo_rectangle (cr, x + GPOINTER_TO_INT (itp->mwidthiterator->data) - 10, y, 20, STAFF_HEIGHT + 1);
842 
843           cairo_fill (cr);
844         }
845       /* Indicate fill status  */
846 #define OPACITY (curmeasure == si->currentmeasure?0.3:0.8)
847          if(itp->allow_duration_error)
848             {
849                 extra_ticks = 0;
850                 itp->allow_duration_error = FALSE;
851             }
852       if (curmeasure->data)
853         {
854 
855             if (extra_ticks == -itp->tickspermeasure)
856                 extra_ticks = 0;//allow empty measures
857 
858           if (extra_ticks > 0)
859                 cairo_set_source_rgba (cr, 1.0, 0.6, 0.6, OPACITY);
860           else if ((extra_ticks < 0)/* && curmeasure->next*/)
861                 cairo_set_source_rgba (cr, 0.6, 0.6, 1, OPACITY);
862 
863           if (((extra_ticks > 0) || (extra_ticks < 0)) &&
864             ((curmeasure->next && curmeasure->next->data) || ((curmeasure->next!= NULL) && (!has_cursor))))
865 
866             {
867               cairo_rectangle (cr, x, y, GPOINTER_TO_INT (itp->mwidthiterator->data), STAFF_HEIGHT + 1);
868               cairo_fill (cr);
869               extra_ticks > 0 ? cairo_set_source_rgb (cr, 1, 0, 0) : cairo_set_source_rgb (cr, 0, 0, 1);
870             }
871           else
872             {
873               cairo_set_source_rgb (cr, 0, 0, 0);
874             }
875         }
876 #undef OPACITY
877       if (extra_ticks == 0)
878         {
879           cairo_set_source_rgb (cr, 0, 0, 0);
880         }
881 
882       //draw the barline
883       cairo_rectangle (cr, x + GPOINTER_TO_INT (itp->mwidthiterator->data), y - 0.5, 1.5, STAFF_HEIGHT + 1);
884       cairo_fill (cr);
885 
886       if ((!curmeasure->next))
887         {
888           /* we've reached the end of the staff and should
889            * draw the heavy part of double-barline unless there is a directive here in which case it takes responsibility for the type of barline */
890           x += 3;
891           if (last_type != LILYDIRECTIVE)
892             {
893               cairo_rectangle (cr, x + GPOINTER_TO_INT (itp->mwidthiterator->data), y - 0.5, 4, STAFF_HEIGHT + 1);
894               cairo_fill (cr);
895             }
896           itp->end = TRUE;
897           if(itp->startposition>-1 && itp->endposition<0)
898             itp->endposition = x + GPOINTER_TO_INT (itp->mwidthiterator->data) + 5;//end play marker after last note if not elsewhere
899         }
900       else
901         {
902           itp->end = FALSE;
903         }
904       cairo_restore (cr);
905     }                           //if cr
906 
907   return extra_ticks != 0;
908 }
909 
910 /**
911  * Draws a single staff
912  * TODO sort out graphics context for active polyphonic voice should
913  * do it here
914  * @param curstaffstruct pointer to the staff to draw
915  * @param y    y position of the staff
916  * @param gui   pointer to the DenemoProject structure
917  * @param itp  pointer to the infotopass structure
918  * return TRUE if the staff has had to made taller
919  */
920 static gboolean
draw_staff(cairo_t * cr,staffnode * curstaff,gint y,DenemoProject * gui,struct infotopass * itp)921 draw_staff (cairo_t * cr, staffnode * curstaff, gint y, DenemoProject * gui, struct infotopass *itp)
922 {
923   DenemoStaff *thestaff = (DenemoStaff *) curstaff->data;
924   gboolean repeat = FALSE;
925   DenemoMovement *si = gui->movement;
926   gint x = (gui->leftmargin+35), i;
927     itp->red = (((thestaff->color)>>24)&0xFF)/255.0;
928     itp->green = (((thestaff->color)>>16)&0xFF)/255.0;
929     itp->blue = (((thestaff->color)>>8)&0xFF)/255.0;
930     itp->alpha = (0xFF ^ ((thestaff->color)&0xFF))/255.0;
931     itp->range = thestaff->range;
932     itp->range_lo = thestaff->range_lo;
933     itp->range_hi = thestaff->range_hi;
934   // if(si->marked_onset_position)
935     //g_debug("repeat"),repeat = TRUE;//we set up the marked onset with this, then need to repeat to draw it
936   //g_debug("drawing staff %d at %d\n", itp->staffnum, y);
937   gint nummeasures = g_list_length (thestaff->themeasures);
938 
939   //g_debug("Of %d current %d\n", nummeasures, itp->measurenum);
940   if (itp->measurenum > nummeasures)
941     cr = NULL;                  //no more drawing on this staff
942   if (cr)
943     {
944       cairo_save (cr);
945 
946       //Draw vertical lines to bind the staffs of the system together
947       if (curstaff->prev)
948         {
949           DenemoStaff *prev = (DenemoStaff *) (curstaff->prev->data);
950           cairo_set_source_rgb (cr, 0, 0, 0);
951           cairo_rectangle (cr, gui->leftmargin, y - STAFF_HEIGHT - prev->space_below - thestaff->space_above, 2, 2 * STAFF_HEIGHT + prev->space_below + thestaff->space_above);
952           cairo_fill (cr);
953         }
954       if (curstaff->next)
955         {
956           DenemoStaff *next = (DenemoStaff *) (curstaff->next->data);
957           //cairo_save(cr);
958           cairo_set_source_rgb (cr, 0, 0, 0);
959           cairo_rectangle (cr, gui->leftmargin, y, 2, 2 * STAFF_HEIGHT + next->space_above + thestaff->space_below);
960           cairo_fill (cr);
961         }
962 
963       if ((DenemoStaff *) si->currentstaff->data == thestaff)
964         cairo_set_source_rgb (cr, 0, 0, 0);
965       else
966         cairo_set_source_rgb (cr, 0.3, 0.3, 0.3);
967     }   //if cr
968 
969 
970 
971 
972   if (!itp->line_end)
973     {                           //not a continuation
974       itp->clef = thestaff->leftmost_clefcontext;
975       if (cr && !(thestaff->voicecontrol & DENEMO_SECONDARY))
976         draw_clef (cr, gui->leftmargin, y, itp->clef);
977       else if (cr)
978         {
979           cairo_save (cr);
980           cairo_set_source_rgb (cr, 231.0 / 255, 215.0 / 255, 39.0 / 255);      //thecolor = &yellow;
981           draw_clef (cr, gui->leftmargin, y, itp->clef);
982           cairo_restore (cr);
983         }
984 
985 
986       itp->key = thestaff->leftmost_keysig->number;
987       if (cr && !(thestaff->voicecontrol & DENEMO_SECONDARY))
988         draw_key (cr, x, y, itp->key, 0, itp->clef->type, TRUE, thestaff->leftmost_keysig);
989       x += si->maxkeywidth;
990       itp->time1 = thestaff->leftmost_timesig->time1;
991       itp->time2 = thestaff->leftmost_timesig->time2;
992       if (cr && !(thestaff->voicecontrol & DENEMO_SECONDARY))
993         {
994           if (si->leftmeasurenum == 1)
995             draw_timesig (cr, x + 5, y, itp->time1, itp->time2, thestaff->leftmost_timesig);
996           else
997             {
998               guint width = gdk_pixbuf_get_width (GDK_PIXBUF (StaffGoBack));
999               guint height = gdk_pixbuf_get_height (GDK_PIXBUF (StaffGoBack));
1000               cairo_save (cr);
1001               gdk_cairo_set_source_pixbuf (cr, GDK_PIXBUF (StaffGoBack), x, y);
1002               cairo_rectangle (cr, x, y, width, height);
1003               cairo_fill (cr);
1004               cairo_restore (cr);
1005             }
1006         }
1007       x += SPACE_FOR_TIME;
1008     }
1009   else
1010     {                           // a continuation line
1011       if (cr && !(thestaff->voicecontrol & DENEMO_SECONDARY))
1012         draw_clef (cr, gui->leftmargin, y, itp->clef);
1013       if (cr && !(thestaff->voicecontrol & DENEMO_SECONDARY))
1014         draw_key (cr, x, y, itp->key, 0, itp->clef->type, TRUE, thestaff->leftmost_keysig);
1015       x += si->maxkeywidth;
1016       x += SPACE_FOR_TIME;      // to allow the same margin ??
1017     }
1018 
1019   *itp->left = itp->measurenum > gui->movement->rightmeasurenum ? gui->movement->rightmeasurenum : itp->measurenum;
1020   memcpy (itp->keyaccs, thestaff->leftmost_keysig->accs, SEVENGINTS);
1021 
1022 
1023   itp->stem_directive = thestaff->leftmost_stem_directive;
1024   itp->tickspermeasure = WHOLE_NUMTICKS * itp->time1 / itp->time2;
1025 
1026   if (cr)
1027     {
1028       /* Draw staff name on first system */
1029       if (!itp->line_end)
1030         {
1031           gint staffname_offset = (thestaff->voicecontrol & DENEMO_PRIMARY) ? 26 : 12;
1032 
1033            if (si->leftmeasurenum == 1)//make a button of it if measure 1 is leftmost
1034              {
1035               drawnormaltext_cr (cr, thestaff->denemo_name->str, gui->leftmargin /*KEY_MARGIN */ , y - staffname_offset + 10);
1036               if (thestaff->subpart)
1037                 drawnormaltext_cr (cr, thestaff->subpart->str, gui->leftmargin +20/*KEY_MARGIN */ , y - staffname_offset + 20);
1038               cairo_save (cr);
1039               cairo_set_source_rgba (cr, 0.2, 0.8, 0.4, 0.4);
1040               cairo_rectangle (cr, gui->leftmargin, y - staffname_offset - 0, 30, 12);
1041               cairo_fill (cr);
1042               cairo_set_source_rgba (cr, 0.0, 0.8, 0.0, 1);
1043               cairo_rectangle (cr, gui->leftmargin, y - staffname_offset - 0, 30, 12);
1044               cairo_stroke (cr);
1045               cairo_restore(cr);
1046              }
1047            else
1048              {
1049               drawnormaltext_cr (cr, thestaff->denemo_name->str, gui->leftmargin - 10 /*KEY_MARGIN */ , y - staffname_offset + 10);
1050               if (thestaff->subpart)
1051                 drawnormaltext_cr (cr, thestaff->subpart->str, gui->leftmargin + 20 /*KEY_MARGIN */ , y - staffname_offset + 20);
1052              }
1053             if(thestaff->hasfakechords)  drawnormaltext_cr (cr, _("Chord Symbols"), gui->leftmargin - 10 /*KEY_MARGIN */ , y - staffname_offset + 20 + 2 * STAFF_HEIGHT);
1054             if(thestaff->hasfigures)  drawnormaltext_cr (cr, _("Figured Bass"), gui->leftmargin - 10 /*KEY_MARGIN */ , y - staffname_offset + 20 + 2 * STAFF_HEIGHT);
1055         }
1056       else
1057         {
1058           cairo_save (cr);
1059           gint staffname_offset = (thestaff->voicecontrol & DENEMO_PRIMARY) ? 26 : 12;
1060           cairo_translate (cr, 2, (y - staffname_offset + 30));
1061           cairo_rotate (cr, -M_PI / 5.0);
1062           drawnormaltext_cr (cr, thestaff->denemo_name->str, 0, 0);
1063           if (thestaff->subpart)
1064                 drawnormaltext_cr (cr, thestaff->subpart->str, 30, 20);
1065           cairo_restore (cr);
1066         }
1067     }                           //if cr
1068 
1069 
1070 
1071   x += transition_offset ();
1072 
1073 
1074 
1075 
1076 
1077 
1078   if ((gui->movement->smf) && (itp->startobj == NULL) && (itp->startposition <= 0) && (si->leftmeasurenum == 1))
1079     itp->startposition = x;
1080 
1081 
1082   /* Loop that will draw each measure. Basically a for loop, but was uglier
1083    * when written that way.  */
1084   itp->curmeasure = g_list_nth (thestaff->themeasures, itp->measurenum - 1);
1085   //g_debug("measurenum %d\nx=%d\n", itp->measurenum, x);
1086 
1087   //FIX in measure.c for case where si->measurewidths is too short
1088   itp->mwidthiterator = g_list_nth (si->measurewidths, itp->measurenum - 1);
1089 
1090   {
1091     //compute itp->leftmosttime here - the time at the start of this system
1092 
1093     objnode *curobj = itp->curmeasure ? (objnode *) ((DenemoMeasure*)itp->curmeasure->data)->objects : NULL;
1094     if (curobj)
1095       {
1096         DenemoObject *mudelaitem = (DenemoObject *) curobj->data;
1097         if (mudelaitem)
1098           itp->leftmosttime = mudelaitem->earliest_time;
1099         else
1100           itp->leftmosttime = 1000000.0;
1101       }
1102     //g_debug("Drawing staff %d leftmost time %f, measurenum %d\n",itp->staffnum, itp->leftmosttime, itp->measurenum);
1103   }
1104 
1105   if (!*itp->scale)
1106     *itp->scale = 100;
1107   if (cr)
1108     {
1109       cairo_scale (cr, 100.0 / (*itp->scale), 1.0);
1110       //cairo_scale(cr,(*itp->scale)/100.0,1.0);
1111     }
1112 
1113   gint scale_before = *itp->scale;
1114   itp->line_end = FALSE;
1115   cairo_t *saved_cr = NULL;
1116   if (itp->source_displayed)
1117     {                           //We have displayed source material below the last staff, so do not draw anymore staff music. We cannot simply skip the drawing routines however, because they determine the rightmost bar for mouse positioning, so we save and restore it.
1118       saved_cr = cr;
1119       cr = NULL;
1120     }
1121 
1122   while ((!itp->line_end) && itp->measurenum <= nummeasures)
1123     {
1124 
1125       if (x + GPOINTER_TO_INT (itp->mwidthiterator->data) + SPACE_FOR_BARLINE > (int) (get_widget_width (Denemo.scorearea) / gui->movement->zoom - (RIGHT_MARGIN + (gui->leftmargin+35) + si->maxkeywidth + SPACE_FOR_TIME)))
1126         itp->line_end = TRUE;
1127 
1128       itp->last_gap = 0;
1129 
1130       if (itp->measurenum == si->currentmeasurenum)
1131         x += measure_transition_offset (si->currentstaffnum == itp->staffnum);
1132       draw_measure (cr, itp->curmeasure, x, y, gui, itp);
1133       if (cr && (Denemo.project->view != DENEMO_PAGE_VIEW) && (si->sources || thestaff->sources) && (si->currentstaffnum == itp->staffnum))
1134         {
1135           GdkPixbuf *source = (GdkPixbuf *) g_list_nth_data (si->sources ? gui->movement->sources : thestaff->sources, itp->measurenum - 1);
1136           if (source)
1137             {
1138               gdouble width = (gdouble) gdk_pixbuf_get_width (GDK_PIXBUF (source));
1139               gdouble height = (gdouble) gdk_pixbuf_get_height (GDK_PIXBUF (source));
1140               gdouble scale = GPOINTER_TO_INT (itp->mwidthiterator->data) / width;
1141               gint ypos = y + 2 * STAFF_HEIGHT + thestaff->space_below;
1142               gint xpos = x;
1143               cairo_save (cr);
1144               if (scale < 1.0)
1145                 {               //too large to fit under the measure
1146                   cairo_translate (cr, x * (1 - scale), ypos * (1 - scale));
1147                   cairo_scale (cr, scale, scale);
1148                 }
1149               else
1150                 xpos = x - (width - GPOINTER_TO_INT (itp->mwidthiterator->data)) / 2;   //narrow, center it
1151               gdk_cairo_set_source_pixbuf (cr, GDK_PIXBUF (source), xpos, ypos);
1152               cairo_rectangle (cr, xpos, ypos, width, height);
1153               cairo_fill (cr);
1154               cairo_restore (cr);
1155               itp->source_displayed = TRUE;
1156             }
1157         }
1158 
1159       x += GPOINTER_TO_INT (itp->mwidthiterator->data) + SPACE_FOR_BARLINE;
1160 
1161 
1162       if (
1163 #if 0
1164 /* do not scale the non page views as it perturbs the display animation and anyway does not add anything */
1165            (Denemo.project->view != DENEMO_PAGE_VIEW && itp->line_end && itp->measurenum > si->rightmeasurenum) ||
1166 #endif
1167            (Denemo.project->view == DENEMO_PAGE_VIEW && itp->line_end && itp->curmeasure->next))
1168         *itp->scale = (int) (100 * x / (get_widget_width (Denemo.scorearea) / gui->movement->zoom));
1169       else
1170         *itp->scale = 100;
1171 
1172       itp->curmeasure = itp->curmeasure->next;
1173       itp->mwidthiterator = itp->mwidthiterator->next;
1174 
1175       itp->measurenum++;
1176       //g_debug("line_end is %d, while itp->measurenum=%d and si->rightmeasurenum=%d\n",  itp->line_end, itp->measurenum, si->rightmeasurenum);
1177       if (!itp->line_end)
1178         {
1179           if (-itp->highy > itp->in_highy && -itp->highy < MAXEXTRASPACE)
1180             {
1181               //g_debug("With %d to change %d\n", -itp->highy, itp->in_highy);
1182               thestaff->space_above = -itp->highy;
1183               repeat = TRUE;
1184             }
1185           if (itp->lowy > itp->in_lowy && itp->lowy < MAXEXTRASPACE)
1186             {
1187               thestaff->space_below = itp->lowy;
1188               repeat = TRUE;
1189             }
1190         }
1191     }                           // end of loop drawing each measure
1192   if (scale_before != *itp->scale)
1193     repeat = TRUE;              /* the first system is already drawn, so it is too late to discover that we needed to scale it */
1194   *itp->right = itp->measurenum - 1;
1195   /* draw lines connecting the staves in this system at the left and right hand ends */
1196   if (cr)
1197     if (curstaff->prev)
1198       {
1199         DenemoStaff *prev = (DenemoStaff *) (curstaff->prev->data);
1200         cairo_set_source_rgb (cr, 0, 0, 0);
1201         cairo_rectangle (cr, x - SPACE_FOR_BARLINE, y - STAFF_HEIGHT - prev->space_below - thestaff->space_above, 2, 2 * STAFF_HEIGHT + prev->space_below + thestaff->space_above);
1202         cairo_fill (cr);
1203       }
1204   if (cr)
1205     if (curstaff->next)
1206       {
1207         DenemoStaff *next = (DenemoStaff *) (curstaff->next->data);
1208         //cairo_save(cr);
1209         cairo_set_source_rgb (cr, 0, 0, 0);
1210         cairo_rectangle (cr, x - SPACE_FOR_BARLINE, y, 2, 2 * STAFF_HEIGHT + next->space_above + thestaff->space_below);
1211         cairo_fill (cr);
1212       }
1213   /* end of draw lines connecting the staves in this system at the left and right hand ends */
1214   if (cr)
1215     if (itp->line_end)
1216       if (itp->measurenum > si->rightmeasurenum)
1217         if (!itp->end)
1218           {
1219             guint width = gdk_pixbuf_get_width (GDK_PIXBUF (StaffGoForward));
1220             guint height = gdk_pixbuf_get_height (GDK_PIXBUF (StaffGoForward));
1221             cairo_save (cr);
1222             gint xx = get_widget_width (Denemo.scorearea) / gui->movement->zoom - width;
1223             gdk_cairo_set_source_pixbuf (cr, GDK_PIXBUF (StaffGoForward), xx, y);
1224             cairo_rectangle (cr, xx, y, width, height);
1225             cairo_fill (cr);
1226             cairo_restore (cr);
1227           }
1228 
1229   if (cr)
1230     cairo_restore (cr);
1231   // if(itp->highy > title_highy)
1232   //  itp->highy = title_highy;
1233 
1234   /* now draw the staff lines, reset itp->slur_stack, and we're done */
1235   if (cr)
1236     {
1237       cairo_set_line_width (cr, 1.0);
1238       for (i = 1; i <= thestaff->no_of_lines; i++)
1239         {
1240           gint yy = y + 2 * LINE_SPACE + ((i % 2) ? (1) : (-1)) * (i / 2) * LINE_SPACE;
1241           cairo_move_to (cr, gui->leftmargin, yy);
1242           cairo_line_to (cr, (x * 100 / (*itp->scale)) - HALF_BARLINE_SPACE, yy);
1243         }
1244       cairo_stroke (cr);
1245     }
1246 
1247   /* Initialize the slur_stack for this staff. For the time being,
1248      slurs that begin and/or end after the portion of the music
1249      that is shown are not drawn. */
1250   if (itp->slur_stack)
1251     {
1252       g_slist_free (itp->slur_stack);
1253       itp->slur_stack = NULL;
1254     }
1255   if (saved_cr)
1256     cr = saved_cr;
1257 
1258   return repeat;
1259 }
1260 
1261 
1262 static void
print_system_separator(cairo_t * cr,gdouble position)1263 print_system_separator (cairo_t * cr, gdouble position)
1264 {
1265   //g_debug("At %f for %d\n", position, Denemo.scorearea->allocation.height);
1266 #define SYSTEM_SEP (6)
1267   cairo_save (cr);
1268   cairo_set_source_rgb (cr, 0.5, 0.0, 0.0);
1269   cairo_rectangle (cr, 0, position - SYSTEM_SEP / 2, get_widget_width (Denemo.scorearea) / Denemo.project->movement->zoom, SYSTEM_SEP);
1270 
1271   cairo_set_source_rgb (cr, 0.7, 0.0, 0.0);
1272   cairo_fill (cr);
1273 #undef SYSTEM_SEP
1274   cairo_restore (cr);
1275 }
1276 
1277 typedef enum colors
1278 { BLACK, RED, GREEN } colors;
1279 static void
draw_playback_marker(cairo_t * cr,gint color,gint pos,gint yy,gint line_height)1280 draw_playback_marker (cairo_t * cr, gint color, gint pos, gint yy, gint line_height)
1281 {
1282   if (!Denemo.prefs.playback_controls)
1283     return;
1284   //g_debug("drawing marker %x at %d %d %d\n", color, pos, yy, line_height);
1285   cairo_save (cr);
1286   cairo_set_line_width (cr, 4.0);
1287   switch (color)
1288     {
1289     case BLACK:
1290       cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
1291       break;
1292     case GREEN:
1293       cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 0.5);
1294       break;
1295     case RED:
1296       cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
1297       break;
1298     }
1299   cairo_move_to (cr, pos, yy - STAFF_HEIGHT);
1300   cairo_line_to (cr, pos, yy - STAFF_HEIGHT + line_height);
1301   cairo_stroke (cr);
1302   switch (color)
1303     {
1304     case GREEN:
1305       drawlargetext_cr (cr, _("Playback Start"), pos - 100, yy);
1306       break;
1307     case RED:
1308       drawlargetext_cr (cr, _("Playback End"), pos - 100, yy);
1309       break;
1310     }
1311   cairo_restore (cr);
1312 }
1313 
1314 static void
draw_playback_markers(cairo_t * cr,struct infotopass * itp,gint yy,gint line_height)1315 draw_playback_markers (cairo_t * cr, struct infotopass *itp, gint yy, gint line_height)
1316 {
1317 
1318   //  if(itp->playposition>-1)
1319   //   draw_playback_marker(cr, BLACK, itp->playposition, yy, line_height);
1320   //  itp->playposition = -1;
1321 
1322   if (itp->startposition > 0)
1323     draw_playback_marker (cr, GREEN, itp->startposition, yy, line_height);
1324   itp->startposition = -1;
1325 
1326   if (itp->endposition > 0)
1327     draw_playback_marker (cr, RED, itp->endposition, yy, line_height);
1328   itp->endposition = -1;
1329 }
1330 
1331 void
draw_score_area()1332 draw_score_area(){
1333   if(!Denemo.non_interactive)
1334     gtk_widget_queue_draw (Denemo.scorearea);
1335 }
1336 
1337 #define MAX_FLIP_STAGES (Denemo.prefs.animation_steps>0?Denemo.prefs.animation_steps:1)
1338 static gboolean
schedule_draw(gint * flip_count)1339 schedule_draw (gint * flip_count)
1340 {
1341   if (*flip_count == -1)
1342     return FALSE;
1343   *flip_count += 1;
1344   //g_debug("flip count %d\n", *flip_count);
1345   if (*flip_count > MAX_FLIP_STAGES)
1346     {
1347       return FALSE;
1348     }
1349   draw_score_area();
1350   return TRUE;
1351 }
1352 
1353 
1354 /**
1355  * This actually draws the score, staff-by-staff
1356  * @param cr cairo context to draw with.
1357  * @param gui pointer to the DenemoProject structure
1358  * returns whether the height of the drawing area was sufficient to draw everything
1359  */
1360 gboolean
draw_score(cairo_t * cr)1361 draw_score (cairo_t * cr)
1362 {                               //g_debug("draw_score %p\n", cr);
1363   if (cr == NULL) return TRUE;//no longer need to side effect the data while doing a dummy draw, however cr is set NULL during draw if no more drawing is needed, so we can't remove all the if (cr) conditionals...
1364   staffnode *curstaff;
1365   gint y = 0;
1366   struct infotopass itp;
1367   gboolean repeat = FALSE;
1368   gdouble leftmost = 10000000.0;
1369   DenemoProject *gui = Denemo.project;
1370   DenemoMovement *si = gui->movement;
1371   gint line_height = get_widget_height (Denemo.scorearea) * gui->movement->system_height / gui->movement->zoom;
1372   static gint flip_count;       //passed to a timer to indicate which stage of animation of page turn should be used when re-drawing, -1 means not animating 0+ are the stages
1373   /* Initialize some fields in itp */
1374 
1375   //g_debug("Printing for %d\n", flip_count);
1376   itp.slur_stack = NULL;
1377   itp.hairpin_stack = NULL;
1378   itp.source_displayed = FALSE;
1379   itp.highy = 0;                //in case there are no objects...
1380   itp.lowy = 0;
1381   itp.last_gap = 0;
1382   itp.last_midi = NULL;
1383   itp.playposition = -1;
1384   itp.startposition = -1;
1385   itp.endposition = -1;
1386   itp.startobj = itp.endobj = NULL;
1387   itp.tupletstart = itp.tuplety = 0;
1388   itp.recordednote = si->recording?si->recording->notes:NULL;
1389   itp.currentframe = (get_playback_time()/get_playback_speed())*(si->recording?si->recording->samplerate:SAMPLERATE);
1390   itp.allow_duration_error = FALSE;
1391 
1392   if (gui->movement->smf)
1393     {
1394       itp.startobj = Startobj;
1395       //g_debug("start %p\n", itp.startobj);
1396 
1397       itp.endobj = Endobj;
1398       //g_debug("Start time %p %f end time %p %f\n", itp.startobj, si->start_time, itp.endobj, si->end_time);
1399     }
1400   if (cr)
1401     cairo_translate (cr, movement_transition_offset (), 0);
1402   /* The colour for staff lines and such is black. */
1403   if (cr)
1404     cairo_set_source_rgb (cr, 0, 0, 0);
1405 
1406   if (cr)
1407     cairo_scale (cr, gui->movement->zoom, gui->movement->zoom);
1408   if (cr)
1409     cairo_translate (cr, 0.5, 0.5);
1410 
1411  if (cr && (si->leftmeasurenum == 1))
1412   {
1413     GList *h, *g;
1414     gint count;
1415     y = si->staffspace / 4;
1416     g_list_free_full (gui->braces, g_free);
1417     gui->braces = NULL;
1418     for (curstaff = si->thescore, count = 1;curstaff;curstaff=curstaff->next, count++)
1419         {
1420         DenemoStaff* staff = (DenemoStaff*)curstaff->data;
1421         gchar *context;
1422 
1423           for (g = staff->staff_directives; g; g = g->next)
1424             {
1425               DenemoDirective *directive = g->data;
1426               if (directive->override & DENEMO_OVERRIDE_AFFIX)
1427                 {
1428                     context =  directive->tag->str;
1429                    if (g_str_has_suffix (context, "Start"))
1430                     {
1431                        DenemoBrace *brace = (DenemoBrace *) g_malloc0 (sizeof(DenemoBrace));
1432                        brace->starty = y + staff->space_above; //g_print ("brace start %d |", brace->starty);
1433                        brace->curly = g_strrstr (context, "Piano") || g_strrstr (context, "Grand");
1434                        brace->startstaff = count;
1435                        gui->braces = g_list_prepend (gui->braces, brace);
1436                    }
1437                    else if (g_str_has_suffix (context, "End"))
1438                     {
1439                     gint number_of_ends = 1;
1440                     if(directive->data)
1441                         number_of_ends = atoi (directive->data->str);
1442                     if (number_of_ends<0 || (number_of_ends>10)) number_of_ends = 1;//sanity check on data in directive
1443                     while (number_of_ends--)
1444                         for (h=gui->braces;h;h=h->next)
1445                             {
1446                                 DenemoBrace *brace = (DenemoBrace *) h->data;
1447                                 if (brace->endstaff)
1448                                     continue;
1449                                 brace->endstaff = count;
1450                                 brace->endy = y + staff->space_above + si->staffspace/4;//g_print ("Brace end %d||", brace->endy);
1451                                 break;
1452                             }
1453                     }
1454                 }
1455             }
1456         y += staff->space_above +staff->space_below + si->staffspace;
1457         }
1458 
1459    // terminate all un-ended braces
1460 
1461     for(g=gui->braces;g;g=g->next)
1462           {
1463               DenemoBrace *brace = (DenemoBrace *) g->data;
1464               if (brace->endstaff == 0) {
1465                 brace->endstaff = count-1;// g_print ("Unended staff terminated at staff %d with %d; ", count-1, y);
1466                 brace->endy = y; //bottom staff value;
1467               }
1468           }
1469     gint off_screen = 0;
1470     gui->leftmargin = BASIC_LEFT_MARGIN + BRACEWIDTH*g_list_length (gui->braces);
1471     if(gui->braces)
1472         {
1473         for (count=1, curstaff = si->thescore;curstaff && (count<si->top_staff);curstaff=curstaff->next, count++)
1474             {
1475             DenemoStaff* staff = (DenemoStaff*)curstaff->data;
1476             if(count==1) off_screen = si->staffspace / 4;
1477             off_screen += staff->space_above + staff->space_below + si->staffspace;
1478         }
1479 
1480     }
1481     //draw all braces
1482     for(count=1, g=gui->braces;g;g=g->next, count++) {
1483             DenemoBrace *brace = (DenemoBrace *) g->data;
1484             cairo_save (cr);
1485             draw_staff_brace (cr, brace->curly, (count*BRACEWIDTH),  (brace->starty - off_screen),
1486                  (brace->endy-brace->starty) + (off_screen?40:15));
1487             cairo_restore (cr);
1488     }
1489  }
1490  else gui->leftmargin = 20;
1491 
1492 
1493   y = 0;
1494 
1495   /* Draw each staff */
1496   for (itp.staffnum = si->top_staff, curstaff = g_list_nth (si->thescore, si->top_staff - 1), (y += si->staffspace / 4); curstaff && itp.staffnum <= si->bottom_staff;  curstaff = curstaff->next, itp.staffnum++)
1497     {
1498       DenemoStaff *staff = (DenemoStaff *) curstaff->data;
1499       g_slist_free (itp.hairpin_stack);//clear any cresc or dim started but not finished; these can just be off-screen, they need not be in error.
1500       itp.hairpin_stack = NULL;
1501       if(cr) if (staff->hidden)
1502       {
1503         gboolean current =  (si->currentstaffnum == itp.staffnum);
1504 
1505         cairo_save (cr);
1506         cairo_set_source_rgba (cr, 0.0, 0.5, 0.5, current?1.0:0.5);
1507         cairo_rectangle (cr, 0, itp.staffnum == si->top_staff? 5 : y - 35, get_widget_width (Denemo.scorearea) / Denemo.project->movement->zoom, 1 + 8*current);
1508         cairo_fill (cr);
1509         cairo_restore (cr);
1510         if (current)
1511             drawtext_cr (cr, _("Current staff is hidden - do not edit!"), 20.0, 100.0, 48.0);
1512         continue;
1513       }
1514       itp.verse = verse_get_current_view (staff);
1515       GdkPixbuf *StaffDirectivesPixbuf = (si->currentstaffnum == itp.staffnum) ? StaffPixbuf : StaffPixbufSmall;
1516       if (si->currentstaffnum == itp.staffnum)
1517         y += staff_transition_offset ();
1518 
1519 
1520       if (curstaff && staff->voicecontrol & DENEMO_PRIMARY)
1521         y += staff->space_above;
1522 
1523       //g_print("Incrementing vertically %d\n", y);
1524       itp.space_above = staff->space_above;
1525       gint top_y = (si->staffspace / 4) + itp.space_above;
1526 
1527       itp.top_y = top_y;
1528       //itp.y = y;
1529       gint highy = staff->space_above;
1530       gint lowy = staff->space_below;
1531 
1532       itp.in_highy = highy, itp.in_lowy = lowy;
1533       itp.highy = 0;            //do not pass on extra_space from one staff to the next
1534       if (flip_count <= 0)
1535         if (cr)
1536           {
1537             cairo_save (cr);
1538             cairo_set_source_rgb (cr, 0.5, 0.5, 1.0);
1539             cairo_rectangle (cr, 0, y, 20/*BASIC LEFT_MARGIN*/, STAFF_HEIGHT /*staff edit */ );
1540             cairo_fill (cr);
1541             //cairo_restore (cr);
1542 
1543 
1544             //  {
1545 
1546                 guint width = gdk_pixbuf_get_width (GDK_PIXBUF (StaffDirectivesPixbuf));
1547                 guint height = gdk_pixbuf_get_height (GDK_PIXBUF (StaffDirectivesPixbuf));
1548               // cairo_save (cr);
1549                 gdk_cairo_set_source_pixbuf (cr, GDK_PIXBUF (StaffDirectivesPixbuf), 0, y);
1550                 cairo_rectangle (cr, 0, y, width, height);
1551                 cairo_fill (cr);
1552 
1553                 cairo_set_source_rgb (cr, 0, 0, 0);
1554                 cairo_rectangle (cr, 0, y, width, height);
1555                 cairo_stroke (cr);
1556 
1557                 cairo_set_source_rgb (cr, 0, 0, 0);
1558                 gint staffnumber = 1 + g_list_position (si->thescore,curstaff);
1559                 gchar *number = g_strdup_printf ("%d", staffnumber);
1560                 if(staffnumber>9)
1561                     drawnormaltext_cr (cr, number, 0, y + STAFF_HEIGHT - 2);
1562                 else
1563                     drawlargetext_cr (cr, number, 0, y + STAFF_HEIGHT - 2);
1564                 g_free (number);
1565 
1566                 cairo_restore (cr);
1567 
1568            //  }
1569 
1570 
1571 
1572 
1573             if (si->leftmeasurenum == 1 && !(staff->voicecontrol & DENEMO_SECONDARY))
1574               {
1575                 /* draw background of clef, keysig, timesig */
1576                 gint key = gui->movement->maxkeywidth;
1577                 gint cmajor = key ? 0 : 5;      //allow some area for keysig in C-major
1578                 cairo_save (cr);
1579 
1580                 cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
1581                 cairo_rectangle (cr, gui->leftmargin, y, (gui->leftmargin+35) - gui->leftmargin - cmajor, STAFF_HEIGHT);  /*clef edit */
1582 
1583                 cairo_rectangle (cr, (gui->leftmargin+35) + key + cmajor, y, SPACE_FOR_TIME - cmajor, STAFF_HEIGHT);      /*timesig edit */
1584                 cairo_fill (cr);
1585 
1586                 cairo_set_source_rgb (cr, 0.5, 0.5, 1.0);
1587                 cairo_rectangle (cr, (gui->leftmargin+35) - cmajor, y, key + 2 * cmajor, STAFF_HEIGHT / 2);       /*keysig sharpen edit */
1588                 cairo_fill (cr);
1589                 cairo_set_source_rgb (cr, 0, 0, 1);
1590                 cairo_set_line_width (cr, 3);
1591                 cairo_rectangle (cr, (gui->leftmargin+35) - cmajor, y, key + 2 * cmajor, STAFF_HEIGHT / 2);
1592                 cairo_stroke (cr);
1593 
1594 
1595                 cairo_set_source_rgb (cr, 1, 0.5, 0.5);
1596                 cairo_rectangle (cr, (gui->leftmargin+35) - cmajor, y + STAFF_HEIGHT / 2, key + 2 * cmajor, STAFF_HEIGHT / 2);    /*keysig flatten edit */
1597                 cairo_fill (cr);
1598                 cairo_set_source_rgb (cr, 1, 0, 0);
1599                 cairo_set_line_width (cr, 3);
1600                 cairo_rectangle (cr, (gui->leftmargin+35) - cmajor, y + STAFF_HEIGHT / 2, key + 2 * cmajor, STAFF_HEIGHT / 2);
1601                 cairo_stroke (cr);
1602 
1603 
1604 
1605                 cairo_restore (cr);
1606               }
1607           }                     //if cr
1608       if (si->currentstaffnum == itp.staffnum)
1609         {
1610 
1611           gint count = count_syllables (staff, si->leftmeasurenum);
1612           if (count < 0)
1613             {
1614               count = -count;
1615               itp.slur_stack = push_slur_stack (itp.slur_stack, 0, 0);
1616             }
1617           reset_lyrics (staff, count);
1618         }
1619 
1620 
1621       itp.measurenum = si->leftmeasurenum;
1622       itp.line_end = FALSE;
1623       itp.left = &gui->lefts[0];
1624       itp.right = &gui->rights[0];
1625       itp.scale = &gui->scales[0];
1626 
1627 
1628 
1629       if (draw_staff (flip_count > 0 ? NULL : cr, curstaff, y, gui, &itp))
1630         repeat = TRUE;
1631 
1632       if (cr)
1633         draw_playback_markers (cr, &itp, y, line_height);
1634 
1635       gint system_num;
1636       system_num = 1;
1637       //g_debug("Drawn staffnum %d, at %d %s.\n", itp.staffnum,  y, itp.line_end?" another line":"End");
1638 
1639       if (cr)
1640         if (itp.staffnum == si->top_staff)
1641           print_system_separator (cr, line_height * system_num);
1642 
1643       system_num++;
1644 
1645       // This block prints out continuations of the staff just printed
1646       {
1647         int yy;
1648         yy = y + line_height;
1649         itp.left++;
1650         itp.right++;
1651         itp.scale++;
1652         if (Denemo.project->movement->playingnow && itp.measurenum >= si->rightmeasurenum)
1653           itp.line_end = FALSE; //don't print whole lines of grayed out music during playback
1654 
1655         while (((itp.left - gui->lefts) < DENEMO_MAX_SYSTEMS - 1) && itp.line_end && (yy < (get_widget_height (Denemo.scorearea) / gui->movement->zoom)))
1656           {
1657             if (cr)
1658               if (itp.staffnum == si->top_staff)
1659                 print_system_separator (cr, line_height * system_num);
1660             system_num++;
1661             if (draw_staff (cr, curstaff, yy, gui, &itp))
1662               repeat = TRUE;
1663             if (itp.staffnum == si->top_staff)  //single criterion for all staffs on whether to draw next page
1664               leftmost = MIN (leftmost, itp.leftmosttime);
1665             if (cr)
1666               draw_playback_markers (cr, &itp, yy, line_height);
1667             yy += line_height;
1668             itp.left++;
1669             itp.right++;
1670             itp.scale++;
1671 
1672           }                     //end while printing out all the systems for this staff
1673 
1674         //g_debug("staff num %d measure %d playhead %f left time %f\nheight %d system_num %d\n", itp.staffnum,itp.measurenum, si->playhead, itp.leftmosttime, yy, system_num);
1675 
1676         si->rightmost_time = itp.rightmosttime;//g_debug("Setting rightmost time to %f\n", si->rightmost_time);
1677 
1678         if ((system_num > 2) && Denemo.project->movement->playingnow && (si->playhead > leftmost) && itp.measurenum <= g_list_length (((DenemoStaff *) curstaff->data)->themeasures) /*(itp.measurenum > (si->rightmeasurenum+1)) */ )
1679           {
1680             //put the next line of music at the top with a break marker
1681             itp.left = &gui->lefts[0];
1682             itp.right = &gui->rights[0];
1683             itp.scale = &gui->scales[0];
1684             if (cr)
1685               {
1686                 cairo_save (cr);
1687                 cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);       //Strong Blue Line to break pages
1688                 cairo_rectangle (cr, 0, line_height - 10, get_widget_width (Denemo.scorearea) / Denemo.project->movement->zoom, 10);
1689                 cairo_fill (cr);
1690                 cairo_restore (cr);
1691               }
1692 
1693             itp.line_end = FALSE;       //to force print of timesig
1694             if (itp.measurenum > (si->rightmeasurenum + 1))
1695               itp.measurenum = si->rightmeasurenum + 1;
1696             gdouble flip;
1697             flip = 1.0;
1698             if ((itp.staffnum == si->top_staff) && (flip_count == -1))
1699               {
1700                 flip = 0.1;
1701                 flip_count = 0;
1702                 //g_debug("Adding timeout");
1703                 g_timeout_add (1000 / MAX_FLIP_STAGES, (GSourceFunc) schedule_draw, &flip_count);
1704               }
1705             //g_debug("drawing %d\n", flip_count);
1706             if (flip_count > 0 && flip_count < MAX_FLIP_STAGES)
1707               flip = flip_count / (gdouble) MAX_FLIP_STAGES;
1708             if (cr)
1709               {
1710                 cairo_translate (cr, get_widget_width (Denemo.scorearea) * (1 - flip) * 0.5 / Denemo.project->movement->zoom, 0.0);
1711                 cairo_scale (cr, flip, 1.0);
1712 
1713                 if (draw_staff (flip_count > 0 ? cr : NULL, curstaff, y, gui, &itp))
1714                   repeat = TRUE;
1715                 cairo_scale (cr, 1 / flip, 1.0);
1716                 cairo_translate (cr, -get_widget_width (Denemo.scorearea) * (1 - flip) * 0.5 / Denemo.project->movement->zoom, 0.0);
1717               }
1718             //draw_break_marker();
1719           }
1720         else
1721           {
1722             if (flip_count != -1)
1723               repeat = TRUE;
1724             //g_debug("Repeating %d\n", repeat);
1725             flip_count = -1;
1726           }
1727        //   if(itp.rightmosttime != si->rightmost_time)
1728         //      g_debug("Resetting %f %f? ",itp.rightmosttime, si->rightmost_time);
1729         // itp.rightmosttime = si->rightmost_time;//We want to ignore the rightmost_time of the flipped over top system that belongs to the next page
1730 
1731       }                         //end of block printing continuations
1732       *itp.left = 0;            //To signal end of valid systems
1733 
1734       if ((!curstaff->next) || ((DenemoStaff *) curstaff->next->data)->voicecontrol & DENEMO_PRIMARY)
1735         {
1736           if (itp.verse)
1737             {
1738               y += LYRICS_HEIGHT;
1739             }
1740         if (curstaff->next)
1741         {
1742           DenemoStaff *next = (DenemoStaff *) (curstaff->next->data);
1743           y += (si->staffspace - next->space_shorten + staff->space_below);
1744         } else
1745          y += (si->staffspace + staff->space_below);
1746       }
1747 
1748     }                           // for all the staffs
1749 
1750   //g_debug("Right most time %f\n", si->rightmost_time);
1751   //  if(itp.last_midi)
1752   //  si->rightmost_time = get_midi_off_time(itp.last_midi);
1753 
1754 
1755   return repeat;
1756 
1757   /* And we're done */
1758 }
1759 
1760 
1761 
1762 
1763 static gint
draw_callback(cairo_t * cr)1764 draw_callback (cairo_t * cr)
1765 {
1766   DenemoProject *gui = Denemo.project;
1767 
1768   //g_debug("expose\n");
1769   if ((!Denemo.project) || (!Denemo.project->movement) || (!Denemo.project->movement->currentmeasure))
1770     {
1771       g_warning ("Cannot draw!");
1772       return TRUE;
1773     }
1774 
1775   /* Layout the score. */
1776   if (layout_needed)
1777     if (draw_score (NULL))
1778       {
1779         set_bottom_staff (gui);
1780         update_vscrollbar (gui);
1781       }
1782   layout_needed = TRUE;
1783   if(Denemo.project->movement->playingnow)
1784     gtk_widget_queue_draw (Denemo.playbackview);
1785 
1786   /* Clear with an appropriate background color. */
1787   if (((DenemoStaff*)Denemo.project->movement->currentstaff->data)->hidden)
1788     cairo_set_source_rgb (cr, 1, 0.8, 0.8);
1789   else if (Denemo.project->input_source != INPUTKEYBOARD && Denemo.project->input_source != INPUTMIDI && (Denemo.prefs.overlays || (Denemo.project->input_source == INPUTAUDIO)) && pitch_entry_active (gui))
1790     {
1791       GdkColor col;
1792       gdk_color_parse ("lightblue", &col);
1793       gdk_cairo_set_source_color (cr, &col);
1794     }
1795   else if (gtk_widget_has_focus (Denemo.scorearea) && gtk_widget_is_focus (Denemo.scorearea))
1796     {
1797       if (Denemo.project->input_source == INPUTMIDI && (Denemo.keyboard_state == GDK_LOCK_MASK || Denemo.keyboard_state == GDK_SHIFT_MASK))      //listening to MIDI-in
1798         cairo_set_source_rgb (cr, 0.9, 0.85, 1.0);
1799       else if (Denemo.project->input_source == INPUTMIDI && Denemo.keyboard_state == GDK_CONTROL_MASK)      //checking pitches
1800         cairo_set_source_rgb (cr, 0.85, 1.0, 0.9);
1801       else
1802         cairo_set_source_rgb (cr, ((0xFF0000 & Denemo.color) >> 16) / 255.0, ((0xFF00 & Denemo.color) >> 8) / 255.0, ((0xFF & Denemo.color)) / 255.0);
1803     }
1804 
1805   else
1806     {
1807       cairo_set_source_rgb (cr, 0.8, 0.8, 0.8); //gray background when key strokes are not being received.
1808     }
1809   cairo_paint (cr);
1810   /* Draw the score. */
1811   draw_score (cr);
1812   return TRUE;
1813 }
1814 
1815 void
update_drawing_cache(void)1816 update_drawing_cache (void)
1817 {
1818   if(Denemo.non_interactive)
1819     return;
1820   draw_score (NULL);
1821 }
1822 
1823 /**
1824  * Here we have the function that actually draws the score. Note that
1825  * it does not clip intelligently at all
1826  */
1827 #if GTK_MAJOR_VERSION==3
1828 gint
scorearea_draw_event(G_GNUC_UNUSED GtkWidget * w,cairo_t * cr)1829 scorearea_draw_event (G_GNUC_UNUSED GtkWidget * w, cairo_t * cr)
1830 {
1831   return draw_callback (cr);
1832 }
1833 #else
1834 gint
scorearea_draw_event(GtkWidget * widget,GdkEventExpose * event)1835 scorearea_draw_event (GtkWidget * widget, GdkEventExpose * event)
1836 {
1837   if (widget == NULL)
1838     {
1839       draw_score (NULL);
1840       return TRUE;
1841     }
1842   /* Setup a cairo context for rendering and clip to the exposed region. */
1843   cairo_t *cr = gdk_cairo_create (event->window);
1844   gdk_cairo_region (cr, event->region);
1845   cairo_clip (cr);
1846   draw_callback (cr);
1847   cairo_destroy (cr);
1848   return TRUE;
1849 }
1850 #endif
1851