use crate::{BoundingBox, DrawCommand, RenderEngine, ScrollState}; use domain::{DisplayHint, Value, WidgetError}; use std::collections::HashMap; use std::time::Duration; pub struct RenderUpdate { pub bounds: BoundingBox, pub commands: Vec, } struct WidgetCache { hint: DisplayHint, data: Vec<(String, Value)>, error: Option, bounds: BoundingBox, scroll: ScrollState, } pub struct RepaintRequest { pub widget_id: u16, pub bounds: BoundingBox, pub display_hint: DisplayHint, pub data: Vec<(String, Value)>, pub error: Option, } pub struct WidgetRenderer { widgets: HashMap, } impl Default for WidgetRenderer { fn default() -> Self { Self::new() } } impl WidgetRenderer { pub fn new() -> Self { Self { widgets: HashMap::new(), } } pub fn apply_repaints( &mut self, engine: &RenderEngine, repaints: Vec, ) -> Vec { let mut updates = Vec::new(); for req in repaints { let content_h = engine.content_height( &req.display_hint, &req.data, req.bounds.width, req.error.as_ref(), ); let scroll = ScrollState::new(req.bounds.height, content_h); let cmds = engine.render_widget( &req.display_hint, &req.data, req.bounds, scroll.offset(), req.error.as_ref(), ); updates.push(RenderUpdate { bounds: req.bounds, commands: cmds, }); self.widgets.insert( req.widget_id, WidgetCache { hint: req.display_hint, data: req.data, error: req.error, bounds: req.bounds, scroll, }, ); } updates } pub fn tick_scroll(&mut self, engine: &RenderEngine, elapsed: Duration) -> Vec { let mut updates = Vec::new(); for cache in self.widgets.values_mut() { if cache.scroll.tick(elapsed) { let cmds = engine.render_widget( &cache.hint, &cache.data, cache.bounds, cache.scroll.offset(), cache.error.as_ref(), ); updates.push(RenderUpdate { bounds: cache.bounds, commands: cmds, }); } } updates } pub fn has_active_scrollers(&self) -> bool { self.widgets.values().any(|c| c.scroll.is_active()) } pub fn clear(&mut self) { self.widgets.clear(); } }