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}, 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 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.rsc.ui_mut().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.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 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); } 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, &mut ui.textures) } pub fn glyphs(&mut self, text: &RenderedText, origin: UiRegion) { let flags_for = |is_color| { if is_color { GlyphPrimitive::IS_COLOR } else { 0 } }; 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.primitive_at( GlyphPrimitive { uv_min: glyph.entry.uv_min, uv_max: glyph.entry.uv_max, view_idx: glyph.entry.view_idx, sampler_idx: glyph.entry.sampler_idx, color: text.color, flags: flags_for(glyph.entry.is_color), }, 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) } }