chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / brac.c
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 */
17 static 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. */
33 struct 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. */
45 struct 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 };
58 static struct LABELLIST Labellist[MAXSTAFFS + 1];
59
60 static short Numvis;            /* how many staffs currently visible */
61 static short Maxlevels;         /* maximum number of nesting levels */
62 static float Nested_brace_adjust = 0.0; /* brace outside a bracket needs
63                                  * some extra space to look good. */
64
65
66 /* static functions */
67 static void free_brac_info P((struct BRAC_INFO *brac_info_p));
68 static void set_brac_info P((struct STAFFSET *staffset_p, int bractype));
69 static int check_brac_overlap P((struct BRAC_INFO *brac_info_p));
70 static void setnestlevel P((struct BRAC_INFO *brac_p,
71                 struct BRAC_INFO *nested_by_p));
72 static void place_labels P((struct MAINLL *mll_p,
73                 struct MAINLL *prev_feed_mll_p));
74 static void init_labellist P((void));
75 static void free_label P((struct LABELINFO *label_p));
76 static struct LABELINFO *newlabelinfo P((char *label, int is_staff_label));
77 static void grouplabel P((struct BRAC_INFO *brac_p, int do_nested,
78                 struct MAINLL *mll_p, struct MAINLL *prev_feed_mll_p));
79 static double west_adjust P((struct MAINLL *mll_p,
80                 struct MAINLL *prev_feed_mll_p));
81 static struct MAINLL *find_prev_feed_mll_p P((struct MAINLL *mll_p));
82 static char * label4staff P((struct MAINLL *mll_p, int s,
83                 struct MAINLL *prev_feed_mll_p));
84 static char * label4group P((struct MAINLL *mll_p, struct BRAC_INFO *brac_p,
85                 struct MAINLL *prev_feed_mll_p));
86 static 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
94 int
95 brac_check (bracelist_p, nbrace, bracklist_p, nbrack)
96
97 struct STAFFSET *bracelist_p;
98 int nbrace;                     /* how many items in bracelist_p */
99 struct STAFFSET *bracklist_p;
100 int 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
150 static void
151 free_brac_info(brac_info_p)
152
153 struct 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
168 static void
169 set_brac_info (staffset_p, bractype)
170
171 struct STAFFSET *staffset_p;    /* staffs to group together */
172 int 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
196 static int
197 check_brac_overlap (brac_info_p)
198
199 struct 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
269 static void
270 setnestlevel(brac_p, nested_by_p)
271
272 struct BRAC_INFO *brac_p;       /* set nesting here */
273 struct 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
293 static void
294 place_labels(mll_p, prev_feed_mll_p)
295
296 struct MAINLL *mll_p;   /* current place in main list, used to determine
297                          * whether to use label or label2. */
298 struct 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
373 static void
374 init_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
393 static void
394 free_label(label_p)
395
396 struct 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
411 static struct LABELINFO *
412 newlabelinfo(label, is_staff_label)
413
414 char *label;            /* text of the label */
415 int 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
433 static void
434 grouplabel(brac_p, do_nested, mll_p, prev_feed_mll_p)
435
436 struct BRAC_INFO *brac_p;       /* info about group of staffs to do */
437 int do_nested;                  /* if YES, process nested staff group. If NO,
438                                  * process non-nested */
439 struct MAINLL *mll_p;           /* used to decide if to use label or label2 */
440 struct 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
535 static double
536 west_adjust(mll_p, prev_feed_mll_p)
537
538 struct MAINLL *mll_p;           /* actual or proposed FEED location,
539                                  * used to decide if to use label or label2 */
540 struct 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
574 double
575 width_left_of_score(mll_p)
576
577 struct 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
583 double
584 pwidth_left_of_score(mll_p, prev_feed_mll_p)
585
586 struct MAINLL *mll_p;           /* actual or proposed location of current FEED,
587                                  * used to decide if to use label or label2 */
588 struct 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
647 int
648 pr_brac(is_restart, x_offset, mll_p)
649
650 int is_restart;         /* YES if being called due to restart */
651 double x_offset;        /* where to print, if is_restart == YES */
652 struct 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
893 static struct MAINLL *
894 find_prev_feed_mll_p(mll_p)
895
896 struct 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
913 static char *
914 label4staff(mll_p, s, prev_feed_mll_p)
915
916 struct MAINLL *mll_p;   /* should point to an actual or proposed FEED location */
917 int s;
918 struct 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
962 static char *
963 label4group(mll_p, brac_p, prev_feed_mll_p)
964
965 struct MAINLL *mll_p;
966 struct BRAC_INFO *brac_p;
967 struct 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
991 static double
992 dflt_label_width(mll_p, prev_feed_mll_p)
993
994 struct MAINLL *mll_p;           /* points to FEED or proposed place
995                                  * where current FEED will be */
996 struct 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 }