use dotzuki_engine::render::painter::Painter;
use dotzuki_engine::render::TilePos;
use crate::layout_engine::elements::text::parse_color;
use crate::layout_engine::types::{CursorParams, DataContext, LayoutElement, Theme};
pub fn render_cursor(
element: &LayoutElement,
params: &CursorParams,
ctx: &DataContext,
theme: &Theme,
painter: &mut dyn Painter,
) {
let base_tx = element.rect.tx.resolve(ctx);
let base_ty = element.rect.ty.resolve(ctx);
let col = params.col.resolve(ctx);
let row = params.row.resolve(ctx);
let tx = base_tx + col * params.col_step;
let ty = base_ty + row * params.row_step;
let color = match params.color.as_deref() {
Some(c) => parse_color(c),
None => theme.cursor_ink(),
};
if theme.proportional(painter.supports_proportional()) {
let mut buf = [0u8; 4];
painter.draw_text_px(tx * 8, ty * 8, params.glyph_char().encode_utf8(&mut buf), color);
} else {
painter.draw_glyph(TilePos::new(tx, ty), params.glyph_char(), color);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::layout_engine::types::{Coord, ElementParams, ElementRect, Visibility};
use dotzuki_engine::render::{Rgba, TileRect};
use std::cell::RefCell;
#[derive(Default)]
struct Rec {
glyphs: RefCell<Vec<(u32, u32, char)>>,
}
impl Painter for Rec {
fn clear(&mut self, _c: Rgba) {}
fn draw_text_box(&mut self, _r: TileRect, _c: Rgba) {}
fn draw_text(&mut self, _p: TilePos, _t: &str, _c: Rgba) {}
fn draw_glyph(&mut self, p: TilePos, g: char, _c: Rgba) {
self.glyphs.borrow_mut().push((p.tx, p.ty, g));
}
fn draw_pixel_rect(&mut self, _x: u32, _y: u32, _w: u32, _h: u32, _c: Rgba) {}
fn draw_gb_tile(&mut self, _p: TilePos, _t: u8, _f: &str, _c: Rgba) {}
}
fn elem(tx: u32, ty: u32, params: CursorParams) -> LayoutElement {
LayoutElement {
id: String::new(),
element_type: "cursor".into(),
rect: ElementRect {
tx: Coord::Literal(tx),
ty: Coord::Literal(ty),
tw: Some(1),
th: Some(1),
},
visible: Visibility::Static(true),
z_index: 0,
params: ElementParams::Cursor(params),
}
}
fn cparams(col: Coord, row: Coord, col_step: u32, row_step: u32) -> CursorParams {
CursorParams { glyph: None, color: None, col, row, col_step, row_step }
}
#[test]
fn grid_position_computed_from_col_row() {
let mut ctx = DataContext::new();
ctx.set("c", 1i64);
ctx.set("r", 1i64);
let e = elem(1, 12, cparams(Coord::Template("{c}".into()), Coord::Template("{r}".into()), 9, 2));
let ElementParams::Cursor(ref p) = e.params else { unreachable!() };
let mut painter = Rec::default();
render_cursor(&e, p, &ctx, &Theme::default(), &mut painter);
assert_eq!(painter.glyphs.borrow()[0], (10, 14, '\u{25B6}'));
}
#[test]
fn defaults_to_base_and_triangle_glyph() {
let e = elem(3, 5, cparams(Coord::Literal(0), Coord::Literal(0), 0, 0));
let ElementParams::Cursor(ref p) = e.params else { unreachable!() };
let mut painter = Rec::default();
render_cursor(&e, p, &DataContext::new(), &Theme::default(), &mut painter);
assert_eq!(painter.glyphs.borrow()[0], (3, 5, '\u{25B6}'));
}
}