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