#[cfg(feature = "layout-diagnostics")] use crate::layout_diagnostics::{self as diag, Counter}; use crate::{ Axis, Holds, LayoutHolds, LayoutLen, Len, Part, Place, Px, PxVec2, RegionAlign, Rel, 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, Placing}, }; 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, /// This widget's frame, per axis: a length of the window, and what a /// fraction it or anything under it declares or reports is a fraction /// of. A length rather than a box, so padding can take from both the /// frame and the box without either becoming the other. pub(super) frame: UiVec2, /// Where this widget's drawing goes, in its region node's coordinates. 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 window in pixels. Frames and boxes become pixels against this one /// unit, regardless of region-node boundaries. pub(super) window: PxVec2, pub(super) mask: MaskIdx, pub(super) textures: Vec, pub(super) primitives: Vec, pub(super) mask_region: Option, /// The previous drawing's owned mask, available for this draw to reclaim. pub(super) mask_slot: Option, /// Only children whose answers were read constrain this widget's answer. pub(super) answer_under: LayoutHolds, pub(super) children: Vec, /// The children whose size this widget read while drawing. pub(super) size_deps: Vec, /// What this draw itself read of the window in pixels, per axis: every /// window until it reads one, then that one, unless it says otherwise. pub(super) window_own: [Holds; 2], /// Its frame's symbolic length where this draw read it, which makes the /// drawing one that holds for that frame alone. pub(super) frame_own_len: [Option; 2], /// The window reads' equivalent for its own box. pub(super) extent_own: [Holds; 2], /// What each child's drawing depends on. Asking a child again replaces /// its drawing, so it replaces this too rather than narrowing it. pub(super) under: Vec<(WidgetId, 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 its region /// node's coordinates. fn resolve(&self, region: UiRegion) -> UiRegion { region.within(&self.extent) } 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 { 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; let mask = Mask { region: resolved, move_idx, }; let masks = &mut self.rsc.ui_mut().masks; self.mask = match self.mask_slot.take() { Some(idx) => { *masks.get_mut(idx) = mask; idx } None => { let idx = masks.push(mask); // The owner keeps the slot alive even with no primitives. masks.push_ref(idx); 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, [None; 2], [Place::Within(Part::All); 2]) } /// Asks a child, saying what its fractions are of and where it is asked. /// /// `narrow` is a length this widget decided for the child's frame, per /// axis, as a length of this widget's own frame: a resolved share, or a /// box a sibling's answer decided. `None` 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. A declared length narrows the frame here whatever the /// caller says. A narrowed frame is placed in the part by the child's /// alignment and is the box the child is asked in. /// /// `place` is where the child is asked, per axis, as a part of this /// widget's box: see [`Place`]. The child draws once, in that box, and /// its answer is placed inside it by re-expressing the drawing. Nothing /// is drawn again in a box an answer chose; a container that puts the /// answer somewhere else says so with [`Self::place_at`]. pub fn widget_at<'s, W: ?Sized>( &'s mut self, id: &'s StrongWidget, narrow: [Option; 2], 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 (frame, extent) = frame_and_extent(self.extent, self.frame, place, narrow, declared, align); #[cfg(feature = "layout-diagnostics")] if region_node { diag::bump(Counter::RegionNodeDraws); diag::region_node(id.id(), self.id, extent); } // A child listed twice would be moved twice. let re_asked = self.children.contains(&id.id()); if !re_asked { self.children.push(id.id()); } let px = frame.to_px(self.window); 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, part: extent, placed: place, asked: place, narrow, re_asked, px, }, None, self.rsc, ); let holds = self.in_parent(holds, extent, place, narrow, declared); let answer_holds = self.in_parent(answer_holds, extent, place, narrow, declared); match self.under.iter_mut().find(|(child, _)| *child == id.id()) { Some((_, kept)) => *kept = holds, None => self.under.push((id.id(), holds)), } DrawResult { child: id, painter: self, size, 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.under.retain(|(child, _)| *child != id.id()); self.state.undraw_rec(id.id(), self.rsc); } /// Puts a child asked about in this draw somewhere else in this /// widget's box: its answer, placed in this part instead. The drawing /// is re-expressed there rather than made again -- what a row does once /// it knows every slot, having measured each child from its cursor. pub fn place_at(&mut self, id: &StrongWidget, place: [Place; 2]) { debug_assert!( self.children.contains(&id.id()), "'{}' placed a child it did not ask about in this draw", self.label() ); let at = self.placing(); self.state.place_in(id.id(), &at, place, self.rsc); } /// This widget as the thing its children are placed within. fn placing(&self) -> Placing { Placing { id: self.id, extent: self.extent, frame: self.frame, window: self.window, depth: self.depth, move_idx: self.move_idx, mask: self.mask, } } /// 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, /// as the length its draw would report: a fraction in it is resolved /// against this widget's frame, which is the frame a child asked with /// nothing narrowed gets. 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)) }); let frame = self.frame.axis(axis); let resolved = hint.map(|hint| hint.within_len(frame)); #[cfg(feature = "layout-diagnostics")] { diag::hint_read(id.id(), self.id, axis, resolved); diag::bump(match resolved { Some(_) => Counter::HintHits, None => Counter::HintMisses, }); } if let Some(hint) = hint { self.depend_on(id); // Resolving a fraction against this frame makes this draw a // function of the frame's length. The fraction to ask about is // the child's own: resolved against a frame of pixels, none is // left to see it by. if hint.rel != Rel::ZERO { self.frame_own_len[axis as usize] = Some(frame); } } resolved } 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 } /// The symbolic length of this widget's frame along one axis: what a /// fraction it or anything under it declares is a fraction of. A /// container reads it to hand a length of it down -- padding, which /// takes its pixels off. Reading it pins the drawing to that frame, the /// way [`Self::extent_len`] pins it to the box. pub fn frame_len(&mut self, axis: Axis) -> Len { let len = self.frame.axis(axis); self.frame_own_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.window.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.window.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; } /// A window length in pixels, which is what every length in layout is /// measured in. Reading one pins the drawing to this window wherever the /// length is a fraction of it; one that is only pixels is that many /// pixels in any window and pins nothing. pub fn to_px(&mut self, len: Len, axis: Axis) -> Px { let window = self.window.axis(axis); if len.rel != Rel::ZERO { let own = &mut self.window_own[axis as usize]; if *own == Holds::ANY { *own = Holds::at(window); } } len.to_px(window) } /// The windows this drawing holds for, stated rather than taken: a /// container that branched on a length in pixels says which side of the /// boundary it was on, which is wider than the one window reading that /// length pins, and replaces it. pub fn window_holds(&mut self, axis: Axis, holds: impl Into) { let holds = holds.into(); debug_assert!( holds.contains(self.window.axis(axis)), "'{}' ({:?}) says its drawing holds for windows that leave out this one", self.label(), self.id ); self.window_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() } } /// Moves what a child depends on into this widget's own terms: this /// method's `impl` block is where a `Painter`'s own boxes are, so it takes /// only what the child was asked with. impl Painter<'_> { /// Window ranges are already about the one unit and combine directly. /// A frame pin becomes this widget's own frame wherever a length of it /// is what reached the child; where only pixels did, no length of this /// frame can change the child's and the pin stops here. /// /// Extent validity maps back through the part of this widget's box, /// where the box the child was asked in is that part; a declared length /// places the box inside the part instead, and then only that length /// reaches the child. A narrowed frame is not one of these: it decides /// what fractions under the child mean and leaves the box the part it /// was given. fn in_parent( &self, holds: LayoutHolds, extent: UiRegion, place: [Place; 2], narrow: [Option; 2], declared: [Option; 2], ) -> LayoutHolds { let mut result = LayoutHolds::ANY; for axis in AXES { let n = axis as usize; // Every read became pixels against the window, so a range on // it is already in this widget's terms. result.window[n] = holds.window[n]; let reaches = narrow[n].is_none() && !matches!(place[n].part(), Part::Sized(_)) && declared[n].is_none_or(|len| len.rel != Rel::ZERO); result.frame_len[n] = holds.frame_len[n].and(reaches.then(|| self.frame.axis(axis))); match (place[n].part(), declared[n].is_some()) { // 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, false) => { 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. A length it pinned // is this widget's length less the part's pixels where the // part is the whole of the box less pixels, which is the one // shape that inverts exactly; any other part pins this // widget's own length. (Part::Of(span), false) => { let part_len = span.len(); result.extent[n] = holds.extent[n].through(part_len); result.extent_len[n] = holds.extent_len[n].map(|pinned| match part_len.rel { Rel::ONE => pinned - Len::from_parts(Rel::ZERO, part_len.px), _ => self.extent.axis(axis).len(), }); } // Its box is a length this widget decided, from its own // frame or from a sibling's answer: no length of this // widget's box reaches it, so what it holds for is a range // on the window and none of it on that box. _ => { result.window[n] = result.window[n].and(holds.extent[n].through(extent.axis(axis).len())); } } } result } } /// 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 frame length and the box a child is asked in, in the coordinates the /// widget asking draws in. /// /// `own` is that widget's own box, and `place` what of it the child is /// given. `narrow` is a frame the container decided for the child -- a row's /// slot, or padding's frame less its pixels -- and [`Part::Sized`] one a /// sibling's answer decided; both are window lengths, like every other /// length here, since a slot of a row is not a fraction of anything the row /// can name. The child's declaration is a fraction of whichever reached it, /// and is the only one of the three that also places the box: a box the /// caller decided is what `place` names. pub(crate) fn frame_and_extent( own: UiRegion, parent_frame: UiVec2, place: [Place; 2], narrow: [Option; 2], declared: [Option; 2], align: RegionAlign, ) -> (UiVec2, UiRegion) { let part = part_of(own, place, align); let mut frame = parent_frame; let mut extent = part; for axis in AXES { let n = axis as usize; let sized = match place[n].part() { Part::Sized(len) => Some(len), _ => None, }; let base = sized .or(narrow[n]) .unwrap_or_else(|| parent_frame.axis(axis)); let len = declared[n] .map(|len| Len::from_parts(len.rel, len.px).within_len(base)) .unwrap_or(base); *frame.axis_mut(axis) = len; if declared[n].is_some() { let slot = part.axis(axis); let start = slot.start + (slot.len() - len).scale(align.axis(axis).rel()); *extent.axis_mut(axis) = UiSpan::new(start, start + len); } } (frame, extent) } /// The part of a widget's own box a `place` names, in the coordinates that /// box is in. fn part_of(extent: UiRegion, place: [Place; 2], align: RegionAlign) -> UiRegion { let mut part = extent; for axis in AXES { *part.axis_mut(axis) = place[axis as usize] .part() .of(*extent.axis(axis), align.axis(axis)); } part }