Commit | Line | Data |
---|---|---|
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 */ | |
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 | } |