Say what may be done to a drawing, and default to nothing
`SizeDependence::{None, Internal, External}` becomes
`OnResize::{Scale, Translate, Redraw}`, which says what the retained path
may do rather than leaving the reader to work it out from a dependency.
`Redraw` is now the default, and that is the substance of this rather
than the naming. `Translate` was, and nothing opted into it: `SetSize`
reports one size and hands its child the whole box, so its pixels change
with the box and carrying them stretched a 100x100 rect across half the
window. A default that is only right for widgets that happen to qualify
is the same fault as an unchecked reuse flag.
`Translate` still does nothing, and now for the reason rather than the
one I gave before: `mov` translates perfectly well, but `ActiveData`'s
`region` is both the box a widget was given and the box its primitives
occupy, and `mov` remaps out of it. Keeping a drawing at its old size
while the box grows leaves those two disagreeing, and the next move
stretches it. Separating them is what the offset chain does.
Caught by rendering `tabs` against `main` rather than by a test, which is
the argument for keeping that check in the loop.
This commit is contained in:
1 parent
ec012c4552
commit
b108645240
8 files changed
+63
-53
No files matched your search
+19
-10
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveData, Axis, DrawLayers, IdLike, MaskIdx, Painter, PixelRegion, Size, SizeDependence,
|
ActiveData, Axis, DrawLayers, IdLike, MaskIdx, OnResize, Painter, PixelRegion, Size,
|
||||||
StrongWidget, UiRegion, UiRsc, WidgetId, Widgets,
|
StrongWidget, UiRegion, UiRsc, WidgetId, Widgets,
|
||||||
util::{HashMap, HashSet, Vec2, forget_ref},
|
util::{HashMap, HashSet, Vec2, forget_ref},
|
||||||
};
|
};
|
||||||
@@ -93,6 +93,7 @@ impl UiRenderState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw widget
|
// draw widget
|
||||||
|
rsc.widgets_mut().needs_redraw.remove(&id);
|
||||||
self.draw_started.insert(id);
|
self.draw_started.insert(id);
|
||||||
|
|
||||||
let mut painter = Painter {
|
let mut painter = Painter {
|
||||||
@@ -202,7 +203,7 @@ impl UiRenderState {
|
|||||||
return Some(size);
|
return Some(size);
|
||||||
}
|
}
|
||||||
if self.reusable(id, region, rsc) {
|
if self.reusable(id, region, rsc) {
|
||||||
// Its drawing stands; the box is written into the primitives.
|
// Its drawing stands; the new box is remapped into the primitives.
|
||||||
self.mov(id, was, region);
|
self.mov(id, was, region);
|
||||||
return Some(size);
|
return Some(size);
|
||||||
}
|
}
|
||||||
@@ -223,12 +224,15 @@ impl UiRenderState {
|
|||||||
[Axis::X, Axis::Y].into_iter().all(|axis| {
|
[Axis::X, Axis::Y].into_iter().all(|axis| {
|
||||||
let offered = region.axis_mut(axis).len();
|
let offered = region.axis_mut(axis).len();
|
||||||
let had = was.axis_mut(axis).len();
|
let had = was.axis_mut(axis).len();
|
||||||
match widget.size_dependence(axis) {
|
match widget.on_resize(axis) {
|
||||||
SizeDependence::None => true,
|
OnResize::Scale => true,
|
||||||
// `Internal` could also keep its drawing when only the room
|
// `Translate` is not acted on yet, and cannot be until a
|
||||||
// around it changed, but that is a translation rather than a
|
// drawing can sit somewhere other than its box. `region` is
|
||||||
// remap, so it waits for the move chain.
|
// both the box a widget was given and the box its primitives
|
||||||
SizeDependence::Internal | SizeDependence::External => offered == had,
|
// are in, and `mov` remaps from it -- so carrying a drawing at
|
||||||
|
// its old size while the box grows makes the next move stretch
|
||||||
|
// it. The offset chain is what separates the two.
|
||||||
|
OnResize::Translate | OnResize::Redraw => offered == had,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -350,14 +354,19 @@ impl UiRenderState {
|
|||||||
|
|
||||||
/// redraws a widget that's currently active (drawn)
|
/// redraws a widget that's currently active (drawn)
|
||||||
pub fn redraw(&mut self, id: WidgetId, rsc: &mut dyn UiRsc) {
|
pub fn redraw(&mut self, id: WidgetId, rsc: &mut dyn UiRsc) {
|
||||||
rsc.widgets_mut().needs_redraw.remove(&id);
|
|
||||||
self.draw_started.remove(&id);
|
self.draw_started.remove(&id);
|
||||||
// Whoever read this widget's size may be a different size now, so the
|
// Whoever read this widget's size may be a different size now, so the
|
||||||
// highest reader is what draws; it reaches this one on the way down.
|
// highest reader is what draws; it reaches this one on the way down,
|
||||||
|
// where the mark is what stops it being reused as it stands. Clearing
|
||||||
|
// it here would hide the change from the draw that came to apply it.
|
||||||
if let Some(top) = self.highest_reader(id) {
|
if let Some(top) = self.highest_reader(id) {
|
||||||
self.redraw(top, rsc);
|
self.redraw(top, rsc);
|
||||||
|
// Cleared by that draw if it reached here; if it did not, this is
|
||||||
|
// no longer drawn and asking again would not end.
|
||||||
|
rsc.widgets_mut().needs_redraw.remove(&id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rsc.widgets_mut().needs_redraw.remove(&id);
|
||||||
|
|
||||||
if self.draw_started.contains(&id) {
|
if self.draw_started.contains(&id) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+21
-16
@@ -15,20 +15,25 @@ pub use tag::*;
|
|||||||
pub use view::*;
|
pub use view::*;
|
||||||
pub use widgets::*;
|
pub use widgets::*;
|
||||||
|
|
||||||
/// How much of the box a widget was handed its drawing depends on, and so
|
/// What may be done to a widget's drawing when the box it was given changes
|
||||||
/// what has to change before it must be drawn again. Asked per axis, because
|
/// on this axis, instead of drawing it again. Asked per axis, because wrapped
|
||||||
/// wrapped text depends on the width it is offered and not on the height.
|
/// text reads the width it is offered and not the height.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub enum SizeDependence {
|
pub enum OnResize {
|
||||||
/// None of it: the box only says where the primitives go, so a new one is
|
/// Stretched to the new box, which is all its drawing ever was.
|
||||||
/// written into them instead of drawn.
|
Scale,
|
||||||
None,
|
/// Carried to the new box at the size it drew, which it keeps.
|
||||||
/// Its own extent, whatever box that sits in. Reusable in any box that
|
Translate,
|
||||||
/// leaves that extent unchanged, including a larger one it does not fill.
|
/// Nothing doing: it draws again.
|
||||||
|
///
|
||||||
|
/// The default, because it is the only answer that is right without
|
||||||
|
/// knowing anything about the widget. The other two are claims that the
|
||||||
|
/// drawing does not change when the box does, and a widget that inherited
|
||||||
|
/// such a claim by accident would be quietly wrong -- `SetSize` reports
|
||||||
|
/// one size and hands its child the whole box, so its pixels very much do
|
||||||
|
/// change.
|
||||||
#[default]
|
#[default]
|
||||||
Internal,
|
Redraw,
|
||||||
/// The extent of the box itself, used or not.
|
|
||||||
External,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Widget: Any {
|
pub trait Widget: Any {
|
||||||
@@ -42,8 +47,8 @@ pub trait Widget: Any {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_dependence(&self, _axis: Axis) -> SizeDependence {
|
fn on_resize(&self, _axis: Axis) -> OnResize {
|
||||||
SizeDependence::Internal
|
OnResize::Translate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,8 +61,8 @@ impl Widget for () {
|
|||||||
Some(Len::ZERO)
|
Some(Len::ZERO)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_dependence(&self, _axis: Axis) -> SizeDependence {
|
fn on_resize(&self, _axis: Axis) -> OnResize {
|
||||||
SizeDependence::None
|
OnResize::Scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -15,8 +15,8 @@ impl Widget for Image {
|
|||||||
Some(Len::abs(self.handle.size().axis(axis)))
|
Some(Len::abs(self.handle.size().axis(axis)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_dependence(&self, _: Axis) -> SizeDependence {
|
fn on_resize(&self, _: Axis) -> OnResize {
|
||||||
SizeDependence::None
|
OnResize::Scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -12,7 +12,7 @@ impl Widget for Masked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// It clips to the box it was given, not to the part its child used.
|
/// It clips to the box it was given, not to the part its child used.
|
||||||
fn size_dependence(&self, _: Axis) -> SizeDependence {
|
fn on_resize(&self, _: Axis) -> OnResize {
|
||||||
SizeDependence::External
|
OnResize::Redraw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -43,8 +43,8 @@ impl Widget for Rect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Its box is its primitive's own region, so a new one is written there.
|
/// Its box is its primitive's own region, so a new one is written there.
|
||||||
fn size_dependence(&self, _: Axis) -> SizeDependence {
|
fn on_resize(&self, _: Axis) -> OnResize {
|
||||||
SizeDependence::None
|
OnResize::Scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ impl Widget for TextEdit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_dependence(&self, axis: Axis) -> SizeDependence {
|
fn on_resize(&self, axis: Axis) -> OnResize {
|
||||||
self.view.size_dependence(axis)
|
self.view.on_resize(axis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,15 +93,15 @@ impl TextView {
|
|||||||
/// a taller one does not. Alignment matters too, and separately: glyphs
|
/// a taller one does not. Alignment matters too, and separately: glyphs
|
||||||
/// anchored to the start of an axis stay put when that extent changes,
|
/// anchored to the start of an axis stay put when that extent changes,
|
||||||
/// but centred or end-aligned ones move even though the shaping stands.
|
/// but centred or end-aligned ones move even though the shaping stands.
|
||||||
pub fn size_dependence(&self, axis: Axis) -> SizeDependence {
|
pub fn on_resize(&self, axis: Axis) -> OnResize {
|
||||||
let reshapes = axis == Axis::X && self.attrs.wrap;
|
let reshapes = axis == Axis::X && self.attrs.wrap;
|
||||||
let anchored = match axis {
|
let anchored = match axis {
|
||||||
Axis::X => self.align.x,
|
Axis::X => self.align.x,
|
||||||
Axis::Y => self.align.y,
|
Axis::Y => self.align.y,
|
||||||
} == AxisAlign::Neg;
|
} == AxisAlign::Neg;
|
||||||
match reshapes || !anchored {
|
match reshapes || !anchored {
|
||||||
true => SizeDependence::External,
|
true => OnResize::Redraw,
|
||||||
false => SizeDependence::Internal,
|
false => OnResize::Translate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,8 +133,8 @@ impl Widget for Text {
|
|||||||
painter.set_size(size);
|
painter.set_size(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_dependence(&self, axis: Axis) -> SizeDependence {
|
fn on_resize(&self, axis: Axis) -> OnResize {
|
||||||
self.view.size_dependence(axis)
|
self.view.on_resize(axis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-14
@@ -10,7 +10,7 @@ use iris::prelude::*;
|
|||||||
struct Counted {
|
struct Counted {
|
||||||
draws: Rc<Cell<usize>>,
|
draws: Rc<Cell<usize>>,
|
||||||
size: Size,
|
size: Size,
|
||||||
dependence: SizeDependence,
|
dependence: OnResize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Counted {
|
impl Widget for Counted {
|
||||||
@@ -19,7 +19,7 @@ impl Widget for Counted {
|
|||||||
painter.set_size(self.size);
|
painter.set_size(self.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_dependence(&self, _: Axis) -> SizeDependence {
|
fn on_resize(&self, _: Axis) -> OnResize {
|
||||||
self.dependence
|
self.dependence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,11 +32,7 @@ impl Counts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn counted(
|
fn counted(h: &mut Harness, size: Size, dependence: OnResize) -> (WeakWidget<Counted>, Counts) {
|
||||||
h: &mut Harness,
|
|
||||||
size: Size,
|
|
||||||
dependence: SizeDependence,
|
|
||||||
) -> (WeakWidget<Counted>, Counts) {
|
|
||||||
let draws = Rc::new(Cell::new(0));
|
let draws = Rc::new(Cell::new(0));
|
||||||
let id = Counted {
|
let id = Counted {
|
||||||
draws: draws.clone(),
|
draws: draws.clone(),
|
||||||
@@ -49,8 +45,8 @@ fn counted(
|
|||||||
|
|
||||||
/// A fixed-width leaf beside one that takes the rest, so changing the first
|
/// A fixed-width leaf beside one that takes the rest, so changing the first
|
||||||
/// hands the second a different box without the output changing.
|
/// hands the second a different box without the output changing.
|
||||||
fn pair(h: &mut Harness, rest: SizeDependence) -> (WeakWidget<Counted>, Counts, WidgetId) {
|
fn pair(h: &mut Harness, rest: OnResize) -> (WeakWidget<Counted>, Counts, WidgetId) {
|
||||||
let (first, _) = counted(h, Size::from((100, 200)), SizeDependence::Internal);
|
let (first, _) = counted(h, Size::from((100, 200)), OnResize::Translate);
|
||||||
let (second, draws) = counted(h, Size::REST, rest);
|
let (second, draws) = counted(h, Size::REST, rest);
|
||||||
h.set_root((first, second).span(Dir::RIGHT));
|
h.set_root((first, second).span(Dir::RIGHT));
|
||||||
(first, draws, second.id())
|
(first, draws, second.id())
|
||||||
@@ -59,7 +55,7 @@ fn pair(h: &mut Harness, rest: SizeDependence) -> (WeakWidget<Counted>, Counts,
|
|||||||
#[test]
|
#[test]
|
||||||
fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() {
|
fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() {
|
||||||
let mut h = Harness::new((400, 200));
|
let mut h = Harness::new((400, 200));
|
||||||
let (first, draws, second) = pair(&mut h, SizeDependence::None);
|
let (first, draws, second) = pair(&mut h, OnResize::Scale);
|
||||||
let settled = draws.get();
|
let settled = draws.get();
|
||||||
assert_corners!(h, second, (100, 0), (400, 200));
|
assert_corners!(h, second, (100, 0), (400, 200));
|
||||||
|
|
||||||
@@ -77,7 +73,7 @@ fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() {
|
fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() {
|
||||||
let mut h = Harness::new((400, 200));
|
let mut h = Harness::new((400, 200));
|
||||||
let (first, draws, second) = pair(&mut h, SizeDependence::External);
|
let (first, draws, second) = pair(&mut h, OnResize::Redraw);
|
||||||
let settled = draws.get();
|
let settled = draws.get();
|
||||||
|
|
||||||
h.rsc[first].size = Size::from((150, 200));
|
h.rsc[first].size = Size::from((150, 200));
|
||||||
@@ -93,8 +89,8 @@ fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn a_span_child_that_declares_its_length_is_drawn_once() {
|
fn a_span_child_that_declares_its_length_is_drawn_once() {
|
||||||
let mut h = Harness::new((400, 200));
|
let mut h = Harness::new((400, 200));
|
||||||
let (told, told_draws) = counted(&mut h, Size::from((100, 200)), SizeDependence::Internal);
|
let (told, told_draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate);
|
||||||
let (asked, asked_draws) = counted(&mut h, Size::from((100, 200)), SizeDependence::Internal);
|
let (asked, asked_draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate);
|
||||||
// The span takes one child's length from its hint and has to draw the
|
// The span takes one child's length from its hint and has to draw the
|
||||||
// other to find out, so only the second is drawn before it is placed.
|
// other to find out, so only the second is drawn before it is placed.
|
||||||
let hinted = told.width(100).add(&mut h.rsc);
|
let hinted = told.width(100).add(&mut h.rsc);
|
||||||
@@ -111,7 +107,7 @@ fn a_span_child_that_declares_its_length_is_drawn_once() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn a_span_relays_out_when_a_child_it_measured_changes() {
|
fn a_span_relays_out_when_a_child_it_measured_changes() {
|
||||||
let mut h = Harness::new((400, 200));
|
let mut h = Harness::new((400, 200));
|
||||||
let (first, _, second) = pair(&mut h, SizeDependence::Internal);
|
let (first, _, second) = pair(&mut h, OnResize::Translate);
|
||||||
|
|
||||||
h.rsc[first].size = Size::from((250, 200));
|
h.rsc[first].size = Size::from((250, 200));
|
||||||
h.frame();
|
h.frame();
|
||||||
|
|||||||
Reference in new issue
Block a user