--- /dev/null
+
+/* Copyright (c) 1995, 1997, 1999, 2000, 2001, 2002, 2003, 2005 by Arkkra Enterprises */
+/* All rights reserved */
+
+/* functions to deal with brace/bracket lists, to make sure they don't
+ * overlap, and then to place the labels to minimize the space they use. */
+
+#include "defines.h"
+#include "structs.h"
+#include "globals.h"
+
+/* padding between labels in inches. **** eventually should adjust padding
+ * based on size??? ***/
+#define LABELPAD 0.125
+
+/* information to be able to determine overlaps in the brace/bracket lists */
+static struct BRAC_INFO {
+ struct STAFFSET *staffset_p; /* bracelist or bracklist item */
+ int bractype; /* BRACELIST or BRACKLIST */
+ struct BRAC_INFO *nested_p; /* pointer to another brace/bracket
+ * item, which has its top on the
+ * same staff, and presumably
+ * is nested inside this one */
+ struct BRAC_INFO *nested_by_p; /* if this one is nested, pointer
+ * to what it is nested by, else NULL */
+ short nestlevel; /* how many levels deep */
+ short topvisstaff; /* top visible staff in range */
+ short botvisstaff; /* bottom visible staff in range */
+} *Brac_info_p [MAXSTAFFS + 1];
+
+
+/* information about a label, either for a staff or group. */
+struct LABELINFO {
+ char *label; /* text of the label */
+ float width; /* strwidth(label) */
+ float west; /* relative distance of left edge of label
+ * from the line between the labels and the
+ * braces/brackets. This will be negative */
+ int is_staff_label; /* YES for staff label, NO for group */
+ struct LABELINFO *next;/* linked list of labels at same y location */
+};
+
+/* information about all the labels that end up being printed left of a
+ * specific staff or between that staff and the one below it. */
+struct LABELLIST {
+ short staffno; /* which staff */
+ struct LABELINFO *label_p; /* list of labels to be printed to
+ * the left of this staff */
+ struct LABELINFO *btwnlabel_p; /* list of labels to be printed
+ * between this staff and the one
+ * below this staff */
+ short pad; /* how many levels of labels
+ * have been put on this staff, either
+ * on the staff itself or on one or
+ * more other staffs that are
+ * grouped with this one */
+};
+static struct LABELLIST Labellist[MAXSTAFFS + 1];
+
+static short Numvis; /* how many staffs currently visible */
+static short Maxlevels; /* maximum number of nesting levels */
+static float Nested_brace_adjust = 0.0; /* brace outside a bracket needs
+ * some extra space to look good. */
+
+
+/* static functions */
+static void free_brac_info P((struct BRAC_INFO *brac_info_p));
+static void set_brac_info P((struct STAFFSET *staffset_p, int bractype));
+static int check_brac_overlap P((struct BRAC_INFO *brac_info_p));
+static void setnestlevel P((struct BRAC_INFO *brac_p,
+ struct BRAC_INFO *nested_by_p));
+static void place_labels P((struct MAINLL *mll_p,
+ struct MAINLL *prev_feed_mll_p));
+static void init_labellist P((void));
+static void free_label P((struct LABELINFO *label_p));
+static struct LABELINFO *newlabelinfo P((char *label, int is_staff_label));
+static void grouplabel P((struct BRAC_INFO *brac_p, int do_nested,
+ struct MAINLL *mll_p, struct MAINLL *prev_feed_mll_p));
+static double west_adjust P((struct MAINLL *mll_p,
+ struct MAINLL *prev_feed_mll_p));
+static struct MAINLL *find_prev_feed_mll_p P((struct MAINLL *mll_p));
+static char * label4staff P((struct MAINLL *mll_p, int s,
+ struct MAINLL *prev_feed_mll_p));
+static char * label4group P((struct MAINLL *mll_p, struct BRAC_INFO *brac_p,
+ struct MAINLL *prev_feed_mll_p));
+static double dflt_label_width P((struct MAINLL *mll_p,
+ struct MAINLL *prev_feed_mll_p));
+
+\f
+
+/* check for overlap between brace and bracket lists. Return YES if okay, NO
+ * if there is something illegal */
+
+int
+brac_check (bracelist_p, nbrace, bracklist_p, nbrack)
+
+struct STAFFSET *bracelist_p;
+int nbrace; /* how many items in bracelist_p */
+struct STAFFSET *bracklist_p;
+int nbrack; /* how many items in bracklist_p */
+
+{
+ register int s; /* staff index into Brac_info_p */
+ register int n; /* index into staffset */
+ int retval = 0; /* return from check_brac_overlap() */
+ static int first_time = YES; /* flag for if first time this function
+ * has been called */
+
+
+ debug(4, "brac_check");
+
+ /* initialize table */
+ for (s = 1; s <= Score.staffs; s++) {
+ if (first_time == NO) {
+ /* only try to free if we know item has been properly
+ * initialized, in case this is ever run on some system
+ * that doesn't initialize pointer arrays to null ptrs */
+ free_brac_info(Brac_info_p[s]);
+ }
+ Brac_info_p[s] = (struct BRAC_INFO *) 0;
+ }
+ first_time = NO;
+ Maxlevels = 0;
+
+ /* Go through each list, attaching each to table slot of its top staff.
+ */
+ for (n = 0; n < nbrace; n++) {
+ set_brac_info( &(bracelist_p[n]), BRACELIST);
+ }
+ for (n = 0; n < nbrack; n++) {
+ set_brac_info( &(bracklist_p[n]), BRACKLIST);
+ }
+
+ /* now check each staff for possible overlap */
+ for (s = 1; s <= Score.staffs; s++) {
+ if (Brac_info_p[s] == (struct BRAC_INFO *) 0) {
+ /* no braces or brackets, so can't be any overlap */
+ continue;
+ }
+
+ retval += check_brac_overlap (Brac_info_p[s]);
+ }
+
+ return(retval == 0 ? YES : NO);
+}
+\f
+
+/* recursively free a linked list of BRAC_INFO structs */
+
+static void
+free_brac_info(brac_info_p)
+
+struct BRAC_INFO *brac_info_p; /* the list to free */
+
+{
+ if (brac_info_p == (struct BRAC_INFO *) 0) {
+ return;
+ }
+
+ free_brac_info(brac_info_p->nested_p);
+ FREE(brac_info_p);
+}
+\f
+
+/* save information about a brace/bracket STAFFSET and link onto list for its
+ * top staff */
+
+static void
+set_brac_info (staffset_p, bractype)
+
+struct STAFFSET *staffset_p; /* staffs to group together */
+int bractype; /* BRACELIST or BRACKLIST */
+
+{
+ struct BRAC_INFO *new_p; /* info to be saved */
+ int s; /* staff num of top staff of staffset */
+
+
+ /* record information */
+ MALLOC(BRAC_INFO, new_p, 1);
+ new_p->staffset_p = staffset_p;
+ new_p->bractype = bractype;
+ new_p->nested_by_p = (struct BRAC_INFO *) 0;
+ new_p->nestlevel = 0;
+
+ /* link into list off of table */
+ s = staffset_p->topstaff;
+ new_p->nested_p = Brac_info_p[s];
+ Brac_info_p[s] = new_p;
+}
+\f
+
+/* check the brace/bracket information for one staff for overlap. Return
+ * number of errors found */
+
+static int
+check_brac_overlap (brac_info_p)
+
+struct BRAC_INFO *brac_info_p;
+
+{
+ register int s;
+
+
+ if (brac_info_p == (struct BRAC_INFO *) 0) {
+ /* end recursion */
+ return(0);
+ }
+
+ /* if no nesting, don't need to do those checks */
+ if (brac_info_p->nested_p != (struct BRAC_INFO *) 0) {
+
+ /* braces can't have anything nested inside them */
+ if (brac_info_p->bractype == BRACELIST) {
+ yyerror("nesting inside a brace not allowed");
+ return(1);
+ }
+
+ /* brace on top of bracket needs extra space */
+ if (brac_info_p->nested_p->bractype == BRACELIST) {
+ Nested_brace_adjust = STEPSIZE;
+ }
+
+ /* check that nested range is a proper subset */
+ if (brac_info_p->nested_p->staffset_p->botstaff
+ >= brac_info_p->staffset_p->botstaff) {
+ yyerror("nested brackets must be subsets of other brackets");
+ return(1);
+ }
+
+ setnestlevel(brac_info_p->nested_p, brac_info_p);
+ }
+
+ /* see if this one overlaps with groups
+ * defined previously */
+ for (s = brac_info_p->staffset_p->topstaff + 1;
+ s <= brac_info_p->staffset_p->botstaff; s++) {
+
+ if (Brac_info_p[s] == (struct BRAC_INFO *) 0) {
+ continue;
+ }
+
+ /* if brace is being nested by something else,
+ * overlap is illegal */
+ if (brac_info_p->bractype == BRACELIST) {
+ yyerror("brace overlap not allowed");
+ return(1);
+ }
+
+ /* if bottom of this staffset is greater than bottom of the one
+ * we are checking, there is illegal overlap */
+ if (Brac_info_p[s]->staffset_p->botstaff
+ > brac_info_p->staffset_p->botstaff) {
+ yyerror("overlapping brackets are not nested");
+ return(1);
+ }
+
+ /* remember who nests this one */
+ setnestlevel(Brac_info_p[s], brac_info_p);
+ }
+
+ /* recurse */
+ return (check_brac_overlap (brac_info_p->nested_p));
+}
+\f
+
+/* when one bracket is nested inside another, record that fact */
+
+static void
+setnestlevel(brac_p, nested_by_p)
+
+struct BRAC_INFO *brac_p; /* set nesting here */
+struct BRAC_INFO *nested_by_p; /* brac_p is nested by this one */
+
+{
+ brac_p->nested_by_p = nested_by_p;
+ brac_p->nestlevel = nested_by_p->nestlevel + 1;
+
+ /* keep track of deepest nesting level */
+ if (brac_p->nestlevel > Maxlevels) {
+ Maxlevels = brac_p->nestlevel;
+ }
+}
+\f
+
+/*
+ * for each label
+ * find which staff the label should go on based on visible
+ *
+ * Determine placement of staff labels, then nested, then outer.
+ */
+
+static void
+place_labels(mll_p, prev_feed_mll_p)
+
+struct MAINLL *mll_p; /* current place in main list, used to determine
+ * whether to use label or label2. */
+struct MAINLL *prev_feed_mll_p; /* actual or proposed location of prev FEED */
+
+{
+ int s; /* index through staffs */
+ int count; /* how many labels */
+ char *label; /* the label being processed */
+ struct LABELINFO *lab_p;/* info about label */
+
+
+ init_labellist();
+ lab_p = (struct LABELINFO *) 0;
+
+ /* put the staff labels on the label list. While we're at it, count
+ * up the number of staffs that are currently visible */
+ for (count = Numvis = 0, s = 1; s <= Score.staffs; s++) {
+ if (svpath(s, VISIBLE)->visible == NO) {
+ continue;
+ }
+
+ /* use label or label2 as appropriate */
+ if ((label = label4staff(mll_p, s, prev_feed_mll_p)) != 0) {
+ lab_p = newlabelinfo(label, YES);
+ }
+
+ /* if there was a label, save info about it */
+ if (lab_p != (struct LABELINFO *) 0) {
+
+ /* staff labels always go as far east as possible */
+ /* Adjust by staffscale, but get from SSV, since
+ * Stepsize won't be up to date. */
+ lab_p->west = (-(lab_p->width) - STEPSIZE)
+ * svpath(s, STAFFSCALE)->staffscale;
+
+ /* link onto list */
+ lab_p->next = Labellist[Numvis].label_p;
+ Labellist[Numvis].label_p = lab_p;
+
+ /* count up number of staff labels */
+ count++;
+
+ /* re-init for next trip through loop */
+ lab_p = (struct LABELINFO *) 0;
+ }
+
+ Labellist[Numvis].staffno = (short) s;
+
+ /* we now know there is one more staff visible */
+ Numvis++;
+ }
+
+ /* if there were any labels, mark all staffs as needing padding
+ * before placing another label. If there were no staff labels,
+ * group labels will go as far east as possible, otherwise the
+ * group labels will be leftward a bit. */
+ if (count > 0) {
+ for (s = 0; s < Numvis; s++) {
+ (Labellist[s].pad)++;
+ }
+ }
+
+ /* do all nested group labels */
+ for (s = 1; s <= Score.staffs; s++) {
+ grouplabel(Brac_info_p[s], YES, mll_p, prev_feed_mll_p);
+ }
+
+ /* do all non-nested group labels */
+ for (s = 1; s <= Score.staffs; s++) {
+ grouplabel(Brac_info_p[s], NO, mll_p, prev_feed_mll_p);
+ }
+}
+\f
+
+/* initialize label list. Free any information currently in the list and
+ * mark everything as empty */
+
+static void
+init_labellist()
+
+{
+ register int s; /* index through label list */
+
+
+ for (s = 0; s <= Numvis; s++) {
+ free_label(Labellist[s].label_p);
+ free_label(Labellist[s].btwnlabel_p);
+ Labellist[s].label_p = Labellist[s].btwnlabel_p
+ = (struct LABELINFO *) 0;
+ Labellist[s].pad = 0;
+ }
+ Numvis = 0;
+}
+\f
+
+/* recursively free linked list of LABELINFO structs */
+
+static void
+free_label(label_p)
+
+struct LABELINFO *label_p; /* free this list */
+
+{
+ if (label_p == (struct LABELINFO *) 0) {
+ return;
+ }
+
+ free_label(label_p->next);
+ FREE(label_p);
+}
+\f
+
+/* allocate a new LABELINFO struct and fill in the label and width. Initialize
+ * west to zero */
+
+static struct LABELINFO *
+newlabelinfo(label, is_staff_label)
+
+char *label; /* text of the label */
+int is_staff_label; /* YES or NO */
+
+{
+ struct LABELINFO *new_p; /* newly allocate place to save info */
+
+
+ MALLOC(LABELINFO, new_p, 1);
+ new_p->label = label;
+ new_p->west = 0.0;
+ new_p->width = strwidth(label);
+ new_p->is_staff_label = is_staff_label;
+ new_p->next = (struct LABELINFO *) 0;
+ return(new_p);
+}
+\f
+
+/* do placement of group labels */
+
+static void
+grouplabel(brac_p, do_nested, mll_p, prev_feed_mll_p)
+
+struct BRAC_INFO *brac_p; /* info about group of staffs to do */
+int do_nested; /* if YES, process nested staff group. If NO,
+ * process non-nested */
+struct MAINLL *mll_p; /* used to decide if to use label or label2 */
+struct MAINLL *prev_feed_mll_p; /* actual or proposed previous FEED */
+
+{
+ struct STAFFSET *staffset_p; /* staffs/label in group */
+ char *label; /* label for group */
+ int index; /* into Labellist */
+ int topindex, botindex; /* index into Labellist of where
+ * group range top & bottom visible
+ * staffs are */
+ int labindex; /* index into Labellist of staff where
+ * label should go */
+ struct LABELINFO *lab_p; /* information about group label */
+ struct LABELINFO **lab_p_p; /* where to insert label info */
+
+
+ if (brac_p == (struct BRAC_INFO *) 0) {
+ /* end recursion */
+ return;
+ }
+
+ if (do_nested == YES) {
+ /* recurse */
+ grouplabel(brac_p->nested_p, do_nested, mll_p, prev_feed_mll_p);
+ if (brac_p->nested_by_p == (struct BRAC_INFO *) 0) {
+ return;
+ }
+ }
+ else if (brac_p->nested_by_p != (struct BRAC_INFO *) 0) {
+ return;
+ }
+
+ /* we'll probably need the staffset info a lot, so get pointer to it */
+ staffset_p = brac_p->staffset_p;
+
+ /* Find index in Labellist of top
+ * and bottom visible staffs of the range */
+ for (topindex = botindex = -1, index = 0; index < Numvis; index++) {
+ if (topindex == -1 && staffset_p->topstaff
+ <= Labellist[index].staffno) {
+ topindex = index;
+ }
+ if (staffset_p->botstaff >= Labellist[index].staffno) {
+ botindex = index;
+ }
+ }
+
+ /* see if there were some visible staffs in this group */
+ if (topindex != -1 && botindex != -1 && botindex >= topindex) {
+
+ brac_p->topvisstaff = Labellist[topindex].staffno;
+ brac_p->botvisstaff = Labellist[botindex].staffno;
+
+ /* figure out which label to use, if any */
+ if ((label = label4group(mll_p, brac_p, prev_feed_mll_p))
+ == (char *) 0) {
+ return;
+ }
+
+ /* find index in list of visible staffs where label should
+ * go. If even number of visible staffs in range, label
+ * goes between two staffs */
+ labindex = (topindex + botindex) / 2;
+ if ((botindex - topindex) & 1) {
+ lab_p_p = &(Labellist[labindex].btwnlabel_p);
+ }
+ else {
+ lab_p_p = &(Labellist[labindex].label_p);
+ }
+
+ lab_p = newlabelinfo(label, NO);
+
+ /* put as far east as possible */
+ lab_p->west = - (lab_p->width);
+
+ lab_p->west -= Labellist[labindex].pad * LABELPAD;
+
+ /* link onto list */
+ lab_p->next = *lab_p_p;
+ *lab_p_p = lab_p;
+
+ /* add padding to all visible staffs in the group range */
+ for ( ; topindex <= botindex; topindex++) {
+ Labellist[topindex].pad++;
+ }
+ }
+ else {
+ /* all staffs in group are invisible */
+ brac_p->topvisstaff = 0;
+ }
+}
+\f
+
+/* determine total width of labels. This is how much to add to
+ * relative west to get absolute location from left margin */
+
+static double
+west_adjust(mll_p, prev_feed_mll_p)
+
+struct MAINLL *mll_p; /* actual or proposed FEED location,
+ * used to decide if to use label or label2 */
+struct MAINLL *prev_feed_mll_p; /* actual or proposed location of preceeding
+ * FEED, used for label/label2 decision */
+
+{
+ register int s; /* index */
+ double minwest = 0.0; /* farthest west distance */
+
+
+ /* find westernmost label */
+ for (s = 0; s < Numvis; s++) {
+ if (Labellist[s].label_p != (struct LABELINFO *) 0) {
+ if (Labellist[s].label_p->west < minwest) {
+ minwest = Labellist[s].label_p->west;
+ }
+ }
+ if (Labellist[s].btwnlabel_p != (struct LABELINFO *) 0) {
+ if (Labellist[s].btwnlabel_p->west < minwest) {
+ minwest = Labellist[s].btwnlabel_p->west;
+ }
+ }
+ }
+
+ /* check for need to use default label on first score.
+ * If default label is needed, it creates an indent. */
+ if (minwest == 0.0) {
+ return(dflt_label_width(mll_p, prev_feed_mll_p));
+ }
+
+ return( - minwest);
+}
+\f
+
+/* return width of braces/brackets and their labels */
+
+double
+width_left_of_score(mll_p)
+
+struct MAINLL *mll_p; /* FEED, used to decide if to use label or label2 */
+
+{
+ return(pwidth_left_of_score(mll_p, find_prev_feed_mll_p(mll_p)));
+}
+
+double
+pwidth_left_of_score(mll_p, prev_feed_mll_p)
+
+struct MAINLL *mll_p; /* actual or proposed location of current FEED,
+ * used to decide if to use label or label2 */
+struct MAINLL *prev_feed_mll_p; /* actual or proposed location of prev FEED */
+
+{
+ double westadj;
+ int n; /* index through brac*lists */
+ int s; /* staff index */
+ int hasbracs; /* YES if there are visible brackets/braces */
+
+
+ if (brac_check(Score.bracelist, Score.nbrace, Score.bracklist,
+ Score.nbrack) == NO) {
+ /* we should have exited before */
+ pfatal("illegal brace/bracket ranges");
+ }
+ /* call functions to determine the placement of all labels and
+ * save that information in the Labellist, then determine how
+ * wide the labels plus braces and brackets are */
+ place_labels(mll_p, prev_feed_mll_p);
+ westadj = west_adjust(mll_p, prev_feed_mll_p);
+
+ /* total is space for the labels (the westadj),
+ * the braces/brackets themselves (based on Maxlevels),
+ * and 2 stepsizes of padding to left of score before brace/brack,
+ * plus special adjustment for brace on top of bracket, if any */
+ /* See if there are any visible brackets/braces.
+ * If so, we'll need to allow space for them, otherwise not. */
+ hasbracs = NO;
+ for (n = 0; n < Score.nbrace && hasbracs == NO; n++) {
+ for (s = Score.bracelist[n].topstaff;
+ s <= Score.bracelist[n].botstaff; s++){
+ if (svpath(s, VISIBLE)->visible == YES) {
+ hasbracs = YES;
+ break;
+ }
+ }
+ }
+ for (n = 0; n < Score.nbrack && hasbracs == NO; n++) {
+ for (s = Score.bracklist[n].topstaff;
+ s <= Score.bracklist[n].botstaff; s++){
+ if (svpath(s, VISIBLE)->visible == YES) {
+ hasbracs = YES;
+ break;
+ }
+ }
+ }
+
+ if (hasbracs == YES) {
+ return(westadj + ((Maxlevels + 2) * 2.0 * STDPAD)
+ + (2.0 * STEPSIZE) + Nested_brace_adjust);
+ }
+ else {
+ return(westadj);
+ }
+}
+\f
+
+/* print braces/brackets and their labels, Return YES if there were braces or
+ * brackets, NO if not. */
+
+int
+pr_brac(is_restart, x_offset, mll_p)
+
+int is_restart; /* YES if being called due to restart */
+double x_offset; /* where to print, if is_restart == YES */
+struct MAINLL *mll_p; /* for FEED for possible margin override, and to
+ * decide if to use label or label2 */
+
+{
+ register int li; /* index into Labellist */
+ register int s; /* staff index */
+ struct LABELINFO *lab_p; /* info about a label */
+ struct LABELINFO *l_p; /* for finding y adjust for overlaps */
+ double y_adjust; /* for overlapping labels */
+ struct BRAC_INFO *brac_p; /* info about brace or bracket */
+ double adj; /* how much to adjust relative west */
+ double x, y, y1;
+ int eff_stafflines; /* how many stafflines there effectively
+ * are, counting the extra space around
+ * staffs with a very small number
+ * of stafflines */
+ double tab_adjust; /* to adjust for TABRATIO */
+ double eff_stepsize; /* STEPSIZE adjusted for staffscale */
+ char *label;
+ int printed_brac = NO; /* if printed any braces/brackets */
+ struct MAINLL *prev_feed_mll_p; /* previous FEED */
+
+
+ debug(512, "pr_brac");
+
+ /* figure out where to place everything */
+ (void) brac_check(Score.bracelist, Score.nbrace, Score.bracklist,
+ Score.nbrack);
+ prev_feed_mll_p = find_prev_feed_mll_p(mll_p);
+ place_labels(mll_p, prev_feed_mll_p);
+ if (is_restart == NO) {
+ adj = west_adjust(mll_p, prev_feed_mll_p)
+ + eff_leftmargin(mll_p);
+
+ /* print labels on visible staffs */
+ for (li = 0; li < Numvis; li++) {
+
+ /* print labels to go by this staff */
+ for (lab_p = Labellist[li].label_p;
+ lab_p != (struct LABELINFO *) 0;
+ lab_p = lab_p->next) {
+ if (lab_p->is_staff_label == YES) {
+ /* Have to adjust by staffscale.
+ * We can't change the label
+ * in the SSV itself because that
+ * would cause problems, so make a copy
+ * and adjust that, then free it
+ * when we are done with it.
+ * Have to get size out of SSV,
+ * because Staffscale won't be
+ * up to date. */
+ MALLOCA(char, label, strlen(lab_p->label) + 1);
+ memcpy(label, lab_p->label,
+ strlen(lab_p->label) + 1);
+ resize_string(label,
+ svpath(Labellist[li].staffno,
+ STAFFSCALE)->staffscale,
+ (char *) 0, -1);
+ }
+ else {
+ label = lab_p->label;
+ }
+
+ x = lab_p->west + adj;
+ /* Move above any other inner labels.
+ * The very inner-most stays centered on the
+ * staff, so ones above that have to be adjusted
+ * by its ascent. This label itself has to
+ * have enough room for half its height,
+ * since it was originally centered,
+ * for any between there, we need to skip
+ * past their entire height.
+ */
+ for (y_adjust = 0.0, l_p = lab_p->next;
+ l_p != 0; l_p = l_p->next) {
+ if (l_p->next == 0) {
+ y_adjust += strascent(
+ l_p->label) + STDPAD;
+ }
+ else {
+ y_adjust += strheight(
+ l_p->label) + STDPAD;
+ }
+ }
+ if (lab_p->next != 0) {
+ y_adjust += strheight(lab_p->label)
+ / 2.0 + STDPAD;
+ }
+ y = Staffs_y[ Labellist[li].staffno ]
+ + (strheight(label) / 2.0)
+ - strascent(label)
+ + y_adjust;
+ pr_string(x, y, label, J_CENTER, (char *) 0, -1);
+ if (lab_p->is_staff_label == YES) {
+ FREE(label);
+ }
+ }
+
+ /* do labels that fall between staffs */
+ for (lab_p = Labellist[li].btwnlabel_p;
+ lab_p != (struct LABELINFO *) 0;
+ lab_p = lab_p->next) {
+ label = lab_p->label;
+ x = lab_p->west + adj;
+ /* y is the midpoint between the staffs,
+ * adjusted by the height/ascent of the label,
+ * and for any other labels. */
+ for (y_adjust = 0.0, l_p = lab_p->next;
+ l_p != 0; l_p = l_p->next) {
+ if (l_p->next == 0) {
+ y_adjust += strascent(
+ l_p->label) + STDPAD;
+ }
+ else {
+ y_adjust += strheight(
+ l_p->label) + STDPAD;
+ }
+ }
+ if (lab_p->next != 0) {
+ y_adjust += strheight(lab_p->label)
+ / 2.0 + STDPAD;
+ }
+ y = (Staffs_y[ Labellist[li].staffno ] +
+ Staffs_y[ Labellist[li+1].staffno ])/2.0
+ + (strheight(label) / 2.0)
+ - strascent(label) + y_adjust;
+ pr_string(x, y, label, J_CENTER, (char *) 0, -1);
+ }
+ }
+ }
+ else {
+ adj = - (Maxlevels * 2.0 * STDPAD);
+ }
+
+ /* print the braces and brackets themselves */
+ for (s = 1; s <= Score.staffs; s++) {
+ for (brac_p = Brac_info_p[s]; brac_p != (struct BRAC_INFO *) 0;
+ brac_p = brac_p->nested_p) {
+ x = x_offset + adj + (Maxlevels - brac_p->nestlevel + 1)
+ * (2.0 * STDPAD) + (2.0 * STEPSIZE)
+ + Nested_brace_adjust;
+ if (brac_p->bractype == BRACELIST) {
+ if (brac_p->nested_by_p == 0) {
+ x += (0.5 * STEPSIZE);
+ }
+ else {
+ x -= (0.5 * STEPSIZE);
+ }
+ }
+ if (brac_p->topvisstaff > 0) {
+ /* figure out y (the top). Start at the y
+ * of the top staff, then adjust as needed. */
+ y = Staffs_y [brac_p->topvisstaff];
+
+ /* figure out how tall the staff is effectively.
+ * Staffs with only a few stafflines are
+ * effectively taller than the number of
+ * stafflines. */
+ if ((eff_stafflines = svpath(
+ brac_p->topvisstaff, STAFFLINES) ->stafflines) < 3) {
+ eff_stafflines = 3;
+ }
+ /* stepsizes are taller on tab staffs */
+ tab_adjust = (is_tab_staff(brac_p->topvisstaff)
+ ? TABRATIO : 1.0);
+
+ /* adjust for height of staff */
+ eff_stepsize = svpath(brac_p->topvisstaff,
+ STAFFSCALE)->staffscale
+ * STEPSIZE;
+ y += (eff_stafflines - 1) * eff_stepsize
+ * tab_adjust;
+
+ /* nested brackets should be a little shorter
+ * vertically to fit inside their parent.
+ * But beyond about 4 levels, if there is
+ * only a single staff, things look
+ * pretty bad, so limit to 4. */
+ y -= (eff_stepsize * (brac_p->nestlevel < 5
+ ? brac_p->nestlevel : 4));
+
+ /* brackets are 1 stepsize taller than braces */
+ if (brac_p->bractype == BRACKLIST) {
+ y += eff_stepsize;
+ }
+
+ /* now calculate y1 (the bottom) by similar
+ * means */
+ y1 = Staffs_y [brac_p->botvisstaff];
+
+ /* figure out how tall the staff is effectively.
+ * Staffs with only a few stafflines are
+ * effectively taller than the number of
+ * stafflines. */
+ if ((eff_stafflines = svpath(
+ brac_p->botvisstaff, STAFFLINES) ->stafflines) < 3) {
+ eff_stafflines = 3;
+ }
+ /* stepsizes are taller on tab staffs */
+ tab_adjust = (is_tab_staff(brac_p->botvisstaff)
+ ? TABRATIO : 1.0);
+
+ /* adjust for height of staff */
+ eff_stepsize = svpath(brac_p->botvisstaff,
+ STAFFSCALE)->staffscale
+ * STEPSIZE;
+ y1 -= (eff_stafflines - 1) * eff_stepsize
+ * tab_adjust;
+
+ /* nested brackets should be a little shorter
+ * vertically to fit inside their parent.
+ * But beyond about 4 levels, if there is
+ * only a single staff, things look
+ * pretty bad, so limit to 4. */
+ y1 += (eff_stepsize * (brac_p->nestlevel < 5
+ ? brac_p->nestlevel : 4));
+
+ /* brackets are 1 stepsize taller than braces */
+ if (brac_p->bractype == BRACKLIST) {
+ y1 -= eff_stepsize;
+ }
+
+ /* now do the actual printing */
+ do_pr_brac(x, y, y1, brac_p->bractype);
+ printed_brac = YES;
+ }
+ }
+ }
+
+ return(printed_brac);
+}
+\f
+
+/* Given one MAINLL pointing to a FEED, find the previous one.
+ * Many functions in this file need the previous feed. At abshorz time,
+ * there may not be an actual FEED yet, it might just be proposed,
+ * so functions at that time need to provide that proposed FEED place.
+ * Once all the FEEDs are determined, we can use this function to
+ * find the previous one.
+ */
+
+static struct MAINLL *
+find_prev_feed_mll_p(mll_p)
+
+struct MAINLL *mll_p;
+
+{
+ for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
+ if (IS_CLEFSIG_FEED(mll_p)) {
+ break;
+ }
+ }
+ return(mll_p);
+}
+\f
+
+/* Determine which label to use for a given staff.
+ * Goes backwards from mll_p, finding if label has been changed more recently
+ * than the previous feed. If so, use that label, else use label2.
+ */
+
+static char *
+label4staff(mll_p, s, prev_feed_mll_p)
+
+struct MAINLL *mll_p; /* should point to an actual or proposed FEED location */
+int s;
+struct MAINLL *prev_feed_mll_p; /* should point to an actual or proposed FEED location */
+
+{
+ for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
+ if (mll_p == prev_feed_mll_p) {
+ break;
+ }
+ if (mll_p->str == S_SSV) {
+ struct SSV *ssv_p = mll_p->u.ssv_p;
+
+ /* If user changed label for this staff in staff
+ * context more recently that the previous feed,
+ * then that's the label we need. */
+ if (ssv_p->context == C_STAFF && ssv_p->staffno == s
+ && ssv_p->used[LABEL] == YES) {
+ return(ssv_p->label);
+ }
+
+ /* If user changed the score-wide label
+ * more recently than the previous feed,
+ * but there isn't any label set in staff context for
+ * this staff to override the score level label,
+ * then the score level label is the one we need. */
+ if (ssv_p->context == C_SCORE &&
+ ssv_p->used[LABEL] == YES &&
+ Staff[s-1].used[LABEL] == NO) {
+ return(ssv_p->label);
+ }
+ }
+ }
+ if (mll_p != 0) {
+ /* Hit another feed before any relevent label changes,
+ * so we need to use label2 */
+ return(svpath(s, LABEL2)->label2);
+ }
+ /* Ran off the top of the song. Use label */
+ return(svpath(s, LABEL)->label);
+}
+\f
+
+/* Given information about a set of grouped staffs,
+ * return the appropriate label to use: label or label2.
+ */
+
+static char *
+label4group(mll_p, brac_p, prev_feed_mll_p)
+
+struct MAINLL *mll_p;
+struct BRAC_INFO *brac_p;
+struct MAINLL *prev_feed_mll_p;
+
+{
+ for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
+ if (mll_p == prev_feed_mll_p) {
+ /* Hasn't changed since previous feed, so label2 */
+ return(brac_p->staffset_p->label2);
+ }
+ if (mll_p->str == S_SSV && mll_p->u.ssv_p->context == C_SCORE &&
+ mll_p->u.ssv_p->used[brac_p->bractype] == YES) {
+ /* found SSV where brace/bracket was changed */
+ break;
+ }
+ }
+ /* Either changed since previous feed or is the first feed in song,
+ * so use label. */
+ return(brac_p->staffset_p->label);
+}
+\f
+
+/* Return width of default label if the default label is needed (for
+ * indent of first score. Returns 0.0 if default label should not be used.
+ */
+
+static double
+dflt_label_width(mll_p, prev_feed_mll_p)
+
+struct MAINLL *mll_p; /* points to FEED or proposed place
+ * where current FEED will be */
+struct MAINLL *prev_feed_mll_p; /* points to previous FEED, or proposed
+ * place where prev FEED will be */
+
+{
+ char dfltlabel[16];
+
+
+ for (mll_p = mll_p->prev; mll_p != 0; mll_p = mll_p->prev) {
+ if (mll_p == prev_feed_mll_p) {
+ /* not the first; so don't use default for first */
+ return(0.0);
+ }
+
+ if (mll_p->str == S_SSV && mll_p->u.ssv_p->context == C_SCORE &&
+ mll_p->u.ssv_p->used[LABEL] == YES) {
+ /* explicit label for first, so don't use default */
+ return(0.0);
+ }
+ }
+ (void) sprintf(dfltlabel, "%c%c ", FONT_TR, DFLT_SIZE);
+ return(strwidth(dfltlabel));
+}