-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
separate border colors #18682
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
base: main
Are you sure you want to change the base?
separate border colors #18682
Conversation
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.
LGTM (assuming CI is fixed)
It looks like your PR is a breaking change, but you didn't provide a migration guide. Please review the instructions for writing migration guides, then expand or revise the content in the migration guides directory to reflect your changes. |
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 is good for an initial implementation.
It's unpleasant how BorderColor stores four colours even though most of the time it will only be using one of them, but other options like having separate components for multi-colored borders or something seem worse.
Drawing the border in multiple passes seems fine. Adding an extra phase item + extracted uinode though for each additional border color is a bit bad, but it doesn't matter for the common single color border case so it should be fine for now.
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
crates/bevy_ui/src/render/mod.rs
Outdated
if let Some(border_color) = maybe_border_color.filter(|bc| !bc.is_fully_transparent()) { | ||
// helper to allow for `Eq` color comparisons so we can build a hashset | ||
let convert = | ||
|c: Color| -> [u8; 16] { bytemuck::cast::<_, [u8; 16]>(c.to_linear()) }; | ||
|
||
// gather unique colors | ||
unique_colors.clear(); | ||
unique_colors.extend( | ||
[ | ||
border_color.left, | ||
border_color.top, | ||
border_color.right, | ||
border_color.bottom, | ||
] | ||
.map(convert), | ||
); | ||
|
||
for &converted_color in unique_colors.iter() { | ||
let color = bytemuck::cast::<[u8; 16], LinearRgba>(converted_color); | ||
|
||
// skip transparent | ||
if color.alpha == 0.0 { | ||
continue; | ||
} | ||
|
||
// gather flags of borders that match this color | ||
let border_flags = [ | ||
(border_color.left, shader_flags::BORDER_LEFT), | ||
(border_color.top, shader_flags::BORDER_TOP), | ||
(border_color.right, shader_flags::BORDER_RIGHT), | ||
(border_color.bottom, shader_flags::BORDER_BOTTOM), | ||
] | ||
.map(|(border_color, flag)| { | ||
if convert(border_color) == converted_color { | ||
flag | ||
} else { | ||
0 | ||
} | ||
}) | ||
.into_iter() | ||
.sum::<u32>(); |
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.
Thought about it again while trying to go to sleep and this seems pretty simple:
if let Some(border_color) = maybe_border_color {
let border_colors = [
border_color.left.to_linear(),
border_color.top.to_linear(),
border_color.right.to_linear(),
border_color.bottom.to_linear(),
];
let mut completed_flags = 0;
for (i, &color) in border_colors.iter().enumerate() {
if color.is_fully_transparent() {
continue;
}
let mut border_flags = BORDER_FLAGS[i];
if completed_flags & border_flags != 0 {
continue;
}
for j in i + 1..4 {
if color == border_colors[j] {
border_flags |= BORDER_FLAGS[j];
}
}
completed_flags |= border_flags;
with
const BORDER_FLAGS: [u32; 4] = [
shader_flags::BORDER_LEFT,
shader_flags::BORDER_TOP,
shader_flags::BORDER_RIGHT,
shader_flags::BORDER_BOTTOM,
];
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.
yes fair enough. has the benefit of predictable ordering too.
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
Objective
allow specifying the left/top/right/bottom border colors separately for ui elements
fixes #14773
Solution
BorderColor
toi chose to do this rather than adding multiple colors to the ExtractedUiNode in order to minimize the impact for the common case where all border colors are the same.
Testing
modified the
borders
example to use separate colors:the behaviour is a bit weird but it mirrors html/css border behaviour.
Migration:
To keep the existing behaviour, just change
BorderColor(color)
intoBorderColor::all(color)
.