Skip to content
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

Constrain padding to resolved inner / outer widget sizes #1494

Merged
merged 6 commits into from
Nov 8, 2022

Conversation

tarkah
Copy link
Member

@tarkah tarkah commented Oct 27, 2022

During layout, padding isn't constrained to the difference between the child widget and parent widgets max limits. This causes the parent widget to have the wrong resolved size and for the child widget to get offset by padding instead of the constrained padding.

This fixes the issue by constraining the padding to the min between itself and limits.max() - child.size(). So far I've fixed Container, Button & Text Input as I've seen instances of this for all of them, but haven't combed the other widgets yet for padding.

Below is an example of the fix implemented on Todos, where both text input and buttons are bleeding over when their size should be 0. I've tested these fixes on some larger projects I maintain and couldn't find any regression in layout.

Feel free to rename things, not sure constrain is the best, I suck at naming :P

Before After
Screenshot from 2022-10-27 12:12:02 Screenshot from 2022-10-27 12:11:35

@@ -34,6 +34,22 @@ impl Size {
height: self.height + padding.vertical() as f32,
}
}

/// Returns the minimum of each component of this size and another
pub fn min(self, other: Self) -> Self {
Copy link
Contributor

@bungoboingo bungoboingo Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was just thinking that I wanted to add this to Iced the other day. Yay 🥳

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be worth to use euclid for geometric primitives. It also allow to create different types for different coordinate systems in order to not mix them.

@@ -71,6 +73,18 @@ impl Padding {
pub fn horizontal(self) -> u16 {
self.left + self.right
}

/// Constrains the padding to fit between the inner & outer [`Size`]
pub fn constrain(self, inner: Size, outer: Size) -> Self {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The algorithm of constraining in min-max range usually named clamp, so

Suggested change
pub fn constrain(self, inner: Size, outer: Size) -> Self {
pub fn clamp(self, inner: Size, outer: Size) -> Self {

Copy link
Member Author

@tarkah tarkah Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought of clamp, but since this isn't passing it a min / max Padding I was unsure if it made sense

Copy link
Contributor

@bungoboingo bungoboingo Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

khronos defines clamp to just be "constrain a value to lie between two further values" so think it works fine for this case. also just makes sense 2 me!

Copy link
Member Author

@tarkah tarkah Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constrain a value..

Welp, guess constrain works then :P

Copy link
Member Author

@tarkah tarkah Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clamp just seems like it should only take Self, Self is my only concern. There's no concept for Padding.min(Size) / Padding.max(Size), so Padding.clamp(Size, Size) feels awkward

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think just leave it as constrain; it's readable & easy to follow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it to fit in 7476663.

@@ -68,3 +84,14 @@ impl From<Size> for Vector<f32> {
Vector::new(size.width, size.height)
}
}

impl std::ops::Sub for Size {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while ur in here, a >, < and =<, => would be appreciated as well for Size if you're in the mood

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure these make sense for Size. Which property would we use for comparison? Area? Where would that be useful?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Area is the big thing I was working with the other day, yeah. Probably could be a separate struct though.

@bungoboingo
Copy link
Contributor

LGTM, tested examples (and removed scrollable from a few to see how the base container would function) and see no regressions, only improvements!

@hecrj hecrj added improvement An internal improvement widget layout labels Nov 8, 2022
Copy link
Member

@hecrj hecrj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thanks! 🙇

I made some small changes here and there. Let me know if I broke anything, and we can merge!

@@ -68,3 +84,14 @@ impl From<Size> for Vector<f32> {
Vector::new(size.width, size.height)
}
}

impl std::ops::Sub for Size {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure these make sense for Size. Which property would we use for comparison? Area? Where would that be useful?

@@ -71,6 +73,18 @@ impl Padding {
pub fn horizontal(self) -> u16 {
self.left + self.right
}

/// Constrains the padding to fit between the inner & outer [`Size`]
pub fn constrain(self, inner: Size, outer: Size) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it to fit in 7476663.

Comment on lines +82 to +85
top: self.top.min((available.height as u16) / 2),
right: self.right.min((available.width as u16) / 2),
bottom: self.bottom.min((available.height as u16) / 2),
left: self.left.min((available.width as u16) / 2),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed these lines so we perform the cast to u16 first and then divide by 2. Integer division by 2 is way faster, and I believe both approaches produce equivalent results in the end.

@tarkah
Copy link
Member Author

tarkah commented Nov 8, 2022

Changes look great, fit is a fit naming choice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improvement An internal improvement layout widget
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants