dartterm/lib/terminal.dart

164 lines
3.1 KiB
Dart
Raw Normal View History

2023-09-06 23:38:53 +00:00
import 'package:dartterm/colors.dart';
2023-09-06 03:11:15 +00:00
import 'package:dartterm/cp437.dart';
import 'package:dartterm/fonts.dart';
import 'package:dartterm/terminal_painter.dart';
import 'package:flutter/material.dart';
class Terminal {
static const int width = 88;
2023-09-06 23:45:34 +00:00
static const int height = 50;
2023-09-06 03:11:15 +00:00
static const int nTiles = width * height;
late List<Tile> tiles;
Terminal() {
tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()];
}
CustomPaint toWidget(BuildContext context) {
var scalingFactor = MediaQuery.devicePixelRatioOf(context);
return CustomPaint(painter: TerminalCustomPainter(this, scalingFactor));
}
(int, int)? toXY(int i) {
if (i < 0 || i > nTiles) {
return null;
}
return (i % width, i ~/ width);
}
int? fromXY(int x, int y) {
if (x < 0 || x >= width) {
return null;
}
if (y < 0 || y >= height) {
return null;
}
return x + y * width;
}
}
2023-09-10 01:40:56 +00:00
class Cursor {
final Terminal t;
int x, y;
Color? _bg, _fg;
Font font = Font.normal;
// TODO: Clip
Cursor({required this.t, required this.x, required this.y});
void clear() {
t.tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()];
}
void putc(int c) {
for (var dx = 0; dx < font.cellWidth; dx += 1) {
for (var dy = 0; dy < font.cellHeight; dy += 1) {
var i = t.fromXY(x + dx, y + dy);
if (i != null) {
final (sourceCx, sourceCy) = (
(c % font.nCellsW) * font.cellWidth + dx,
(c ~/ font.nCellsW) * font.cellHeight + dy
);
t.tiles[i].content = Content(font.imageName, sourceCx, sourceCy);
final (bg, fg) = (_bg, _fg);
if (bg != null) {
t.tiles[i].bg = bg;
}
if (fg != null) {
t.tiles[i].fg = fg;
}
}
}
}
}
void puts(String s) {
var startX = x;
for (final c in toCp437String(s)) {
if (c == 10) {
// newline
x = startX;
y += font.cellHeight;
continue;
}
if (c == 13) {
// carriage return
x = startX;
continue;
}
putc(c);
x += font.cellWidth;
}
}
Cursor fg(Color c) {
_fg = c;
return this;
}
Cursor bg(Color c) {
_bg = c;
return this;
}
Cursor small() {
font = Font.small;
return this;
}
Cursor normal() {
font = Font.normal;
return this;
}
Cursor big() {
font = Font.big;
return this;
}
}
class Clip {}
2023-09-06 03:11:15 +00:00
class Tile {
Content? content;
Color bg;
Color fg;
Tile(this.content, this.bg, this.fg);
2023-09-06 23:38:53 +00:00
static Tile empty() => Tile(null, Palette.defaultBg, Palette.defaultFg);
2023-09-06 03:11:15 +00:00
}
class Content {
final String sourceImage;
final int sourceCx;
final int sourceCy;
const Content(this.sourceImage, this.sourceCx, this.sourceCy);
}
// reexports
2023-09-10 01:40:56 +00:00
Terminal _terminal = Terminal();
2023-09-06 03:11:15 +00:00
const int width = Terminal.width;
const int height = Terminal.height;
const int nTiles = Terminal.nTiles;
Widget toWidget(BuildContext context) {
2023-09-10 01:40:56 +00:00
return _terminal.toWidget(context);
}
void clear() {
at(0, 0).clear();
}
Cursor at(int x, int y) {
return Cursor(t: _terminal, x: x, y: y);
2023-09-06 03:11:15 +00:00
}