paint method

  1. @override
void paint(
  1. PaintingContext context,
  2. Offset offset
)
override

Default paint implementation.

RenderBox paints no self-content; it forwards painting to its RenderBox children. Subclasses override to draw their own content.

Implementation

@override
void paint(PaintingContext context, Offset offset) {
  final originX = offset.dx + x;
  final originY = offset.dy + y;
  final canvas = context.canvas;
  final visualLayout = _ensureVisualLayout(width);
  final cursor = visualLayout.positionForOffset(
    _cursorSourceOffset(),
    affinity: _cursorAffinity,
  );
  var effectiveScrollLine = _scrollLine.clamp(
    0,
    (visualLayout.lines.length - height).clamp(0, visualLayout.lines.length),
  );
  if (_focused && (_softWrap || _maxHeightLines != null) && height > 0) {
    if (cursor.row < effectiveScrollLine) {
      effectiveScrollLine = cursor.row;
    } else if (cursor.row >= effectiveScrollLine + height) {
      effectiveScrollLine = cursor.row - height + 1;
    }
  }
  var effectiveScrollCell = _softWrap ? 0 : _scrollCell;
  if (_focused && _maxHeightLines != null && !_softWrap && width > 0) {
    if (cursor.cell < effectiveScrollCell) {
      effectiveScrollCell = cursor.cell;
    } else if (cursor.cell >= effectiveScrollCell + width) {
      effectiveScrollCell = cursor.cell - width + 1;
    }
  }

  if (_backgroundColor != null) {
    canvas.fillRect(
      Rect.fromLTWH(originX, originY, width, height),
      _backgroundColor!,
    );
  }

  final isEmpty = _lines.length == 1 && _lines[0].isEmpty;
  if (isEmpty && _placeholder != null && !_focused) {
    // Render placeholder dimmed on first row only, cell-aware.
    final dim = Color(
      _color.r * 0.5,
      _color.g * 0.5,
      _color.b * 0.5,
      _color.a,
    );
    final ph = _placeholder!;
    var col = 0;
    for (final cluster in ph.characters) {
      final cw = terminalCellWidth(cluster);
      if (col + cw > width) break;
      canvas.drawText(
        cluster,
        Offset(originX + col, originY),
        dim,
        background: _backgroundColor,
      );
      col += cw;
    }
  } else {
    for (var row = 0; row < height; row++) {
      final lineIdx = effectiveScrollLine + row;
      if (lineIdx >= visualLayout.lines.length) break;
      final line = visualLayout.lines[lineIdx];
      var cellAccum = 0;
      var paintedCol = 0;
      paintLine:
      for (final run in line.runs) {
        for (final cluster in run.text.characters) {
          final clusterWidth = terminalCellWidth(cluster);
          if (cellAccum + clusterWidth <= effectiveScrollCell) {
            cellAccum += clusterWidth;
            continue;
          }
          // If a wide cluster straddles the left edge, drop it whole.
          if (cellAccum < effectiveScrollCell) {
            cellAccum += clusterWidth;
            continue;
          }
          if (paintedCol + clusterWidth > width) break paintLine;
          canvas.drawText(
            cluster,
            Offset(originX + paintedCol, originY + row),
            _color,
            background: _backgroundColor,
          );
          paintedCol += clusterWidth;
          cellAccum += clusterWidth;
        }
      }
    }
  }

  if (_focused) {
    final cursorRow = cursor.row - effectiveScrollLine;
    final cursorCell = _softWrap && width > 0 && cursor.cell >= width
        ? width - 1
        : cursor.cell;
    final cursorCol = cursorCell - effectiveScrollCell;
    if (cursorRow >= 0 &&
        cursorRow < height &&
        cursorCol >= 0 &&
        cursorCol < width) {
      _cursorController.showCursor(
        this,
        originX + cursorCol,
        originY + cursorRow,
        style: _cursorStyle,
        color: _cursorColor,
      );
    } else {
      _cursorController.hideCursorFor(this);
    }
  } else {
    _cursorController.hideCursorFor(this);
  }
}