Started working on CG UI primitives. rendering to a canvas
This commit is contained in:
parent
232d9351c1
commit
52647a9ce1
4 changed files with 178 additions and 45 deletions
90
src/ui.ts
Normal file
90
src/ui.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import type { UIValue } from './types';
|
||||
|
||||
export function render(ui: UIValue, canvas: HTMLCanvasElement) {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
renderUI(ui, ctx, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function renderUI(ui: UIValue, ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
switch (ui.kind) {
|
||||
case 'rect':
|
||||
ctx.fillStyle = ui.color;
|
||||
ctx.fillRect(x, y, ui.w, ui.h);
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.font = '16px monospace';
|
||||
ctx.fillText(ui.content, x + ui.x, y + ui.y);
|
||||
break;
|
||||
|
||||
case 'row': {
|
||||
let offsetX = 0;
|
||||
for (const child of ui.children) {
|
||||
renderUI(child, ctx, x + offsetX, y);
|
||||
offsetX += measure(child).width + ui.gap;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'column': {
|
||||
let offsetY = 0;
|
||||
for (const child of ui.children) {
|
||||
renderUI(child, ctx, x, y + offsetY);
|
||||
offsetY += measure(child).height + ui.gap;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'clickable': {
|
||||
renderUI(ui.child, ctx, x, y);
|
||||
break;
|
||||
}
|
||||
case 'padding':
|
||||
renderUI(ui.child, ctx, x + ui.amount, y + ui.amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function measure(ui: UIValue): { width: number, height: number } {
|
||||
switch (ui.kind) {
|
||||
case 'rect': return { width: ui.w, height: ui.h };
|
||||
case 'text': return { width: ui.content.length * 10, height: 20 }; // TODO
|
||||
case 'row': {
|
||||
let totalWidth = 0;
|
||||
let maxHeight = 0;
|
||||
for (const child of ui.children) {
|
||||
const size = measure(child);
|
||||
totalWidth += size.width;
|
||||
maxHeight = Math.max(maxHeight, size.height);
|
||||
}
|
||||
totalWidth += ui.gap * (ui.children.length - 1);
|
||||
return { width: totalWidth, height: maxHeight };
|
||||
}
|
||||
case 'column': {
|
||||
let totalHeight = 0;
|
||||
let maxWidth = 0;
|
||||
for (const child of ui.children) {
|
||||
const size = measure(child);
|
||||
totalHeight += size.height;
|
||||
maxWidth = Math.max(maxWidth, size.width);
|
||||
}
|
||||
totalHeight += ui.gap * (ui.children.length - 1);
|
||||
return { width: maxWidth, height: totalHeight };
|
||||
}
|
||||
case 'clickable':
|
||||
return measure(ui.child);
|
||||
case 'padding': {
|
||||
const childSize = measure(ui.child);
|
||||
return {
|
||||
width: childSize.width + ui.amount * 2,
|
||||
height: childSize.height + ui.amount * 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { width: 0, height: 0 };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue