Make the frame a length of the window and the box a region
There is one coordinate unit, the window. Every box in the tree is a region in window units and a widget's frame is a length in the same units, which is only what fractions resolve against, so the box need not be the frame and padding can take from both without either becoming the other. A region node's entry is a translation -- a rel 1 region anchored where its box starts -- rather than a box, so nothing composes a frame back up a chain and a node that moves is one entry write. Padding is then an inset of both: its pixels come off the frame, so rel(1.0) under it fills the padded widget rather than overflowing it, and off the box, so what is drawn sits inside. A length a container decides for a child's frame is a length of the window like everything else here -- a row's slot, padding's frame less its pixels, or the box a stack's sizing child decided, which arrives as Part::Sized -- because a slot of a row is not a fraction of anything the row can name, the same reason a node entry is a translation. A declaration is a fraction of whichever of those reached it, and is the only one that also places the box. Frame validity is a pin beside the box's, not a range: a range of window pixels cannot say which frame an answer is a fraction of, since two frames are different lengths at the same window size. A widget pins its frame by reading it or by being answered with it under a fractional rule, and the pin composes up wherever a length of this frame is what reached the child. Also here, because the diagnosis needed them: the shrinker reports the shrunk tree's own divergence with each level's frame, ask, box and size warm against cold, and there is a size-resize case -- a change and then a resize, the order that shows an answer kept as a fraction of the wrong length, which every other case compares at the window it was made at. Three defects the reports found, each pinned: a rule changed over two pads relocated the column under them instead of dividing it again (seed 59, depth 5, resize-size), a share inside padding had the padding taken off twice, and a root resolved its own rule twice. fmt and clippy clean with and without layout-diagnostics, 121 suite, 20 core, 11 generated, the 400-seed depth-5 shrinker over all sixteen cases. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0ef87ebfcf
commit
1512d8418b
15 files changed
+680
-444
No files matched your search
+163
-169
@@ -17,26 +17,20 @@ 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.
|
||||
/// 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<Len>; 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,
|
||||
/// 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<TextureHandle>,
|
||||
pub(super) primitives: Vec<RetainedPrimitive>,
|
||||
@@ -46,10 +40,13 @@ pub struct Painter<'a> {
|
||||
pub(super) children: Vec<WidgetId>,
|
||||
/// The children whose size this widget read while drawing.
|
||||
pub(super) size_deps: Vec<WidgetId>,
|
||||
/// 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.
|
||||
/// 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) frame_own: [Holds; 2],
|
||||
/// The same for its own box.
|
||||
/// 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<Len>; 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.
|
||||
@@ -76,12 +73,10 @@ impl<'a> Painter<'a> {
|
||||
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.
|
||||
/// 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).within(&self.frame)
|
||||
region.within(&self.extent)
|
||||
}
|
||||
|
||||
fn write_resolved<P: Primitive>(
|
||||
@@ -173,27 +168,19 @@ impl<'a> Painter<'a> {
|
||||
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 declared_narrow = narrowed_by(declared);
|
||||
let narrow = [
|
||||
declared_narrow[0].or(narrow[0]),
|
||||
declared_narrow[1].or(narrow[1]),
|
||||
];
|
||||
let (local, extent) = frame_and_extent(part_of(self.extent, place), narrow, align);
|
||||
let within = match local == UiRegion::FULL {
|
||||
true => self.frame,
|
||||
false => local.within(&self.frame),
|
||||
};
|
||||
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, within);
|
||||
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 = local.size().to_px(self.px);
|
||||
let px = frame.to_px(self.window);
|
||||
let (size, answer_holds, holds) = self.state.draw_inner(
|
||||
id.id(),
|
||||
DrawInfo {
|
||||
@@ -203,8 +190,7 @@ impl<'a> Painter<'a> {
|
||||
parent_move: self.move_idx,
|
||||
region_node,
|
||||
mask: self.mask,
|
||||
frame: local,
|
||||
frame_abs: within,
|
||||
frame,
|
||||
part: extent,
|
||||
place,
|
||||
offer_place: place,
|
||||
@@ -215,9 +201,8 @@ impl<'a> Painter<'a> {
|
||||
None,
|
||||
self.rsc,
|
||||
);
|
||||
let own = self.extent;
|
||||
let compose = |holds| in_parent(holds, local, extent, place, narrow, own);
|
||||
let holds = compose(holds);
|
||||
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)),
|
||||
@@ -225,8 +210,8 @@ impl<'a> Painter<'a> {
|
||||
DrawResult {
|
||||
child: id,
|
||||
painter: self,
|
||||
size: in_parent_frame(size, local.size(), declared),
|
||||
answer_holds: compose(answer_holds),
|
||||
size,
|
||||
answer_holds,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,8 +243,8 @@ impl<'a> Painter<'a> {
|
||||
Placing {
|
||||
id: self.id,
|
||||
extent: self.extent,
|
||||
local: self.frame,
|
||||
px: self.px,
|
||||
frame: self.frame,
|
||||
window: self.window,
|
||||
depth: self.depth,
|
||||
move_idx: self.move_idx,
|
||||
mask: self.mask,
|
||||
@@ -367,6 +352,17 @@ impl<'a> Painter<'a> {
|
||||
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.
|
||||
@@ -402,7 +398,7 @@ impl<'a> Painter<'a> {
|
||||
/// [`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 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);
|
||||
@@ -418,7 +414,7 @@ impl<'a> Painter<'a> {
|
||||
let part = self.extent.axis(axis).len();
|
||||
let holds = holds.into();
|
||||
debug_assert!(
|
||||
holds.contains(part.to_px(self.px.axis(axis))),
|
||||
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
|
||||
@@ -426,26 +422,19 @@ impl<'a> Painter<'a> {
|
||||
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
|
||||
/// One window axis in pixels. Every length in layout is a length of the
|
||||
/// window, so this is what one becomes pixels against.
|
||||
pub fn window_px_len(&self, axis: Axis) -> Px {
|
||||
self.window.axis(axis)
|
||||
}
|
||||
|
||||
/// [`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<Holds>) {
|
||||
/// A validity range already stated about the window. Containers use
|
||||
/// this after branching on a window-unit length.
|
||||
pub fn window_holds(&mut self, axis: Axis, holds: impl Into<Holds>) {
|
||||
let holds = holds.into();
|
||||
debug_assert!(
|
||||
holds.contains(self.px.axis(axis)),
|
||||
"'{}' ({:?}) says its drawing holds for lengths that leave out its frame",
|
||||
holds.contains(self.window.axis(axis)),
|
||||
"'{}' ({:?}) says its drawing holds for windows that leave out this one",
|
||||
self.label(),
|
||||
self.id
|
||||
);
|
||||
@@ -537,81 +526,77 @@ impl PrimitiveLike for &TextureHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// `own` is this widget's own box, for a pin that cannot be said exactly.
|
||||
pub(crate) fn in_parent(
|
||||
holds: LayoutHolds,
|
||||
frame: UiRegion,
|
||||
extent: UiRegion,
|
||||
place: [Place; 2],
|
||||
narrow: [Option<Len>; 2],
|
||||
own: UiRegion,
|
||||
) -> 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(), narrow[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. 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), None) => {
|
||||
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),
|
||||
_ => own.axis(axis).len(),
|
||||
});
|
||||
}
|
||||
// Its box is a part of this widget's frame, or a length of it
|
||||
// decided here: 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),
|
||||
);
|
||||
/// 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<'_> {
|
||||
/// Frame ranges are already ranges on the window 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<Len>; 2],
|
||||
declared: [Option<LayoutLen>; 2],
|
||||
) -> LayoutHolds {
|
||||
let mut result = LayoutHolds::ANY;
|
||||
for axis in AXES {
|
||||
let n = axis as usize;
|
||||
// Every frame range is already a range on the window: the
|
||||
// widget's own read converted through its frame exactly once.
|
||||
result.frame[n] = holds.frame[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 part of this widget's frame, or a length of
|
||||
// it decided here: 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
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<LayoutLen>; 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
|
||||
@@ -676,49 +661,58 @@ pub(crate) fn placed_extent(
|
||||
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<LayoutLen>; 2]) -> [Option<Len>; 2] {
|
||||
declared.map(|declared| declared.map(|len| Len::from_parts(len.rel, len.px)))
|
||||
}
|
||||
|
||||
/// The frame a child is asked in and the box it is asked in, both in the
|
||||
/// coordinates of the widget asking.
|
||||
/// The frame length and the box a child is asked in, in the coordinates the
|
||||
/// widget asking draws in.
|
||||
///
|
||||
/// `part` is what of the caller's own box the child is given. `narrow` is a
|
||||
/// length decided for the child's frame -- a rule, a share, a box a sibling
|
||||
/// decided -- which makes the frame the box the child is asked in: that
|
||||
/// length is what decided where it goes, placed in the part by the child's
|
||||
/// alignment. Where nothing narrowed it, the frame is the caller's own and
|
||||
/// the part is the box.
|
||||
///
|
||||
/// A length rather than a position, so that a child placed again is put back
|
||||
/// in whatever part it is given rather than where it first was.
|
||||
/// `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(
|
||||
part: UiRegion,
|
||||
own: UiRegion,
|
||||
parent_frame: UiVec2,
|
||||
place: [Place; 2],
|
||||
narrow: [Option<Len>; 2],
|
||||
declared: [Option<LayoutLen>; 2],
|
||||
align: RegionAlign,
|
||||
) -> (UiRegion, UiRegion) {
|
||||
let mut frame = UiRegion::FULL;
|
||||
) -> (UiVec2, UiRegion) {
|
||||
let part = part_of(own, place, align);
|
||||
let mut frame = parent_frame;
|
||||
let mut extent = part;
|
||||
for (axis, narrow) in AXES.into_iter().zip(narrow) {
|
||||
if let Some(len) = narrow {
|
||||
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());
|
||||
*frame.axis_mut(axis) = UiSpan::new(start, start + len);
|
||||
*extent.axis_mut(axis) = UiSpan::FULL;
|
||||
*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
|
||||
}
|
||||
Reference in new issue
Block a user