performLayout method
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);
}