paint method

  1. @override
String paint()
override

Implementation

@override
String paint() {
  if (children.isEmpty) return '';
  final child = children.first;
  final content = child.paint();

  // Use the layout-allocated child size for positioning, not the painted
  // output dimensions.  The painted output's visible width can vary per
  // line (shorter text lines, ANSI escapes, etc.) which causes the
  // scrollbar to shift left/right.  The layout size is stable.
  final layoutW = child.size.width.toInt();
  final layoutH = child.size.height.toInt();
  // Fall back to painted dimensions only when layout reports zero.
  final paintedSize = Layout.getSize(content);
  final stableW = layoutW > 0 ? layoutW : paintedSize.width;
  final stableH = layoutH > 0 ? layoutH : paintedSize.height;
  if (stableW <= 0 || stableH <= 0) {
    return content;
  }

  var thumbWidth = math.max(1, thickness);
  final trackWidth = math.max(thumbWidth, gutterWidth ?? thumbWidth);
  final isHovered = hovered || _hoveredScrollbars.contains(zoneId);
  final effectiveTrackStyle = isHovered
      ? (hoverTrackStyle ?? trackStyle)
      : trackStyle;
  final effectiveThumbStyle = isHovered
      ? (hoverThumbStyle ?? thumbStyle)
      : thumbStyle;
  final effectiveTrackGradient = isHovered
      ? (hoverTrackGradient ?? trackGradient)
      : trackGradient;
  final effectiveThumbGradient = isHovered
      ? (hoverThumbGradient ?? thumbGradient)
      : thumbGradient;
  final effectiveTrackChar = isHovered
      ? (hoverTrackChar ?? trackChar)
      : trackChar;
  final effectiveThumbChar = isHovered
      ? (hoverThumbChar ?? thumbChar)
      : thumbChar;
  final expandThumbToTrack =
      thumbUsesBackground && effectiveThumbChar.trim().isEmpty;
  if (expandThumbToTrack && trackWidth > thumbWidth) {
    thumbWidth = trackWidth;
  }

  final allowCaps =
      roundedCaps && !thumbUsesBackground && effectiveThumbChar != ' ';
  final capTop = thumbCapTopChar ?? (allowCaps ? '▀' : null);
  final capBottom = thumbCapBottomChar ?? (allowCaps ? '▄' : null);
  final bar = _renderScrollbar(
    controller: controller,
    height: stableH,
    trackWidth: trackWidth,
    thumbWidth: thumbWidth,
    trackStyle: effectiveTrackStyle,
    thumbStyle: effectiveThumbStyle,
    trackGradient: effectiveTrackGradient,
    thumbGradient: effectiveThumbGradient,
    trackUsesBackground: trackUsesBackground,
    thumbUsesBackground: thumbUsesBackground,
    trackChar: effectiveTrackChar,
    thumbChar: effectiveThumbChar,
    thumbCapTopChar: capTop,
    thumbCapBottomChar: capBottom,
    zoneId: zoneId,
  );
  if (bar.isEmpty) return content;

  if (!overlay) {
    // Use a canvas to position the scrollbar at a stable offset based on
    // the layout-allocated width rather than the painted content width.
    final gapW = math.max(0, gap);
    final totalW = stableW + gapW + trackWidth;
    final canvas = Canvas(totalW, stableH);
    _drawStyledContent(canvas, content, 0, 0);
    final barX = stableW + gapW;
    _drawStyledContent(canvas, bar, barX, 0);
    return canvas.render();
  }

  final canvas = Canvas(stableW, stableH);
  _drawStyledContent(canvas, content, 0, 0);
  final barX = math.max(0, stableW - trackWidth);
  final barOverwritesSpaces =
      trackUsesBackground ||
      thumbUsesBackground ||
      (effectiveTrackGradient?.useBackground ?? false) ||
      (effectiveThumbGradient?.useBackground ?? false);
  _drawStyledContent(
    canvas,
    bar,
    barX,
    0,
    treatSpacesAsTransparent: !barOverwritesSpaces,
  );
  return canvas.render();
}