chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / brac.c
CommitLineData
69695f33
MW
1
2/* Copyright (c) 1995, 1997, 1999, 2000, 2001, 2002, 2003, 2005 by Arkkra Enterprises */
3/* All rights reserved */
4
5/* functions to deal with brace/bracket lists, to make sure they don't
6 * overlap, and then to place the labels to minimize the space they use. */
7
8#include "defines.h"
9#include "structs.h"
10#include "globals.h"
11
12/* padding between labels in inches. **** eventually should adjust padding
13 * based on size??? ***/
14#define LABELPAD 0.125
15
16/* information to be able to determine overlaps in the brace/bracket lists */
17static struct BRAC_INFO {
18 struct STAFFSET *staffset_p; /* bracelist or bracklist item */
19 int bractype; /* BRACELIST or BRACKLIST */
20 struct BRAC_INFO *nested_p; /* pointer to another brace/bracket
21 * item, which has its top on the
22 * same staff, and presumably
23 * is nested inside this one */
24 struct BRAC_INFO *nested_by_p; /* if this one is nested, pointer
25 * to what it is nested by, else NULL */
26 short nestlevel; /* how many levels deep */
27 short topvisstaff; /* top visible staff in range */
28 short botvisstaff; /* bottom visible staff in range */
29} *Brac_info_p [MAXSTAFFS + 1];
30
31
32/* information about a label, either for a staff or group. */
33struct LABELINFO {
34 char *label; /* text of the label */
35 float width; /* strwidth(label) */
36 float west; /* relative distance of left edge of label
37 * from the line between the labels and the
38 * braces/brackets. This will be negative */
39 int is_staff_label; /* YES for staff label, NO for group */
40 struct LABELINFO *next;/* linked list of labels at same y location */
41};
42
43/* information about all the labels that end up being printed left of a
44 * specific staff or between that staff and the one below it. */
45struct LABELLIST {
46 short staffno; /* which staff */
47 struct LABELINFO *label_p; /* list of labels to be printed to
48 * the left of this staff */
49 struct LABELINFO *btwnlabel_p; /* list of labels to be printed
50 * between this staff and the one
51 * below this staff */
52 short pad; /* how many levels of labels
53 * have been put on this staff, either
54 * on the staff itself or on one or
55 * more other staffs that are
56 * grouped with this one */
57};
58static struct LABELLIST Labellist[MAXSTAFFS + 1];
59
60static short Numvis; /* how many staffs currently visible */
61static short Maxlevels; /* maximum number of nesting levels */
62static float Nested_brace_adjust = 0.0; /* brace outside a bracket needs
63 * some extra space to look good. */
64
65
66/* static functions */
67static void free_brac_info P((struct BRAC_INFO *brac_info_p));
68static void set_brac_info P((struct STAFFSET *staffset_p, int bractype));
69static int check_brac_overlap P((struct BRAC_INFO *brac_info_p));
70static void setnestlevel P((struct BRAC_INFO *brac_p,
71 struct BRAC_INFO *nested_by_p));
72static void place_labels P((struct MAINLL *mll_p,
73 struct MAINLL *prev_feed_mll_p));
74static void init_labellist P((void));
75static void free_label P((struct LABELINFO *label_p));
76static struct LABELINFO *newlabelinfo P((char *label, int is_staff_label));
77static void grouplabel P((struct BRAC_INFO *brac_p, int do_nested,
78 struct MAINLL *mll_p, struct MAINLL *prev_feed_mll_p));
79static double west_adjust P((struct MAINLL *mll_p,
80 struct MAINLL *prev_feed_mll_p));
81static struct MAINLL *find_prev_feed_mll_p P((struct MAINLL *mll_p));
82static char * label4staff P((struct MAINLL *mll_p, int s,
83 struct MAINLL *prev_feed_mll_p));
84static char * label4group P((struct MAINLL *mll_p, struct BRAC_INFO *brac_p,
85 struct MAINLL *prev_feed_mll_p));
86static double dflt_label_width P((struct MAINLL *mll_p,
87 struct MAINLL *prev_feed_mll_p));
88
89\f
90
91/* check for overlap between brace and bracket lists. Return YES if okay, NO
92 * if there is something illegal */
93
94int
95brac_check (bracelist_p, nbrace, bracklist_p, nbrack)
96
97struct STAFFSET *bracelist_p;
98int nbrace; /* how many items in bracelist_p */
99struct STAFFSET *bracklist_p;
100int nbrack; /* how many items in bracklist_p */
101
102{
103 register int s; /* staff index into Brac_info_p */
104 register int n; /* index into staffset */
105 int retval = 0; /* return from check_brac_overlap() */
106 static int first_time = YES; /* flag for if first time this function
107 * has been called */
108
109
110 debug(4, "brac_check");
111
112 /* initialize table */
113 for (s = 1; s <= Score.staffs; s++) {
114 if (first_time == NO) {
115 /* only try to free if we know item has been properly
116 * initialized, in case this is ever run on some system
117 * that doesn't initialize pointer arrays to null ptrs */
118 free_brac_info(Brac_info_p[s]);
119 }
120 Brac_info_p[s] = (struct BRAC_INFO *) 0;
121 }
122 first_time = NO;
123 Maxlevels = 0;
124
125 /* Go through each list, attaching each to table slot of its top staff.
126 */
127 for (n = 0; n < nbrace; n++) {
128 set_brac_info( &(bracelist_p[n]), BRACELIST);
129 }
130 for (n = 0; n < nbrack; n++) {
131 set_brac_info( &(bracklist_p[n]), BRACKLIST);
132 }
133
134 /* now check each staff for possible overlap */
135 for (s = 1; s <= Score.staffs; s++) {
136 if (Brac_info_p[s] == (struct BRAC_INFO *) 0) {
137 /* no braces or brackets, so can't be any overlap */
138 continue;
139 }
140
141 retval += check_brac_overlap (Brac_info_p[s]);
142 }
143
144 return(retval == 0 ? YES : NO);
145}
146\f
147
148/* recursively free a linked list of BRAC_INFO structs */
149
150static void
151free_brac_info(brac_info_p)
152
153struct BRAC_INFO *brac_info_p; /* the list to free */
154
155{
156 if (brac_info_p == (struct BRAC_INFO *) 0) {
157 return;
158 }
159
160 free_brac_info(brac_info_p->nested_p);
161 FREE(brac_info_p);
162}
163\f
164
165/* save information about a brace/bracket STAFFSET and link onto list for its
166 * top staff */
167
168static void
169set_brac_info (staffset_p, bractype)
170
171struct STAFFSET *staffset_p; /* staffs to group together */
172int bractype; /* BRACELIST or BRACKLIST */
173
174{
175 struct BRAC_INFO *new_p; /* info to be saved */
176 int s; /* staff num of top staff of staffset */
177
178
179 /* record information */
180 MALLOC(BRAC_INFO, new_p, 1);
181 new_p->staffset_p = staffset_p;
182 new_p->bractype = bractype;
183 new_p->nested_by_p = (struct BRAC_INFO *) 0;
184 new_p->nestlevel = 0;
185
186 /* link into list off of table */
187 s = staffset_p->topstaff;
188 new_p->nested_p = Brac_info_p[s];
189 Brac_info_p[s] = new_p;
190}
191\f
192
193/* check the brace/bracket information for one staff for overlap. Return
194 * number of errors found */
195
196static int
197check_brac_overlap (brac_info_p)
198
199struct BRAC_INFO *brac_info_p;
200
201{
202 register int s;
203
204
205 if (brac_info_p == (struct BRAC_INFO *) 0) {
206 /* end recursion */
207 return(0);
208 }
209
210 /* if no nesting, don't need to do those checks */
211 if (brac_info_p->nested_p != (struct BRAC_INFO *) 0) {
212
213 /* braces can't have anything nested inside them */
214 if (brac_info_p->bractype == BRACELIST) {
215 yyerror("nesting inside a brace not allowed");
216 return(1);
217 }
218
219 /* brace on top of bracket needs extra space */
220 if (brac_info_p->nested_p->bractype == BRACELIST) {
221 Nested_brace_adjust = STEPSIZE;
222 }
223
224 /* check that nested range is a proper subset */
225 if (brac_info_p->nested_p->staffset_p->botstaff
226 >= brac_info_p->staffset_p->botstaff) {
227 yyerror("nested brackets must be subsets of other brackets");
228 return(1);
229 }
230
231 setnestlevel(brac_info_p->nested_p, brac_info_p);
232 }
233
234 /* see if this one overlaps with groups
235 * defined previously */
236 for (s = brac_info_p->staffset_p->topstaff + 1;
237 s <= brac_info_p->staffset_p->botstaff; s++) {
238
239 if (Brac_info_p[s] == (struct BRAC_INFO *) 0) {
240 continue;
241 }
242
243 /* if brace is being nested by something else,
244 * overlap is illegal */
245 if (brac_info_p->bractype == BRACELIST) {
246 yyerror("brace overlap not allowed");
247 return(1);
248 }
249
250 /* if bottom of this staffset is greater than bottom of the one
251 * we are checking, there is illegal overlap */
252 if (Brac_info_p[s]->staffset_p->botstaff
253 > brac_info_p->staffset_p->botstaff) {
254 yyerror("overlapping brackets are not nested");
255 return(1);
256 }
257
258 /* remember who nests this one */
259 setnestlevel(Brac_info_p[s], brac_info_p);
260 }
261
262 /* recurse */
263 return (check_brac_overlap (brac_info_p->nested_p));
264}
265\f
266
267/* when one bracket is nested inside another, record that fact */
268
269static void
270setnestlevel(brac_p, nested_by_p)
271
272struct BRAC_INFO *brac_p; /* set nesting here */
273struct BRAC_INFO *nested_by_p; /* brac_p is nested by this one */
274
275{
276 brac_p->nested_by_p = nested_by_p;
277 brac_p->nestlevel = nested_by_p->nestlevel + 1;
278
279 /* keep track of deepest nesting level */
280 if (brac_p->nestlevel > Maxlevels) {
281 Maxlevels = brac_p->nestlevel;
282 }
283}
284\f
285
286/*
287 * for each label
288 * find which staff the label should go on based on visible
289 *
290 * Determine placement of staff labels, then nested, then outer.
291 */
292
293static void
294place_labels(mll_p, prev_feed_mll_p)
295
296struct MAINLL *mll_p; /* current place in main list, used to determine
297 * whether to use label or label2. */
298struct MAINLL *prev_feed_mll_p; /* actual or proposed location of prev FEED */
299
300{
301 int s; /* index through staffs */
302 int count; /* how many labels */
303 char *label; /* the label being processed */
304 struct LABELINFO *lab_p;/* info about label */
305
306
307 init_labellist();
308 lab_p = (struct LABELINFO *) 0;
309
310 /* put the staff labels on the label list. While we're at it, count
311 * up the number of staffs that are currently visible */
312 for (count = Numvis = 0, s = 1; s <= Score.staffs; s++) {
313 if (svpath(s, VISIBLE)->visible == NO) {
314 continue;
315 }
316
317 /* use label or label2 as appropriate */
318 if ((label = label4staff(mll_p, s, prev_feed_mll_p)) != 0) {
319 lab_p = newlabelinfo(label, YES);
320 }
321
322 /* if there was a label, save info about it */
323 if (lab_p != (struct LABELINFO *) 0) {
324
325 /* staff labels always go as far east as possible */
326 /* Adjust by staffscale, but get from SSV, since
327 * Stepsize won't be up to date. */
328 lab_p->west = (-(lab_p->width) - STEPSIZE)
329 * svpath(s, STAFFSCALE)->staffscale;
330
331 /* link onto list */
332 lab_p->next = Labellist[Numvis].label_p;
333 Labellist[Numvis].label_p = lab_p;
334
335 /* count up number of staff labels */
336 count++;
337
338 /* re-init for next trip through loop */
339 lab_p = (struct LABELINFO *) 0;
340 }
341
342 Labellist[Numvis].staffno = (short) s;
343
344 /* we now know there is one more staff visible */
345 Numvis++;
346 }
347
348 /* if there were any labels, mark all staffs as needing padding
349 * before placing another label. If there were no staff labels,
350 * group labels will go as far east as possible, otherwise the
351 * group labels will be leftward a bit. */
352 if (count > 0) {
353 for (s = 0; s < Numvis; s++) {
354 (Labellist[s].pad)++;
355 }
356 }
357
358 /* do all nested group labels */
359 for (s = 1; s <= Score.staffs; s++) {
360 grouplabel(Brac_info_p[s], YES, mll_p, prev_feed_mll_p);
361 }
362
363 /* do all non-nested group labels */
364 for (s = 1; s <= Score.staffs; s++) {
365 grouplabel(Brac_info_p[s], NO, mll_p, prev_feed_mll_p);
366 }
367}
368\f
369
370/* initialize label list. Free any information currently in the list and
371 * mark everything as empty */
372
373static void
374init_labellist()
375
376{
377 register int s; /* index through label list */
378
379
380 for (s = 0; s <= Numvis; s++) {
381 free_label(Labellist[s].label_p);
382 free_label(Labellist[s].btwnlabel_p);
383 Labellist[s].label_p = Labellist[s].btwnlabel_p
384 = (struct LABELINFO *) 0;
385 Labellist[s].pad = 0;
386 }
387 Numvis = 0;
388}
389\f
390
391/* recursively free linked list of LABELINFO structs */
392
393static void
394free_label(label_p)
395
396struct LABELINFO *label_p; /* free this list */
397
398{
399 if (label_p == (struct LABELINFO *) 0) {
400 return;
401 }
402
403 free_label(label_p->next);
404 FREE(label_p);
405}
406\f
407
408/* allocate a new LABELINFO struct and fill in the label and width. Initialize
409 * west to zero */
410
411static struct LABELINFO *
412newlabelinfo(label, is_staff_label)
413
414char *label; /* text of the label */
415int is_staff_label; /* YES or NO */
416
417{
418 struct LABELINFO *new_p; /* newly allocate place to save info */
419
420
421 MALLOC(LABELINFO, new_p, 1);
422 new_p->label = label;
423 new_p->west = 0.0;
424 new_p->width = strwidth(label);
425 new_p->is_staff_label = is_staff_label;
426 new_p->next = (struct LABELINFO *) 0;
427 return(new_p);
428}
429\f
430
431/* do placement of group labels */
432
433static void
434grouplabel(brac_p, do_nested, mll_p, prev_feed_mll_p)
435
436struct BRAC_INFO *brac_p; /* info about group of staffs to do */
437int do_nested; /* if YES, process nested staff group. If NO,
438 * process non-nested */
439struct MAINLL *mll_p; /* used to decide if to use label or label2 */
440struct MAINLL *prev_feed_mll_p; /* actual or proposed previous FEED */
441
442{
443 struct STAFFSET *staffset_p; /* staffs/label in group */
444 char *label; /* label for group */
445 int index; /* into Labellist */
446 int topindex, botindex; /* index into Labellist of where
447 * group range top & bottom visible
448 * staffs are */
449 int labindex; /* index into Labellist of staff where
450 * label should go */
451 struct LABELINFO *lab_p; /* information about group label */
452 struct LABELINFO **lab_p_p; /* where to insert label info */
453
454
455 if (brac_p == (struct BRAC_INFO *) 0) {
456 /* end recursion */
457 return;
458 }
459
460 if (do_nested == YES) {
461 /* recurse */
462 grouplabel(brac_p->nested_p, do_nested, mll_p, prev_feed_mll_p);
463 if (brac_p->nested_by_p == (struct BRAC_INFO *) 0) {
464 return;
465 }
466 }
467 else if (brac_p->nested_by_p != (struct BRAC_INFO *) 0) {
468 return;
469 }
470
471 /* we'll probably need the staffset info a lot, so get pointer to it */
472 staffset_p = brac_p->staffset_p;
473
474 /* Find index in Labellist of top
475 * and bottom visible staffs of the range */
476 for (topindex = botindex = -1, index = 0; index < Numvis; index++) {
477 if (topindex == -1 && staffset_p->topstaff
478 <= Labellist[index].staffno) {
479 topindex = index;
480 }
481 if (staffset_p->botstaff >= Labellist[index].staffno) {
482 botindex = index;
483 }
484 }
485
486 /* see if there were some visible staffs in this group */
487 if (topindex != -1 && botindex != -1 && botindex >= topindex) {
488
489 brac_p->topvisstaff = Labellist[topindex].staffno;
490 brac_p->botvisstaff = Labellist[botindex].staffno;
491
492 /* figure out which label to use, if any */
493 if ((label = label4group(mll_p, brac_p, prev_feed_mll_p))
494 == (char *) 0) {
495 return;
496 }
497
498 /* find index in list of visible staffs where label should
499 * go. If even number of visible staffs in range, label
500 * goes between two staffs */
501 labindex = (topindex + botindex) / 2;
502 if ((botindex - topindex) & 1) {
503 lab_p_p = &(Labellist[labindex].btwnlabel_p);
504 }
505 else {
506 lab_p_p = &(Labellist[labindex].label_p);
507 }
508
509 lab_p = newlabelinfo(label, NO);
510
511 /* put as far east as possible */
512 lab_p->west = - (lab_p->width);
513
514 lab_p->west -= Labellist[labindex].pad * LABELPAD;
515
516 /* link onto list */
517 lab_p->next = *lab_p_p;
518 *lab_p_p = lab_p;
519
520 /* add padding to all visible staffs in the group range */
521 for ( ; topindex <= botindex; topindex++) {
522 Labellist[topindex].pad++;
523 }
524 }
525 else {
526 /* all staffs in group are invisible */
527 brac_p->topvisstaff = 0;
528 }
529}
530\f
531
532/* determine total width of labels. This is how much to add to
533 * relative west to get absolute location from left margin */
534
535static double
536west_adjust(mll_p, prev_feed_mll_p)
537
538struct MAINLL *mll_p; /* actual or proposed FEED location,
539 * used to decide if to use label or label2 */
540struct MAINLL *prev_feed_mll_p; /* actual or proposed location of preceeding
541 * FEED, used for label/label2 decision */
542
543{
544 register int s; /* index */
545 double minwest = 0.0; /* farthest west distance */
546
547
548 /* find westernmost label */
549 for (s = 0; s < Numvis; s++) {
550 if (Labellist[s].label_p != (struct LABELINFO *) 0) {
551 if (Labellist[s].label_p->west < minwest) {
552 minwest = Labellist[s].label_p->west;
553 }
554 }
555 if (Labellist[s].btwnlabel_p != (struct LABELINFO *) 0) {
556 if (Labellist[s].btwnlabel_p->west < minwest) {
557 minwest = Labellist[s].btwnlabel_p->west;
558 }
559 }
560 }
561
562 /* check for need to use default label on first score.
563 * If default label is needed, it creates an indent. */
564 if (minwest == 0.0) {
565 return(dflt_label_width(mll_p, prev_feed_mll_p));
566 }
567
568 return( - minwest);
569}
570\f
571
572/* return width of braces/brackets and their labels */
573
574double
575width_left_of_score(mll_p)
576
577struct MAINLL *mll_p; /* FEED, used to decide if to use label or label2 */
578
579{
580 return(pwidth_left_of_score(mll_p, find_prev_feed_mll_p(mll_p)));
581}
582
583double
584pwidth_left_of_score(mll_p, prev_feed_mll_p)
585
586struct MAINLL *mll_p; /* actual or proposed location of current FEED,
587 * used to decide if to use label or label2 */
588struct MAINLL *prev_feed_mll_p; /* actual or proposed location of prev FEED */
589
590{
591 double westadj;
592 int n; /* index through brac*lists */
593 int s; /* staff index */
594 int hasbracs; /* YES if there are visible brackets/braces */
595
596
597 if (brac_check(Score.bracelist, Score.nbrace, Score.bracklist,
598 Score.nbrack) == NO) {
599 /* we should have exited before */
600 pfatal("illegal brace/bracket ranges");
601 }
602 /* call functions to determine the placement of all labels and
603 * save that information in the Labellist, then determine how
604 * wide the labels plus braces and brackets are */
605 place_labels(mll_p, prev_feed_mll_p);
606 westadj = west_adjust(mll_p, prev_feed_mll_p);
607
608 /* total is space for the labels (the westadj),
609 * the braces/brackets themselves (based on Maxlevels),
610 * and 2 stepsizes of padding to left of score before brace/brack,
611 * plus special adjustment for brace on top of bracket, if any */
612 /* See if there are any visible brackets/braces.
613 * If so, we'll need to allow space for them, otherwise not. */
614 hasbracs = NO;
615 for (n = 0; n < Score.nbrace && hasbracs == NO; n++) {
616 for (s = Score.bracelist[n].topstaff;
617 s <= Score.bracelist[n].botstaff; s++){
618 if (svpath(s, VISIBLE)->visible == YES) {
619 hasbracs = YES;
620 break;
621 }
622 }
623 }
624 for (n = 0; n < Score.nbrack && hasbracs == NO; n++) {
625 for (s = Score.bracklist[n].topstaff;
626 s <= Score.bracklist[n].botstaff; s++){
627 if (svpath(s, VISIBLE)->visible == YES) {
628 hasbracs = YES;
629 break;
630 }
631 }
632 }
633
634 if (hasbracs == YES) {
635 return(westadj + ((Maxlevels + 2) * 2.0 * STDPAD)
636 + (2.0 * STEPSIZE) + Nested_brace_adjust);
637 }
638 else {
639 return(westadj);
640 }
641}
642\f
643
644/* print braces/brackets and their labels, Return YES if there were braces or
645 * brackets, NO if not. */
646
647int
648pr_brac(is_restart, x_offset, mll_p)
649
650int is_restart; /* YES if being called due to restart */
651double x_offset; /* where to print, if is_restart == YES */
652struct MAINLL *mll_p; /* for FEED for possible margin override, and to
653 * decide if to use label or label2 */
654
655{
656 register int li; /* index into Labellist */
657 register int s; /* staff index */
658 struct LABELINFO *lab_p; /* info about a label */
659 struct LABELINFO *l_p; /* for finding y adjust for overlaps */
660 double y_adjust; /* for overlapping labels */
661 struct BRAC_INFO *brac_p; /* info about brace or bracket */
662 double adj; /* how much to adjust relative west */
663 double x, y, y1;
664 int eff_stafflines; /* how many stafflines there effectively
665 * are, counting the extra space around
666 * staffs with a very small number
667 * of stafflines */
668 double tab_adjust; /* to adjust for TABRATIO */
669 double eff_stepsize; /* STEPSIZE adjusted for staffscale */
670 char *label;
671 int printed_brac = NO; /* if printed any braces/brackets */
672 struct MAINLL *prev_feed_mll_p; /* previous FEED */
673
674
675 debug(512, "pr_brac");
676
677 /* figure out where to place everything */
678 (void) brac_check(Score.bracelist, Score.nbrace, Score.bracklist,
679 Score.nbrack);
680 prev_feed_mll_p = find_prev_feed_mll_p(mll_p);
681 place_labels(mll_p, prev_feed_mll_p);
682 if (is_restart == NO) {
683 adj = west_adjust(mll_p, prev_feed_mll_p)
684 + eff_leftmargin(mll_p);
685
686 /* print labels on visible staffs */
687 for (li = 0; li < Numvis; li++) {
688
689 /* print labels to go by this staff */
690 for (lab_p = Labellist[li].label_p;
691 lab_p != (struct LABELINFO *) 0;
692 lab_p = lab_p->next) {
693 if (lab_p->is_staff_label == YES) {
694 /* Have to adjust by staffscale.
695 * We can't change the label
696 * in the SSV itself because that
697 * would cause problems, so make a copy
698 * and adjust that, then free it
699 * when we are done with it.
700 * Have to get size out of SSV,
701 * because Staffscale won't be
702 * up to date. */
703 MALLOCA(char, label, strlen(lab_p->label) + 1);
704 memcpy(label, lab_p->label,
705 strlen(lab_p->label) + 1);
706 resize_string(label,
707 svpath(Labellist[li].staffno,
708 STAFFSCALE)->staffscale,
709 (char *) 0, -1);
710 }
711 else {
712 label = lab_p->label;
713 }
714
715 x = lab_p->west + adj;
716 /* Move above any other inner labels.
717 * The very inner-most stays centered on the
718 * staff, so ones above that have to be adjusted
719 * by its ascent. This label itself has to
720 * have enough room for half its height,
721 * since it was originally centered,
722 * for any between there, we need to skip
723 * past their entire height.
724 */
725 for (y_adjust = 0.0, l_p = lab_p->next;
726 l_p != 0; l_p = l_p->next) {
727 if (l_p->next == 0) {
728 y_adjust += strascent(
729 l_p->label) + STDPAD;
730 }
731 else {
732 y_adjust += strheight(
733 l_p->label) + STDPAD;
734 }
735 }
736 if (lab_p->next != 0) {
737 y_adjust += strheight(lab_p->label)
738 / 2.0 + STDPAD;
739 }
740 y = Staffs_y[ Labellist[li].staffno ]
741 + (strheight(label) / 2.0)
742 - strascent(label)
743 + y_adjust;
744 pr_string(x, y, label, J_CENTER, (char *) 0, -1);
745 if (lab_p->is_staff_label == YES) {
746 FREE(label);
747 }
748 }
749
750 /* do labels that fall between staffs */
751 for (lab_p = Labellist[li].btwnlabel_p;
752 lab_p != (struct LABELINFO *) 0;
753 lab_p = lab_p->next) {
754 label = lab_p->label;
755 x = lab_p->west + adj;
756 /* y is the midpoint between the staffs,
757 * adjusted by the height/ascent of the label,
758 * and for any other labels. */
759 for (y_adjust = 0.0, l_p = lab_p->next;
760 l_p != 0; l_p = l_p->next) {
761 if (l_p->next == 0) {
762 y_adjust += strascent(
763 l_p->label) + STDPAD;
764 }
765 else {
766 y_adjust += strheight(
767 l_p->label) + STDPAD;
768 }
769 }
770 if (lab_p->next != 0) {
771 y_adjust += strheight(lab_p->label)
772 / 2.0 + STDPAD;
773 }
774 y = (Staffs_y[ Labellist[li].staffno ] +
775 Staffs_y[ Labellist[li+1].staffno ])/2.0
776 + (strheight(label) / 2.0)
777 - strascent(label) + y_adjust;
778 pr_string(x, y, label, J_CENTER, (char *) 0, -1);
779 }
780 }
781 }
782 else {
783 adj = - (Maxlevels * 2.0 * STDPAD);
784 }
785
786 /* print the braces and brackets themselves */
787 for (s = 1; s <= Score.staffs; s++) {
788 for (brac_p = Brac_info_p[s]; brac_p != (struct BRAC_INFO *) 0;
789 brac_p = brac_p->nested_p) {
790 x = x_offset + adj + (Maxlevels - brac_p->nestlevel + 1)
791 * (2.0 * STDPAD) + (2.0 * STEPSIZE)
792 + Nested_brace_adjust;
793 if (brac_p->bractype == BRACELIST) {
794 if (brac_p->nested_by_p == 0) {
795 x += (0.5 * STEPSIZE);
796 }
797 else {
798 x -= (0.5 * STEPSIZE);
799 }
800 }
801 if (brac_p->topvisstaff > 0) {
802 /* figure out y (the top). Start at the y
803 * of the top staff, then adjust as needed. */
804 y = Staffs_y [brac_p->topvisstaff];
805
806 /* figure out how tall the staff is effectively.
807 * Staffs with only a few stafflines are
808 * effectively taller than the number of
809 * stafflines. */
810 if ((eff_stafflines = svpath(
811 brac_p->topvisstaff, STAFFLINES) ->stafflines) < 3) {
812 eff_stafflines = 3;
813 }
814 /* stepsizes are taller on tab staffs */
815 tab_adjust = (is_tab_staff(brac_p->topvisstaff)
816 ? TABRATIO : 1.0);
817
818 /* adjust for height of staff */
819 eff_stepsize = svpath(brac_p->topvisstaff,
820 STAFFSCALE)->staffscale
821 * STEPSIZE;
822 y += (eff_stafflines - 1) * eff_stepsize
823 * tab_adjust;
824
825 /* nested brackets should be a little shorter
826 * vertically to fit inside their parent.
827 * But beyond about 4 levels, if there is
828 * only a single staff, things look
829 * pretty bad, so limit to 4. */
830 y -= (eff_stepsize * (brac_p->nestlevel < 5
831 ? brac_p->nestlevel : 4));
832
833 /* brackets are 1 stepsize taller than braces */
834 if (brac_p->bractype == BRACKLIST) {
835 y += eff_stepsize;
836 }
837
838 /* now calculate y1 (the bottom) by similar
839 * means */
840 y1 = Staffs_y [brac_p->botvisstaff];
841
842 /* figure out how tall the staff is effectively.
843 * Staffs with only a few stafflines are
844 * effectively taller than the number of
845 * stafflines. */
846 if ((eff_stafflines = svpath(
847 brac_p->botvisstaff, STAFFLINES) ->stafflines) < 3) {
848 eff_stafflines = 3;
849 }
850 /* stepsizes are taller on tab staffs */
851 tab_adjust = (is_tab_staff(brac_p->botvisstaff)
852 ? TABRATIO : 1.0);
853
854 /* adjust for height of staff */
855 eff_stepsize = svpath(brac_p->botvisstaff,
856 STAFFSCALE)->staffscale
857 * STEPSIZE;
858 y1 -= (eff_stafflines - 1) * eff_stepsize
859 * tab_adjust;
860
861 /* nested brackets should be a little shorter
862 * vertically to fit inside their parent.
863 * But beyond about 4 levels, if there is
864 * only a single staff, things look
865 * pretty bad, so limit to 4. */
866 y1 += (eff_stepsize * (brac_p->nestlevel < 5
867 ? brac_p->nestlevel : 4));
868
869 /* brackets are 1 stepsize taller than braces */
870 if (brac_p->bractype == BRACKLIST) {
871 y1 -= eff_stepsize;
872 }
873
874 /* now do the actual printing */
875 do_pr_brac(x, y, y1, brac_p->bractype);
876 printed_brac = YES;
877 }
878 }
879 }
880
881 return(printed_brac);
882}
883\f
884
885/* Given one MAINLL pointing to a FEED, find the previous one.
886 * Many functions in this file need the previous feed. At abshorz time,
887 * there may not be an actual FEED yet, it might just be proposed,
888 * so functions at that time need to provide that proposed FEED place.
889 * Once all the FEEDs are determined, we can use this function to
890 * find the previous one.
891 */
892
893static struct MAINLL *
894find_prev_feed_mll_p(mll_p)
895
896struct MAINLL *mll_p;
897
898{
899 for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
900 if (IS_CLEFSIG_FEED(mll_p)) {
901 break;
902 }
903 }
904 return(mll_p);
905}
906\f
907
908/* Determine which label to use for a given staff.
909 * Goes backwards from mll_p, finding if label has been changed more recently
910 * than the previous feed. If so, use that label, else use label2.
911 */
912
913static char *
914label4staff(mll_p, s, prev_feed_mll_p)
915
916struct MAINLL *mll_p; /* should point to an actual or proposed FEED location */
917int s;
918struct MAINLL *prev_feed_mll_p; /* should point to an actual or proposed FEED location */
919
920{
921 for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
922 if (mll_p == prev_feed_mll_p) {
923 break;
924 }
925 if (mll_p->str == S_SSV) {
926 struct SSV *ssv_p = mll_p->u.ssv_p;
927
928 /* If user changed label for this staff in staff
929 * context more recently that the previous feed,
930 * then that's the label we need. */
931 if (ssv_p->context == C_STAFF && ssv_p->staffno == s
932 && ssv_p->used[LABEL] == YES) {
933 return(ssv_p->label);
934 }
935
936 /* If user changed the score-wide label
937 * more recently than the previous feed,
938 * but there isn't any label set in staff context for
939 * this staff to override the score level label,
940 * then the score level label is the one we need. */
941 if (ssv_p->context == C_SCORE &&
942 ssv_p->used[LABEL] == YES &&
943 Staff[s-1].used[LABEL] == NO) {
944 return(ssv_p->label);
945 }
946 }
947 }
948 if (mll_p != 0) {
949 /* Hit another feed before any relevent label changes,
950 * so we need to use label2 */
951 return(svpath(s, LABEL2)->label2);
952 }
953 /* Ran off the top of the song. Use label */
954 return(svpath(s, LABEL)->label);
955}
956\f
957
958/* Given information about a set of grouped staffs,
959 * return the appropriate label to use: label or label2.
960 */
961
962static char *
963label4group(mll_p, brac_p, prev_feed_mll_p)
964
965struct MAINLL *mll_p;
966struct BRAC_INFO *brac_p;
967struct MAINLL *prev_feed_mll_p;
968
969{
970 for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
971 if (mll_p == prev_feed_mll_p) {
972 /* Hasn't changed since previous feed, so label2 */
973 return(brac_p->staffset_p->label2);
974 }
975 if (mll_p->str == S_SSV && mll_p->u.ssv_p->context == C_SCORE &&
976 mll_p->u.ssv_p->used[brac_p->bractype] == YES) {
977 /* found SSV where brace/bracket was changed */
978 break;
979 }
980 }
981 /* Either changed since previous feed or is the first feed in song,
982 * so use label. */
983 return(brac_p->staffset_p->label);
984}
985\f
986
987/* Return width of default label if the default label is needed (for
988 * indent of first score. Returns 0.0 if default label should not be used.
989 */
990
991static double
992dflt_label_width(mll_p, prev_feed_mll_p)
993
994struct MAINLL *mll_p; /* points to FEED or proposed place
995 * where current FEED will be */
996struct MAINLL *prev_feed_mll_p; /* points to previous FEED, or proposed
997 * place where prev FEED will be */
998
999{
1000 char dfltlabel[16];
1001
1002
1003 for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
1004 if (mll_p == prev_feed_mll_p) {
1005 /* not the first; so don't use default for first */
1006 return(0.0);
1007 }
1008
1009 if (mll_p->str == S_SSV && mll_p->u.ssv_p->context == C_SCORE &&
1010 mll_p->u.ssv_p->used[LABEL] == YES) {
1011 /* explicit label for first, so don't use default */
1012 return(0.0);
1013 }
1014 }
1015 (void) sprintf(dfltlabel, "%c%c ", FONT_TR, DFLT_SIZE);
1016 return(strwidth(dfltlabel));
1017}