-
Notifications
You must be signed in to change notification settings - Fork 127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve bounding rect code #874
Conversation
@@ -75,18 +75,10 @@ fn compose_widget( | |||
); | |||
let parent_bounding_rect = parent_state.bounding_rect; | |||
|
|||
// This could be further optimized by more tightly clipping the child bounding rect according to the clip path. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This note about optimization is not present after the code was moved. Is it still a valid future thing to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or is that the new call to overlaps
? Either way, the logic in this code has changed, so the PR title that this is just adding documentation starts to become misleading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you renamed it after I started looking at it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This note about optimization is not present after the code was moved. Is it still a valid future thing to do?
I'd have to ask @Philipp-M. I'm not sure the note about optimization made sense in the original PR. I'd rather remove it unless we can point at a specific optimization we expect to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well since the bounds might need to be bigger when transforming the AABB (due to not being able to tighly fit a transformed AABB), it's probably larger afterwards.
An optimization might be an OOB to more tightly represent the widget, or more optimally an arbitrary shape.
I'm not sure how useful that comment is, but at least it hints that this is not yet optimal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine not hinting at a future optimization, because I highly doubt there will be one. Tightly clipping an arbitrary path in an oriented bounding box is a hard problem, and it's unclear that it would have any performance benefit at all.
99.9% of cases are going to be AABBs anyway, for which the current code is close to optimal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'm not too attached to that comment, feel free to remove it.
@Philipp-M Any chance you can review this weekend? Otherwise, I expect to merge on Monday. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little bit uncomfortable with this change in this form TBH.
I do think we may even want to get rid of layout rects completely, and just keep the "OOB" (ignoring children, i.e. transformed local layout rect?) which is defined by the origin
and size
* window_transform
to keep it more simple.
masonry/src/core/contexts.rs
Outdated
pub fn global_layout_rect(&self) -> Rect { | ||
Rect::from_origin_size(self.widget_state.window_origin(), self.widget_state.size) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether this is really useful at all, as this doesn't really represent the (global) widgets position, bounds or size (due to potential transformations).
I wonder whether we should get rid of "layout rects"?
I think they cause more confusion than being helpful.
## Layout rect | ||
|
||
A widget's layout rect includes its self-declared size, and the position attributed by its parent (local position) / parents (global position). | ||
|
||
Pointer events cannot target a widget if they are outside its layout rect, though they can target its children (see **Bounding rect** section). | ||
|
||
A layout rect doesn't necessarily have a formal definition; it's generally where the widget will be drawn, though a widget can be drawn outside its layout rect; it's usually a widget's own space and containers will try to avoid having its children's layout rects overlap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this section should somehow explain, that a widget can be transformed by its transform.
Pointer events also only reach the widget, when they intersect the transformed widget, thus I don't think it's currently correct. Try for example transformations on the left portal in the xilem http_cats example, to see what I mean.
A widget's bounding rect is a rectangle inside of which pointer events might affect either the widget or its descendants. | ||
|
||
In general, the bounding rect is a union or a widget's layout rect and the bounding rects of all its descendants. | ||
|
||
The bounding rects of the widget tree form a kind of "bounding volume hierarchy": when looking to find which widget a pointer is on, Masonry will automatically exclude any widget if the pointer is outside its bounding rect. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth mentioning that bounding rects currently are in window space and axis aligned.
@@ -75,18 +75,10 @@ fn compose_widget( | |||
); | |||
let parent_bounding_rect = parent_state.bounding_rect; | |||
|
|||
// This could be further optimized by more tightly clipping the child bounding rect according to the clip path. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well since the bounds might need to be bigger when transforming the AABB (due to not being able to tighly fit a transformed AABB), it's probably larger afterwards.
An optimization might be an OOB to more tightly represent the widget, or more optimally an arbitrary shape.
I'm not sure how useful that comment is, but at least it hints that this is not yet optimal.
masonry/src/testing/harness.rs
Outdated
@@ -472,8 +472,7 @@ impl TestHarness { | |||
#[track_caller] | |||
pub fn mouse_move_to(&mut self, id: WidgetId) { | |||
let widget = self.get_widget(id); | |||
let local_widget_center = (widget.ctx().size() / 2.0).to_vec2().to_point(); | |||
let widget_center = widget.ctx().widget_state.window_transform * local_widget_center; | |||
let widget_center = widget.ctx().global_layout_rect().center(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this change is correct, in that a transformed widget might not be hit.
On second thought, I agree with @Philipp-M that the "layout rect" concept doesn't really make sense anymore with arbitrary transforms. I've edited the documentation to reflect this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'm much more comfortable with this.
I think the PR could already be handling the added TODOs (as IME merged TODOs are less likely to be handled, and I don't think they are a lot of work to handle), but I'm not going to block on this.
/// This method will panic if [`LayoutCtx::run_layout`] and [`LayoutCtx::place_child`] | ||
/// have not been called yet for the child. | ||
// TODO - Remove (used in Flex) | ||
#[doc(hidden)] | ||
#[track_caller] | ||
pub fn child_layout_rect(&self, child: &WidgetPod<impl Widget + ?Sized>) -> Rect { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's only used in Flex maybe:
pub fn child_layout_rect(&self, child: &WidgetPod<impl Widget + ?Sized>) -> Rect { | |
pub(crate) fn child_layout_rect(&self, child: &WidgetPod<impl Widget + ?Sized>) -> Rect { |
Might also be worth to fix the parts where the code is used in Flex
?
So that we can get rid of it entirely here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a whole PR on its own.
<!-- TODO - Include illustration. --> | ||
|
||
<!-- TODO - Add section about clip paths and pointer detection. --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you plan to handle the TODOs in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to refactor how clip paths work at some point, it would be part of that.
## Layout rect | ||
|
||
Previous versions of Masonry had a concept of a widget's "layout rect", composed of its self-declared size and the position attributed by its parent. | ||
|
||
However, given that widgets can have arbitrary transforms, the concept of an axis-aligned layout rect doesn't really make sense anymore. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it's even worth mentioning anymore, when all the methods are all "private" and planned to be deleted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to keep it at least until all references are removed from the code, including private code.
@@ -75,18 +75,10 @@ fn compose_widget( | |||
); | |||
let parent_bounding_rect = parent_state.bounding_rect; | |||
|
|||
// This could be further optimized by more tightly clipping the child bounding rect according to the clip path. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'm not too attached to that comment, feel free to remove it.
Deprecate local_layout_rect method. Add global_layout_rect method.
83cfa80
to
b7fc034
Compare
Document concepts of "layout rect" and "bounding rect".
Deprecate
local_layout_rect()
method.Add
global_layout_rect()
method.Remove
transform_changed()
method.Improve bounding rect merging code.
Tweak
TestHarness::mouse_move_to
.Tweak WidgetState doc.