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

Ui Node Borders #7795

Merged
merged 34 commits into from
Jun 14, 2023
Merged

Ui Node Borders #7795

merged 34 commits into from
Jun 14, 2023

Conversation

ickshonpe
Copy link
Contributor

@ickshonpe ickshonpe commented Feb 23, 2023

Objective

Implement borders for UI nodes.

Relevant discussion: #7785
Related: #5924, #3991

borders

Solution

Add an extraction function to draw the borders.


Can only do one colour rectangular borders due to the limitations of the Bevy UI renderer.

Maybe it can be combined with #3991 eventually to add curved border support.

Changelog

  • Added a component BorderColor.
  • Added the extract_uinode_borders system to the UI Render App.
  • Added the UI example borders

* Added the module `border`
* Added `BorderStyle` and `CalculatedBorder` types.
* Added `border_style` and `calculated_border` fields to `NodeBundle` and `ButtonBundle`
* Added the `extract_uinode_borders` system to the UI Render App.
* Added the `calculate_borders_system` which calculates the border geometry for each node.
* Added the UI example `borders`
* Changed the button example to give the button a border.
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-UI Graphical user interfaces, styles, layouts, and widgets labels Feb 23, 2023
@alice-i-cecile alice-i-cecile added this to the 0.11 milestone Feb 23, 2023
@alice-i-cecile alice-i-cecile self-requested a review February 23, 2023 16:19
* Changed `calculate_borders_system` to remove the previous border geometry of degnerate nodes before continuing.
@ickshonpe
Copy link
Contributor Author

I'm not sure what the overflow behaviour for borders should be. I have it clamp the border thickness to the size of the node at the moment, which seems reasonable enough.

@nicoburns
Copy link
Contributor

I'm not sure what the overflow behaviour for borders should be. I have it clamp the border thickness to the size of the node at the moment, which seems reasonable enough.

As far as I can see, Chrome will always expand nodes to fit borders. And it seems that Taffy also implements this. So from Bevy's perspective, I think this will be a case of "never happens" (or at least shouldn't).

@nicoburns
Copy link
Contributor

Update: Taffy does not in fact do this. We'll probably want to fix Taffy here.

@mockersf
Copy link
Member

mockersf commented Feb 23, 2023

