renderContainerContent function
String
renderContainerContent({
- required String contentStr,
- EdgeInsets? padding,
- EdgeInsets? margin,
- num? width,
- num? height,
- Color? background,
- Color? foreground,
- Color? color,
- Decoration? decoration,
- Decoration? foregroundDecoration,
- Alignment? alignment,
- HorizontalAlign align = HorizontalAlign.left,
- VerticalAlign verticalAlign = VerticalAlign.top,
Implementation
String renderContainerContent({
required String contentStr,
EdgeInsets? padding,
EdgeInsets? margin,
num? width,
num? height,
Color? background,
Color? foreground,
Color? color,
Decoration? decoration,
Decoration? foregroundDecoration,
Alignment? alignment,
HorizontalAlign align = HorizontalAlign.left,
VerticalAlign verticalAlign = VerticalAlign.top,
}) {
final span = TuiTrace.begin(
'renderContainerContent',
tag: TraceTag.paint,
extra: 'w=$width h=$height',
);
final contentWidth = Layout.getWidth(contentStr);
final contentHeight = Layout.getHeight(contentStr);
// Extract BoxDecoration fields.
final boxDecoration = decoration is BoxDecoration ? decoration : null;
final border = boxDecoration?.border;
final borderRadius = boxDecoration?.borderRadius;
final gradient = boxDecoration?.gradient;
// Compute border edge sizes (each edge consumes cells).
final borderLeft = border != null && border.isVisible
? border.getLeftSize()
: 0;
final borderRight = border != null && border.isVisible
? border.getRightSize()
: 0;
final borderTop = border != null && border.isVisible
? border.getTopSize()
: 0;
final borderBottom = border != null && border.isVisible
? border.getBottomSize()
: 0;
final borderH = borderLeft + borderRight;
final borderV = borderTop + borderBottom;
final hasBorder = border != null && border.isVisible;
final hasGradient = gradient != null && gradient.colors.length >= 2;
final padLeft = roundClamp(padding?.left ?? 0);
final padRight = roundClamp(padding?.right ?? 0);
final padTop = roundClamp(padding?.top ?? 0);
final padBottom = roundClamp(padding?.bottom ?? 0);
final marginLeft = roundClamp(margin?.left ?? 0);
final marginRight = roundClamp(margin?.right ?? 0);
final marginTop = roundClamp(margin?.top ?? 0);
final marginBottom = roundClamp(margin?.bottom ?? 0);
// Inner width/height includes border + padding + content.
final paddedWidth = contentWidth + padLeft + padRight + borderH;
final paddedHeight = contentHeight + padTop + padBottom + borderV;
final resolvedWidth = resolveDimension(width);
final resolvedHeight = resolveDimension(height);
final innerWidth = resolvedWidth ?? paddedWidth;
final innerHeight = resolvedHeight ?? paddedHeight;
final targetWidth = innerWidth + marginLeft + marginRight;
final targetHeight = innerHeight + marginTop + marginBottom;
if (targetWidth == 0 || targetHeight == 0) {
span.end(extra: 'empty');
return '';
}
final bgColor = colorToUvColor(color ?? decoration?.color ?? background);
final fgColor = colorToUvColor(foregroundDecoration?.color ?? foreground);
final bgStyle = UvStyle(bg: bgColor, fg: fgColor);
final hasVisualStyle =
bgColor != null || fgColor != null || hasBorder || hasGradient;
if (!hasVisualStyle &&
padLeft == 0 &&
padRight == 0 &&
padTop == 0 &&
padBottom == 0 &&
marginLeft == 0 &&
marginRight == 0 &&
marginTop == 0 &&
marginBottom == 0 &&
targetWidth == contentWidth &&
targetHeight == contentHeight) {
span.end(extra: 'passthrough size=${targetWidth}x$targetHeight');
return contentStr;
}
// Compute alignment and content offset (inside border + padding).
final resolvedAlign = alignment == null
? align
: horizontalFromAlignment(alignment);
final resolvedVertical = alignment == null
? verticalAlign
: verticalFromAlignment(alignment);
final availableWidth = math.max(0, innerWidth - padLeft - padRight - borderH);
final availableHeight = math.max(
0,
innerHeight - padTop - padBottom - borderV,
);
final alignedX = resolvedWidth != null
? offsetForHorizontal(resolvedAlign, availableWidth, contentWidth)
: 0;
final alignedY = resolvedHeight != null
? offsetForVertical(resolvedVertical, availableHeight, contentHeight)
: 0;
final offsetX = marginLeft + borderLeft + padLeft + alignedX;
final offsetY = marginTop + borderTop + padTop + alignedY;
if (!hasVisualStyle &&
offsetX >= 0 &&
offsetY >= 0 &&
!needsPlainContainerCanvasComposition(contentStr)) {
final result = renderPlainContainerContent(
content: contentStr,
contentHeight: contentHeight,
targetWidth: targetWidth,
targetHeight: targetHeight,
marginLeft: marginLeft,
marginTop: marginTop,
padLeft: padLeft,
padTop: padTop,
alignedX: alignedX,
alignedY: alignedY,
);
span.end(extra: 'plain size=${targetWidth}x$targetHeight');
return result;
}
final canvas = Canvas(targetWidth, targetHeight);
// Fill inner area (inside margin, including border) with background cells.
if (!bgStyle.isZero) {
final bgCell = Cell(content: ' ', width: 1, style: bgStyle);
for (var y = marginTop; y < marginTop + innerHeight; y++) {
for (var x = marginLeft; x < marginLeft + innerWidth; x++) {
canvas.setCell(x, y, bgCell.clone());
}
}
}
// Apply gradient to background cells (inside border, row-by-row).
if (hasGradient) {
final gradientAreaTop = marginTop + borderTop;
final gradientAreaHeight = math.max(0, innerHeight - borderV);
if (gradientAreaHeight > 0) {
final gradientColors = blend1D(
gradientAreaHeight,
gradient.colors,
hasDarkBackground: hasDarkBackground,
);
for (var row = 0; row < gradientAreaHeight; row++) {
final rowColor = colorToUvColor(gradientColors[row]);
final rowStyle = UvStyle(bg: rowColor, fg: fgColor);
final rowCell = Cell(content: ' ', width: 1, style: rowStyle);
final y = gradientAreaTop + row;
for (
var x = marginLeft + borderLeft;
x < marginLeft + innerWidth - borderRight;
x++
) {
canvas.setCell(x, y, rowCell.clone());
}
}
}
}
// Draw content.
if (contentStr.isNotEmpty) {
// Use the gradient-aware bg style for the content area: if gradient is
// active, the row-specific bg is already on the canvas cells and
// _drawStyledContent merges bg from bgStyle only when the source cell
// has no bg. We pass the base bgStyle here; for gradient containers the
// canvas already has per-row bg so the merge is harmless.
drawStyledContent(
canvas,
contentStr,
offsetX,
offsetY,
bgStyle,
contentWidth: contentWidth,
contentHeight: contentHeight,
);
}
// Draw border characters onto the canvas.
if (hasBorder) {
final bx = marginLeft; // border area origin x
final by = marginTop; // border area origin y
final bw = innerWidth; // border area width
final bh = innerHeight; // border area height
// Resolve corner characters (apply borderRadius).
var cornerTL = border.topLeft;
var cornerTR = border.topRight;
var cornerBL = border.bottomLeft;
var cornerBR = border.bottomRight;
if (borderRadius != null) {
if (borderRadius.topLeft > 0) cornerTL = '╭';
if (borderRadius.topRight > 0) cornerTR = '╮';
if (borderRadius.bottomLeft > 0) cornerBL = '╰';
if (borderRadius.bottomRight > 0) cornerBR = '╯';
}
final borderStyle = UvStyle(bg: bgColor, fg: fgColor);
// Top-left corner.
if (cornerTL.isNotEmpty) {
canvas.setCell(
bx,
by,
Cell(content: cornerTL, width: 1, style: borderStyle),
);
}
// Top-right corner.
if (cornerTR.isNotEmpty) {
canvas.setCell(
bx + bw - 1,
by,
Cell(content: cornerTR, width: 1, style: borderStyle),
);
}
// Bottom-left corner.
if (cornerBL.isNotEmpty) {
canvas.setCell(
bx,
by + bh - 1,
Cell(content: cornerBL, width: 1, style: borderStyle),
);
}
// Bottom-right corner.
if (cornerBR.isNotEmpty) {
canvas.setCell(
bx + bw - 1,
by + bh - 1,
Cell(content: cornerBR, width: 1, style: borderStyle),
);
}
// Top edge.
if (border.top.isNotEmpty) {
for (var x = bx + borderLeft; x < bx + bw - borderRight; x++) {
canvas.setCell(
x,
by,
Cell(content: border.top, width: 1, style: borderStyle),
);
}
}
// Bottom edge.
if (border.bottom.isNotEmpty) {
for (var x = bx + borderLeft; x < bx + bw - borderRight; x++) {
canvas.setCell(
x,
by + bh - 1,
Cell(content: border.bottom, width: 1, style: borderStyle),
);
}
}
// Left edge.
if (border.left.isNotEmpty) {
for (var y = by + borderTop; y < by + bh - borderBottom; y++) {
canvas.setCell(
bx,
y,
Cell(content: border.left, width: 1, style: borderStyle),
);
}
}
// Right edge.
if (border.right.isNotEmpty) {
for (var y = by + borderTop; y < by + bh - borderBottom; y++) {
canvas.setCell(
bx + bw - 1,
y,
Cell(content: border.right, width: 1, style: borderStyle),
);
}
}
}
var result = canvas.render();
if (resolvedWidth != null ||
resolvedHeight != null ||
marginLeft > 0 ||
marginRight > 0 ||
marginTop > 0 ||
marginBottom > 0) {
result = padToWidth(result, targetWidth, targetHeight);
}
span.end(extra: 'size=${targetWidth}x$targetHeight');
return result;
}