textui/display.ts

106 lines
2.5 KiB
TypeScript

import { BufferLocation, BufferSize, Char, Color } from "./base.ts";
type DisplayKeyEvent = { key: string };
type DisplayClickEvent = { click: BufferLocation };
type DisplaySizeEvent = { size: BufferSize };
type DisplayEvent = Readonly<
| DisplayKeyEvent
| DisplayClickEvent
| DisplaySizeEvent
>;
type DisplayEventCombined = Partial<
& DisplayKeyEvent
& DisplayClickEvent
& DisplaySizeEvent
>;
/**
* Display protocol, to allow the UI to draw things on "screen"
*/
export class Display {
private events: DisplayEvent[] = [];
private known_size = { w: 0, h: 0 };
/**
* Init the display (will be the first method called)
*/
async init(): Promise<void> {
this.known_size = await this.getSize();
}
/**
* Restore the display as before *init*
*/
async uninit(): Promise<void> {
}
/**
* Get the current grid size
*/
async getSize(): Promise<BufferSize> {
return { w: 0, h: 0 };
}
/**
* Setup the palette for color display
*
* If the display supports the whole RGB range, it may return the array as-is.
* If the display only supports a limited palette, it may return only supported colors.
*
* From this call forward, colors will be received by numbered index in the returned array.
*/
async setupPalette(colors: readonly Color[]): Promise<readonly Color[]> {
return [];
}
/**
* Set the cursor visibility
*/
async setCursorVisibility(visible: boolean): Promise<void> {
}
/**
* Flush the display
*/
async flush(): Promise<void> {
}
/**
* Draw a single character on screen
*/
async setChar(at: BufferLocation, char: Char): Promise<void> {
}
/**
* Push a new event
*/
async pushEvent(event: DisplayEvent): Promise<void> {
if (!this.events.some((ev) => sameEvent(ev, event))) {
this.events.push(event);
}
}
/**
* Get the queued events
*/
async getEvents(auto_resize = true): Promise<DisplayEventCombined[]> {
// TODO check only a few cycles?
if (auto_resize) {
const size = await this.getSize();
if (size.w != this.known_size.w || size.h != this.known_size.h) {
this.known_size = size;
await this.pushEvent({ size });
}
}
const result = this.events;
this.events = [];
return result;
}
}
function sameEvent(ev1: DisplayEventCombined, ev2: DisplayEventCombined) {
return ev1.key == ev2.key && ev1.click?.x == ev2.click?.x &&
ev1.click?.y == ev2.click?.y && ev1.size?.w == ev2.size?.w &&
ev1.size?.h == ev2.size?.h;
}