Skip to content

Constrain padding to resolved inner / outer widget sizes#1494

Merged
hecrj merged 6 commits into
iced-rs:masterfrom
tarkah:fix/padding
Nov 8, 2022
Merged

Constrain padding to resolved inner / outer widget sizes#1494
hecrj merged 6 commits into
iced-rs:masterfrom
tarkah:fix/padding

Conversation

@tarkah

@tarkah tarkah commented Oct 27, 2022

Copy link
Copy Markdown
Member

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

Comment thread core/src/size.rs
}

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

@bungoboingo bungoboingo Oct 27, 2022

Copy link
Copy Markdown
Contributor

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
Copy Markdown

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.

Comment thread core/src/padding.rs Outdated
}

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

Copy link
Copy Markdown

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 {

@tarkah tarkah Oct 27, 2022

Copy link
Copy Markdown
Member Author

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

@bungoboingo bungoboingo Oct 27, 2022

Copy link
Copy Markdown
Contributor

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!

@tarkah tarkah Oct 27, 2022

Copy link
Copy Markdown
Member Author

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

@tarkah tarkah Oct 27, 2022

Copy link
Copy Markdown
Member Author

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
Copy Markdown
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
Copy Markdown
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 thread core/src/size.rs
}
}

impl std::ops::Sub for Size {

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

@hecrj hecrj left a comment

Copy link
Copy Markdown
Member

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!

Comment thread core/src/size.rs
}
}

impl std::ops::Sub for Size {

Copy link
Copy Markdown
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?

Comment thread core/src/padding.rs Outdated
}

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

Copy link
Copy Markdown
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 thread core/src/padding.rs
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
Copy Markdown
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

tarkah commented Nov 8, 2022

Copy link
Copy Markdown
Member Author

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