bevy/examples/ui/overflow.rs

126 lines
5 KiB
Rust
Raw Normal View History

Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
//! Simple example demonstrating overflow behavior.
use bevy::{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)
Make clipped areas of UI nodes non-interactive (#10454) # Objective Problems: * The clipped, non-visible regions of UI nodes are interactive. * `RelativeCursorPostion` is set relative to the visible part of the node. It should be relative to the whole node. * The `RelativeCursorPostion::mouse_over` method returns `true` when the mouse is over a clipped part of a node. fixes #10470 ## Solution Intersect a node's bounding rect with its clipping rect before checking if it contains the cursor. Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. Instead of checking if the normalized cursor position lies within a unit square, it instead checks if it is contained by `normalized_visible_node_rect`. Added outlines to the `overflow` example that appear when the cursor is over the visible part of the images, but not the clipped area. --- ## Changelog * `ui_focus_system` intersects a node's bounding rect with its clipping rect before checking if mouse over. * Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. * `RelativeCursorPostion` is calculated relative to the whole node's position and size, not only the visible part. * `RelativeCursorPosition::mouse_over` only returns true when the mouse is over an unclipped region of the UI node. * Removed the `Deref` and `DerefMut` derives from `RelativeCursorPosition` as it is no longer a single field struct. * Added some outlines to the `overflow` example that respond to `Interaction` changes. ## Migration Guide The clipped areas of UI nodes are no longer interactive. `RelativeCursorPostion` is now calculated relative to the whole node's position and size, not only the visible part. Its `mouse_over` method only returns true when the cursor is over an unclipped part of the node. `RelativeCursorPosition` no longer implements `Deref` and `DerefMut`.
2023-11-22 14:30:38 +00:00
.add_systems(Update, update_outlines)
Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
.run();
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2dBundle::default());
let text_style = TextStyle {
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
font_size: 20.0,
..default()
Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
};
let image = asset_server.load("branding/icon.png");
commands
.spawn(NodeBundle {
style: Style {
Have a separate implicit viewport node per root node + make viewport node `Display::Grid` (#9637) # Objective Make `bevy_ui` "root" nodes more intuitive to use/style by: - Removing the implicit flexbox styling (such as stretch alignment) that is applied to them, and replacing it with more intuitive CSS Grid styling (notably with stretch alignment disabled in both axes). - Making root nodes layout independently of each other. Instead of there being a single implicit "viewport" node that all root nodes are children of, there is now an implicit "viewport" node *per root node*. And layout of each tree is computed separately. ## Solution - Remove the global implicit viewport node, and instead create an implicit viewport node for each user-specified root node. - Keep track of both the user-specified root nodes and the implicit viewport nodes in a separate `Vec`. - Use the window's size as the `available_space` parameter to `Taffy.compute_layout` rather than setting it on the implicit viewport node (and set the viewport to `height: 100%; width: 100%` to make this "just work"). --- ## Changelog - Bevy UI now lays out root nodes independently of each other in separate layout contexts. - The implicit viewport node (which contains each user-specified root node) is now `Display::Grid` with `align_items` and `justify_items` both set to `Start`. ## Migration Guide - Bevy UI now lays out root nodes independently of each other in separate layout contexts. If you were relying on your root nodes being able to affect each other's layouts, then you may need to wrap them in a single root node. - The implicit viewport node (which contains each user-specified root node) is now `Display::Grid` with `align_items` and `justify_items` both set to `Start`. You may need to add `height: Val::Percent(100.)` to your root nodes if you were previously relying on being implicitly set.
2023-09-19 15:14:46 +00:00
width: Val::Percent(100.),
height: Val::Percent(100.),
Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..Default::default()
},
background_color: Color::ANTIQUE_WHITE.into(),
..Default::default()
})
.with_children(|parent| {
for overflow in [
Overflow::visible(),
Overflow::clip_x(),
Overflow::clip_y(),
Overflow::clip(),
] {
parent
.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
align_items: AlignItems::Center,
margin: UiRect::horizontal(Val::Px(25.)),
..Default::default()
},
..Default::default()
})
.with_children(|parent| {
let label = format!("{overflow:#?}");
parent
.spawn(NodeBundle {
style: Style {
padding: UiRect::all(Val::Px(10.)),
margin: UiRect::bottom(Val::Px(25.)),
..Default::default()
},
background_color: Color::DARK_GRAY.into(),
..Default::default()
})
.with_children(|parent| {
parent.spawn(TextBundle {
text: Text::from_section(label, text_style.clone()),
..Default::default()
});
});
parent
.spawn(NodeBundle {
style: Style {
width: Val::Px(100.),
height: Val::Px(100.),
Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
padding: UiRect {
left: Val::Px(25.),
top: Val::Px(25.),
..Default::default()
},
overflow,
..Default::default()
},
background_color: Color::GRAY.into(),
..Default::default()
})
.with_children(|parent| {
Make clipped areas of UI nodes non-interactive (#10454) # Objective Problems: * The clipped, non-visible regions of UI nodes are interactive. * `RelativeCursorPostion` is set relative to the visible part of the node. It should be relative to the whole node. * The `RelativeCursorPostion::mouse_over` method returns `true` when the mouse is over a clipped part of a node. fixes #10470 ## Solution Intersect a node's bounding rect with its clipping rect before checking if it contains the cursor. Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. Instead of checking if the normalized cursor position lies within a unit square, it instead checks if it is contained by `normalized_visible_node_rect`. Added outlines to the `overflow` example that appear when the cursor is over the visible part of the images, but not the clipped area. --- ## Changelog * `ui_focus_system` intersects a node's bounding rect with its clipping rect before checking if mouse over. * Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. * `RelativeCursorPostion` is calculated relative to the whole node's position and size, not only the visible part. * `RelativeCursorPosition::mouse_over` only returns true when the mouse is over an unclipped region of the UI node. * Removed the `Deref` and `DerefMut` derives from `RelativeCursorPosition` as it is no longer a single field struct. * Added some outlines to the `overflow` example that respond to `Interaction` changes. ## Migration Guide The clipped areas of UI nodes are no longer interactive. `RelativeCursorPostion` is now calculated relative to the whole node's position and size, not only the visible part. Its `mouse_over` method only returns true when the cursor is over an unclipped part of the node. `RelativeCursorPosition` no longer implements `Deref` and `DerefMut`.
2023-11-22 14:30:38 +00:00
parent.spawn((
ImageBundle {
image: UiImage::new(image.clone()),
style: Style {
min_width: Val::Px(100.),
min_height: Val::Px(100.),
..Default::default()
},
background_color: Color::WHITE.into(),
Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
..Default::default()
},
Make clipped areas of UI nodes non-interactive (#10454) # Objective Problems: * The clipped, non-visible regions of UI nodes are interactive. * `RelativeCursorPostion` is set relative to the visible part of the node. It should be relative to the whole node. * The `RelativeCursorPostion::mouse_over` method returns `true` when the mouse is over a clipped part of a node. fixes #10470 ## Solution Intersect a node's bounding rect with its clipping rect before checking if it contains the cursor. Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. Instead of checking if the normalized cursor position lies within a unit square, it instead checks if it is contained by `normalized_visible_node_rect`. Added outlines to the `overflow` example that appear when the cursor is over the visible part of the images, but not the clipped area. --- ## Changelog * `ui_focus_system` intersects a node's bounding rect with its clipping rect before checking if mouse over. * Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. * `RelativeCursorPostion` is calculated relative to the whole node's position and size, not only the visible part. * `RelativeCursorPosition::mouse_over` only returns true when the mouse is over an unclipped region of the UI node. * Removed the `Deref` and `DerefMut` derives from `RelativeCursorPosition` as it is no longer a single field struct. * Added some outlines to the `overflow` example that respond to `Interaction` changes. ## Migration Guide The clipped areas of UI nodes are no longer interactive. `RelativeCursorPostion` is now calculated relative to the whole node's position and size, not only the visible part. Its `mouse_over` method only returns true when the cursor is over an unclipped part of the node. `RelativeCursorPosition` no longer implements `Deref` and `DerefMut`.
2023-11-22 14:30:38 +00:00
Interaction::default(),
Outline {
width: Val::Px(2.),
offset: Val::Px(2.),
color: Color::NONE,
},
));
Split UI `Overflow` by axis (#8095) # Objective Split the UI overflow enum so that overflow can be set for each axis separately. ## Solution Change `Overflow` from an enum to a struct with `x` and `y` `OverflowAxis` fields, where `OverflowAxis` is an enum with `Clip` and `Visible` variants. Modify `update_clipping` to calculate clipping for each axis separately. If only one axis is clipped, the other axis is given infinite bounds. <img width="642" alt="overflow" src="https://user-images.githubusercontent.com/27962798/227592983-568cf76f-7e40-48c4-a511-43c886f5e431.PNG"> --- ## Changelog * Split the UI overflow implementation so overflow can be set for each axis separately. * Added the enum `OverflowAxis` with `Clip` and `Visible` variants. * Changed `Overflow` to a struct with `x` and `y` fields of type `OverflowAxis`. * `Overflow` has new methods `visible()` and `hidden()` that replace its previous `Clip` and `Visible` variants. * Added `Overflow` helper methods `clip_x()` and `clip_y()` that return a new `Overflow` value with the given axis clipped. * Modified `update_clipping` so it calculates clipping for each axis separately. If a node is only clipped on a single axis, the other axis is given `-f32::INFINITY` to `f32::INFINITY` clipping bounds. ## Migration Guide The `Style` property `Overflow` is now a struct with `x` and `y` fields, that allow for per-axis overflow control. Use these helper functions to replace the variants of `Overflow`: * Replace `Overflow::Visible` with `Overflow::visible()` * Replace `Overflow::Hidden` with `Overflow::clip()`
2023-04-17 22:23:52 +00:00
});
});
}
});
}
Make clipped areas of UI nodes non-interactive (#10454) # Objective Problems: * The clipped, non-visible regions of UI nodes are interactive. * `RelativeCursorPostion` is set relative to the visible part of the node. It should be relative to the whole node. * The `RelativeCursorPostion::mouse_over` method returns `true` when the mouse is over a clipped part of a node. fixes #10470 ## Solution Intersect a node's bounding rect with its clipping rect before checking if it contains the cursor. Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. Instead of checking if the normalized cursor position lies within a unit square, it instead checks if it is contained by `normalized_visible_node_rect`. Added outlines to the `overflow` example that appear when the cursor is over the visible part of the images, but not the clipped area. --- ## Changelog * `ui_focus_system` intersects a node's bounding rect with its clipping rect before checking if mouse over. * Added the field `normalized_visible_node_rect` to `RelativeCursorPosition`. This is set to the bounds of the unclipped area of the node rect by `ui_focus_system` expressed in normalized coordinates relative to the entire node. * `RelativeCursorPostion` is calculated relative to the whole node's position and size, not only the visible part. * `RelativeCursorPosition::mouse_over` only returns true when the mouse is over an unclipped region of the UI node. * Removed the `Deref` and `DerefMut` derives from `RelativeCursorPosition` as it is no longer a single field struct. * Added some outlines to the `overflow` example that respond to `Interaction` changes. ## Migration Guide The clipped areas of UI nodes are no longer interactive. `RelativeCursorPostion` is now calculated relative to the whole node's position and size, not only the visible part. Its `mouse_over` method only returns true when the cursor is over an unclipped part of the node. `RelativeCursorPosition` no longer implements `Deref` and `DerefMut`.
2023-11-22 14:30:38 +00:00
fn update_outlines(mut outlines_query: Query<(&mut Outline, Ref<Interaction>)>) {
for (mut outline, interaction) in outlines_query.iter_mut() {
if interaction.is_changed() {
outline.color = match *interaction {
Interaction::Pressed => Color::RED,
Interaction::Hovered => Color::WHITE,
Interaction::None => Color::NONE,
};
}
}
}