diff --git a/crates/bevy_ui/src/render/debug_overlay.rs b/crates/bevy_ui/src/render/debug_overlay.rs index 79001f3ba1..aa9440b8d8 100644 --- a/crates/bevy_ui/src/render/debug_overlay.rs +++ b/crates/bevy_ui/src/render/debug_overlay.rs @@ -1,3 +1,4 @@ +use crate::shader_flags; use crate::ui_node::ComputedNodeTarget; use crate::CalculatedClip; use crate::ComputedNode; @@ -106,7 +107,7 @@ pub fn extract_debug_overlay( flip_y: false, border: BorderRect::all(debug_options.line_width / uinode.inverse_scale_factor()), border_radius: uinode.border_radius(), - node_type: NodeType::Border, + node_type: NodeType::Border(shader_flags::BORDER_ALL), }, main_entity: entity.into(), }); diff --git a/crates/bevy_ui/src/render/gradient.rs b/crates/bevy_ui/src/render/gradient.rs index b908e148e9..b9e0018b1e 100644 --- a/crates/bevy_ui/src/render/gradient.rs +++ b/crates/bevy_ui/src/render/gradient.rs @@ -32,6 +32,8 @@ use bevy_sprite::BorderRect; use bevy_transform::prelude::GlobalTransform; use bytemuck::{Pod, Zeroable}; +use super::shader_flags::BORDER_ALL; + pub const UI_GRADIENT_SHADER_HANDLE: Handle = weak_handle!("10116113-aac4-47fa-91c8-35cbe80dddcb"); @@ -388,7 +390,7 @@ pub fn extract_gradients( for (gradients, node_type) in [ (gradient.map(|g| &g.0), NodeType::Rect), - (gradient_border.map(|g| &g.0), NodeType::Border), + (gradient_border.map(|g| &g.0), NodeType::Border(BORDER_ALL)), ] .iter() .filter_map(|(g, n)| g.map(|g| (g, *n))) @@ -742,8 +744,8 @@ pub fn prepare_gradient( let uvs = { [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y] }; - let mut flags = if gradient.node_type == NodeType::Border { - shader_flags::BORDER + let mut flags = if let NodeType::Border(borders) = gradient.node_type { + borders } else { 0 }; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 8b0d6bad87..4232d207a2 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -229,7 +229,7 @@ pub struct ExtractedUiNode { #[derive(Clone, Copy, Debug, PartialEq)] pub enum NodeType { Rect, - Border, + Border(u32), // shader flags } pub enum ExtractedUiItem { @@ -522,30 +522,63 @@ pub fn extract_uinode_borders( // Don't extract borders with zero width along all edges if computed_node.border() != BorderRect::ZERO { - if let Some(border_color) = maybe_border_color.filter(|bc| !bc.0.is_fully_transparent()) - { - extracted_uinodes.uinodes.push(ExtractedUiNode { - stack_index: computed_node.stack_index, - color: border_color.0.into(), - rect: Rect { - max: computed_node.size(), - ..Default::default() - }, - image, - clip: maybe_clip.map(|clip| clip.clip), - extracted_camera_entity, - item: ExtractedUiItem::Node { - atlas_scaling: None, - transform: global_transform.compute_matrix(), - flip_x: false, - flip_y: false, - border: computed_node.border(), - border_radius: computed_node.border_radius(), - node_type: NodeType::Border, - }, - main_entity: entity.into(), - render_entity: commands.spawn(TemporaryRenderEntity).id(), - }); + 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(), + ]; + + const BORDER_FLAGS: [u32; 4] = [ + shader_flags::BORDER_LEFT, + shader_flags::BORDER_TOP, + shader_flags::BORDER_RIGHT, + shader_flags::BORDER_BOTTOM, + ]; + 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; + + extracted_uinodes.uinodes.push(ExtractedUiNode { + stack_index: computed_node.stack_index, + color, + rect: Rect { + max: computed_node.size(), + ..Default::default() + }, + image, + clip: maybe_clip.map(|clip| clip.clip), + extracted_camera_entity, + item: ExtractedUiItem::Node { + atlas_scaling: None, + transform: global_transform.compute_matrix(), + flip_x: false, + flip_y: false, + border: computed_node.border(), + border_radius: computed_node.border_radius(), + node_type: NodeType::Border(border_flags), + }, + main_entity: entity.into(), + render_entity: commands.spawn(TemporaryRenderEntity).id(), + }); + } } } @@ -574,7 +607,7 @@ pub fn extract_uinode_borders( flip_y: false, border: BorderRect::all(computed_node.outline_width()), border_radius: computed_node.outline_radius(), - node_type: NodeType::Border, + node_type: NodeType::Border(shader_flags::BORDER_ALL), }, main_entity: entity.into(), }); @@ -1081,11 +1114,15 @@ pub mod shader_flags { pub const TEXTURED: u32 = 1; /// Ordering: top left, top right, bottom right, bottom left. pub const CORNERS: [u32; 4] = [0, 2, 2 | 4, 4]; - pub const BORDER: u32 = 8; pub const RADIAL: u32 = 16; pub const FILL_START: u32 = 32; pub const FILL_END: u32 = 64; pub const CONIC: u32 = 128; + pub const BORDER_LEFT: u32 = 256; + pub const BORDER_TOP: u32 = 512; + pub const BORDER_RIGHT: u32 = 1024; + pub const BORDER_BOTTOM: u32 = 2048; + pub const BORDER_ALL: u32 = BORDER_LEFT + BORDER_TOP + BORDER_RIGHT + BORDER_BOTTOM; } pub fn queue_uinodes( @@ -1394,8 +1431,8 @@ pub fn prepare_uinodes( }; let color = extracted_uinode.color.to_f32_array(); - if *node_type == NodeType::Border { - flags |= shader_flags::BORDER; + if let NodeType::Border(border_flags) = *node_type { + flags |= border_flags; } for i in 0..4 { diff --git a/crates/bevy_ui/src/render/ui.wgsl b/crates/bevy_ui/src/render/ui.wgsl index 67e57d8312..e7c7ec4350 100644 --- a/crates/bevy_ui/src/render/ui.wgsl +++ b/crates/bevy_ui/src/render/ui.wgsl @@ -5,7 +5,12 @@ const TEXTURED = 1u; const RIGHT_VERTEX = 2u; const BOTTOM_VERTEX = 4u; -const BORDER: u32 = 8u; +// must align with BORDER_* shader_flags from bevy_ui/render/mod.rs +const BORDER_LEFT: u32 = 256u; +const BORDER_TOP: u32 = 512u; +const BORDER_RIGHT: u32 = 1024u; +const BORDER_BOTTOM: u32 = 2048u; +const BORDER_ANY: u32 = BORDER_LEFT + BORDER_TOP + BORDER_RIGHT + BORDER_BOTTOM; fn enabled(flags: u32, mask: u32) -> bool { return (flags & mask) != 0u; @@ -116,6 +121,27 @@ fn sd_inset_rounded_box(point: vec2, size: vec2, radius: vec4, in return sd_rounded_box(inner_point, inner_size, r); } +fn nearest_border_active(point_vs_mid: vec2, size: vec2, width: vec4, flags: u32) -> bool { + if (flags & BORDER_ANY) == BORDER_ANY { + return true; + } + + // get point vs top left + let point = clamp(point_vs_mid + size * 0.49999, vec2(0.0), size); + + let left = point.x / width.x; + let top = point.y / width.y; + let right = (size.x - point.x) / width.z; + let bottom = (size.y - point.y) / width.w; + + let min_dist = min(min(left, top), min(right, bottom)); + + return (enabled(flags, BORDER_LEFT) && min_dist == left) || + (enabled(flags, BORDER_TOP) && min_dist == top) || + (enabled(flags, BORDER_RIGHT) && min_dist == right) || + (enabled(flags, BORDER_BOTTOM) && min_dist == bottom); +} + // get alpha for antialiasing for sdf fn antialias(distance: f32) -> f32 { // Using the fwidth(distance) was causing artifacts, so just use the distance. @@ -128,6 +154,7 @@ fn draw_uinode_border( size: vec2, radius: vec4, border: vec4, + flags: u32, ) -> vec4 { // Signed distances. The magnitude is the distance of the point from the edge of the shape. // * Negative values indicate that the point is inside the shape. @@ -147,6 +174,9 @@ fn draw_uinode_border( // outside the outside edge, or inside the inner edge have positive signed distance. let border_distance = max(external_distance, -internal_distance); + // check if this node should apply color for the nearest border + let nearest_border = select(0.0, 1.0, nearest_border_active(point, size, border, flags)); + #ifdef ANTI_ALIAS // At external edges with no border, `border_distance` is equal to zero. // This select statement ensures we only perform anti-aliasing where a non-zero width border @@ -158,7 +188,7 @@ fn draw_uinode_border( #endif // Blend mode ALPHA_BLENDING is used for UI elements, so we don't premultiply alpha here. - return vec4(color.rgb, saturate(color.a * t)); + return vec4(color.rgb, saturate(color.a * t * nearest_border)); } fn draw_uinode_background( @@ -188,8 +218,8 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 { // This allows us to draw both textured and untextured shapes together in the same batch. let color = select(in.color, in.color * texture_color, enabled(in.flags, TEXTURED)); - if enabled(in.flags, BORDER) { - return draw_uinode_border(color, in.point, in.size, in.radius, in.border); + if enabled(in.flags, BORDER_ANY) { + return draw_uinode_border(color, in.point, in.size, in.radius, in.border, in.flags); } else { return draw_uinode_background(color, in.point, in.size, in.radius, in.border); } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index fc0cf0d127..3c6b8b0a90 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1,5 +1,5 @@ use crate::{FocusPolicy, UiRect, Val}; -use bevy_color::Color; +use bevy_color::{Alpha, Color}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{prelude::*, system::SystemParam}; use bevy_math::{vec4, Rect, UVec2, Vec2, Vec4Swizzles}; @@ -2036,17 +2036,40 @@ impl> From for BackgroundColor { derive(serde::Serialize, serde::Deserialize), reflect(Serialize, Deserialize) )] -pub struct BorderColor(pub Color); +pub struct BorderColor { + pub top: Color, + pub right: Color, + pub bottom: Color, + pub left: Color, +} impl> From for BorderColor { fn from(color: T) -> Self { - Self(color.into()) + Self::all(color.into()) } } impl BorderColor { /// Border color is transparent by default. - pub const DEFAULT: Self = BorderColor(Color::NONE); + pub const DEFAULT: Self = BorderColor::all(Color::NONE); + + /// Helper to create a `BorderColor` struct with all borders set to the given color + pub const fn all(color: Color) -> Self { + Self { + top: color, + bottom: color, + left: color, + right: color, + } + } + + /// Check if all contained border colors are transparent + pub fn is_fully_transparent(&self) -> bool { + self.top.is_fully_transparent() + && self.bottom.is_fully_transparent() + && self.left.is_fully_transparent() + && self.right.is_fully_transparent() + } } impl Default for BorderColor { diff --git a/examples/3d/color_grading.rs b/examples/3d/color_grading.rs index 0b2616c187..17ee0cdacf 100644 --- a/examples/3d/color_grading.rs +++ b/examples/3d/color_grading.rs @@ -252,7 +252,7 @@ fn add_button_for_value( margin: UiRect::right(Val::Px(12.0)), ..default() }, - BorderColor(Color::WHITE), + BorderColor::all(Color::WHITE), BorderRadius::MAX, BackgroundColor(Color::BLACK), )) diff --git a/examples/3d/split_screen.rs b/examples/3d/split_screen.rs index c11fb2e3cc..8baaacd69b 100644 --- a/examples/3d/split_screen.rs +++ b/examples/3d/split_screen.rs @@ -137,7 +137,7 @@ fn setup( align_items: AlignItems::Center, ..default() }, - BorderColor(Color::WHITE), + BorderColor::all(Color::WHITE), BackgroundColor(Color::srgb(0.25, 0.25, 0.25)), )) .with_children(|parent| { diff --git a/examples/animation/animation_graph.rs b/examples/animation/animation_graph.rs index 76da8a6644..610074744f 100644 --- a/examples/animation/animation_graph.rs +++ b/examples/animation/animation_graph.rs @@ -295,7 +295,7 @@ fn setup_node_rects(commands: &mut Commands) { justify_content: JustifyContent::Center, ..default() }, - BorderColor(WHITE.into()), + BorderColor::all(WHITE.into()), Outline::new(Val::Px(1.), Val::ZERO, Color::WHITE), )); @@ -349,7 +349,7 @@ fn setup_node_lines(commands: &mut Commands) { border: UiRect::bottom(Val::Px(1.0)), ..default() }, - BorderColor(WHITE.into()), + BorderColor::all(WHITE.into()), )); } @@ -364,7 +364,7 @@ fn setup_node_lines(commands: &mut Commands) { border: UiRect::left(Val::Px(1.0)), ..default() }, - BorderColor(WHITE.into()), + BorderColor::all(WHITE.into()), )); } } diff --git a/examples/animation/animation_masks.rs b/examples/animation/animation_masks.rs index 72408260d6..07261b40df 100644 --- a/examples/animation/animation_masks.rs +++ b/examples/animation/animation_masks.rs @@ -255,7 +255,7 @@ fn add_mask_group_control( margin: UiRect::ZERO, ..default() }, - BorderColor(Color::WHITE), + BorderColor::all(Color::WHITE), BorderRadius::all(Val::Px(3.0)), BackgroundColor(Color::BLACK), )) @@ -292,7 +292,7 @@ fn add_mask_group_control( border: UiRect::top(Val::Px(1.0)), ..default() }, - BorderColor(Color::WHITE), + BorderColor::all(Color::WHITE), )) .with_children(|builder| { for (index, label) in [ @@ -321,7 +321,7 @@ fn add_mask_group_control( }, ..default() }, - BorderColor(Color::WHITE), + BorderColor::all(Color::WHITE), AnimationControl { group_id: mask_group_id, label: *label, diff --git a/examples/helpers/widgets.rs b/examples/helpers/widgets.rs index 5d83c18c12..14873acc5f 100644 --- a/examples/helpers/widgets.rs +++ b/examples/helpers/widgets.rs @@ -28,7 +28,7 @@ pub struct RadioButtonText; pub const BUTTON_BORDER: UiRect = UiRect::all(Val::Px(1.0)); /// The color of the border that surrounds buttons. -pub const BUTTON_BORDER_COLOR: BorderColor = BorderColor(Color::WHITE); +pub const BUTTON_BORDER_COLOR: BorderColor = BorderColor::all(Color::WHITE); /// The amount of rounding to apply to button corners. pub const BUTTON_BORDER_RADIUS_SIZE: Val = Val::Px(6.0); diff --git a/examples/testbed/full_ui.rs b/examples/testbed/full_ui.rs index 551785ca0f..02f69ce955 100644 --- a/examples/testbed/full_ui.rs +++ b/examples/testbed/full_ui.rs @@ -221,7 +221,7 @@ fn setup(mut commands: Commands, asset_server: Res) { justify_content: JustifyContent::Center, ..default() }, - BorderColor(LIME.into()), + BorderColor::all(LIME.into()), BackgroundColor(Color::srgb(0.8, 0.8, 1.)), )) .with_children(|parent| { diff --git a/examples/testbed/ui.rs b/examples/testbed/ui.rs index 1877016426..f81fbac0b4 100644 --- a/examples/testbed/ui.rs +++ b/examples/testbed/ui.rs @@ -227,7 +227,7 @@ mod borders { ..default() }, BackgroundColor(MAROON.into()), - BorderColor(RED.into()), + BorderColor::all(RED.into()), Outline { width: Val::Px(10.), offset: Val::Px(10.), @@ -319,7 +319,7 @@ mod box_shadow { border: UiRect::all(Val::Px(2.)), ..default() }, - BorderColor(WHITE.into()), + BorderColor::all(WHITE.into()), border_radius, BackgroundColor(BLUE.into()), BoxShadow::new( @@ -417,7 +417,7 @@ mod overflow { overflow, ..default() }, - BorderColor(RED.into()), + BorderColor::all(RED.into()), BackgroundColor(Color::WHITE), )) .with_children(|parent| { @@ -519,7 +519,7 @@ mod layout_rounding { ..Default::default() }, BackgroundColor(MAROON.into()), - BorderColor(DARK_BLUE.into()), + BorderColor::all(DARK_BLUE.into()), )); } }); diff --git a/examples/ui/borders.rs b/examples/ui/borders.rs index c85bd22ee5..745345219e 100644 --- a/examples/ui/borders.rs +++ b/examples/ui/borders.rs @@ -120,7 +120,12 @@ fn setup(mut commands: Commands) { ..default() }, BackgroundColor(MAROON.into()), - BorderColor(RED.into()), + BorderColor { + top: RED.into(), + bottom: YELLOW.into(), + left: GREEN.into(), + right: BLUE.into(), + }, Outline { width: Val::Px(6.), offset: Val::Px(6.), @@ -182,7 +187,12 @@ fn setup(mut commands: Commands) { ..default() }, BackgroundColor(MAROON.into()), - BorderColor(RED.into()), + BorderColor { + top: RED.into(), + bottom: YELLOW.into(), + left: GREEN.into(), + right: BLUE.into(), + }, BorderRadius::px( border_size(border.left, border.top), border_size(border.right, border.top), diff --git a/examples/ui/box_shadow.rs b/examples/ui/box_shadow.rs index c30a1d6ce7..b008fba88b 100644 --- a/examples/ui/box_shadow.rs +++ b/examples/ui/box_shadow.rs @@ -202,7 +202,7 @@ fn setup(mut commands: Commands) { border: UiRect::all(Val::Px(4.)), ..default() }, - BorderColor(LIGHT_SKY_BLUE.into()), + BorderColor::all(LIGHT_SKY_BLUE.into()), BorderRadius::all(Val::Px(20.)), BackgroundColor(DEEP_SKY_BLUE.into()), BoxShadow(vec![ @@ -253,7 +253,7 @@ fn box_shadow_node_bundle( border: UiRect::all(Val::Px(4.)), ..default() }, - BorderColor(LIGHT_SKY_BLUE.into()), + BorderColor::all(LIGHT_SKY_BLUE.into()), border_radius, BackgroundColor(DEEP_SKY_BLUE.into()), BoxShadow::new( diff --git a/examples/ui/button.rs b/examples/ui/button.rs index 8436d937b1..e533a84867 100644 --- a/examples/ui/button.rs +++ b/examples/ui/button.rs @@ -44,7 +44,7 @@ fn button_system( input_focus.set(entity); **text = "Press".to_string(); *color = PRESSED_BUTTON.into(); - border_color.0 = RED.into(); + *border_color = BorderColor::all(RED.into()); // The accessibility system's only update the button's state when the `Button` component is marked as changed. button.set_changed(); @@ -53,14 +53,14 @@ fn button_system( input_focus.set(entity); **text = "Hover".to_string(); *color = HOVERED_BUTTON.into(); - border_color.0 = Color::WHITE; + *border_color = BorderColor::all(Color::WHITE); button.set_changed(); } Interaction::None => { input_focus.clear(); **text = "Button".to_string(); *color = NORMAL_BUTTON.into(); - border_color.0 = Color::BLACK; + *border_color = BorderColor::all(Color::BLACK); } } } @@ -93,7 +93,7 @@ fn button(asset_server: &AssetServer) -> impl Bundle + use<> { align_items: AlignItems::Center, ..default() }, - BorderColor(Color::BLACK), + BorderColor::all(Color::BLACK), BorderRadius::MAX, BackgroundColor(NORMAL_BUTTON), children![( diff --git a/examples/ui/directional_navigation.rs b/examples/ui/directional_navigation.rs index b6f4a0d051..41b0a4b012 100644 --- a/examples/ui/directional_navigation.rs +++ b/examples/ui/directional_navigation.rs @@ -361,9 +361,9 @@ fn highlight_focused_element( if input_focus.0 == Some(entity) && input_focus_visible.0 { // Don't change the border size / radius here, // as it would result in wiggling buttons when they are focused - border_color.0 = FOCUSED_BORDER.into(); + *border_color = BorderColor::all(FOCUSED_BORDER.into()); } else { - border_color.0 = Color::NONE; + *border_color = BorderColor::DEFAULT; } } } diff --git a/examples/ui/ghost_nodes.rs b/examples/ui/ghost_nodes.rs index abcebae3ff..6678b24a80 100644 --- a/examples/ui/ghost_nodes.rs +++ b/examples/ui/ghost_nodes.rs @@ -83,7 +83,7 @@ fn create_button() -> impl Bundle { align_items: AlignItems::Center, ..default() }, - BorderColor(Color::BLACK), + BorderColor::all(Color::BLACK), BorderRadius::MAX, BackgroundColor(Color::srgb(0.15, 0.15, 0.15)), ) diff --git a/examples/ui/overflow.rs b/examples/ui/overflow.rs index 2bd9aa873e..c5764ce328 100644 --- a/examples/ui/overflow.rs +++ b/examples/ui/overflow.rs @@ -72,7 +72,7 @@ fn setup(mut commands: Commands, asset_server: Res) { overflow, ..default() }, - BorderColor(Color::BLACK), + BorderColor::all(Color::BLACK), BackgroundColor(GRAY.into()), )) .with_children(|parent| { diff --git a/examples/ui/overflow_clip_margin.rs b/examples/ui/overflow_clip_margin.rs index 81c7d6a829..aebcc06828 100644 --- a/examples/ui/overflow_clip_margin.rs +++ b/examples/ui/overflow_clip_margin.rs @@ -67,7 +67,7 @@ fn setup(mut commands: Commands, asset_server: Res) { ..default() }, BackgroundColor(GRAY.into()), - BorderColor(Color::BLACK), + BorderColor::all(Color::BLACK), )) .with_children(|parent| { parent diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index 95b0008664..72a072d788 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -221,7 +221,7 @@ fn spawn_button( margin: UiRect::horizontal(Val::Px(2.)), ..Default::default() }, - BorderColor(if active { + BorderColor::all(if active { ACTIVE_BORDER_COLOR } else { INACTIVE_BORDER_COLOR @@ -345,7 +345,7 @@ fn update_radio_buttons_colors( ) }; - border_query.get_mut(id).unwrap().0 = border_color; + *border_query.get_mut(id).unwrap() = BorderColor::all(border_color); for &child in children_query.get(id).into_iter().flatten() { color_query.get_mut(child).unwrap().0 = inner_color; for &grandchild in children_query.get(child).into_iter().flatten() { diff --git a/examples/ui/tab_navigation.rs b/examples/ui/tab_navigation.rs index c6060bd848..0924269353 100644 --- a/examples/ui/tab_navigation.rs +++ b/examples/ui/tab_navigation.rs @@ -42,17 +42,17 @@ fn button_system( Interaction::Pressed => { **text = "Press".to_string(); *color = PRESSED_BUTTON.into(); - border_color.0 = RED.into(); + *border_color = BorderColor::all(RED.into()); } Interaction::Hovered => { **text = "Hover".to_string(); *color = HOVERED_BUTTON.into(); - border_color.0 = Color::WHITE; + *border_color = BorderColor::all(Color::WHITE); } Interaction::None => { **text = "Button".to_string(); *color = NORMAL_BUTTON.into(); - border_color.0 = Color::BLACK; + *border_color = BorderColor::all(Color::BLACK); } } } @@ -198,7 +198,7 @@ fn create_button(parent: &mut ChildSpawnerCommands<'_>, asset_server: &AssetServ align_items: AlignItems::Center, ..default() }, - BorderColor(Color::BLACK), + BorderColor::all(Color::BLACK), BorderRadius::MAX, BackgroundColor(NORMAL_BUTTON), TabIndex(0), diff --git a/examples/ui/viewport_debug.rs b/examples/ui/viewport_debug.rs index 5d0ea92749..58790f9381 100644 --- a/examples/ui/viewport_debug.rs +++ b/examples/ui/viewport_debug.rs @@ -75,7 +75,7 @@ fn spawn_with_viewport_coords(commands: &mut Commands) { flex_wrap: FlexWrap::Wrap, ..default() }, - BorderColor(PALETTE[0].into()), + BorderColor::all(PALETTE[0].into()), Coords::Viewport, )) .with_children(|builder| { @@ -87,7 +87,7 @@ fn spawn_with_viewport_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[2].into()), - BorderColor(PALETTE[9].into()), + BorderColor::all(PALETTE[9].into()), )); builder.spawn(( @@ -107,7 +107,7 @@ fn spawn_with_viewport_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[4].into()), - BorderColor(PALETTE[8].into()), + BorderColor::all(PALETTE[8].into()), )); builder.spawn(( @@ -118,7 +118,7 @@ fn spawn_with_viewport_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[5].into()), - BorderColor(PALETTE[8].into()), + BorderColor::all(PALETTE[8].into()), )); builder.spawn(( @@ -138,7 +138,7 @@ fn spawn_with_viewport_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[7].into()), - BorderColor(PALETTE[9].into()), + BorderColor::all(PALETTE[9].into()), )); }); } @@ -153,7 +153,7 @@ fn spawn_with_pixel_coords(commands: &mut Commands) { flex_wrap: FlexWrap::Wrap, ..default() }, - BorderColor(PALETTE[1].into()), + BorderColor::all(PALETTE[1].into()), Coords::Pixel, )) .with_children(|builder| { @@ -165,7 +165,7 @@ fn spawn_with_pixel_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[2].into()), - BorderColor(PALETTE[9].into()), + BorderColor::all(PALETTE[9].into()), )); builder.spawn(( @@ -185,7 +185,7 @@ fn spawn_with_pixel_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[4].into()), - BorderColor(PALETTE[8].into()), + BorderColor::all(PALETTE[8].into()), )); builder.spawn(( @@ -196,7 +196,7 @@ fn spawn_with_pixel_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[5].into()), - BorderColor(PALETTE[8].into()), + BorderColor::all(PALETTE[8].into()), )); builder.spawn(( @@ -216,7 +216,7 @@ fn spawn_with_pixel_coords(commands: &mut Commands) { ..default() }, BackgroundColor(PALETTE[7].into()), - BorderColor(PALETTE[9].into()), + BorderColor::all(PALETTE[9].into()), )); }); } diff --git a/examples/ui/viewport_node.rs b/examples/ui/viewport_node.rs index 5e6964005d..5a94813d39 100644 --- a/examples/ui/viewport_node.rs +++ b/examples/ui/viewport_node.rs @@ -102,7 +102,7 @@ fn test( border: UiRect::all(Val::Px(5.0)), ..default() }, - BorderColor(Color::WHITE), + BorderColor::all(Color::WHITE), ViewportNode::new(camera), )) .observe(on_drag_viewport); diff --git a/release-content/migration-guides/separate-border-colors.md b/release-content/migration-guides/separate-border-colors.md new file mode 100644 index 0000000000..28929f22f2 --- /dev/null +++ b/release-content/migration-guides/separate-border-colors.md @@ -0,0 +1,6 @@ +--- +title: Separate Border Colors +pull_requests: [18682] +--- + +The `BorderColor` struct now contains separate fields for each edge, `top`, `bottom`, `left`, `right`. To keep the existing behavior, replace `BorderColor(color)` with `BorderColor::all(color)`, and `border_color.0 = new_color` with `*border_color = BorderColor::all(new_color)`.