#[cfg(feature = "layout-diagnostics")] use crate::layout_diagnostics::{self as diag, Counter}; use crate::{ Axis, Holds, LayoutHolds, LayoutLen, Len, Part, Place, Px, PxVec2, RegionAlign, RenderedText, RetainedPrimitive, Size, StrongWidget, TextAttrs, TextBuffer, TextData, TextureHandle, UiRegion, UiRenderState, UiRsc, UiSpan, UiVec2, Weight, WidgetId, Widgets, render::{ GlyphPrimitive, Mask, MaskIdx, MoveIdx, Primitive, PrimitiveInst, PrimitiveKind, TexturePrimitive, }, ui::render_state::DrawInfo, }; const AXES: [Axis; 2] = [Axis::X, Axis::Y]; /// makes your surfaces look pretty pub struct Painter<'a> { pub(super) state: &'a mut UiRenderState, pub(super) rsc: &'a mut dyn UiRsc, /// What a fraction this widget declares or reports is a fraction of, in /// the coordinates of `move_idx`: forwarded from its parent unchanged /// through a span, a stack or a scroll, and narrowed only by what was /// decided above it -- a declared length, or the root. Its length /// is the same on every ask of the widget, which is what keeps a fraction /// under it from being resolved twice. pub(super) frame: UiRegion, /// Where this widget's drawing goes, in the frame's own coordinates. /// Everything it writes is in these coordinates, and its children are /// placed as parts of it. pub(super) extent: UiRegion, /// The extent's symbolic length where this draw read it, which makes the /// drawing one that holds for that length alone -- the way reading a /// length in pixels makes it hold for that number of pixels. pub(super) extent_len: [Option; 2], /// The frame in pixels, which its children's frames are a length of: /// threaded down rather than composed back up the chain, so every length /// in layout is one multiply from its parent's and [`Holds::through`] /// inverts exactly that. pub(super) px: PxVec2, pub(super) mask: MaskIdx, pub(super) textures: Vec, pub(super) primitives: Vec, pub(super) mask_region: Option, /// Only children whose answers were read constrain this widget's answer. pub(super) answer_under: LayoutHolds, pub(super) children: Vec, /// The children asked about so far, so the first place each was asked in /// is the one recorded as its offer. pub(super) offered: Vec, /// Whether this draw is at the place its parent first asked about, which /// makes the questions it asks the ones a cold layout asks and their /// answers the ones to keep. pub(super) at_offer: bool, /// The children whose size this widget read while drawing. pub(super) size_deps: Vec, /// What this draw itself read of its frame in pixels, per axis: every /// length until it reads one, then that one, unless it says otherwise. pub(super) frame_own: [Holds; 2], /// The same for its own box. pub(super) extent_own: [Holds; 2], /// Dependencies of every child drawing, including unmeasured overlays. pub(super) under: LayoutHolds, /// The movable region this widget's primitives are positioned through: /// its own when opted in, otherwise the nearest ancestor's. pub(super) move_idx: MoveIdx, pub layer: usize, /// The layer this widget was entered on, which its children's layers are /// counted from however far `layer` has walked. pub(super) own_layer: usize, pub(super) depth: 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) { self.write_resolved(kind, primitive, region, self.resolve(region)); } /// A box in this widget's extent coordinates, composed into the /// coordinates its move slot is in: through the extent, then through the /// frame the extent is a part of. The same two steps a recomposition /// replays, so a moved drawing lands where a cold one does. fn resolve(&self, region: UiRegion) -> UiRegion { region.within(&self.extent).within(&self.frame) } fn write_resolved( &mut self, kind: PrimitiveKind