Would it be possible to combine this PR with creating a new type specific for borders instead of UiRect (#7710) to have the width/color by border side in this PR?

@ickshonpe
Copy link
Contributor Author

Would it be possible to combine this PR with creating a new type specific for borders instead of UiRect (#7710) to have the width/color by border side in this PR?

I think I'd prefer to keep this PR just focused on the implementation if we can.

* moved `compute_matrix` out of loop
* added comments to border module
* removed border overflow clamping
* Renamed `BorderStyle` to `BorderColor` and made it a tuple-struct.
* Added `BorderBundle` which contains the components needed by a node to draw a border.
* Renamed the `border_style` fields of `NodeBundle` and `ButtonBundle` to `border_color`.
@doup
Copy link
Contributor

doup commented Mar 7, 2023

I'm not sure what the overflow behaviour for borders should be. I have it clamp the border thickness to the size of the node at the moment, which seems reasonable enough.

If this refers to what happens when border overflows I suppose it depends on the parent node "overflow" property? Related though, is how the border affects the node size (CSS box-sizing), I would say that the most sane way is to grow the border inwards, see box-sizing: border-box: https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing

I mean, if the node has 200px width, and has a 10px border, which is the size of the node? 200px? 220px?

(ignore me if this unrelated 😅 )

@nicoburns
Copy link
Contributor

nicoburns commented Mar 7, 2023

I mean, if the node has 200px width, and has a 10px border, which is the size of the node? 200px? 220px?

It is indeed 200px (the border grows inwards) because we use box-sizing: border-box (historical note: it used to be 200px in internet explorer and 220px in Firefox - now you know why web dev was such a nightmare in the past). However, on the web if the node is 0px and has a 10px border, then the node will end up 20px wide. I'm currently implementing this in Taffy here: DioxusLabs/taffy#372, after which I don't think bevy will need to worry about this as borders will always fit in the computed layout.

@doup
Copy link
Contributor

doup commented Mar 8, 2023

I'm old enough to have suffered those CSS quirks… 😅 Anyway, I was asking because ickshonpe was asking about overflow behaviour; for a moment I though Bevy wasn't doing border-box.

Although, I totally forgot that the sum of borders could be bigger than width… nice that it's being fixed. The PR you link means that size will be computed as: max(size, border + padding)?

Btw, unrelated, but just wanted to mention that you're doing an amazing job with Taffy. ❤️

@nicoburns
Copy link
Contributor

nicoburns commented Mar 8, 2023

for a moment I though Bevy wasn't doing border-box

We're definitely doing border-box! Making that the default (well, only) style is our one (intentional) deviation from the web. We have had content-box support requested, but I'm pretty reluctant to add it. Yoga, from which Taffy was originally derived mentions that it's model is (unintentionally I think) a bit of a hybrid between border-box and content-box, so it's possible we're not completely compliant with the border-box model. But I think we're pretty close now if not.

The PR you link means that size will be computed as: max(size, border + padding)?

Yes, although the computation of size in that formula is itself quite complex, involving the size, min_size,max_size and aspect_ratio styles. As well as the node's content based size and it's flexbox alignment.

Btw, unrelated, but just wanted to mention that you're doing an amazing job with Taffy. ❤️

Thanks!

@nicoburns nicoburns mentioned this pull request Jun 2, 2023
@mockersf
Copy link
Member

mockersf commented Jun 8, 2023

running example many_buttons without text:

  • without borders, around 250 fps
  • with borders on each button: around 120 fps

I think it's probably OK but there's definitely a perf impact

@ickshonpe
Copy link
Contributor Author

running example many_buttons without text:

  • without borders, around 250 fps
  • with borders on each button: around 120 fps

I think it's probably OK but there's definitely a perf impact

Yep considering that by adding borders to many_buttons you draw an extra 50000 quads it's not that bad. If performance is really crucial you can always fall back to the old method of drawing a border by using margins or padding to draw a node within another node.

@alice-i-cecile alice-i-cecile requested review from JMS55 and IceSentry June 9, 2023 16:11
match value {
Val::Auto => 0.,
Val::Px(px) => px.max(0.),
Val::Percent(percent) => (parent_width * percent / 100.).max(0.),
Copy link
Member

Choose a reason for hiding this comment

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

I'd like to see a comment here about why we decided to use parent width specifically. IIRC it's consistent with CSS, but it's arbitrary enough that it's helpful to call out.

},
];

let transform = global_transform.compute_matrix();
Copy link
Member

Choose a reason for hiding this comment

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

This name is quite unclear.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is just the regular transform of the uinode. In the loop it's translated to the center of each rectangle that constitutes the border. It feels to me like it might be confusing to call it anything else.

@alice-i-cecile
Copy link
Member

Approach seems good, code is generally good. Examples are fine, if still pretty artificial. There are a few tricky bits of math that would really benefit from a bit more explanation.

@alice-i-cecile
Copy link
Member

@natasria could we get your opinion on this PR vs 8381? They're both trying to do the same thing: we should pick one and merge it for the upcoming release :)

@togetherwithasteria
Copy link
Contributor

@natasria could we get your opinion on this PR vs 8381? They're both trying to do the same thing: we should pick one and merge it for the upcoming release :)

Well, feature-wise #8381 has border radiuses, but it forces the borders to be the same for all sides, this PR allows specifying for different borders in the sides.

#8381 still have rough edges to polish on border radiuses (it's just aliased borders so the name is true? <3 ) and sharp transition issues too, but I don't feel it's a blocker.

@togetherwithasteria
Copy link
Contributor

I've just realized the border limitations, oh my god. T_T

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Jun 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Feature A new feature, making something new possible S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants