use rosace_core::types::{Point, Rect, Size};
use rosace_layout::Constraints;
use rosace_render::{Color, FontCache, PictureRecorder, SkiaCanvas};
use rosace_theme::{ThemeData, built_in};
use super::{Widget, LayoutCtx, PaintCtx};
pub struct WidgetApp {
pub width: u32,
pub height: u32,
background: Option<Color>,
pub font: FontCache,
pub theme: ThemeData,
}
impl WidgetApp {
pub fn new(width: u32, height: u32) -> Self {
let font = FontCache::system_ui()
.or_else(FontCache::system_mono)
.expect("no system font found");
Self {
width,
height,
background: None,
font,
theme: built_in::dark_theme(),
}
}
pub fn background(mut self, c: Color) -> Self { self.background = Some(c); self }
pub fn with_font(mut self, f: FontCache) -> Self { self.font = f; self }
pub fn theme(mut self, t: ThemeData) -> Self { self.theme = t; self }
pub fn dark(mut self) -> Self { self.theme = built_in::dark_theme(); self }
pub fn light(mut self) -> Self { self.theme = built_in::light_theme(); self }
fn resolve_bg(&self) -> Color {
self.background.unwrap_or_else(|| {
let c = self.theme.colors.background;
Color::rgba(
(c.r * 255.0) as u8,
(c.g * 255.0) as u8,
(c.b * 255.0) as u8,
(c.a * 255.0) as u8,
)
})
}
pub fn render(&self, root: &dyn Widget) -> SkiaCanvas {
rosace_theme::set_theme(self.theme.clone());
let mut canvas = SkiaCanvas::new(self.width, self.height);
canvas.clear(self.resolve_bg());
let constraints = Constraints::tight(self.width as f32, self.height as f32);
let lctx = LayoutCtx::new(constraints, &self.font, &self.theme);
let size = root.layout(&lctx);
let mut recorder = PictureRecorder::new();
let mut ctx = PaintCtx::root(
&mut recorder,
Rect {
origin: Point { x: 0.0, y: 0.0 },
size: Size {
width: size.width.min(self.width as f32),
height: size.height.min(self.height as f32),
},
},
&self.font,
self.theme.clone(),
std::rc::Rc::new(std::cell::RefCell::new(super::RenderTree::new())),
);
root.paint(&mut ctx);
let picture = recorder.finish();
canvas.play_picture(&picture, &self.font);
canvas
}
pub fn render_into(&self, canvas: &mut SkiaCanvas, root: &dyn Widget) {
rosace_theme::set_theme(self.theme.clone());
canvas.clear(self.resolve_bg());
let w = canvas.width() as f32;
let h = canvas.height() as f32;
let constraints = Constraints::tight(w, h);
let lctx = LayoutCtx::new(constraints, &self.font, &self.theme);
let size = root.layout(&lctx);
let mut recorder = PictureRecorder::new();
let mut ctx = PaintCtx::root(
&mut recorder,
Rect {
origin: Point { x: 0.0, y: 0.0 },
size: Size {
width: size.width.min(w),
height: size.height.min(h),
},
},
&self.font,
self.theme.clone(),
std::rc::Rc::new(std::cell::RefCell::new(super::RenderTree::new())),
);
root.paint(&mut ctx);
let picture = recorder.finish();
canvas.play_picture(&picture, &self.font);
}
pub fn render_png(&self, root: &dyn Widget) -> Vec<u8> {
self.render(root)
.encode_png()
.expect("png encode failed")
}
}