Carry a length as a rule beside a widget, not a widget around it
`.width()` built a `SetSize` whose whole job was to answer `size_hint`, so every declared length cost a widget, an `ActiveData` and a link of chain to say one number. It is now a `SizeRule` per axis on `WidgetData`, beside `region_node`, resolved by `Painter` where the widget is drawn. `SetSize` and `MaxSize` are gone; `MaxSize` had no caller but its own builders. That settles which of two answers is the size. A rule wins on the axis it names and the `Size` returned by `draw` answers the rest, applied once in `draw_inner` rather than by each widget that could carry one -- so the widget under a rule never learns of it. `Painter::size_hint` reads the rule first for the same reason: a rule that beats what a widget would draw has to beat what it says about itself. `declared_lens` still falls back to a non-leftover `size_hint`, which is how an image or a gap gets its own pixel size rather than the whole offer. That is the offer's business rather than a declaration's, and it falls away when a widget occupies its reported size inside the box it was offered. `known` and `declared` are separate because a share is a length to whoever divides one and not to whoever composes a box: `.width(leftover(3))` is known without drawing but cannot narrow anything. Checked: fmt, clippy, 85 tests, and 100 generated seeds agreeing warm against cold in 67.6 s. `minimal`, `text` and `view` render byte-identical at 1920x1200; `tabs` differs only in the widget count it prints about itself, which is two wrapper types smaller.
This commit is contained in:
1 parent
0283c9d6c7
commit
8220a78d4a
21 files changed
+252
-214
No files matched your search
+29
-17
@@ -2,7 +2,7 @@
|
|||||||
use crate::layout_diagnostics::{self as diag, Counter};
|
use crate::layout_diagnostics::{self as diag, Counter};
|
||||||
use crate::{
|
use crate::{
|
||||||
Axis, Holds, Len, RenderedText, Size, StrongWidget, TextAttrs, TextBuffer, TextData,
|
Axis, Holds, Len, RenderedText, Size, StrongWidget, TextAttrs, TextBuffer, TextData,
|
||||||
TextureHandle, UiRegion, UiRenderState, UiRsc, UiScalar, UiVec2, Widget, WidgetId,
|
TextureHandle, UiRegion, UiRenderState, UiRsc, UiScalar, UiVec2, WidgetId, Widgets,
|
||||||
render::{
|
render::{
|
||||||
GlyphPrimitive, Mask, MaskIdx, MoveIdx, Primitive, PrimitiveHandle, PrimitiveInst,
|
GlyphPrimitive, Mask, MaskIdx, MoveIdx, Primitive, PrimitiveHandle, PrimitiveInst,
|
||||||
PrimitiveKind, TexturePrimitive,
|
PrimitiveKind, TexturePrimitive,
|
||||||
@@ -111,16 +111,12 @@ impl<'a> Painter<'a> {
|
|||||||
self.widget_at(id, region)
|
self.widget_at(id, region)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What a widget declares its lengths to be, which whoever draws it
|
/// What a widget's rules declare its lengths to be, which whoever draws
|
||||||
/// resolves into its box. `leftover` is not among them: a part of what is
|
/// it resolves into its box. Reading them depends on nothing -- the box
|
||||||
/// left over is only a length to the widget dividing one, so it passes
|
/// that comes of them is kept on the child, and `redraw` compares it
|
||||||
/// up in the size instead. Reading it depends on nothing -- the box that
|
/// there.
|
||||||
/// comes of it is kept on the child, and `redraw` compares it there.
|
|
||||||
fn declared_lens<W: ?Sized>(&self, id: &StrongWidget<W>) -> [Option<Len>; 2] {
|
fn declared_lens<W: ?Sized>(&self, id: &StrongWidget<W>) -> [Option<Len>; 2] {
|
||||||
let Some(widget) = self.rsc.widgets().get_dyn(id.id()) else {
|
declared_lens(self.rsc.widgets(), id.id())
|
||||||
return [None; 2];
|
|
||||||
};
|
|
||||||
AXES.map(|axis| declared_len(widget, axis))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes back a child that was drawn only to find out how long it is.
|
/// Takes back a child that was drawn only to find out how long it is.
|
||||||
@@ -201,11 +197,14 @@ impl<'a> Painter<'a> {
|
|||||||
/// What a child says its length is without being drawn, if it can say.
|
/// What a child says its length is without being drawn, if it can say.
|
||||||
/// Asking counts as reading its size.
|
/// Asking counts as reading its size.
|
||||||
pub fn size_hint<W: ?Sized>(&mut self, id: &StrongWidget<W>, axis: Axis) -> Option<Len> {
|
pub fn size_hint<W: ?Sized>(&mut self, id: &StrongWidget<W>, axis: Axis) -> Option<Len> {
|
||||||
let hint = self
|
let widgets = self.rsc.widgets();
|
||||||
.rsc
|
// A rule is the answer where there is one: it wins over whatever the
|
||||||
.widgets()
|
// widget would draw, so it has to win over what the widget says too.
|
||||||
.get_dyn(id.id())
|
let hint = widgets.size_rules(id.id()).axis(axis).known().or_else(|| {
|
||||||
.and_then(|widget| widget.size_hint(axis));
|
widgets
|
||||||
|
.get_dyn(id.id())
|
||||||
|
.and_then(|widget| widget.size_hint(axis))
|
||||||
|
});
|
||||||
#[cfg(feature = "layout-diagnostics")]
|
#[cfg(feature = "layout-diagnostics")]
|
||||||
diag::hint_read(id.id(), self.id, axis, hint);
|
diag::hint_read(id.id(), self.id, axis, hint);
|
||||||
match hint {
|
match hint {
|
||||||
@@ -439,8 +438,21 @@ impl PrimitiveLike for &TextureHandle {
|
|||||||
/// What a widget declares a length of its box to be. `leftover` is not one: a
|
/// 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,
|
/// share of what is left over is only a length to the widget dividing one,
|
||||||
/// so it passes up in the size instead.
|
/// so it passes up in the size instead.
|
||||||
pub(crate) fn declared_len(widget: &dyn Widget, axis: Axis) -> Option<Len> {
|
pub(crate) fn declared_lens(widgets: &Widgets, id: WidgetId) -> [Option<Len>; 2] {
|
||||||
widget.size_hint(axis).filter(|len| len.leftover == 0.0)
|
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 == 0.0)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes a widget's declared lengths in the box `region` is given in, since a
|
/// Takes a widget's declared lengths in the box `region` is given in, since a
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#[cfg(feature = "layout-diagnostics")]
|
#[cfg(feature = "layout-diagnostics")]
|
||||||
use crate::layout_diagnostics::{self as diag, Counter, ReuseOutcome, TimerKind};
|
use crate::layout_diagnostics::{self as diag, Counter, ReuseOutcome, TimerKind};
|
||||||
use crate::ui::painter::declared_len;
|
use crate::ui::painter::declared_lens;
|
||||||
use crate::{
|
use crate::{
|
||||||
ActiveData, Axis, DrawLayers, Holds, IdLike, Len, MaskIdx, MoveIdx, Moves, Painter,
|
ActiveData, Axis, DrawLayers, Holds, IdLike, Len, MaskIdx, MoveIdx, Moves, Painter,
|
||||||
PixelRegion, Size, StrongWidget, UiRegion, UiRsc, UiScalar, UiSpan, WidgetId, Widgets,
|
PixelRegion, Size, StrongWidget, UiRegion, UiRsc, UiScalar, UiSpan, WidgetId, Widgets,
|
||||||
@@ -256,6 +256,14 @@ impl UiRenderState {
|
|||||||
"'{}' ({id:?}) drew a size its size_hint disagrees with",
|
"'{}' ({id:?}) drew a size its size_hint disagrees with",
|
||||||
rsc.widgets().label(id)
|
rsc.widgets().label(id)
|
||||||
);
|
);
|
||||||
|
// A rule wins on the axis it names, and the draw answers the rest.
|
||||||
|
// Applied here so it is one place rather than every widget that could
|
||||||
|
// carry one, and so the widget under a rule never learns of it.
|
||||||
|
let rules = rsc.widgets().size_rules(id);
|
||||||
|
let size = Size {
|
||||||
|
x: rules.x.apply(size.x),
|
||||||
|
y: rules.y.apply(size.y),
|
||||||
|
};
|
||||||
let holds = [own[0].and(under[0]), own[1].and(under[1])];
|
let holds = [own[0].and(under[0]), own[1].and(under[1])];
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
holds[0].contains(px.x) && holds[1].contains(px.y),
|
holds[0].contains(px.x) && holds[1].contains(px.y),
|
||||||
@@ -739,11 +747,7 @@ impl UiRenderState {
|
|||||||
// whether to draw it at all, so a change to either is the parent's
|
// whether to draw it at all, so a change to either is the parent's
|
||||||
// to draw -- with the mark left on, so the parent draws it rather
|
// to draw -- with the mark left on, so the parent draws it rather
|
||||||
// than keeping it.
|
// than keeping it.
|
||||||
let declared_changed = rsc.widgets().get_dyn(id).is_some_and(|widget| {
|
let declared_changed = declared_lens(rsc.widgets(), id) != active.declared;
|
||||||
AXES.into_iter()
|
|
||||||
.zip(active.declared)
|
|
||||||
.any(|(axis, was)| declared_len(widget, axis) != was)
|
|
||||||
});
|
|
||||||
if let Some(parent) = active.parent
|
if let Some(parent) = active.parent
|
||||||
&& (declared_changed || !active.drawn)
|
&& (declared_changed || !active.drawn)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use crate::Widget;
|
use crate::{SizeRules, Widget};
|
||||||
|
|
||||||
pub struct WidgetData {
|
pub struct WidgetData {
|
||||||
pub widget: Box<dyn Widget>,
|
pub widget: Box<dyn Widget>,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub(super) region_node: bool,
|
pub(super) region_node: bool,
|
||||||
|
pub(super) size: SizeRules,
|
||||||
/// dynamic borrow checking
|
/// dynamic borrow checking
|
||||||
pub borrowed: bool,
|
pub borrowed: bool,
|
||||||
}
|
}
|
||||||
@@ -18,6 +19,7 @@ impl WidgetData {
|
|||||||
widget: Box::new(widget),
|
widget: Box::new(widget),
|
||||||
label,
|
label,
|
||||||
region_node: false,
|
region_node: false,
|
||||||
|
size: SizeRules::default(),
|
||||||
borrowed: false,
|
borrowed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::any::Any;
|
|||||||
mod data;
|
mod data;
|
||||||
mod handle;
|
mod handle;
|
||||||
mod like;
|
mod like;
|
||||||
|
mod size_rule;
|
||||||
mod tag;
|
mod tag;
|
||||||
mod view;
|
mod view;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
@@ -11,6 +12,7 @@ mod widgets;
|
|||||||
pub use data::*;
|
pub use data::*;
|
||||||
pub use handle::*;
|
pub use handle::*;
|
||||||
pub use like::*;
|
pub use like::*;
|
||||||
|
pub use size_rule::*;
|
||||||
pub use tag::*;
|
pub use tag::*;
|
||||||
pub use view::*;
|
pub use view::*;
|
||||||
pub use widgets::*;
|
pub use widgets::*;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
use crate::{Axis, Len};
|
||||||
|
|
||||||
|
/// What a widget's length on one axis is, as a rule its parent applies where
|
||||||
|
/// it draws it rather than an answer the widget gives about itself.
|
||||||
|
///
|
||||||
|
/// A rule and a drawn size are not two opinions to reconcile: a rule wins on
|
||||||
|
/// the axis it names, and the `Size` returned by `draw` answers only the axes
|
||||||
|
/// with no rule. That is what lets a span divide its space around a length
|
||||||
|
/// nobody has drawn yet, and it is why a rule lives beside the widget rather
|
||||||
|
/// than inside it -- the widget under the rule never has to know about it.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||||
|
pub enum SizeRule {
|
||||||
|
/// Whatever the widget reports from drawing.
|
||||||
|
#[default]
|
||||||
|
Free,
|
||||||
|
/// This length, whatever the widget reports.
|
||||||
|
Exact(Len),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SizeRule {
|
||||||
|
/// The length this rule gives without the widget being drawn, if it can
|
||||||
|
/// give one. `leftover` is never among them: a share is a length only to
|
||||||
|
/// whoever divides one, so it passes up in the reported size instead and
|
||||||
|
/// is resolved there.
|
||||||
|
pub fn declared(&self) -> Option<Len> {
|
||||||
|
match self {
|
||||||
|
Self::Exact(len) if len.leftover == 0.0 => Some(*len),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The length this rule fixes, whether or not it can narrow a box. A
|
||||||
|
/// share is a length the widget's parent still has to divide, so it is
|
||||||
|
/// known here and resolved there -- unlike `declared`, which is only the
|
||||||
|
/// ones that give a box directly.
|
||||||
|
pub fn known(&self) -> Option<Len> {
|
||||||
|
match self {
|
||||||
|
Self::Free => None,
|
||||||
|
Self::Exact(len) => Some(*len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The length a widget reporting `reported` ends up with.
|
||||||
|
pub fn apply(&self, reported: Len) -> Len {
|
||||||
|
match self {
|
||||||
|
Self::Free => reported,
|
||||||
|
Self::Exact(len) => *len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Len> for SizeRule {
|
||||||
|
fn from(len: Len) -> Self {
|
||||||
|
Self::Exact(len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<Len>> for SizeRule {
|
||||||
|
fn from(len: Option<Len>) -> Self {
|
||||||
|
len.map_or(Self::Free, Self::Exact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One rule per axis, which is how a widget carries a length on one axis and
|
||||||
|
/// leaves the other to whatever it draws.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||||
|
pub struct SizeRules {
|
||||||
|
pub x: SizeRule,
|
||||||
|
pub y: SizeRule,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SizeRules {
|
||||||
|
pub fn axis(&self, axis: Axis) -> SizeRule {
|
||||||
|
match axis {
|
||||||
|
Axis::X => self.x,
|
||||||
|
Axis::Y => self.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn axis_mut(&mut self, axis: Axis) -> &mut SizeRule {
|
||||||
|
match axis {
|
||||||
|
Axis::X => &mut self.x,
|
||||||
|
Axis::Y => &mut self.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
IdLike, StrongWidget, WeakWidget, Widget, WidgetData, WidgetId,
|
Axis, IdLike, SizeRule, SizeRules, StrongWidget, WeakWidget, Widget, WidgetData, WidgetId,
|
||||||
util::{DynBorrower, HashSet, SlotVec, forget_mut, to_mut},
|
util::{DynBorrower, HashSet, SlotVec, forget_mut, to_mut},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,6 +118,36 @@ impl Widgets {
|
|||||||
self.needs_redraw.insert(id);
|
self.needs_redraw.insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The length rules whoever draws this widget applies to its box.
|
||||||
|
pub fn size_rules(&self, id: impl IdLike) -> SizeRules {
|
||||||
|
self.data(id).unwrap().size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets one axis's rule. The widget is marked rather than its parent
|
||||||
|
/// because the parent is not known here; `redraw` escalates a changed
|
||||||
|
/// declared length to whoever resolves it.
|
||||||
|
pub fn set_size_rule(&mut self, id: impl IdLike, axis: Axis, rule: SizeRule) {
|
||||||
|
let id = id.id();
|
||||||
|
let data = self.data_mut(id).unwrap();
|
||||||
|
if *data.size.axis_mut(axis) == rule {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*data.size.axis_mut(axis) = rule;
|
||||||
|
self.needs_redraw.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Both axes at once, for a caller holding a pair.
|
||||||
|
pub fn set_size_rules(
|
||||||
|
&mut self,
|
||||||
|
id: impl IdLike,
|
||||||
|
x: impl Into<SizeRule>,
|
||||||
|
y: impl Into<SizeRule>,
|
||||||
|
) {
|
||||||
|
let id = id.id();
|
||||||
|
self.set_size_rule(id, Axis::X, x.into());
|
||||||
|
self.set_size_rule(id, Axis::Y, y.into());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> {
|
pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> {
|
||||||
self.vec.get_mut(id.id())
|
self.vec.get_mut(id.id())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,13 @@ impl Harness {
|
|||||||
self.render.resize(size);
|
self.render.resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Changes a length rule after the fact, the way `.width()` sets one.
|
||||||
|
pub fn set_len(&mut self, id: impl IdLike, axis: Axis, len: impl Into<Len>) {
|
||||||
|
self.rsc
|
||||||
|
.widgets_mut()
|
||||||
|
.set_size_rule(id, axis, SizeRule::Exact(len.into()));
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the root and lays it out, so a pointer event has something to hit.
|
/// Sets the root and lays it out, so a pointer event has something to hit.
|
||||||
pub fn set_root<T>(&mut self, widget: impl WidgetLike<DefaultRsc<HarnessState>, T>) {
|
pub fn set_root<T>(&mut self, widget: impl WidgetLike<DefaultRsc<HarnessState>, T>) {
|
||||||
widget.set_root(&mut self.rsc, &mut self.state);
|
widget.set_root(&mut self.rsc, &mut self.state);
|
||||||
|
|||||||
+9
-11
@@ -8,14 +8,14 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// The declared lengths of one `SetSize`, by axis.
|
/// The declared lengths of one widget carrying a size rule, by axis.
|
||||||
pub type Lens = [Option<Len>; 2];
|
pub type Lens = [Option<Len>; 2];
|
||||||
|
|
||||||
/// What a test changes between two trees grown from the same seed, so the
|
/// What a test changes between two trees grown from the same seed, so the
|
||||||
/// warm one can be mutated and the cold one grown that way to begin with.
|
/// warm one can be mutated and the cold one grown that way to begin with.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Edits {
|
pub struct Edits {
|
||||||
/// Declared sizes, by the order the `SetSize` wrappers were made.
|
/// Declared sizes, by the order the rules were put on.
|
||||||
pub sizes: HashMap<usize, Lens>,
|
pub sizes: HashMap<usize, Lens>,
|
||||||
/// Which children a span has, by the order the spans were made.
|
/// Which children a span has, by the order the spans were made.
|
||||||
pub spans: HashMap<usize, SpanEdit>,
|
pub spans: HashMap<usize, SpanEdit>,
|
||||||
@@ -75,7 +75,7 @@ const WORDS: &str = "Wrapping shapes one source into as many lines as the box \
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Tree {
|
pub struct Tree {
|
||||||
pub ids: Vec<WidgetId>,
|
pub ids: Vec<WidgetId>,
|
||||||
pub sized: Vec<WeakWidget<SetSize>>,
|
pub sized: Vec<WidgetId>,
|
||||||
pub spans: Vec<Spanned>,
|
pub spans: Vec<Spanned>,
|
||||||
pub scrolls: Vec<WeakWidget<Scroll>>,
|
pub scrolls: Vec<WeakWidget<Scroll>>,
|
||||||
/// Children a `SpanEdit` took out, held so that dropping the last share
|
/// Children a `SpanEdit` took out, held so that dropping the last share
|
||||||
@@ -201,15 +201,13 @@ impl<Rsc: UiRsc + 'static> Grow<'_, Rsc> {
|
|||||||
let idx = self.tree.sized.len();
|
let idx = self.tree.sized.len();
|
||||||
let lens = [self.len(), self.len()];
|
let lens = [self.len(), self.len()];
|
||||||
let lens = self.edits.sizes.get(&idx).copied().unwrap_or(lens);
|
let lens = self.edits.sizes.get(&idx).copied().unwrap_or(lens);
|
||||||
let id = SetSize {
|
let id = inner.id();
|
||||||
inner,
|
self.rsc
|
||||||
x: lens[0],
|
.ui_mut()
|
||||||
y: lens[1],
|
.widgets
|
||||||
}
|
.set_size_rules(id, lens[0], lens[1]);
|
||||||
.add(self.rsc);
|
|
||||||
self.tree.sized.push(id);
|
self.tree.sized.push(id);
|
||||||
self.tree.ids.push(id.id());
|
inner
|
||||||
id.add_strong(self.rsc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node(&mut self, depth: usize) -> StrongWidget {
|
fn node(&mut self, depth: usize) -> StrongWidget {
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub struct MaxSize {
|
|
||||||
pub inner: StrongWidget,
|
|
||||||
pub x: Option<Len>,
|
|
||||||
pub y: Option<Len>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for MaxSize {
|
|
||||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
|
||||||
let child = painter.widget(&self.inner).size();
|
|
||||||
let own = painter.px_size();
|
|
||||||
Size {
|
|
||||||
x: capped(child.x, self.x, own.x),
|
|
||||||
y: capped(child.y, self.y, own.y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capped(len: Len, max: Option<Len>, own: f32) -> Len {
|
|
||||||
match max {
|
|
||||||
Some(max) if len.apply_leftover().to_px(own) > max.apply_leftover().to_px(own) => max,
|
|
||||||
_ => len,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,15 @@
|
|||||||
mod align;
|
mod align;
|
||||||
mod layer;
|
mod layer;
|
||||||
mod max_size;
|
|
||||||
mod offset;
|
mod offset;
|
||||||
mod pad;
|
mod pad;
|
||||||
mod scroll;
|
mod scroll;
|
||||||
mod set_size;
|
|
||||||
mod span;
|
mod span;
|
||||||
mod stack;
|
mod stack;
|
||||||
|
|
||||||
pub use align::*;
|
pub use align::*;
|
||||||
pub use layer::*;
|
pub use layer::*;
|
||||||
pub use max_size::*;
|
|
||||||
pub use offset::*;
|
pub use offset::*;
|
||||||
pub use pad::*;
|
pub use pad::*;
|
||||||
pub use scroll::*;
|
pub use scroll::*;
|
||||||
pub use set_size::*;
|
|
||||||
pub use span::*;
|
pub use span::*;
|
||||||
pub use stack::*;
|
pub use stack::*;
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub struct SetSize {
|
|
||||||
pub inner: StrongWidget,
|
|
||||||
pub x: Option<Len>,
|
|
||||||
pub y: Option<Len>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for SetSize {
|
|
||||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
|
||||||
// Nothing to apply: a declared length is taken where this widget is
|
|
||||||
// drawn, so the box it has already is that length, and `leftover` is a
|
|
||||||
// share only whoever divides a length can work out. Both reach them
|
|
||||||
// through `size_hint`.
|
|
||||||
let child = painter.widget(&self.inner).size();
|
|
||||||
Size {
|
|
||||||
x: self.x.unwrap_or(child.x),
|
|
||||||
y: self.y.unwrap_or(child.y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A declared axis is known without looking at the child, which is what
|
|
||||||
/// lets a span lay out around `.height(leftover(1))` without drawing it.
|
|
||||||
fn size_hint(&self, axis: Axis) -> Option<Len> {
|
|
||||||
match axis {
|
|
||||||
Axis::X => self.x,
|
|
||||||
Axis::Y => self.y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+23
-33
@@ -39,48 +39,38 @@ widget_trait! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sized(self, size: impl Into<Size>) -> impl WidgetFn<Rsc, SetSize> {
|
fn sized(self, size: impl Into<Size>) -> impl WidgetIdFn<Rsc, WL::Widget> {
|
||||||
let size = size.into();
|
let size = size.into();
|
||||||
move |state| SetSize {
|
move |state| {
|
||||||
inner: self.add_strong(state),
|
let id = self.add(state);
|
||||||
x: Some(size.x),
|
let widgets = &mut state.ui_mut().widgets;
|
||||||
y: Some(size.y),
|
widgets.set_size_rule(id, Axis::X, SizeRule::Exact(size.x));
|
||||||
|
widgets.set_size_rule(id, Axis::Y, SizeRule::Exact(size.y));
|
||||||
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_width(self, len: impl Into<Len>) -> impl WidgetFn<Rsc, MaxSize> {
|
fn width(self, len: impl Into<Len>) -> impl WidgetIdFn<Rsc, WL::Widget> {
|
||||||
let len = len.into();
|
let len = len.into();
|
||||||
move |state| MaxSize {
|
move |state| {
|
||||||
inner: self.add_strong(state),
|
let id = self.add(state);
|
||||||
x: Some(len),
|
state
|
||||||
y: None,
|
.ui_mut()
|
||||||
|
.widgets
|
||||||
|
.set_size_rule(id, Axis::X, SizeRule::Exact(len));
|
||||||
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_height(self, len: impl Into<Len>) -> impl WidgetFn<Rsc, MaxSize> {
|
fn height(self, len: impl Into<Len>) -> impl WidgetIdFn<Rsc, WL::Widget> {
|
||||||
let len = len.into();
|
let len = len.into();
|
||||||
move |state| MaxSize {
|
move |state| {
|
||||||
inner: self.add_strong(state),
|
let id = self.add(state);
|
||||||
x: None,
|
state
|
||||||
y: Some(len),
|
.ui_mut()
|
||||||
}
|
.widgets
|
||||||
}
|
.set_size_rule(id, Axis::Y, SizeRule::Exact(len));
|
||||||
|
id
|
||||||
fn width(self, len: impl Into<Len>) -> impl WidgetFn<Rsc, SetSize> {
|
|
||||||
let len = len.into();
|
|
||||||
move |state| SetSize {
|
|
||||||
inner: self.add_strong(state),
|
|
||||||
x: Some(len),
|
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(self, len: impl Into<Len>) -> impl WidgetFn<Rsc, SetSize> {
|
|
||||||
let len = len.into();
|
|
||||||
move |state| SetSize {
|
|
||||||
inner: self.add_strong(state),
|
|
||||||
x: None,
|
|
||||||
y: Some(len),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ use iris::prelude::*;
|
|||||||
|
|
||||||
/// A row of a fixed height under a bar, so changing the bar's height moves the
|
/// A row of a fixed height under a bar, so changing the bar's height moves the
|
||||||
/// row without changing the box it is given: the move path, repeatedly.
|
/// row without changing the box it is given: the move path, repeatedly.
|
||||||
fn plant(h: &mut Harness, bar_height: f32) -> (WeakWidget<SetSize>, WeakWidget<Rect>) {
|
fn plant(h: &mut Harness, bar_height: f32) -> (WeakWidget<Rect>, WeakWidget<Rect>) {
|
||||||
let bar = rect(Color::RED).height(bar_height).add(&mut h.rsc);
|
let bar = rect(Color::RED).height(bar_height).add(&mut h.rsc);
|
||||||
let inner = rect(Color::BLUE).add(&mut h.rsc);
|
let inner = rect(Color::BLUE).add(&mut h.rsc);
|
||||||
let row = (inner, rect(Color::GREEN)).span(Dir::RIGHT).height(100);
|
let row = (inner, rect(Color::GREEN)).span(Dir::RIGHT).height(100);
|
||||||
@@ -33,7 +33,7 @@ fn a_subtree_moved_many_times_stays_where_a_cold_layout_puts_it() {
|
|||||||
let mut height = 40.0;
|
let mut height = 40.0;
|
||||||
for step in 0..MOVES {
|
for step in 0..MOVES {
|
||||||
height = 40.0 + (step % 300) as f32 * 0.37;
|
height = 40.0 + (step % 300) as f32 * 0.37;
|
||||||
warm.rsc[bar].y = Some(Len::px(height));
|
warm.set_len(bar, Axis::Y, height);
|
||||||
warm.frame();
|
warm.frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-10
@@ -61,9 +61,9 @@ fn resize_one(h: &mut Harness, tree: &Tree, idx: usize, rng: &mut Rng) -> Lens {
|
|||||||
Some(Len::px(20.0 + rng.below(180) as f32)),
|
Some(Len::px(20.0 + rng.below(180) as f32)),
|
||||||
Some(Len::px(20.0 + rng.below(180) as f32)),
|
Some(Len::px(20.0 + rng.below(180) as f32)),
|
||||||
];
|
];
|
||||||
let sized = &mut h.rsc[tree.sized[idx]];
|
h.rsc
|
||||||
sized.x = lens[0];
|
.widgets_mut()
|
||||||
sized.y = lens[1];
|
.set_size_rules(tree.sized[idx], lens[0], lens[1]);
|
||||||
lens
|
lens
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,18 +174,25 @@ fn reshuffle(
|
|||||||
/// written out by hand. A fuzz failure is a lead; the fast test that replaces
|
/// written out by hand. A fuzz failure is a lead; the fast test that replaces
|
||||||
/// it has to be buildable from what the failure printed.
|
/// it has to be buildable from what the failure printed.
|
||||||
fn describe(id: WidgetId, h: &Harness) -> String {
|
fn describe(id: WidgetId, h: &Harness) -> String {
|
||||||
|
let rules = h.rsc.widgets().size_rules(id);
|
||||||
|
let rule = |r: SizeRule| match r.known() {
|
||||||
|
Some(len) => format!("{len}"),
|
||||||
|
None => "-".into(),
|
||||||
|
};
|
||||||
|
// A size rule is a property of whatever carries it, so it prints with
|
||||||
|
// that widget rather than as one of its own.
|
||||||
|
match (rules.x, rules.y) {
|
||||||
|
(SizeRule::Free, SizeRule::Free) => describe_widget(id, h),
|
||||||
|
(x, y) => format!("{}[x:{},y:{}]", describe_widget(id, h), rule(x), rule(y)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn describe_widget(id: WidgetId, h: &Harness) -> String {
|
||||||
let label = h.rsc.widgets().label(id).to_string();
|
let label = h.rsc.widgets().label(id).to_string();
|
||||||
let Some(widget) = h.rsc.widgets().get_dyn(id) else {
|
let Some(widget) = h.rsc.widgets().get_dyn(id) else {
|
||||||
return label;
|
return label;
|
||||||
};
|
};
|
||||||
let any: &dyn std::any::Any = widget;
|
let any: &dyn std::any::Any = widget;
|
||||||
let len = |l: &Option<Len>| match l {
|
|
||||||
Some(l) => format!("{l}"),
|
|
||||||
None => "-".into(),
|
|
||||||
};
|
|
||||||
if let Some(w) = any.downcast_ref::<SetSize>() {
|
|
||||||
return format!("SetSize{{x:{},y:{}}}", len(&w.x), len(&w.y));
|
|
||||||
}
|
|
||||||
if let Some(w) = any.downcast_ref::<Span>() {
|
if let Some(w) = any.downcast_ref::<Span>() {
|
||||||
let sign = if w.dir.sign == Sign::Neg { "-" } else { "+" };
|
let sign = if w.dir.sign == Sign::Neg { "-" } else { "+" };
|
||||||
return format!(
|
return format!(
|
||||||
|
|||||||
+13
-26
@@ -81,7 +81,7 @@ fn a_child_drawn_twice_moves_once() {
|
|||||||
h.set_root((left, centered).span(Dir::RIGHT));
|
h.set_root((left, centered).span(Dir::RIGHT));
|
||||||
assert_corners!(h, inner, (100, 0), (300, 200));
|
assert_corners!(h, inner, (100, 0), (300, 200));
|
||||||
|
|
||||||
h.rsc[left].x = Some(Len::px(150));
|
h.set_len(left, Axis::X, 150);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert_corners!(h, inner, (150, 0), (350, 200));
|
assert_corners!(h, inner, (150, 0), (350, 200));
|
||||||
@@ -131,7 +131,7 @@ fn a_fixed_box_is_drawn_again_rather_than_stretched() {
|
|||||||
h.set_root(stack.align(Align::TOP));
|
h.set_root(stack.align(Align::TOP));
|
||||||
assert_corners!(h, panel, (0, 0), (400, 100));
|
assert_corners!(h, panel, (0, 0), (400, 100));
|
||||||
|
|
||||||
h.rsc[leaf].y = Some(Len::px(250));
|
h.set_len(leaf, Axis::Y, 250);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert_corners!(h, panel, (0, 0), (400, 250));
|
assert_corners!(h, panel, (0, 0), (400, 250));
|
||||||
@@ -146,7 +146,7 @@ fn a_moved_subtree_takes_its_children_with_it() {
|
|||||||
h.set_root((first, row).span(Dir::DOWN));
|
h.set_root((first, row).span(Dir::DOWN));
|
||||||
assert_corners!(h, inner, (10, 50), (390, 70));
|
assert_corners!(h, inner, (10, 50), (390, 70));
|
||||||
|
|
||||||
h.rsc[first].y = Some(Len::px(80));
|
h.set_len(first, Axis::Y, 80);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
// The row opted into one movable region, so its descendants follow one
|
// The row opted into one movable region, so its descendants follow one
|
||||||
@@ -167,7 +167,7 @@ fn a_fixed_length_child_keeps_it_when_the_box_around_it_grows() {
|
|||||||
assert_corners!(h, fixed, (100, 0), (150, 200));
|
assert_corners!(h, fixed, (100, 0), (150, 200));
|
||||||
assert_corners!(h, leftover, (150, 0), (400, 200));
|
assert_corners!(h, leftover, (150, 0), (400, 200));
|
||||||
|
|
||||||
h.rsc[bar].x = Some(Len::px(200));
|
h.set_len(bar, Axis::X, 200);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
// The panel's box is 100 shorter, so the fixed child is the same 50 wide
|
// The panel's box is 100 shorter, so the fixed child is the same 50 wide
|
||||||
@@ -195,7 +195,7 @@ fn a_box_with_a_fixed_length_can_be_stretched_on_its_other_axis() {
|
|||||||
h.set_root((bar, column).span(Dir::RIGHT));
|
h.set_root((bar, column).span(Dir::RIGHT));
|
||||||
assert_corners!(h, inner, (110, 10), (390, 30));
|
assert_corners!(h, inner, (110, 10), (390, 30));
|
||||||
|
|
||||||
h.rsc[bar].x = Some(Len::px(200));
|
h.set_len(bar, Axis::X, 200);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert_corners!(h, inner, (210, 10), (390, 30));
|
assert_corners!(h, inner, (210, 10), (390, 30));
|
||||||
@@ -282,24 +282,14 @@ fn drawn_edges(h: &Harness, id: WidgetId, axis: Axis) -> (f32, f32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn hairline(h: &mut Harness, marks: &mut Vec<WidgetId>) -> StrongWidget {
|
fn hairline(h: &mut Harness, marks: &mut Vec<WidgetId>) -> StrongWidget {
|
||||||
let inner = rect(Color::RED).add_strong(&mut h.rsc);
|
let mark = rect(Color::RED).width(1).add_strong(&mut h.rsc);
|
||||||
let mark = SetSize {
|
|
||||||
inner,
|
|
||||||
x: Some(Len::px(1.0)),
|
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add_strong(&mut h.rsc);
|
|
||||||
marks.push(mark.id());
|
marks.push(mark.id());
|
||||||
mark
|
mark
|
||||||
}
|
}
|
||||||
|
|
||||||
fn share(h: &mut Harness, inner: StrongWidget, ratio: f32) -> StrongWidget {
|
fn share(h: &mut Harness, inner: StrongWidget, ratio: f32) -> StrongWidget {
|
||||||
SetSize {
|
h.set_len(&inner, Axis::X, Len::leftover(ratio));
|
||||||
inner,
|
inner
|
||||||
x: Some(Len::leftover(ratio)),
|
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add_strong(&mut h.rsc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shares in weights no binary fraction lands on, a padding on one branch
|
/// Shares in weights no binary fraction lands on, a padding on one branch
|
||||||
@@ -402,18 +392,15 @@ fn only_a_pure_leftover_child_disappears_when_nothing_is_left() {
|
|||||||
|
|
||||||
// An undrawn child remains a dependency of the span, so making room for
|
// An undrawn child remains a dependency of the span, so making room for
|
||||||
// it draws it without rebuilding the tree.
|
// it draws it without rebuilding the tree.
|
||||||
h.rsc[fixed].x = Some(Len::px(60));
|
h.set_len(fixed, Axis::X, 60);
|
||||||
h.frame();
|
h.frame();
|
||||||
assert_corners!(h, leftover, (60, 0), (100, 20));
|
assert_corners!(h, leftover, (60, 0), (100, 20));
|
||||||
|
|
||||||
let mut h = Harness::new((100, 20));
|
let mut h = Harness::new((100, 20));
|
||||||
let fixed = rect(Color::RED).width(100).add(&mut h.rsc);
|
let fixed = rect(Color::RED).width(100).add(&mut h.rsc);
|
||||||
let mixed = SetSize {
|
let mixed = rect(Color::BLUE)
|
||||||
inner: rect(Color::BLUE).add_strong(&mut h.rsc),
|
.width(Len::px(20) + Len::LEFTOVER)
|
||||||
x: Some(Len::px(20) + Len::LEFTOVER),
|
.add(&mut h.rsc);
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
h.set_root((fixed, mixed).span(Dir::RIGHT));
|
h.set_root((fixed, mixed).span(Dir::RIGHT));
|
||||||
|
|
||||||
// Pixels and fractions still overflow; only a child whose entire length
|
// Pixels and fractions still overflow; only a child whose entire length
|
||||||
@@ -432,7 +419,7 @@ fn leftover_children_disappear_at_the_exact_fixed_content_boundary() {
|
|||||||
assert!(h.region(&a).is_some());
|
assert!(h.region(&a).is_some());
|
||||||
assert!(h.region(&b).is_some());
|
assert!(h.region(&b).is_some());
|
||||||
|
|
||||||
h.rsc[first].y = Some(Len::px(96.0));
|
h.set_len(first, Axis::Y, 96.0);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert!(h.region(&a).is_none());
|
assert!(h.region(&a).is_none());
|
||||||
|
|||||||
@@ -216,7 +216,11 @@ fn layout_cost() {
|
|||||||
trace_selected(&tree);
|
trace_selected(&tree);
|
||||||
let sized = tree.sized[0];
|
let sized = tree.sized[0];
|
||||||
run("size", frames, &mut harness, move |harness, frame| {
|
run("size", frames, &mut harness, move |harness, frame| {
|
||||||
harness.rsc[sized].x = Some(Len::px(100.0 + (frame % 2) as f32 * 40.0));
|
let len = Len::px(100.0 + (frame % 2) as f32 * 40.0);
|
||||||
|
harness
|
||||||
|
.rsc
|
||||||
|
.widgets_mut()
|
||||||
|
.set_size_rule(sized, Axis::X, SizeRule::Exact(len));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ fn remapping_rows_every_frame() {
|
|||||||
}
|
}
|
||||||
h.set_root(span);
|
h.set_root(span);
|
||||||
for i in 0..FRAMES {
|
for i in 0..FRAMES {
|
||||||
h.rsc[first].y = Some(Len::px(40.0 + (i % 2) as f32));
|
h.set_len(first, Axis::Y, 40.0 + (i % 2) as f32);
|
||||||
h.frame();
|
h.frame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-4
@@ -236,7 +236,7 @@ fn a_parent_that_only_read_a_hint_relays_out_when_the_hint_changes() {
|
|||||||
h.set_root(parent);
|
h.set_root(parent);
|
||||||
assert_corners!(h, inner, (0, 0), (400, 80));
|
assert_corners!(h, inner, (0, 0), (400, 80));
|
||||||
|
|
||||||
h.rsc[inner].y = Some(Len::px(120));
|
h.set_len(inner, Axis::Y, 120);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert_corners!(h, inner, (0, 0), (400, 120));
|
assert_corners!(h, inner, (0, 0), (400, 120));
|
||||||
@@ -484,7 +484,7 @@ fn stretching_a_subtree_carries_the_children_in_it() {
|
|||||||
let settled = draws.get();
|
let settled = draws.get();
|
||||||
assert_corners!(h, inner, (0, 40), (400, 400));
|
assert_corners!(h, inner, (0, 40), (400, 400));
|
||||||
|
|
||||||
h.rsc[first].y = Some(Len::px(80));
|
h.set_len(first, Axis::Y, 80);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -508,7 +508,7 @@ fn a_widened_row_redraws_what_reads_its_length_and_nothing_else() {
|
|||||||
h.set_root((bar, row).span(Dir::RIGHT));
|
h.set_root((bar, row).span(Dir::RIGHT));
|
||||||
let (settled_wrap, settled_back) = (wrap_draws.get(), back_draws.get());
|
let (settled_wrap, settled_back) = (wrap_draws.get(), back_draws.get());
|
||||||
|
|
||||||
h.rsc[bar].x = Some(Len::px(200));
|
h.set_len(bar, Axis::X, 200);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
// The span reads every child's size, so redrawing one takes the span
|
// The span reads every child's size, so redrawing one takes the span
|
||||||
@@ -534,7 +534,7 @@ fn a_declared_length_child_is_not_redrawn_when_the_box_around_it_grows() {
|
|||||||
h.set_root((bar, row).span(Dir::RIGHT));
|
h.set_root((bar, row).span(Dir::RIGHT));
|
||||||
let settled = draws.get();
|
let settled = draws.get();
|
||||||
|
|
||||||
h.rsc[bar].x = Some(Len::px(200));
|
h.set_len(bar, Axis::X, 200);
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|
||||||
assert_eq!(draws.get(), settled, "its own length did not change");
|
assert_eq!(draws.get(), settled, "its own length did not change");
|
||||||
|
|||||||
+2
-6
@@ -159,12 +159,8 @@ impl Node {
|
|||||||
}
|
}
|
||||||
Node::Sized(x, y, kid) => {
|
Node::Sized(x, y, kid) => {
|
||||||
let inner = kid.build(h, out, spans);
|
let inner = kid.build(h, out, spans);
|
||||||
SetSize {
|
h.rsc.widgets_mut().set_size_rules(&inner, *x, *y);
|
||||||
inner,
|
inner
|
||||||
x: *x,
|
|
||||||
y: *y,
|
|
||||||
}
|
|
||||||
.add_strong(&mut h.rsc)
|
|
||||||
}
|
}
|
||||||
Node::Scroll(down, kid) => {
|
Node::Scroll(down, kid) => {
|
||||||
let inner = kid.build(h, out, spans);
|
let inner = kid.build(h, out, spans);
|
||||||
|
|||||||
@@ -10,12 +10,7 @@ use iris::prelude::*;
|
|||||||
fn plant(h: &mut Harness) -> Vec<WidgetId> {
|
fn plant(h: &mut Harness) -> Vec<WidgetId> {
|
||||||
let plain = wtext("Wrapping").size(16).wrap(false).add(&mut h.rsc);
|
let plain = wtext("Wrapping").size(16).wrap(false).add(&mut h.rsc);
|
||||||
let wrapped = wtext("Wrapping shapes").size(16).wrap(true).add(&mut h.rsc);
|
let wrapped = wtext("Wrapping shapes").size(16).wrap(true).add(&mut h.rsc);
|
||||||
let sized = SetSize {
|
let sized = wrapped.width(76).add(&mut h.rsc);
|
||||||
inner: wrapped.add_strong(&mut h.rsc),
|
|
||||||
x: Some(Len::px(76.0)),
|
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
let aligned = Aligned {
|
let aligned = Aligned {
|
||||||
inner: sized.add_strong(&mut h.rsc),
|
inner: sized.add_strong(&mut h.rsc),
|
||||||
align: Align {
|
align: Align {
|
||||||
@@ -108,12 +103,7 @@ fn plant_fixed(h: &mut Harness) -> Vec<WidgetId> {
|
|||||||
}
|
}
|
||||||
.add(&mut h.rsc);
|
.add(&mut h.rsc);
|
||||||
let inner = (aligned,).span(Dir::RIGHT).add(&mut h.rsc);
|
let inner = (aligned,).span(Dir::RIGHT).add(&mut h.rsc);
|
||||||
let sized = SetSize {
|
let sized = inner.sized((189, 176)).add(&mut h.rsc);
|
||||||
inner: inner.add_strong(&mut h.rsc),
|
|
||||||
x: Some(Len::px(189.0)),
|
|
||||||
y: Some(Len::px(176.0)),
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
let filler = rect(Color::RED).add(&mut h.rsc);
|
let filler = rect(Color::RED).add(&mut h.rsc);
|
||||||
let root = (filler, sized).span(Dir::RIGHT).add(&mut h.rsc);
|
let root = (filler, sized).span(Dir::RIGHT).add(&mut h.rsc);
|
||||||
h.state.root = Some(root.add_strong(&mut h.rsc));
|
h.state.root = Some(root.add_strong(&mut h.rsc));
|
||||||
|
|||||||
+6
-24
@@ -15,12 +15,7 @@ use iris::prelude::*;
|
|||||||
fn plant(h: &mut Harness) -> Vec<WidgetId> {
|
fn plant(h: &mut Harness) -> Vec<WidgetId> {
|
||||||
let plain = wtext("Wrapping").size(16).wrap(false).add(&mut h.rsc);
|
let plain = wtext("Wrapping").size(16).wrap(false).add(&mut h.rsc);
|
||||||
let wrapped = wtext("Wrapping shapes").size(16).wrap(true).add(&mut h.rsc);
|
let wrapped = wtext("Wrapping shapes").size(16).wrap(true).add(&mut h.rsc);
|
||||||
let sized = SetSize {
|
let sized = wrapped.width(76).add(&mut h.rsc);
|
||||||
inner: wrapped.add_strong(&mut h.rsc),
|
|
||||||
x: Some(Len::px(76.0)),
|
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
let aligned = Aligned {
|
let aligned = Aligned {
|
||||||
inner: sized.add_strong(&mut h.rsc),
|
inner: sized.add_strong(&mut h.rsc),
|
||||||
align: Align {
|
align: Align {
|
||||||
@@ -110,12 +105,7 @@ fn plant_fixed(h: &mut Harness) -> Vec<WidgetId> {
|
|||||||
}
|
}
|
||||||
.add(&mut h.rsc);
|
.add(&mut h.rsc);
|
||||||
let inner = (aligned,).span(Dir::RIGHT).add(&mut h.rsc);
|
let inner = (aligned,).span(Dir::RIGHT).add(&mut h.rsc);
|
||||||
let sized = SetSize {
|
let sized = inner.sized((189, 176)).add(&mut h.rsc);
|
||||||
inner: inner.add_strong(&mut h.rsc),
|
|
||||||
x: Some(Len::px(189.0)),
|
|
||||||
y: Some(Len::px(176.0)),
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
let filler = rect(Color::RED).add(&mut h.rsc);
|
let filler = rect(Color::RED).add(&mut h.rsc);
|
||||||
let root = (filler, sized).span(Dir::RIGHT).add(&mut h.rsc);
|
let root = (filler, sized).span(Dir::RIGHT).add(&mut h.rsc);
|
||||||
h.state.root = Some(root.add_strong(&mut h.rsc));
|
h.state.root = Some(root.add_strong(&mut h.rsc));
|
||||||
@@ -235,12 +225,7 @@ fn plant_scrolled(h: &mut Harness, swapped: bool) -> (Vec<WidgetId>, [WeakWidget
|
|||||||
}
|
}
|
||||||
.add(&mut h.rsc);
|
.add(&mut h.rsc);
|
||||||
let block = rect(Color::RED).add(&mut h.rsc);
|
let block = rect(Color::RED).add(&mut h.rsc);
|
||||||
let fixed = SetSize {
|
let fixed = block.width(87).add(&mut h.rsc);
|
||||||
inner: block.add_strong(&mut h.rsc),
|
|
||||||
x: Some(Len::px(87.0)),
|
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
let mut outer_children: Vec<StrongWidget> =
|
let mut outer_children: Vec<StrongWidget> =
|
||||||
vec![fixed.add_strong(&mut h.rsc), inner.add_strong(&mut h.rsc)];
|
vec![fixed.add_strong(&mut h.rsc), inner.add_strong(&mut h.rsc)];
|
||||||
if swapped {
|
if swapped {
|
||||||
@@ -253,12 +238,9 @@ fn plant_scrolled(h: &mut Harness, swapped: bool) -> (Vec<WidgetId>, [WeakWidget
|
|||||||
ortho: OrthoSize::Children,
|
ortho: OrthoSize::Children,
|
||||||
}
|
}
|
||||||
.add(&mut h.rsc);
|
.add(&mut h.rsc);
|
||||||
let through = SetSize {
|
// Carried no rule even before rules were a property: it is here to be a
|
||||||
inner: outer.add_strong(&mut h.rsc),
|
// widget between the span and the scroll, not to declare anything.
|
||||||
x: None,
|
let through = (outer,).span(Dir::RIGHT).add(&mut h.rsc);
|
||||||
y: None,
|
|
||||||
}
|
|
||||||
.add(&mut h.rsc);
|
|
||||||
let scroll = Scroll::new(through.add_strong(&mut h.rsc), Axis::X).add(&mut h.rsc);
|
let scroll = Scroll::new(through.add_strong(&mut h.rsc), Axis::X).add(&mut h.rsc);
|
||||||
h.state.root = Some(scroll.add_strong(&mut h.rsc));
|
h.state.root = Some(scroll.add_strong(&mut h.rsc));
|
||||||
(
|
(
|
||||||
|
|||||||
Reference in new issue
Block a user