#[non_exhaustive]pub enum SizePolicy {
Fixed,
HeightForWidth,
Intrinsic,
}Expand description
How an entry’s local_bounds is decided each layout pass.
The default, Fixed, is what every scene had before this
existed: the model owns both axes and nothing measures anything. The other
two hand one or both axes to the widget, which is the only thing that can
answer “how tall is this text at this width”.
§Heavyweight only, and why
A lightweight SceneItem has no layout_response to
ask — it publishes its own AABB, and
Scene::add_item_dynamic already re-reads that
each build. A widget’s height is not a value it publishes; it is the answer
to a question asked at a width. So the two mechanisms are not variants of
each other, and this one is refused for a lightweight entry rather than
silently doing nothing: Scene::set_size_policy
returns false.
§What is measured, and what is not
A view measures exactly the cards it gives a non-zero size — the ones
inside its viewport. Not the ones it keeps alive in the retention band, and
not the one the user is interacting with if the camera has left it behind:
those are laid out at Size::ZERO, so there is nothing a measurement could
be for. A card the camera has never shown keeps the size add_widget_item
was handed, and is corrected on the first pass that places it, in the same
frame it appears. That is the
contract ListView::auto_item_height already makes for rows: the number in
the model is an estimate until the thing has been on screen, and every
whole-scene query that reads it —
scene_rect_extent, the spatial index, a marquee,
a minimap — reads the estimate for a card that has never been realised.
Give a plausible one; the alternative is measuring every card in the scene
on every pass, which is the cost the viewport cull exists to avoid.
§The measurement must be idempotent
A measured height feeds back into the model, and the model feeds the next
pass. A body whose layout_response answers differently for the same width
— because it mutates state, or because its natural height depends on the
height it was given — would oscillate forever. The view bounds that, and it
is careful about what an oscillation is: 100 → 120 → 100 is one when the
body is answering its own last answer, and is a user typing a character that
wraps and then deleting it when it is not. The two are indistinguishable
from the numbers, and freezing the second is the most ordinary editing
action there is.
What separates them is who drove the pass. A body’s answer is a function
of its content and of the width it is offered; at a fixed width its content
cannot change without something dirtying the card — a Signal bound at
Relayout, a rebuild, a fresh node — whereas the view’s own write dirties
only the view and what is above it. So on the pass a write causes, the card
reads clean, and a clean card that answers differently is reading back what
was written to it. The view takes the taller of the two answers, and after a
couple of such contradictions stops taking new ones for the rest of the
chain — which writes nothing, and a pass that writes nothing schedules no
successor. A non-idempotent body therefore costs a bounded number of passes
per external event rather than an unbounded number for ever, and an edited
one is never bounded at all. See
[teksilo_core::widget::Widget::cacheable_layout]
for the framework’s own statement of the same obligation.
§A resize does not reach an axis the content owns
HeightForWidth keeps its width, so the selection
frame resizes it horizontally and the words decide the rest; the vertical
half of a corner drag is neutralised in
Scene::apply_transform_delta,
because a height written there is one the next pass measures straight back
over. Intrinsic owns neither axis, so
Scene::transformable_roots offers it
no resize handles at all. And a measurement taken while a gesture is
previewing a transform is placed but never written: the preview is
recomputed from the gesture’s frozen start frame each sample, so a previewed
width that reached the model would be scaled again on the next one.
#[non_exhaustive]: this crate has out-of-tree consumers.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Fixed
The model owns both axes. Today’s behaviour, and the default, so every existing scene is bit-identical.
HeightForWidth
The model owns the width; the height is measured from the widget at that width on every pass that lays it out.
The right policy for text: a note’s width is authored (you drag its edge)
and its height follows the words. scene_rect(id).height becomes
advisory for such an entry — it reports the last measured height, not the
one add_widget_item was handed.
Intrinsic
Both axes are measured: the entry shrink-wraps its widget.
For content that knows its own size on both axes — a pinned label, a
badge, a fixed-aspect thumbnail. The rect passed to add_widget_item
supplies only the position.
Trait Implementations§
Source§impl Clone for SizePolicy
impl Clone for SizePolicy
Source§fn clone(&self) -> SizePolicy
fn clone(&self) -> SizePolicy
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for SizePolicy
Source§impl Debug for SizePolicy
impl Debug for SizePolicy
Source§impl Default for SizePolicy
impl Default for SizePolicy
Source§fn default() -> SizePolicy
fn default() -> SizePolicy
impl Eq for SizePolicy
Source§impl PartialEq for SizePolicy
impl PartialEq for SizePolicy
impl StructuralPartialEq for SizePolicy
Auto Trait Implementations§
impl Freeze for SizePolicy
impl RefUnwindSafe for SizePolicy
impl Send for SizePolicy
impl Sync for SizePolicy
impl Unpin for SizePolicy
impl UnsafeUnpin for SizePolicy
impl UnwindSafe for SizePolicy
Blanket Implementations§
§impl<T> AnyEq for T
impl<T> AnyEq for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.impl<T> ErasedDestructor for Twhere
T: 'static,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more