/*************************************************
*    The PMW Music Typesetter - 3rd incarnation  *
*************************************************/

/* Copyright (c) Philip Hazel, 1991 - 2018 */

/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: May 2018 */


/* This file contains code for outputting warning key/time signatures, in a
pseudo-bar at the end of a line. */

#include "pmwhdr.h"
#include "outhdr.h"



/*************************************************
*             Output warning bar                 *
*************************************************/

/* We have to take care that multiple items on different sized staves line up.
This is somewhat messy, but it's easier to isolate the whole thing here in one
function than to spread it about with zillions of conditionals in the normal
setting code.

Arguments:  none
Returns:    nothing
*/

void
out_warnbar(void)
{
BOOL done= FALSE;
int x = out_barx;
int count;

/* Loop for each column of signatures */

for (count = 0; !done; count++)
  {
  int maxwidth = 0;
  int ystave = out_yposition;
  int stave;

  /* Done remains TRUE if we don't actually print anything */

  done = TRUE;
  for (stave = 1; stave <= out_laststave; stave++)
    {
    if (mac_teststave2(curmovt->staves, out_sysblock->notsuspend, stave))
      {
      bstr *p = ((curmovt->stavetable)[stave])->barindex[out_bar];

      if (p != NULL)
        {
        int type = p->type;
        int thiscount = count;

        mac_setstavesize(stave);

        while (type != b_End)
          {
          switch(type)
            {
            case b_Jump:
            p = (bstr *)(((b_Jumpstr *)p)->next);
            break;

            case b_note:     /* Give up when hit a note */
            goto ENDSTAVE;
            break;

            case b_time:
            if (thiscount-- <= 0)
              {
              b_timestr *t = (b_timestr *)p;
              if (t->warn)
                {
                int xx = x;
                int spacing = (count == 0)? curmovt->timespacing :
                                            curmovt->startline->timespace;
                int width = spacing +
                  mac_muldiv(main_stavemagn, misc_timewidth(t->time) + 1000, 1000);
                if (width > maxwidth) maxwidth = width;
                if (count == 0) xx -= 2000;
                out_writetime(xx + spacing, ystave, t->time);
                done = FALSE;
                }
              goto ENDSTAVE;
              }
            break;

            /* If the key signature has zero width (C major, A minor, or a
            custom empty signature), ignore it completely. This occurs only
            when there has been a change from some other key, and it follows
            the cancellation signature. Leaving it in messes up the spacing for
            any subsequent time signature. */

            case b_key:
            if (misc_keywidth(((b_keystr *)p)->key, out_cont[stave].clef) != 0 &&
                thiscount-- <= 0)
              {
              b_keystr *k = (b_keystr *)p;
              if (k->warn)
                {
                int xx = x;
                int spacing = curmovt->keyspacing;
                int width = spacing +
                  mac_muldiv(main_stavemagn,
                             misc_keywidth(k->key, out_cont[stave].clef) + 1000,
                             1000);
                if (width > maxwidth) maxwidth = width;

                if (curmovt->keydoublebar && !out_lastbarwide)
                  {
                  int i;
                  int ybarend = ystave;
                  BOOL another =
                     (out_sysblock->notsuspend[stave >> 5] &
                       (-main_bit[stave & 0x1f])) > main_bit[stave & 0x1f];
                  if (!another)
                    for (i = (stave >> 5) + 1; i < STAVE_BITVEC_SIZE; i++)
                      if (out_sysblock->notsuspend[i] != 0)
                        { another = TRUE; break; }
                  if (another && mac_testNstave(curmovt->breakbarlines, stave))
                    ybarend += out_sysblock->stavespacing[stave];
                  ps_barline(out_lastbarlinex, ystave, ybarend, bar_double);
                  }
                else xx -= 1000;
                out_writekey(xx + spacing, ystave, out_cont[stave].clef, k->key);
                }
              done = FALSE;
              goto ENDSTAVE;
              }
            break;
            }

          p = (bstr *)((uschar *)p + length_table[type]);
          type = p->type;
          }
        }

      ENDSTAVE:
      ystave += out_sysblock->stavespacing[stave];
      }
    }
  x += maxwidth;
  }

/* Set a "last bar line" value as it is used for the stave length */

out_lastbarlinex = (out_sysblock->flags & sysblock_stretch)?
  curmovt->linelength : x + 2000;
}

/* End of setwarn.c */
