use crate::{ Axis, Len, RenderedText, Size, SizeCtx, StrongWidget, TextAttrs, TextBuffer, TextData, TextureHandle, UiRegion, UiRenderState, UiRsc, UiScalar, UiVec2, Widget, WidgetId, render::{ GlyphPrimitive, Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst, PrimitiveKind, TexturePrimitive, }, util::Vec2, }; /// makes your surfaces look pretty pub struct Painter<'a> { pub(super) state: &'a mut UiRenderState, pub(super) rsc: &'a mut dyn UiRsc, pub(super) region: UiRegion, pub(super) mask: MaskIdx, pub(super) textures: Vec, pub(super) primitives: Vec, pub(super) children: Vec, pub layer: usize, pub(super) id: WidgetId, } impl<'a> Painter<'a> { fn primitive_at(&mut self, primitive: P, region: UiRegion) { let kind = self.rsc.ui_mut().primitives.kind::

(); self.write(kind, primitive, region); } /// Takes the kind, for a caller writing many of one primitive. fn write(&mut self, kind: PrimitiveKind

, primitive: P, region: UiRegion) { let h = self.state.layers.write( self.layer, PrimitiveInst { kind, id: self.id, primitive, region, mask_idx: self.mask, }, ); self.push_primitive(h); } fn push_primitive(&mut self, h: PrimitiveHandle) { if self.mask != MaskIdx::NONE { // TODO: I have no clue if this works at all :joy: self.rsc.ui_mut().masks.push_ref(self.mask); } self.primitives.push(h); } /// Writes a primitive to be rendered pub fn primitive(&mut self, primitive: impl PrimitiveLike) { let primitive = primitive.into_primitive(self); self.primitive_at(primitive, self.region) } pub fn primitive_within(&mut self, primitive: impl PrimitiveLike, region: UiRegion) { let primitive = primitive.into_primitive(self); self.primitive_at(primitive, region.within(&self.region)); } pub fn set_mask(&mut self, region: UiRegion) { assert!(self.mask == MaskIdx::NONE); self.mask = self.rsc.ui_mut().masks.push(Mask { region }); } /// Draws a widget within this widget's region. pub fn widget(&mut self, id: &StrongWidget) { 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: &StrongWidget, region: UiRegion) { self.widget_at(id, region.within(&self.region)); } fn widget_at(&mut self, id: &StrongWidget, region: UiRegion) { self.children.push(id.id()); self.state.draw_inner( self.layer, id.id(), region, Some(self.id), self.mask, None, self.rsc, ); } pub fn render_text( &mut self, buffer: &mut TextBuffer, attrs: &TextAttrs, width: Option, ) -> RenderedText { let ui = self.rsc.ui_mut(); ui.text.render(buffer, attrs, width) } // TODO: merge the text methods into the primitive ones. pub fn glyphs(&mut self, text: &RenderedText, origin: UiRegion) { let kind = self.rsc.ui_mut().primitives.kind::(); for glyph in text.glyphs.iter() { let mut region = origin; region.x.end = region.x.start; region.y.end = region.y.start; let mut region = region.offset(UiVec2::abs(glyph.offset)); region.x.end = region.x.start + UiScalar::abs(glyph.entry.width as f32); region.y.end = region.y.start + UiScalar::abs(glyph.entry.height as f32); self.write( kind, GlyphPrimitive { uv_min: glyph.entry.uv_min, uv_max: glyph.entry.uv_max, layer: glyph.entry.layer, color: text.color, flags: glyph.entry.flags(), }, region, ); } } pub fn region(&self) -> UiRegion { self.region } pub fn size(&mut self, id: &StrongWidget) -> Size { self.size_ctx().size(id) } pub fn len_axis(&mut self, id: &StrongWidget, 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.rsc.ui_mut().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.rsc.widgets().data(self.id).unwrap().label } pub fn id(&self) -> &WidgetId { &self.id } pub fn size_ctx(&mut self) -> SizeCtx<'_> { self.state.size_ctx(self.id, self.region.size(), self.rsc) } } /// What `Painter::primitive` takes: a primitive, or something that yields one /// and does whatever else drawing it needs. pub trait PrimitiveLike { type Primitive: Primitive; fn into_primitive(self, painter: &mut Painter) -> Self::Primitive; } impl PrimitiveLike for P { type Primitive = P; fn into_primitive(self, _: &mut Painter) -> P { self } } impl PrimitiveLike for &TextureHandle { type Primitive = TexturePrimitive; /// Retains a share of the handle, so the slot the primitive names cannot /// be freed and reused while it is still drawn. fn into_primitive(self, painter: &mut Painter) -> TexturePrimitive { painter.textures.push(self.clone()); self.into() } }