Add alignment to text display
This commit is contained in:
parent
2bedecb677
commit
a571d6cc2a
|
|
@ -138,6 +138,11 @@ export enum Glyphs {
|
|||
DIAMOND = '♦',
|
||||
}
|
||||
|
||||
export enum AlignHorizontal {
|
||||
LEFT = 'left',
|
||||
RIGHT = 'right',
|
||||
}
|
||||
|
||||
export const isVertical = (char: string) => char === Glyphs.SINGLE_VERTICAL || char === Glyphs.DOUBLE_VERTICAL;
|
||||
export const isHorizontal = (char: string) => char === Glyphs.SINGLE_HORIZONTAL || char === Glyphs.DOUBLE_HORIZONTAL;
|
||||
export const isCorner = (char: string) => [
|
||||
|
|
@ -145,7 +150,14 @@ export const isCorner = (char: string) => [
|
|||
Glyphs.DOUBLE_TOP_LEFT, Glyphs.DOUBLE_TOP_RIGHT, Glyphs.DOUBLE_BOTTOM_LEFT, Glyphs.DOUBLE_BOTTOM_RIGHT,
|
||||
].includes(char as Glyphs);
|
||||
|
||||
interface BoxOptions {
|
||||
interface StringOptions {
|
||||
fg?: ColorLike;
|
||||
bg?: ColorLike;
|
||||
alignH?: AlignHorizontal;
|
||||
anchorH?: AlignHorizontal;
|
||||
}
|
||||
|
||||
interface BoxOptions extends StringOptions {
|
||||
vertical?: string;
|
||||
horizontal?: string;
|
||||
topLeft?: string;
|
||||
|
|
@ -153,8 +165,6 @@ interface BoxOptions {
|
|||
bottomLeft?: string;
|
||||
bottomRight?: string;
|
||||
fill?: Char;
|
||||
fg?: ColorLike;
|
||||
bg?: ColorLike;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
|
|
@ -313,9 +323,14 @@ export class TextDisplay {
|
|||
return [this.chars[y * this.width + x], this.fgs[y * this.width + x], this.bgs[y * this.width + x]];
|
||||
}
|
||||
|
||||
setRegion(x: number, y: number, region: TextRegion) {
|
||||
setRegion(region: TextRegion, x: number, y: number, anchorH = AlignHorizontal.LEFT) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
|
||||
if (anchorH === AlignHorizontal.RIGHT) {
|
||||
x -= region.width + 1;
|
||||
}
|
||||
|
||||
const { chars, fgs, bgs } = region[REGION_DATA];
|
||||
const rw = region.width;
|
||||
const x0 = Math.max(this.clipLeft, x);
|
||||
|
|
@ -375,15 +390,31 @@ export class TextDisplay {
|
|||
return new TextRegion(data);
|
||||
}
|
||||
|
||||
drawString(text: unknown, x: number, y: number, fg: ColorLike = DEFAULT_FG, bg: ColorLike = DEFAULT_BG) {
|
||||
drawString(
|
||||
text: unknown, x: number, y: number,
|
||||
options: StringOptions,
|
||||
) {
|
||||
x = x | 0; y = y | 0;
|
||||
const {
|
||||
fg = DEFAULT_FG,
|
||||
bg = DEFAULT_BG,
|
||||
alignH = AlignHorizontal.LEFT,
|
||||
anchorH = AlignHorizontal.LEFT,
|
||||
} = options;
|
||||
const lines = String(text).split('\n');
|
||||
const maxWidth = lines.reduce((m, line) => Math.max(m, line.length), 0);
|
||||
|
||||
if (anchorH === AlignHorizontal.RIGHT) {
|
||||
x -= maxWidth - 1;
|
||||
}
|
||||
|
||||
for (let row = 0; row < lines.length; row++) {
|
||||
const line = lines[row];
|
||||
let line = lines[row];
|
||||
const ry = y + row;
|
||||
if (ry < this.clipTop || ry >= this.clipBottom) continue;
|
||||
const offset = alignH === AlignHorizontal.RIGHT ? maxWidth - line.length : 0;
|
||||
for (let col = 0; col < line.length; col++) {
|
||||
this.setCharRaw(x + col, ry, line[col], fg, bg);
|
||||
this.setCharRaw(x + col + offset, ry, line[col], fg, bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -428,8 +459,13 @@ export class TextDisplay {
|
|||
bg = DEFAULT_BG,
|
||||
fill,
|
||||
title,
|
||||
anchorH = AlignHorizontal.LEFT,
|
||||
} = options;
|
||||
|
||||
if (anchorH === AlignHorizontal.RIGHT) {
|
||||
x -= width + 1;
|
||||
}
|
||||
|
||||
this.setCharRaw(x, y, topLeft, fg, bg);
|
||||
this.setCharRaw(x + width + 1, y, topRight, fg, bg);
|
||||
this.setCharRaw(x, y + height + 1, bottomLeft, fg, bg);
|
||||
|
|
@ -446,7 +482,7 @@ export class TextDisplay {
|
|||
this.drawVLine(x + width + 1, y + 1, y + height, [vertical, fg, bg]);
|
||||
|
||||
if (title) {
|
||||
this.drawString(title, x + 1, y, fg, bg);
|
||||
this.drawString(title, x + 1, y, { fg, bg });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -455,13 +491,26 @@ export class TextDisplay {
|
|||
const {
|
||||
fg = DEFAULT_FG,
|
||||
bg = DEFAULT_BG,
|
||||
alignH = AlignHorizontal.LEFT,
|
||||
anchorH = AlignHorizontal.LEFT,
|
||||
title,
|
||||
} = options;
|
||||
const lines = String(text).split('\n');
|
||||
const width = lines.reduce((m, line) => Math.max(m, line.length), 0);
|
||||
const textWidth = lines.reduce((m, line) => Math.max(m, line.length), 0);
|
||||
const height = lines.length;
|
||||
|
||||
let width = textWidth;
|
||||
if (title) {
|
||||
width = Math.max(width, title.length);
|
||||
}
|
||||
|
||||
let dx = anchorH === AlignHorizontal.RIGHT ? -1 : 1;
|
||||
if (alignH === AlignHorizontal.LEFT && anchorH === AlignHorizontal.RIGHT) {
|
||||
dx -= width - textWidth;
|
||||
}
|
||||
|
||||
this.drawBox(x, y, width, height, { ...options, fill: ' ' });
|
||||
this.drawString(text, x + 1, y + 1, fg, bg);
|
||||
this.drawString(text, x + dx, y + 1, { fg, bg, alignH, anchorH });
|
||||
}
|
||||
|
||||
fillBox(x: number, y: number, width: number, height: number, char: Char = Glyphs.FULL_BLOCK) {
|
||||
|
|
|
|||
|
|
@ -42,11 +42,11 @@ export class TextDisplaySystem extends System {
|
|||
const region = data instanceof TextRegion ? data : new TextRegion(data);
|
||||
|
||||
if (absolute || !offset || !viewportClipRect) {
|
||||
this.display.setRegion(x, y, region);
|
||||
this.display.setRegion(region, x, y);
|
||||
} else {
|
||||
const clipRect = this.display.getClipRect();
|
||||
this.display.setClipRect(viewportClipRect);
|
||||
this.display.setRegion(x - offset.x, y - offset.y, region);
|
||||
this.display.setRegion(region, x - offset.x, y - offset.y);
|
||||
this.display.setClipRect(clipRect);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue