| 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 | } |