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
@@ -1,7 +1,7 @@
|
||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||
|
||||
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},
|
||||
};
|
||||
|
||||
@@ -118,6 +118,36 @@ impl Widgets {
|
||||
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> {
|
||||
self.vec.get_mut(id.id())
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user