performLayout method

void performLayout(
  1. ChantContext ctxt
)

Implementation

void performLayout(ChantContext ctxt) {
  final staffSpaces = this.staffSpaces;
  final staffLineCount = score.staffLineCount;
  final theme = ctxt.theme;
  notationBounds = Rect.fromXYWH(
    staffLeft,
    -(ctxt.staffLineWeight / 2 +
            staffLineCount * 2 -
            1 +
            theme.minSpaceAboveStaff) *
        ctxt.staffInterval,
    staffRight - staffLeft,
    (ctxt.staffLineWeight + (staffSpaces * 2) + theme.minSpaceAboveStaff) *
        ctxt.staffInterval,
  );

  var notations = score.notations;
  int lastNeumeIndex = extraTextOnlyIndex == null
      ? notationsStartIndex + numNotationsOnLine
      : extraTextOnlyIndex!;
  int lastIndex = notationsStartIndex + numNotationsOnLine;
  ChantNotationElement notation;

  notationBounds += startingClef!.bounds;

  lyricLineHeight =
      ctxt.textStyles['lyric']['size'] *
      (ctxt.textStyles['lyric']['lineHeight'] ?? 1.1);
  lyricLineBaseline = 0;
  numLyricLines = 0;

  altLineHeight = 0;
  altLineBaseline = 0;
  numAltLines = 0;

  translationLineHeight =
      ctxt.textStyles['translation']['size'] *
      (ctxt.textStyles['translation']['lineHeight'] ?? 1.1);
  translationLineBaseline = 0;
  numTranslationLines = 0;

  final aboveLinesLineHeight =
      ctxt.textStyles['al']['size'] *
      (ctxt.textStyles['al']['lineHeight'] ?? 1.1);

  for (int i = notationsStartIndex; i < lastNeumeIndex; i++) {
    notation = notations[i];

    if (notation.bounds.height != 0 || notation.bounds.width != 0) {
      notationBounds += notation.bounds;
    }

    if (notation.lyrics.isNotEmpty && notation.lyrics[0].text.isNotEmpty) {
      if (notation.lyrics[0].origin.y > lyricLineBaseline) {
        lyricLineBaseline = notation.lyrics[0].origin.y;
      }
      if (notation.lyrics.length > numLyricLines) {
        numLyricLines = notation.lyrics.length;
      }
    }

    if (notation.alText.isNotEmpty && numAltLines < notation.alText.length) {
      if (notation.alText[0].bounds.height > altLineHeight) {
        altLineHeight = notation.alText[0].bounds.height;
      }
      if (notation.alText[0].origin.y > altLineBaseline) {
        altLineBaseline = notation.alText[0].origin.y;
      }
      if (notation.alText.length > numAltLines) {
        numAltLines = notation.alText.length;
      }
    }

    if (notation.translationText.isNotEmpty &&
        notation.translationText[0].text.isNotEmpty) {
      if (notation.translationText[0].origin.y > translationLineBaseline) {
        translationLineBaseline = notation.translationText[0].origin.y;
      }
      if (notation.translationText.length > numTranslationLines) {
        numTranslationLines = notation.translationText.length;
      }
    }
  }

  if (custos != null) notationBounds += custos!.bounds;

  for (var brace in braces) {
    notationBounds += brace.bounds;
  }

  final notationBoundsOffset =
      notationBounds.bottom + theme.minSpaceBelowStaff * ctxt.staffInterval;
  lyricLineBaseline += notationBoundsOffset;
  translationLineBaseline += notationBoundsOffset;
  altLineBaseline +=
      notationBounds.y - altLineHeight - ctxt.staffInterval * 0.5;

  for (int i = notationsStartIndex; i < lastNeumeIndex; i++) {
    notation = notations[i];
    double offset = 0;
    for (int j = 0; j < notation.lyrics.length; j++) {
      notation.lyrics[j].bounds = notation.lyrics[j].bounds.copyWith(
        y: offset + lyricLineBaseline,
      );
      offset += lyricLineHeight;
    }

    for (int j = 0; j < notation.translationText.length; j++) {
      notation.translationText[j].bounds = notation.translationText[j].bounds
          .copyWith(y: offset + translationLineBaseline);
      offset += translationLineHeight;
    }

    offset = 0;
    for (int j = 0; j < notation.alText.length; j++) {
      notation.alText[j].bounds = notation.alText[j].bounds.copyWith(
        y: offset + altLineBaseline,
      );
      offset -= aboveLinesLineHeight;
    }
  }

  extraTextOnlyHeight = 0;
  if (ctxt.useExtraTextOnly) {
    int extraTextOnlyLyricIndex = this.extraTextOnlyLyricIndex;
    if (extraTextOnlyIndex == null) {
      var lastNotation = lastNeumeIndex > 0
          ? notations[lastNeumeIndex - 1]
          : null;
      if (lastNotation is ChantLineBreak) {
        lastNotation = (lastNeumeIndex > 1)
            ? notations[lastNeumeIndex - 2]
            : null;
      }
      if (lastNotation is TextOnly &&
          lastNotation.lyrics.length == 1 &&
          lastNotation.lyrics[0].bounds.height > lyricLineHeight) {
        extraTextOnlyHeight = lyricLineHeight;
      }
    } else {
      Lyric lastLyric;
      double xOffset = 0;
      double offset = (numLyricLines - 1) * lyricLineHeight;
      offset += numTranslationLines * translationLineHeight;
      int extraLines = 0;
      for (int i = extraTextOnlyIndex!; i < lastIndex; i++) {
        notation = notations[i];
        if (notation.lyrics.length <= extraTextOnlyLyricIndex) continue;
        lastLyric = notation.lyrics[extraTextOnlyLyricIndex];
        if (lastLyric.lineWidth != null) {
          xOffset = staffRight - lastLyric.lineWidth!;
          offset += lyricLineHeight;
          extraLines++;
        }
        extraLines += lastLyric.numLines - 1;
        lastLyric.bounds = lastLyric.bounds.copyWith(
          y: offset + lyricLineBaseline,
        );
        notation.bounds = notation.bounds.copyWith(
          x: notation.bounds.x + xOffset,
        );
      }
      extraTextOnlyHeight = lyricLineHeight * extraLines;
    }
  }

  if (startingClef!.hasLyrics) {
    double offset = 0;
    for (int j = 0; j < startingClef!.lyrics.length; j++) {
      startingClef!.lyrics[j].bounds = startingClef!.lyrics[j].bounds
          .copyWith(y: offset + lyricLineBaseline);
      offset += lyricLineHeight;
    }
  }

  if (notationsStartIndex == 0) {
    if (score.annotation case Annotations a) {
      a.bounds = a.bounds.copyWith(
        x: staffLeft / 2,
        y: -ctxt.staffInterval * (staffLineCount * 2 - 1),
      );
      if (score.dropCap case DropCap dc) {
        final dcHeight = ctxt.textMeasurer.measureMHeight(dc, ctxt);
        final lOffset = ctxt.textMeasurer.align == .baseline
            ? 0
            : lyricLineHeight;
        final highestNonCollidingY =
            lyricLineBaseline -
            a.bounds.height +
            a.origin.y +
            lOffset -
            a.padding -
            dcHeight;
        a.bounds = a.bounds.copyWith(
          y: highestNonCollidingY < a.bounds.y
              ? highestNonCollidingY
              : (a.bounds.y + highestNonCollidingY) / 2,
        );
        if (a.bounds.y < notationBounds.y) {
          notationBounds = notationBounds.copyWith(
            y: score.annotation!.bounds.y,
            height: notationBounds.height + notationBounds.y - a.bounds.y,
          );
        }
      }
      a.bounds = a.bounds.copyWith(y: a.bounds.y + a.origin.y);
    }

    if (score.dropCap case DropCap dc) {
      dc.bounds = dc.bounds.copyWith(
        x: staffLeft / 2,
        y: lyricLineBaseline - dc.origin.y + dc.baselineOffset(ctxt),
      );
      notationBounds += dc.bounds;
      if (ctxt.textMeasurer.align == .baseline) {
        dc.bounds = dc.bounds.copyWith(y: lyricLineBaseline);
      }
    }
  }

  if (numLyricLines > 0) {
    final lyricAndTextRect = Rect.fromXYWH(
      0,
      notationBoundsOffset,
      0,
      lyricLineHeight * numLyricLines +
          extraTextOnlyHeight +
          translationLineHeight * numTranslationLines,
    );
    notationBounds += lyricAndTextRect;
  }
  if (numAltLines > 0) {
    final altLineTextRect = Rect.fromXYWH(
      0,
      notationBounds.y -
          altLineHeight -
          0.5 * ctxt.staffInterval -
          aboveLinesLineHeight * (numAltLines - 1),
      0,
      aboveLinesLineHeight * numAltLines,
    );
    notationBounds += altLineTextRect;
  }
  notationBounds += Rect.fromXYWH(
    0,
    -ctxt.staffInterval,
    0,
    (ctxt.staffLineWeight / 2 + theme.minSpaceBelowStaff) *
        ctxt.staffInterval,
  );
  double totalHeight = notationBounds.height;

  bounds = bounds.copyWith(
    x: 0,
    y: notationBounds.y,
    width: notationBounds.right,
    height: totalHeight,
  );

  origin = Point(staffLeft, -notationBounds.y);
}