, primitive: P, region: UiRegion, resolved: UiRegion, ) { #[cfg(feature = "layout-diagnostics")] diag::bump(Counter::PrimitiveWrites); let h = self.state.layers.write( self.layer, PrimitiveInst { kind, id: self.id, primitive, region: resolved, mask_idx: self.mask, move_idx: self.move_idx, }, ); self.push_primitive(RetainedPrimitive { handle: h, region }); } fn push_primitive(&mut self, h: RetainedPrimitive) { 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 over the whole of this widget's own box. pub fn primitive(&mut self, primitive: impl PrimitiveLike) { let primitive = primitive.into_primitive(self); self.primitive_at(primitive, UiRegion::FULL) } /// Writes a primitive in a part of this widget's own box, in that box's /// coordinates. pub fn primitive_within(&mut self, primitive: impl PrimitiveLike, region: UiRegion) { let primitive = primitive.into_primitive(self); self.primitive_at(primitive, region); } /// Sets a mask, in this widget's own box's coordinates. pub fn set_mask(&mut self, region: UiRegion) { self.mask_region = Some(region); assert!(self.mask == MaskIdx::NONE); let resolved = self.resolve(region); let move_idx = self.move_idx; self.mask = self.rsc.ui_mut().masks.push(Mask { region: resolved, move_idx, }); } /// Draws a widget in the whole of this widget's own box, with the frame /// forwarded unchanged: what a container that is only a wrapper around /// one child wants, and what every transparent container passes for the /// frame. pub fn widget<'s, W: ?Sized>(&'s mut self, id: &'s StrongWidget) -> DrawResult<'s, 'a, W> { self.widget_at(id, UiRegion::FULL, [Place::Within(Part::All); 2]) } /// Draws a child, saying what its fractions are of and where its drawing /// goes. /// /// `frame` is that reference, in this widget's own frame coordinates: /// [`UiRegion::FULL`] forwards this widget's frame, which is what a /// container that only divides room passes, so a fraction under it means /// the same wherever it sits and however deeply it is nested. Narrowing /// it is for what is decided from above, and a declared length narrows /// it here. /// /// `place` is where the drawing goes, per axis, as a part of this /// widget's extent: see [`Place`]. A narrowed frame is its own extent, /// since the narrowing is what said where the drawing goes. pub fn widget_at<'s, W: ?Sized>( &'s mut self, id: &'s StrongWidget, frame: UiRegion, place: [Place; 2], ) -> DrawResult<'s, 'a, W> { let region_node = self.rsc.widgets().is_region_node(id.id()); let declared = self.declared_lens(id); let align = self.rsc.widgets().alignment(id.id()); let (local, extent) = frame_and_extent( frame, part_of(self.extent, place), narrowed_by(declared, frame), align, ); let within = match local == UiRegion::FULL { true => self.frame, false => local.within(&self.frame), }; #[cfg(feature = "layout-diagnostics")] if region_node { diag::bump(Counter::RegionNodeDraws); diag::region_node(id.id(), self.id, within); } // A child listed twice would be moved twice. if !self.children.contains(&id.id()) { self.children.push(id.id()); } let first_ask = self.offer(id.id()); let offer_place = if first_ask { place } else { self.state .active .get(&id.id()) .map_or(place, |a| a.offer_place) }; let px = local.size().to_px(self.px); // The answer and what it holds for, both about the place asked in. // The child's record may say something else once its drawing has been // placed: a drawing made again in its placed box holds for that box. let (size, answer_holds, holds) = self.state.draw_inner( id.id(), DrawInfo { layer: self.layer, parent: Some(self.id), depth: self.depth + 1, parent_move: self.move_idx, region_node, mask: self.mask, frame: local, frame_abs: within, part: extent, place, offer_place, px, }, None, self.rsc, ); let compose = |holds| in_parent(holds, local, extent, place, declared); self.under = self.under.and(compose(holds)); DrawResult { child: id, painter: self, size: in_parent_frame(size, local.size(), declared), answer_holds: compose(answer_holds), } } /// Takes back a child that was drawn only to find out how long it is. /// Its drawing is dropped and it is not one of this widget's children /// this frame; what it answered is still something this widget asked. pub fn undraw(&mut self, id: &StrongWidget) { self.children.retain(|child| *child != id.id()); self.state.undraw_rec(id.id(), self.rsc); } /// What a widget's rules declare its lengths to be, which whoever draws /// it resolves into its frame. Reading them depends on nothing -- the box /// that comes of them is kept on the child, and `redraw` compares it /// there. fn declared_lens(&self, id: &StrongWidget) -> [Option; 2] { declared_lens(self.rsc.widgets(), id.id()) } /// What a child says its length is without being drawn, if it can say. /// Asking counts as reading its size. pub fn size_hint(&mut self, id: &StrongWidget, axis: Axis) -> Option { let widgets = self.rsc.widgets(); // A rule is the answer where there is one: it wins over whatever the // widget would draw, so it has to win over what the widget says too. let hint = widgets.size_rules(id.id()).axis(axis).exact().or_else(|| { widgets .get_dyn(id.id()) .and_then(|widget| widget.size_hint(axis)) }); #[cfg(feature = "layout-diagnostics")] diag::hint_read(id.id(), self.id, axis, hint); match hint { Some(hint) => { #[cfg(feature = "layout-diagnostics")] diag::bump(Counter::HintHits); self.depend_on(id); Some(hint) } None => { #[cfg(feature = "layout-diagnostics")] diag::bump(Counter::HintMisses); None } } } /// Whether this is the first box a child is asked about in during a draw /// that is itself the one its parent measured -- the question a cold /// layout asks, whose answer is the one to keep. A drawing made again in /// a box chosen from an answer asks about that box instead, and what it /// hears back is not a measurement of anything. fn offer(&mut self, child: WidgetId) -> bool { if !self.at_offer || self.offered.contains(&child) { return false; } self.offered.push(child); true } fn depend_on(&mut self, child: &StrongWidget) { if !self.size_deps.contains(&child.id()) { self.size_deps.push(child.id()); } } pub fn render_text<'b>( &mut self, buffer: &'b mut TextBuffer, attrs: &TextAttrs, width: Option, ) -> &'b RenderedText { #[cfg(feature = "layout-diagnostics")] diag::render_text(self.id, self.rsc.widgets().label(self.id), width); let ui = self.rsc.ui_mut(); ui.text.render(buffer, attrs, width) } /// Writes glyphs in the selected frame or extent coordinates. // TODO: merge the text methods into the primitive ones. pub fn glyphs(&mut self, text: &RenderedText, origin: UiRegion) { // Glyph offsets and sizes are pixels, which compose additively. // Only the shared origin needs composing through the extent. let resolved = self.resolve(origin); let kind = self.rsc.ui_mut().primitives.kind::(); for glyph in text.glyphs.iter() { let place = |mut region: UiRegion| { region.x.end = region.x.start; region.y.end = region.y.start; let mut region = region.offset(UiVec2::from_px(glyph.offset)); let size = PxVec2::new( Px::from_int(glyph.entry.width as i32), Px::from_int(glyph.entry.height as i32), ); region.x.end = region.x.start.offset(size.x); region.y.end = region.y.start.offset(size.y); region }; self.write_resolved( 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(), }, place(origin), place(resolved), ); } } /// The symbolic length of this widget's own box along one axis, in the /// lengths of its frame that it places its children in. Reading it pins /// the drawing to that length -- and to nothing about where the box /// starts, which is what lets a container move without being drawn /// again. One axis at a time, because a container that divides one axis /// holds for any length of the other. pub fn extent_len(&mut self, axis: Axis) -> Len { let len = self.extent.axis(axis).len(); self.extent_len[axis as usize] = Some(len); len } /// Where this widget sits in a box longer than the length it takes. A /// widget that positions its own content reads it to place that content /// the way the box around it would have placed the widget. pub fn alignment(&self) -> RegionAlign { self.rsc.widgets().alignment(self.id) } /// Whether a rule beside this widget gives its length on `axis` outright, /// which makes whatever it reports for that axis moot. A rule that only /// bounds the length is not one of these: the answer is still the /// widget's to give, and something still has to work it out. /// /// The widget under a rule does not otherwise learn of it -- this is for /// a container deciding whether reading its children across an axis is /// worth anything, since reading one is also what makes its own size /// depend on it. pub fn has_exact_size(&self, axis: Axis) -> bool { self.rsc .widgets() .size_rules(self.id) .axis(axis) .exact() .is_some() } /// This widget's own box in pixels. Reading it makes the drawing one /// that holds for this box only, until `holds` says how far it goes. pub fn px_size(&mut self) -> PxVec2 { PxVec2::new(self.px_len(Axis::X), self.px_len(Axis::Y)) } /// One axis of this widget's own box in pixels. Prefer this to /// [`Self::px_size`] when the other axis cannot affect the drawing. pub fn px_len(&mut self, axis: Axis) -> Px { let part = self.extent.axis(axis).len(); let len = part.to_px(self.px.axis(axis)); let own = &mut self.extent_own[axis as usize]; if *own == Holds::ANY { *own = Holds::at(len); } len } /// The lengths of this widget's own box on `axis` that what it is drawing /// holds for -- the same primitives, in the same fractions and offsets /// of the box, and the same reported size. A widget that read its length /// in pixels holds for that one alone until it says otherwise. pub fn holds(&mut self, axis: Axis, holds: impl Into) { let part = self.extent.axis(axis).len(); let holds = holds.into(); debug_assert!( holds.contains(part.to_px(self.px.axis(axis))), "'{}' ({:?}) says its drawing holds for lengths that leave out its own box", self.label(), self.id ); self.extent_own[axis as usize] = holds; } /// One axis of this widget's frame in pixels -- what a fraction of its /// area resolves against, and so what a container divides among its /// children. Its own box is a part of this one. pub fn frame_px_len(&mut self, axis: Axis) -> Px { let len = self.px.axis(axis); let own = &mut self.frame_own[axis as usize]; if *own == Holds::ANY { *own = Holds::at(len); } len } /// [`Self::holds`] stated about the frame rather than about this /// widget's own box, for a container whose drawing turns on what its /// fractions are of rather than on the part of it it took. pub fn frame_holds(&mut self, axis: Axis, holds: impl Into) { let holds = holds.into(); debug_assert!( holds.contains(self.px.axis(axis)), "'{}' ({:?}) says its drawing holds for lengths that leave out its frame", self.label(), self.id ); self.frame_own[axis as usize] = holds; } 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); } /// The layer this widget's `n`th child draws on, addressed rather than /// walked to. A container that measures one child by drawing it can ask /// on the layer that child will end up on, and then the second ask is a /// reuse rather than a second drawing on another layer. pub fn child_layer_at(&mut self, n: usize) { let mut at = self.state.layers.child(self.own_layer); for _ in 0..n { at = self.state.layers.next(at); } self.layer = at; } 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 } } /// A child that has just been drawn. Reading its size records that this /// widget's own size depends on it; dropping it without reading draws the /// child and leaves the parent independent of what it came to. pub struct DrawResult<'p, 'a, W: ?Sized> { painter: &'p mut Painter<'a>, child: &'p StrongWidget, size: Size, answer_holds: LayoutHolds, } impl DrawResult<'_, '_, W> { pub fn size(self) -> Size { #[cfg(feature = "layout-diagnostics")] { diag::bump(Counter::SizeReads); diag::size_read(self.child.id(), self.painter.id, self.size); } self.painter.depend_on(self.child); self.painter.answer_under = self.painter.answer_under.and(self.answer_holds); self.size } pub fn len(self, axis: Axis) -> LayoutLen { self.size().axis(axis) } } /// 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() } } /// What a child depends on, said about the boxes the widget that drew it /// has rather than the ones the child was given. /// /// `frame` is the child's frame in this widget's frame coordinates and /// `extent` the box it was given, in the child's own frame coordinates. Both /// reach it as one length, so what it holds for maps back through that /// length exactly -- and where the box it was given is this widget's own, /// what it says about that box is what this widget can say about its own. pub(crate) fn in_parent( holds: LayoutHolds, frame: UiRegion, extent: UiRegion, place: [Place; 2], declared: [Option; 2], ) -> LayoutHolds { let mut result = LayoutHolds::ANY; for axis in AXES { let n = axis as usize; let frame_len = frame.axis(axis).len(); result.frame[n] = holds.frame[n].through(frame_len); match (place[n].part(), declared[n]) { // Its box is this widget's own, or a part of it in that box's // own lengths: so what it holds for is a range on this widget's // own box, which is what lets that box move without a redraw. A // length it pinned is this widget's length wherever the part is // the whole of it, and pins the same way. (Part::All, None) => { result.extent[n] = holds.extent[n]; result.extent_len[n] = holds.extent_len[n]; } // Its box is a part of this widget's own box, in that box's own // lengths, so what it holds for maps back through that part into // a range on this widget's box. (Part::Of(span), None) => { result.extent[n] = holds.extent[n].through(span.len()); } // Its box is a part of this widget's frame: a length of the // frame is all that reaches it, so what it holds for is a range // on the frame and none of it on this widget's own box. _ => { result.frame[n] = result.frame[n].and( holds.extent[n] .through(extent.axis(axis).len()) .through(frame_len), ); } } } result } /// A child's answer as lengths of the parent's own region. A widget reports /// a fraction of its own region, and `of` is that region as a length of this /// one. Pixels come through untouched, being that many pixels wherever they /// end up. A declared axis is already the parent's: it resolved the rule in /// its own region, and the rule is what the report says. fn in_parent_frame(size: Size, of: UiVec2, declared: [Option; 2]) -> Size { let mut size = size; for (axis, declared) in AXES.into_iter().zip(declared) { if declared.is_none() { *size.axis_mut(axis) = size.axis(axis).within_len(of.axis(axis)); } } size } /// What a widget declares a length of its box to be. `leftover` is not one: a /// share of what is left over is only a length to the widget dividing one, /// so it passes up in the size instead. pub(crate) fn declared_lens(widgets: &Widgets, id: WidgetId) -> [Option; 2] { let rules = widgets.size_rules(id); let widget = widgets.get_dyn(id); AXES.map(|axis| { rules.axis(axis).declared().or_else(|| { // A hint still narrows the box where no rule does, which is how a // widget with a natural pixel size -- an image, a gap -- gets that // size rather than the whole offer. That is the offer's business // rather than a declaration's, and this falls away once a widget // occupies its reported size inside the box it was offered. widget .and_then(|widget| widget.size_hint(axis)) .filter(|len| len.leftover == Weight::ZERO) }) }) } /// Whether what a widget reported along an axis is the whole of the box it /// is in rather than a part to be placed inside it. A share fills, because a /// share is a length only to whoever divides one, and whoever did is the one /// that handed down this box. A declared axis does too: the rule already gave /// the region its length, and the rule's length is what the widget reports /// there. And an axis the parent decided from the answer is /// the answer already. pub(crate) fn fills(reported: LayoutLen, declared: Option, decided: bool) -> bool { reported.leftover != Weight::ZERO || declared.is_some() || decided } /// Where a widget's drawing goes inside the part its parent gave it: what /// it reported, on the side of the part its alignment says, and the whole /// part wherever the answer fills it. /// /// The length it reported is a length of its frame, and the part is one too, /// so this takes one from the other rather than composing it into the part. /// That is what makes a fraction the same fraction wherever the part it is /// placed in sits and however long it is -- the fraction is resolved once, /// here, against the frame it was reported of. pub(crate) fn placed_extent( part: UiRegion, size: Size, declared: [Option; 2], fill: [bool; 2], align: RegionAlign, ) -> UiRegion { let mut placed = part; for axis in AXES { let n = axis as usize; let reported = size.axis(axis); if fills(reported, declared[n], fill[n]) { continue; } let len = Len::from_parts(reported.rel, reported.px); let span = placed.axis_mut(axis); span.start += (span.len() - len).scale(align.axis(axis).rel()); span.end = span.start + len; } placed } /// The part of a widget's own box a `place` names, in the coordinates that /// box is in. pub(crate) fn part_of(extent: UiRegion, place: [Place; 2]) -> UiRegion { let mut part = extent; for axis in AXES { *part.axis_mut(axis) = place[axis as usize].part().of(*extent.axis(axis)); } part } /// The length a rule gives a child's frame, per axis: a fraction in it is a /// fraction of the frame the child was given, which is the one length the /// rule can mean. pub(crate) fn narrowed_by(declared: [Option; 2], frame: UiRegion) -> [Option; 2] { AXES.map(|axis| { declared[axis as usize] .map(|len| Len::from_parts(len.rel, len.px).within_len(frame.axis(axis).len())) }) } /// The frame a child is asked in and the box its drawing goes in, both in /// the coordinates of the widget asking. /// /// `frame` is what the caller said the child's fractions are of, and `part` /// what of the caller's own box the drawing takes. `narrow` is the length a /// declared rule gives the frame, which makes the frame the box the drawing /// goes in -- a rule is what decided where it goes, and there is nothing /// left to place inside it. A caller that narrowed the frame itself said the /// same thing. /// /// The length is the caller's to supply so that a widget asked again gets /// the frame it already has rather than a second resolution of its rule. pub(crate) fn frame_and_extent( mut frame: UiRegion, part: UiRegion, narrow: [Option; 2], align: RegionAlign, ) -> (UiRegion, UiRegion) { let mut extent = part; for (axis, narrow) in AXES.into_iter().zip(narrow) { let span = frame.axis_mut(axis); let narrowed = match narrow { Some(len) => { let slot = part.axis(axis); let start = slot.start + (slot.len() - len).scale(align.axis(axis).rel()); *span = UiSpan::new(start, start + len); true } None => *span != UiSpan::FULL, }; if narrowed { *extent.axis_mut(axis) = UiSpan::FULL; } } (frame, extent) }