use crate::{ Axis, Len, RenderedText, Size, SizeCtx, TextAttrs, TextBuffer, TextData, TextureHandle, Ui, UiRegion, UiVec2, WidgetHandle, WidgetId, render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst}, ui::draw_state::DrawState, util::{HashMap, Vec2}, }; /// makes your surfaces look pretty pub struct Painter<'a, 'b, State> { pub(super) state: &'a mut DrawState<'b, State>, pub(super) region: UiRegion, pub(super) mask: MaskIdx, pub(super) textures: Vec, pub(super) primitives: Vec, pub(super) children: Vec, pub(super) children_width: HashMap, pub(super) children_height: HashMap, pub layer: usize, pub(super) id: WidgetId, } /// stores information for children about the highest level parent that needed their size /// so that they can redraw the parent if their size changes #[derive(Clone, Copy, Debug, Default)] pub struct ResizeRef { pub x: Option<(WidgetId, (UiVec2, Len))>, pub y: Option<(WidgetId, (UiVec2, Len))>, } /// important non rendering data for retained drawing #[derive(Debug)] pub struct ActiveData { pub id: WidgetId, pub region: UiRegion, pub parent: Option, pub textures: Vec, pub primitives: Vec, pub children: Vec, pub resize: ResizeRef, pub mask: MaskIdx, pub layer: usize, } impl<'a, 'c, State: 'static> Painter<'a, 'c, State> { fn primitive_at(&mut self, primitive: P, region: UiRegion) { let h = self.state.layers.write( self.layer, PrimitiveInst { id: self.id, primitive, region, mask_idx: self.mask, }, ); if self.mask != MaskIdx::NONE { // TODO: I have no clue if this works at all :joy: self.state.masks.push_ref(self.mask); } self.primitives.push(h); } /// Writes a primitive to be rendered pub fn primitive(&mut self, primitive: P) { self.primitive_at(primitive, self.region) } pub fn primitive_within(&mut self, primitive: P, region: UiRegion) { self.primitive_at(primitive, region.within(&self.region)); } pub fn set_mask(&mut self, region: UiRegion) { assert!(self.mask == MaskIdx::NONE); self.mask = self.state.masks.push(Mask { region }); } /// Draws a widget within this widget's region. pub fn widget(&mut self, id: &WidgetHandle) { self.widget_at(id, self.region); } /// Draws a widget somewhere within this one. /// Useful for drawing child widgets in select areas. pub fn widget_within(&mut self, id: &WidgetHandle, region: UiRegion) { self.widget_at(id, region.within(&self.region)); } fn widget_at(&mut self, id: &WidgetHandle, region: UiRegion) { self.children.push(id.id()); self.state .draw_inner(self.layer, id.id(), region, Some(self.id), self.mask, None); } pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) { self.textures.push(handle.clone()); self.primitive_at(handle.primitive(), region.within(&self.region)); } pub fn texture(&mut self, handle: &TextureHandle) { self.textures.push(handle.clone()); self.primitive(handle.primitive()); } pub fn texture_at(&mut self, handle: &TextureHandle, region: UiRegion) { self.textures.push(handle.clone()); self.primitive_at(handle.primitive(), region); } /// returns (handle, offset from top left) pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText { self.state .ui .text .draw(buffer, attrs, &mut self.state.ui.textures) } pub fn region(&self) -> UiRegion { self.region } pub fn size(&mut self, id: &WidgetHandle) -> Size { self.size_ctx().size(id) } pub fn len_axis(&mut self, id: &WidgetHandle, axis: Axis) -> Len { match axis { Axis::X => self.size_ctx().width(id), Axis::Y => self.size_ctx().height(id), } } pub fn output_size(&self) -> Vec2 { self.state.output_size } pub fn px_size(&mut self) -> Vec2 { self.region.size().to_abs(self.state.output_size) } pub fn text_data(&mut self) -> &mut TextData { &mut self.state.text } pub fn child_layer(&mut self) { self.layer = self.state.layers.child(self.layer); } pub fn next_layer(&mut self) { self.layer = self.state.layers.next(self.layer); } pub fn label(&self) -> &str { &self.state.widgets.data(self.id).unwrap().label } pub fn id(&self) -> &WidgetId { &self.id } pub fn size_ctx(&mut self) -> SizeCtx<'_, State> { self.state.size_ctx( self.id, self.region.size(), self.id, &mut self.children_width, &mut self.children_height, ) } } impl Ui { }