| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- import 'package:flutter/material.dart';
- import 'package:flutter/widgets.dart';
- import 'package:xterm/buffer/cell_flags.dart';
- import 'package:xterm/buffer/line/line.dart';
- import 'package:xterm/mouse/position.dart';
- import 'package:xterm/terminal/terminal_ui_interaction.dart';
- import 'package:xterm/theme/terminal_style.dart';
- import 'package:xterm/util/bit_flags.dart';
- import 'char_size.dart';
- import 'cache.dart';
- class TerminalPainter extends CustomPainter {
- TerminalPainter({
- required this.terminal,
- required this.style,
- required this.charSize,
- required this.textLayoutCache,
- });
- final TerminalUiInteraction terminal;
- final TerminalStyle style;
- final CellSize charSize;
- final TextLayoutCache textLayoutCache;
- @override
- void paint(Canvas canvas, Size size) {
- _paintBackground(canvas);
- // if (oscillator.value) {
- // }
- _paintText(canvas);
- _paintSelection(canvas);
- }
- void _paintBackground(Canvas canvas) {
- final lines = terminal.getVisibleLines();
- for (var row = 0; row < lines.length; row++) {
- final line = lines[row];
- final offsetY = row * charSize.cellHeight;
- // final cellCount = math.min(terminal.viewWidth, line.length);
- final cellCount = terminal.terminalWidth;
- for (var col = 0; col < cellCount; col++) {
- final cellWidth = line.cellGetWidth(col);
- if (cellWidth == 0) {
- continue;
- }
- final cellFgColor = line.cellGetFgColor(col);
- final cellBgColor = line.cellGetBgColor(col);
- final effectBgColor = line.cellHasFlag(col, CellFlags.inverse)
- ? cellFgColor
- : cellBgColor;
- if (effectBgColor == 0x00) {
- continue;
- }
- // when a program reports black as background then it "really" means transparent
- if (effectBgColor == 0xFF000000) {
- continue;
- }
- // final cellFlags = line.cellGetFlags(i);
- // final cell = line.getCell(i);
- // final attr = cell.attr;
- final offsetX = col * charSize.cellWidth;
- final effectWidth = charSize.cellWidth * cellWidth + 1;
- final effectHeight = charSize.cellHeight + 1;
- // background color is already painted with opacity by the Container of
- // TerminalPainter so wo don't need to fallback to
- // terminal.theme.background here.
- final paint = Paint()..color = Color(effectBgColor);
- canvas.drawRect(
- Rect.fromLTWH(offsetX, offsetY, effectWidth, effectHeight),
- paint,
- );
- }
- }
- }
- void _paintSelection(Canvas canvas) {
- final paint = Paint()..color = Colors.white.withOpacity(0.3);
- for (var y = 0; y < terminal.terminalHeight; y++) {
- final offsetY = y * charSize.cellHeight;
- final absoluteY = terminal.convertViewLineToRawLine(y) -
- terminal.scrollOffsetFromBottom;
- for (var x = 0; x < terminal.terminalWidth; x++) {
- var cellCount = 0;
- while (
- (terminal.selection?.contains(Position(x + cellCount, absoluteY)) ??
- false) &&
- x + cellCount < terminal.terminalWidth) {
- cellCount++;
- }
- if (cellCount == 0) {
- continue;
- }
- final offsetX = x * charSize.cellWidth;
- final effectWidth = cellCount * charSize.cellWidth;
- final effectHeight = charSize.cellHeight;
- canvas.drawRect(
- Rect.fromLTWH(offsetX, offsetY, effectWidth, effectHeight),
- paint,
- );
- x += cellCount;
- }
- }
- }
- void _paintText(Canvas canvas) {
- final lines = terminal.getVisibleLines();
- for (var row = 0; row < lines.length; row++) {
- final line = lines[row];
- final offsetY = row * charSize.cellHeight;
- // final cellCount = math.min(terminal.viewWidth, line.length);
- final cellCount = terminal.terminalWidth;
- for (var col = 0; col < cellCount; col++) {
- final width = line.cellGetWidth(col);
- if (width == 0) {
- continue;
- }
- final offsetX = col * charSize.cellWidth;
- _paintCell(canvas, line, col, offsetX, offsetY);
- }
- }
- }
- void _paintCell(
- Canvas canvas,
- BufferLine line,
- int cell,
- double offsetX,
- double offsetY,
- ) {
- final codePoint = line.cellGetContent(cell);
- final fgColor = line.cellGetFgColor(cell);
- final bgColor = line.cellGetBgColor(cell);
- final flags = line.cellGetFlags(cell);
- if (codePoint == 0 || flags.hasFlag(CellFlags.invisible)) {
- return;
- }
- // final cellHash = line.cellGetHash(cell);
- final cellHash = hashValues(codePoint, fgColor, bgColor, flags);
- var character = textLayoutCache.getLayoutFromCache(cellHash);
- if (character != null) {
- canvas.drawParagraph(character, Offset(offsetX, offsetY));
- return;
- }
- final cellColor = flags.hasFlag(CellFlags.inverse) ? bgColor : fgColor;
- var color = Color(cellColor);
- if (flags & CellFlags.faint != 0) {
- color = color.withOpacity(0.5);
- }
- final styleToUse = PaintHelper.getStyleToUse(
- style,
- color,
- bold: flags.hasFlag(CellFlags.bold),
- italic: flags.hasFlag(CellFlags.italic),
- underline: flags.hasFlag(CellFlags.underline),
- );
- character = textLayoutCache.performAndCacheLayout(
- String.fromCharCode(codePoint), styleToUse, cellHash);
- canvas.drawParagraph(character, Offset(offsetX, offsetY));
- }
- @override
- bool shouldRepaint(CustomPainter oldDelegate) {
- /// paint only when the terminal has changed since last paint.
- return terminal.dirty;
- }
- }
- class CursorPainter extends CustomPainter {
- final bool visible;
- final CellSize charSize;
- final bool focused;
- final bool blinkVisible;
- final int cursorColor;
- final int textColor;
- final String composingString;
- final TextLayoutCache textLayoutCache;
- final TerminalStyle style;
- CursorPainter({
- required this.visible,
- required this.charSize,
- required this.focused,
- required this.blinkVisible,
- required this.cursorColor,
- required this.textColor,
- required this.composingString,
- required this.textLayoutCache,
- required this.style,
- });
- @override
- void paint(Canvas canvas, Size size) {
- bool isVisible = visible && (blinkVisible || composingString != '');
- if (isVisible) {
- _paintCursor(canvas);
- }
- }
- @override
- bool shouldRepaint(covariant CustomPainter oldDelegate) {
- if (oldDelegate is CursorPainter) {
- return blinkVisible != oldDelegate.blinkVisible ||
- focused != oldDelegate.focused ||
- visible != oldDelegate.visible ||
- charSize.cellWidth != oldDelegate.charSize.cellWidth ||
- charSize.cellHeight != oldDelegate.charSize.cellHeight ||
- composingString != oldDelegate.composingString;
- }
- return true;
- }
- void _paintCursor(Canvas canvas) {
- final paint = Paint()
- ..color = Color(cursorColor)
- ..strokeWidth = focused ? 0.0 : 1.0
- ..style = focused ? PaintingStyle.fill : PaintingStyle.stroke;
- canvas.drawRect(
- Rect.fromLTWH(0, 0, charSize.cellWidth, charSize.cellHeight), paint);
- if (composingString != '') {
- final styleToUse = PaintHelper.getStyleToUse(style, Color(textColor));
- final character = textLayoutCache.performAndCacheLayout(
- composingString, styleToUse, null);
- canvas.drawParagraph(character, Offset(0, 0));
- }
- }
- }
- class PaintHelper {
- static TextStyle getStyleToUse(
- TerminalStyle style,
- Color color, {
- bool bold = false,
- bool italic = false,
- bool underline = false,
- }) {
- return (style.textStyleProvider != null)
- ? style.textStyleProvider!(
- color: color,
- fontSize: style.fontSize,
- fontWeight: bold ? FontWeight.bold : FontWeight.normal,
- fontStyle: italic ? FontStyle.italic : FontStyle.normal,
- decoration:
- underline ? TextDecoration.underline : TextDecoration.none,
- )
- : TextStyle(
- color: color,
- fontSize: style.fontSize,
- fontWeight: bold ? FontWeight.bold : FontWeight.normal,
- fontStyle: italic ? FontStyle.italic : FontStyle.normal,
- decoration:
- underline ? TextDecoration.underline : TextDecoration.none,
- fontFamily: 'monospace',
- fontFamilyFallback: style.fontFamily,
- );
- }
- }
|