
# Objective Limited implementation of the CSS property `overflow-clip-margin` https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-margin Allows you to control the visible area for clipped content when using overfllow-clip, -hidden, or -scroll and expand it with a margin. Based on #15442 Fixes #15468 ## Solution Adds a new field to Style: `overflow_clip_margin: OverflowClipMargin`. The field is ignored unless overflow-clip, -hidden or -scroll is set on at least one axis. `OverflowClipMargin` has these associated constructor functions: ``` pub const fn content_box() -> Self; pub const fn padding_box() -> Self; pub const fn border_box() -> Self; ``` You can also use the method `with_margin` to increases the size of the visible area: ``` commands .spawn(NodeBundle { style: Style { width: Val::Px(100.), height: Val::Px(100.), padding: UiRect::all(Val::Px(20.)), border: UiRect::all(Val::Px(5.)), overflow: Overflow::clip(), overflow_clip_margin: OverflowClipMargin::border_box().with_margin(25.), ..Default::default() }, border_color: Color::BLACK.into(), background_color: GRAY.into(), ..Default::default() }) ``` `with_margin` expects a length in logical pixels, negative values are clamped to zero. ## Notes * To keep this PR as simple as possible I omitted responsive margin values support. This could be added in a follow up if we want it. * CSS also supports a `margin-box` option but we don't have access to the margin values in `Node` so it's probably not feasible to implement atm. ## Testing ```cargo run --example overflow_clip_margin``` <img width="396" alt="overflow-clip-margin" src="https://github.com/user-attachments/assets/07b51cd6-a565-4451-87a0-fa079429b04b"> ## Migration Guide Style has a new field `OverflowClipMargin`. It allows users to set the visible area for clipped content when using overflow-clip, -hidden, or -scroll and expand it with a margin. There are three associated constructor functions `content_box`, `padding_box` and `border_box`: * `content_box`: elements painted outside of the content box area (the innermost part of the node excluding the padding and border) of the node are clipped. This is the new default behaviour. * `padding_box`: elements painted outside outside of the padding area of the node are clipped. * `border_box`: elements painted outside of the bounds of the node are clipped. This matches the behaviour from Bevy 0.14. There is also a `with_margin` method that increases the size of the visible area by the given number in logical pixels, negative margin values are clamped to zero. `OverflowClipMargin` is ignored unless overflow-clip, -hidden or -scroll is also set on at least one axis of the UI node. --------- Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
103 lines
4.5 KiB
Rust
103 lines
4.5 KiB
Rust
//! Simple example demonstrating the `OverflowClipMargin` style property.
|
|
|
|
use bevy::{color::palettes::css::*, prelude::*, winit::WinitSettings};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
// Only run the app when there is user input. This will significantly reduce CPU/GPU use.
|
|
.insert_resource(WinitSettings::desktop_app())
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
commands.spawn(Camera2d);
|
|
|
|
let image = asset_server.load("branding/icon.png");
|
|
|
|
commands
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
width: Val::Percent(100.),
|
|
height: Val::Percent(100.),
|
|
align_items: AlignItems::Center,
|
|
justify_content: JustifyContent::Center,
|
|
row_gap: Val::Px(40.),
|
|
flex_direction: FlexDirection::Column,
|
|
..Default::default()
|
|
},
|
|
background_color: ANTIQUE_WHITE.into(),
|
|
..Default::default()
|
|
})
|
|
.with_children(|parent| {
|
|
for overflow_clip_margin in [
|
|
OverflowClipMargin::border_box().with_margin(25.),
|
|
OverflowClipMargin::border_box(),
|
|
OverflowClipMargin::padding_box(),
|
|
OverflowClipMargin::content_box(),
|
|
] {
|
|
parent
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
flex_direction: FlexDirection::Row,
|
|
column_gap: Val::Px(20.),
|
|
..Default::default()
|
|
},
|
|
..Default::default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
padding: UiRect::all(Val::Px(10.)),
|
|
margin: UiRect::bottom(Val::Px(25.)),
|
|
..Default::default()
|
|
},
|
|
background_color: Color::srgb(0.25, 0.25, 0.25).into(),
|
|
..Default::default()
|
|
})
|
|
.with_child(Text(format!("{overflow_clip_margin:#?}")));
|
|
|
|
parent
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
margin: UiRect::top(Val::Px(10.)),
|
|
width: Val::Px(100.),
|
|
height: Val::Px(100.),
|
|
padding: UiRect::all(Val::Px(20.)),
|
|
border: UiRect::all(Val::Px(5.)),
|
|
overflow: Overflow::clip(),
|
|
overflow_clip_margin,
|
|
..Default::default()
|
|
},
|
|
border_color: Color::BLACK.into(),
|
|
background_color: GRAY.into(),
|
|
..Default::default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
min_width: Val::Px(50.),
|
|
min_height: Val::Px(50.),
|
|
..Default::default()
|
|
},
|
|
background_color: LIGHT_CYAN.into(),
|
|
..Default::default()
|
|
})
|
|
.with_child(ImageBundle {
|
|
image: UiImage::new(image.clone()),
|
|
style: Style {
|
|
min_width: Val::Px(100.),
|
|
min_height: Val::Px(100.),
|
|
..Default::default()
|
|
},
|
|
..Default::default()
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|