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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions core/src/padding.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::Size;

/// An amount of space to pad for each side of a box
///
/// You can leverage the `From` trait to build [`Padding`] conveniently:
Expand Down Expand Up @@ -71,9 +73,21 @@ impl Padding {
pub fn horizontal(self) -> u16 {
self.left + self.right
}

/// Fits the [`Padding`] between the provided `inner` and `outer` [`Size`].
pub fn fit(self, inner: Size, outer: Size) -> Self {
let available = (outer - inner).max(Size::ZERO);

Padding {
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),
Comment on lines +82 to +85
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.

}
}
}

impl std::convert::From<u16> for Padding {
impl From<u16> for Padding {
fn from(p: u16) -> Self {
Padding {
top: p,
Expand All @@ -84,7 +98,7 @@ impl std::convert::From<u16> for Padding {
}
}

impl std::convert::From<[u16; 2]> for Padding {
impl From<[u16; 2]> for Padding {
fn from(p: [u16; 2]) -> Self {
Padding {
top: p[0],
Expand All @@ -95,7 +109,7 @@ impl std::convert::From<[u16; 2]> for Padding {
}
}

impl std::convert::From<[u16; 4]> for Padding {
impl From<[u16; 4]> for Padding {
fn from(p: [u16; 4]) -> Self {
Padding {
top: p[0],
Expand Down
27 changes: 27 additions & 0 deletions core/src/size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Size {
width: self.width.min(other.width),
height: self.height.min(other.height),
}
}

/// Returns the maximum of each component of this size and another
pub fn max(self, other: Self) -> Self {
Size {
width: self.width.max(other.width),
height: self.height.max(other.height),
}
}
}

impl From<[f32; 2]> for Size {
Expand Down Expand Up @@ -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.

type Output = Size;

fn sub(self, rhs: Self) -> Self::Output {
Size {
width: self.width - rhs.width,
height: self.height - rhs.height,
}
}
}
9 changes: 5 additions & 4 deletions native/src/widget/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,13 @@ pub fn layout<Renderer>(
padding: Padding,
layout_content: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
) -> layout::Node {
let limits = limits.width(width).height(height).pad(padding);
let limits = limits.width(width).height(height);

let mut content = layout_content(renderer, &limits);
content.move_to(Point::new(padding.left.into(), padding.top.into()));
let mut content = layout_content(renderer, &limits.pad(padding));
let padding = padding.fit(content.size(), limits.max());
let size = limits.pad(padding).resolve(content.size()).pad(padding);

let size = limits.resolve(content.size()).pad(padding);
content.move_to(Point::new(padding.left.into(), padding.top.into()));

layout::Node::with_children(size, vec![content])
}
Expand Down
8 changes: 4 additions & 4 deletions native/src/widget/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,11 @@ pub fn layout<Renderer>(
.max_width(max_width)
.max_height(max_height)
.width(width)
.height(height)
.pad(padding);
.height(height);

let mut content = layout_content(renderer, &limits.loose());
let size = limits.resolve(content.size());
let mut content = layout_content(renderer, &limits.pad(padding).loose());
let padding = padding.fit(content.size(), limits.max());
let size = limits.pad(padding).resolve(content.size());

content.move_to(Point::new(padding.left.into(), padding.top.into()));
content.align(
Expand Down
10 changes: 7 additions & 3 deletions native/src/widget/text_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,15 +350,19 @@ where
{
let text_size = size.unwrap_or_else(|| renderer.default_size());

let limits = limits
let text_limits = limits
.pad(padding)
.width(width)
.height(Length::Units(text_size));
let limits = limits.width(width).height(Length::Shrink);

let mut text = layout::Node::new(text_limits.resolve(Size::ZERO));
let padding = padding.fit(text.size(), limits.max());
let size = limits.pad(padding).resolve(text.size()).pad(padding);

let mut text = layout::Node::new(limits.resolve(Size::ZERO));
text.move_to(Point::new(padding.left.into(), padding.top.into()));

layout::Node::with_children(text.size().pad(padding), vec![text])
layout::Node::with_children(size, vec![text])
}

/// Processes an [`Event`] and updates the [`State`] of a [`TextInput`]
Expand Down