bevy/crates/bevy_ui/src/ui_node.rs

416 lines
13 KiB
Rust
Raw Normal View History

use crate::{Size, UiRect};
use bevy_asset::Handle;
Enforce type safe usage of Handle::get (#4794) # Objective - Sometimes, people might load an asset as one type, then use it with an `Asset`s for a different type. - See e.g. #4784. - This is especially likely with the Gltf types, since users may not have a clear conceptual model of what types the assets will be. - We had an instance of this ourselves, in the `scene_viewer` example ## Solution - Make `Assets::get` require a type safe handle. --- ## Changelog ### Changed - `Assets::<T>::get` and `Assets::<T>::get_mut` now require that the passed handles are `Handle<T>`, improving the type safety of handles. ### Added - `HandleUntyped::typed_weak`, a helper function for creating a weak typed version of an exisitng `HandleUntyped`. ## Migration Guide `Assets::<T>::get` and `Assets::<T>::get_mut` now require that the passed handles are `Handle<T>`, improving the type safety of handles. If you were previously passing in: - a `HandleId`, use `&Handle::weak(id)` instead, to create a weak handle. You may have been able to store a type safe `Handle` instead. - a `HandleUntyped`, use `&handle_untyped.typed_weak()` to create a weak handle of the specified type. This is most likely to be the useful when using [load_folder](https://docs.rs/bevy_asset/latest/bevy_asset/struct.AssetServer.html#method.load_folder) - a `Handle<U>` of of a different type, consider whether this is the correct handle type to store. If it is (i.e. the same handle id is used for multiple different Asset types) use `Handle::weak(handle.id)` to cast to a different type.
2022-05-30 16:59:44 +00:00
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
Move `sprite::Rect` into `bevy_math` (#5686) # Objective Promote the `Rect` utility of `sprite::Rect`, which defines a rectangle by its minimum and maximum corners, to the `bevy_math` crate to make it available as a general math type to all crates without the need to depend on the `bevy_sprite` crate. Fixes #5575 ## Solution Move `sprite::Rect` into `bevy_math` and fix all uses. Implement `Reflect` for `Rect` directly into the `bevy_reflect` crate by having `bevy_reflect` depend on `bevy_math`. This looks like a new dependency, but the `bevy_reflect` was "cheating" for other math types by directly depending on `glam` to reflect other math types, thereby giving the illusion that there was no dependency on `bevy_math`. In practice conceptually Bevy's math types are reflected into the `bevy_reflect` crate to avoid a dependency of that crate to a "lower level" utility crate like `bevy_math` (which in turn would make `bevy_reflect` be a dependency of most other crates, and increase the risk of circular dependencies). So this change simply formalizes that dependency in `Cargo.toml`. The `Rect` struct is also augmented in this change with a collection of utility methods to improve its usability. A few uses cases are updated to use those new methods, resulting is more clear and concise syntax. --- ## Changelog ### Changed - Moved the `sprite::Rect` type into `bevy_math`. ### Added - Added several utility methods to the `math::Rect` type. ## Migration Guide The `bevy::sprite::Rect` type moved to the math utility crate as `bevy::math::Rect`. You should change your imports from `use bevy::sprite::Rect` to `use bevy::math::Rect`.
2022-09-02 12:35:23 +00:00
use bevy_math::{Rect, Vec2};
add `#[reflect(Default)]` to create default value for reflected types (#3733) ### Problem It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be. ### Solution 1. add `ReflectDefault` type ```rust #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box<dyn Reflect>, } impl ReflectDefault { pub fn default(&self) -> Box<dyn Reflect> { (self.default)() } } impl<T: Reflect + Default> FromType<T> for ReflectDefault { fn from_type() -> Self { ReflectDefault { default: || Box::new(T::default()), } } } ``` 2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.) This makes it possible to add the default value of a component to an entity without any compile-time information: ```rust fn main() { let mut app = App::new(); app.register_type::<Camera>(); let type_registry = app.world.get_resource::<TypeRegistry>().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap(); let reflect_default = camera_registration.data::<ReflectDefault>().unwrap(); let reflect_component = camera_registration .data::<ReflectComponent>() .unwrap() .clone(); let default = reflect_default.default(); drop(type_registry); let entity = app.world.spawn().id(); reflect_component.add_component(&mut app.world, entity, &*default); let camera = app.world.entity(entity).get::<Camera>().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both?
2022-05-03 19:20:13 +00:00
use bevy_reflect::prelude::*;
use bevy_render::{
color::Color,
texture::{Image, DEFAULT_IMAGE_HANDLE},
};
2020-11-28 00:39:59 +00:00
use serde::{Deserialize, Serialize};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
2020-01-13 00:51:21 +00:00
/// Describes the size of a UI node
#[derive(Component, Debug, Clone, Default, Reflect)]
add `#[reflect(Default)]` to create default value for reflected types (#3733) ### Problem It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be. ### Solution 1. add `ReflectDefault` type ```rust #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box<dyn Reflect>, } impl ReflectDefault { pub fn default(&self) -> Box<dyn Reflect> { (self.default)() } } impl<T: Reflect + Default> FromType<T> for ReflectDefault { fn from_type() -> Self { ReflectDefault { default: || Box::new(T::default()), } } } ``` 2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.) This makes it possible to add the default value of a component to an entity without any compile-time information: ```rust fn main() { let mut app = App::new(); app.register_type::<Camera>(); let type_registry = app.world.get_resource::<TypeRegistry>().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap(); let reflect_default = camera_registration.data::<ReflectDefault>().unwrap(); let reflect_component = camera_registration .data::<ReflectComponent>() .unwrap() .clone(); let default = reflect_default.default(); drop(type_registry); let entity = app.world.spawn().id(); reflect_component.add_component(&mut app.world, entity, &*default); let camera = app.world.entity(entity).get::<Camera>().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both?
2022-05-03 19:20:13 +00:00
#[reflect(Component, Default)]
2020-01-13 00:51:21 +00:00
pub struct Node {
/// The size of the node as width and height in pixels
pub size: Vec2,
2020-01-13 00:51:21 +00:00
}
2020-07-26 19:27:09 +00:00
/// An enum that describes possible types of value in flexbox layout options
#[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum Val {
/// No value defined
#[default]
2020-07-26 19:27:09 +00:00
Undefined,
/// Automatically determine this value
2020-07-26 19:27:09 +00:00
Auto,
/// Set this value in pixels
2020-07-26 19:27:09 +00:00
Px(f32),
/// Set this value in percent
2020-07-26 19:27:09 +00:00
Percent(f32),
}
impl Add<f32> for Val {
type Output = Val;
2020-07-28 21:24:03 +00:00
2020-07-26 19:27:09 +00:00
fn add(self, rhs: f32) -> Self::Output {
match self {
Val::Undefined => Val::Undefined,
Val::Auto => Val::Auto,
Val::Px(value) => Val::Px(value + rhs),
Val::Percent(value) => Val::Percent(value + rhs),
}
}
}
impl AddAssign<f32> for Val {
fn add_assign(&mut self, rhs: f32) {
match self {
2020-07-28 21:24:03 +00:00
Val::Undefined | Val::Auto => {}
Val::Px(value) | Val::Percent(value) => *value += rhs,
2020-07-26 19:27:09 +00:00
}
}
}
impl Sub<f32> for Val {
type Output = Val;
fn sub(self, rhs: f32) -> Self::Output {
match self {
Val::Undefined => Val::Undefined,
Val::Auto => Val::Auto,
Val::Px(value) => Val::Px(value - rhs),
Val::Percent(value) => Val::Percent(value - rhs),
}
}
}
impl SubAssign<f32> for Val {
fn sub_assign(&mut self, rhs: f32) {
match self {
Val::Undefined | Val::Auto => {}
Val::Px(value) | Val::Percent(value) => *value -= rhs,
}
}
}
impl Mul<f32> for Val {
type Output = Val;
fn mul(self, rhs: f32) -> Self::Output {
match self {
Val::Undefined => Val::Undefined,
Val::Auto => Val::Auto,
Val::Px(value) => Val::Px(value * rhs),
Val::Percent(value) => Val::Percent(value * rhs),
}
}
}
impl MulAssign<f32> for Val {
fn mul_assign(&mut self, rhs: f32) {
match self {
Val::Undefined | Val::Auto => {}
Val::Px(value) | Val::Percent(value) => *value *= rhs,
}
}
}
impl Div<f32> for Val {
type Output = Val;
fn div(self, rhs: f32) -> Self::Output {
match self {
Val::Undefined => Val::Undefined,
Val::Auto => Val::Auto,
Val::Px(value) => Val::Px(value / rhs),
Val::Percent(value) => Val::Percent(value / rhs),
}
}
}
impl DivAssign<f32> for Val {
fn div_assign(&mut self, rhs: f32) {
match self {
Val::Undefined | Val::Auto => {}
Val::Px(value) | Val::Percent(value) => *value /= rhs,
}
}
}
/// Describes the style of a UI node
///
/// It uses the [Flexbox](https://cssreference.io/flexbox/) system.
///
/// **Note:** Bevy's UI is upside down compared to how Flexbox normally works, to stay consistent with engine paradigms about layouting from
/// the upper left corner of the display
#[derive(Component, Clone, PartialEq, Debug, Reflect)]
add `#[reflect(Default)]` to create default value for reflected types (#3733) ### Problem It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be. ### Solution 1. add `ReflectDefault` type ```rust #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box<dyn Reflect>, } impl ReflectDefault { pub fn default(&self) -> Box<dyn Reflect> { (self.default)() } } impl<T: Reflect + Default> FromType<T> for ReflectDefault { fn from_type() -> Self { ReflectDefault { default: || Box::new(T::default()), } } } ``` 2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.) This makes it possible to add the default value of a component to an entity without any compile-time information: ```rust fn main() { let mut app = App::new(); app.register_type::<Camera>(); let type_registry = app.world.get_resource::<TypeRegistry>().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap(); let reflect_default = camera_registration.data::<ReflectDefault>().unwrap(); let reflect_component = camera_registration .data::<ReflectComponent>() .unwrap() .clone(); let default = reflect_default.default(); drop(type_registry); let entity = app.world.spawn().id(); reflect_component.add_component(&mut app.world, entity, &*default); let camera = app.world.entity(entity).get::<Camera>().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both?
2022-05-03 19:20:13 +00:00
#[reflect(Component, Default, PartialEq)]
2020-07-26 19:27:09 +00:00
pub struct Style {
/// Whether to arrange this node and its children with flexbox layout
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361) # Objective UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited. However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes. ## Solution Fixes #5360. I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match. **NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope. ## Paths not taken ### Separate `Disabled` component This is a much larger and more controversial change, and not well-scoped to UI. Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on. Splitting this behavior would be more complex, and substantially violate user expectations. ### A separate limbo world Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity. ### Using change detection to reduce the amount of redundant work Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system. We simply don't have the tests or benchmarks here to justify this. ## Changelog - UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
///
/// If this is set to [`Display::None`], this node will be collapsed.
2020-07-26 19:27:09 +00:00
pub display: Display,
/// Whether to arrange this node relative to other nodes, or positioned absolutely
2020-07-26 19:27:09 +00:00
pub position_type: PositionType,
/// Which direction the content of this node should go
2020-07-26 19:27:09 +00:00
pub direction: Direction,
/// Whether to use column or row layout
2020-07-26 19:27:09 +00:00
pub flex_direction: FlexDirection,
/// How to wrap nodes
2020-07-26 19:27:09 +00:00
pub flex_wrap: FlexWrap,
/// How items are aligned according to the cross axis
2020-07-26 19:27:09 +00:00
pub align_items: AlignItems,
/// Like align_items but for only this item
2020-07-26 19:27:09 +00:00
pub align_self: AlignSelf,
/// How to align each line, only applies if flex_wrap is set to
/// [`FlexWrap::Wrap`] and there are multiple lines of items
2020-07-26 19:27:09 +00:00
pub align_content: AlignContent,
/// How items align according to the main axis
2020-07-26 19:27:09 +00:00
pub justify_content: JustifyContent,
/// The position of the node as described by its Rect
pub position: UiRect,
/// The margin of the node
pub margin: UiRect,
/// The padding of the node
pub padding: UiRect,
/// The border of the node
pub border: UiRect,
/// Defines how much a flexbox item should grow if there's space available
2020-07-26 19:27:09 +00:00
pub flex_grow: f32,
/// How to shrink if there's not enough space available
2020-07-26 19:27:09 +00:00
pub flex_shrink: f32,
/// The initial size of the item
2020-07-26 19:27:09 +00:00
pub flex_basis: Val,
/// The size of the flexbox
pub size: Size,
/// The minimum size of the flexbox
pub min_size: Size,
/// The maximum size of the flexbox
pub max_size: Size,
/// The aspect ratio of the flexbox
2020-07-26 19:27:09 +00:00
pub aspect_ratio: Option<f32>,
/// How to handle overflow
pub overflow: Overflow,
2020-07-26 19:27:09 +00:00
}
impl Default for Style {
fn default() -> Self {
Self {
display: Default::default(),
position_type: Default::default(),
direction: Default::default(),
flex_direction: Default::default(),
flex_wrap: Default::default(),
align_items: Default::default(),
align_self: Default::default(),
align_content: Default::default(),
justify_content: Default::default(),
position: Default::default(),
margin: Default::default(),
padding: Default::default(),
border: Default::default(),
flex_grow: 0.0,
flex_shrink: 1.0,
flex_basis: Val::Auto,
size: Size::AUTO,
min_size: Size::AUTO,
max_size: Size::AUTO,
2020-07-26 19:27:09 +00:00
aspect_ratio: Default::default(),
overflow: Default::default(),
2020-07-26 19:27:09 +00:00
}
}
}
/// How items are aligned according to the cross axis
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum AlignItems {
/// Items are aligned at the start
2020-07-26 19:27:09 +00:00
FlexStart,
/// Items are aligned at the end
2020-07-26 19:27:09 +00:00
FlexEnd,
/// Items are aligned at the center
2020-07-26 19:27:09 +00:00
Center,
/// Items are aligned at the baseline
2020-07-26 19:27:09 +00:00
Baseline,
/// Items are stretched across the whole cross axis
#[default]
2020-07-26 19:27:09 +00:00
Stretch,
}
/// Works like [`AlignItems`] but applies only to a single item
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum AlignSelf {
/// Use the value of [`AlignItems`]
#[default]
2020-07-26 19:27:09 +00:00
Auto,
/// If the parent has [`AlignItems::Center`] only this item will be at the start
2020-07-26 19:27:09 +00:00
FlexStart,
/// If the parent has [`AlignItems::Center`] only this item will be at the end
2020-07-26 19:27:09 +00:00
FlexEnd,
/// If the parent has [`AlignItems::FlexStart`] only this item will be at the center
2020-07-26 19:27:09 +00:00
Center,
/// If the parent has [`AlignItems::Center`] only this item will be at the baseline
2020-07-26 19:27:09 +00:00
Baseline,
/// If the parent has [`AlignItems::Center`] only this item will stretch along the whole cross axis
2020-07-26 19:27:09 +00:00
Stretch,
}
/// Defines how each line is aligned within the flexbox.
///
/// It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum AlignContent {
/// Each line moves towards the start of the cross axis
2020-07-26 19:27:09 +00:00
FlexStart,
/// Each line moves towards the end of the cross axis
2020-07-26 19:27:09 +00:00
FlexEnd,
/// Each line moves towards the center of the cross axis
2020-07-26 19:27:09 +00:00
Center,
/// Each line will stretch to fill the remaining space
#[default]
2020-07-26 19:27:09 +00:00
Stretch,
/// Each line fills the space it needs, putting the remaining space, if any
/// inbetween the lines
2020-07-26 19:27:09 +00:00
SpaceBetween,
/// Each line fills the space it needs, putting the remaining space, if any
/// around the lines
2020-07-26 19:27:09 +00:00
SpaceAround,
}
/// Defines the text direction
///
/// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left).
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum Direction {
/// Inherit from parent node
#[default]
2020-07-26 19:27:09 +00:00
Inherit,
/// Text is written left to right
LeftToRight,
/// Text is written right to left
RightToLeft,
2020-07-26 19:27:09 +00:00
}
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361) # Objective UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited. However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes. ## Solution Fixes #5360. I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match. **NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope. ## Paths not taken ### Separate `Disabled` component This is a much larger and more controversial change, and not well-scoped to UI. Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on. Splitting this behavior would be more complex, and substantially violate user expectations. ### A separate limbo world Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity. ### Using change detection to reduce the amount of redundant work Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system. We simply don't have the tests or benchmarks here to justify this. ## Changelog - UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
/// Whether to use a Flexbox layout model.
///
/// Part of the [`Style`] component.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum Display {
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361) # Objective UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited. However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes. ## Solution Fixes #5360. I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match. **NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope. ## Paths not taken ### Separate `Disabled` component This is a much larger and more controversial change, and not well-scoped to UI. Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on. Splitting this behavior would be more complex, and substantially violate user expectations. ### A separate limbo world Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity. ### Using change detection to reduce the amount of redundant work Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system. We simply don't have the tests or benchmarks here to justify this. ## Changelog - UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
/// Use Flexbox layout model to determine the position of this [`Node`].
#[default]
2020-07-26 19:27:09 +00:00
Flex,
Disable UI node `Interaction` when `ComputedVisibility` is false (#5361) # Objective UI nodes can be hidden by setting their `Visibility` property. Since #5310 was merged, this is now ergonomic to use, as visibility is now inherited. However, UI nodes still receive (and store) interactions when hidden, resulting in surprising hidden state (and an inability to otherwise disable UI nodes. ## Solution Fixes #5360. I've updated the `ui_focus_system` to accomplish this in a minimally intrusive way, and updated the docs to match. **NOTE:** I have not added automated tests to verify this behavior, as we do not currently have a good testing paradigm for `bevy_ui`. I'm not thrilled with that by any means, but I'm not sure fixing it is within scope. ## Paths not taken ### Separate `Disabled` component This is a much larger and more controversial change, and not well-scoped to UI. Furthermore, it is extremely rare that you want hidden UI elements to function: the most common cases are for things like changing tabs, collapsing elements or so on. Splitting this behavior would be more complex, and substantially violate user expectations. ### A separate limbo world Mentioned in the linked issue. Super cool, but all of the problems of the `Disabled` component solution with a whole new RFC-worth of complexity. ### Using change detection to reduce the amount of redundant work Adds a lot of complexity for questionable performance gains. Likely involves a complete refactor of the entire system. We simply don't have the tests or benchmarks here to justify this. ## Changelog - UI nodes are now always in an `Interaction::None` state while they are hidden (via the `ComputedVisibility` component).
2022-07-20 21:26:47 +00:00
/// Use no layout, don't render this node and its children.
///
/// If you want to hide a node and its children,
/// but keep its layout in place, set its [`Visibility`](bevy_render::view::Visibility) component instead.
2020-07-26 19:27:09 +00:00
None,
}
/// Defines how flexbox items are ordered within a flexbox
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum FlexDirection {
/// Same way as text direction along the main axis
#[default]
2020-07-26 19:27:09 +00:00
Row,
Change UI coordinate system to have origin at top left corner (#6000) # Objective Fixes #5572 ## Solution Approach is to invert the Y-axis of the UI Camera by changing the UI projection matrix to render the UI upside down. After that I'm trying to fix all issues, that pop up: - interaction expected the "old" position - images and text were displayed upside-down - baseline of text was based on the top of the glyph instead of bottom ... probably a lot more. --- Result when running examples: <details> <summary>Button example</summary> main branch: ![button main](https://user-images.githubusercontent.com/4232644/190856087-61dd1d98-42b5-4238-bd97-149744ddfeba.png) this pr: ![button pr](https://user-images.githubusercontent.com/4232644/190856097-3f4bc97a-ed15-4e97-b7f1-2b2dd6bb8b14.png) </details> <details> <summary>Text example</summary> m ![text main](https://user-images.githubusercontent.com/4232644/192142831-4cf19aa1-f49a-485e-af7b-374d6f5c396c.png) ain branch: this pr: ![text pr fixed](https://user-images.githubusercontent.com/4232644/192142829-c433db3b-32e1-4ee8-b493-0b4a4d9c8e70.png) </details> <details> <summary>Text debug example</summary> main branch: ![text_debug main](https://user-images.githubusercontent.com/4232644/192142822-940aefa6-e502-410b-8da4-5570f77b5df2.png) this pr: ![text_debug pr fixed](https://user-images.githubusercontent.com/4232644/194547010-8c968f5c-5a71-4ffc-871d-790c06d48016.png) </details> <details> <summary>Transparency UI example</summary> main branch: ![transparency_ui main](https://user-images.githubusercontent.com/4232644/190856172-328c60fe-3622-4598-97d5-2f1595db13b3.png) this pr: ![transperency_ui pr](https://user-images.githubusercontent.com/4232644/190856179-a2dafb99-41ea-45a9-9dd6-400fa3ef24b9.png) </details> <details> <summary>UI example</summary> **ui example** main branch: ![ui main](https://user-images.githubusercontent.com/4232644/192142812-e20ba31a-6841-46d9-a785-4198cf22dc99.png) this pr: ![ui pr fixed](https://user-images.githubusercontent.com/4232644/192142788-cc0b74e0-7710-4faa-b5a2-60270a5da77c.png) </details> ## Changelog UI coordinate system and cursor position was changed from bottom left origin, y+ up to top left origin, y+ down. ## Migration Guide All flex layout should be inverted (ColumnReverse => Column, FlexStart => FlexEnd, WrapReverse => Wrap) System where dealing with cursor position should be changed to account for cursor position being based on the top left instead of bottom left
2022-10-11 12:51:44 +00:00
/// Flex from top to bottom
2020-07-26 19:27:09 +00:00
Column,
/// Opposite way as text direction along the main axis
2020-07-26 19:27:09 +00:00
RowReverse,
Change UI coordinate system to have origin at top left corner (#6000) # Objective Fixes #5572 ## Solution Approach is to invert the Y-axis of the UI Camera by changing the UI projection matrix to render the UI upside down. After that I'm trying to fix all issues, that pop up: - interaction expected the "old" position - images and text were displayed upside-down - baseline of text was based on the top of the glyph instead of bottom ... probably a lot more. --- Result when running examples: <details> <summary>Button example</summary> main branch: ![button main](https://user-images.githubusercontent.com/4232644/190856087-61dd1d98-42b5-4238-bd97-149744ddfeba.png) this pr: ![button pr](https://user-images.githubusercontent.com/4232644/190856097-3f4bc97a-ed15-4e97-b7f1-2b2dd6bb8b14.png) </details> <details> <summary>Text example</summary> m ![text main](https://user-images.githubusercontent.com/4232644/192142831-4cf19aa1-f49a-485e-af7b-374d6f5c396c.png) ain branch: this pr: ![text pr fixed](https://user-images.githubusercontent.com/4232644/192142829-c433db3b-32e1-4ee8-b493-0b4a4d9c8e70.png) </details> <details> <summary>Text debug example</summary> main branch: ![text_debug main](https://user-images.githubusercontent.com/4232644/192142822-940aefa6-e502-410b-8da4-5570f77b5df2.png) this pr: ![text_debug pr fixed](https://user-images.githubusercontent.com/4232644/194547010-8c968f5c-5a71-4ffc-871d-790c06d48016.png) </details> <details> <summary>Transparency UI example</summary> main branch: ![transparency_ui main](https://user-images.githubusercontent.com/4232644/190856172-328c60fe-3622-4598-97d5-2f1595db13b3.png) this pr: ![transperency_ui pr](https://user-images.githubusercontent.com/4232644/190856179-a2dafb99-41ea-45a9-9dd6-400fa3ef24b9.png) </details> <details> <summary>UI example</summary> **ui example** main branch: ![ui main](https://user-images.githubusercontent.com/4232644/192142812-e20ba31a-6841-46d9-a785-4198cf22dc99.png) this pr: ![ui pr fixed](https://user-images.githubusercontent.com/4232644/192142788-cc0b74e0-7710-4faa-b5a2-60270a5da77c.png) </details> ## Changelog UI coordinate system and cursor position was changed from bottom left origin, y+ up to top left origin, y+ down. ## Migration Guide All flex layout should be inverted (ColumnReverse => Column, FlexStart => FlexEnd, WrapReverse => Wrap) System where dealing with cursor position should be changed to account for cursor position being based on the top left instead of bottom left
2022-10-11 12:51:44 +00:00
/// Flex from bottom to top
2020-07-26 19:27:09 +00:00
ColumnReverse,
}
/// Defines how items are aligned according to the main axis
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum JustifyContent {
/// Pushed towards the start
#[default]
2020-07-26 19:27:09 +00:00
FlexStart,
/// Pushed towards the end
2020-07-26 19:27:09 +00:00
FlexEnd,
/// Centered along the main axis
2020-07-26 19:27:09 +00:00
Center,
/// Remaining space is distributed between the items
2020-07-26 19:27:09 +00:00
SpaceBetween,
/// Remaining space is distributed around the items
2020-07-26 19:27:09 +00:00
SpaceAround,
/// Like [`JustifyContent::SpaceAround`] but with even spacing between items
2020-07-26 19:27:09 +00:00
SpaceEvenly,
}
/// Whether to show or hide overflowing items
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Reflect, Serialize, Deserialize)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
pub enum Overflow {
/// Show overflowing items
#[default]
Visible,
/// Hide overflowing items
Hidden,
}
2020-07-26 19:27:09 +00:00
/// The strategy used to position this node
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum PositionType {
/// Relative to all other nodes with the [`PositionType::Relative`] value
#[default]
2020-07-26 19:27:09 +00:00
Relative,
/// Independent of all other nodes
///
/// As usual, the `Style.position` field of this node is specified relative to its parent node
2020-07-26 19:27:09 +00:00
Absolute,
}
/// Defines if flexbox items appear on a single line or on multiple lines
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize, Reflect)]
2022-08-02 22:40:29 +00:00
#[reflect(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum FlexWrap {
/// Single line, will overflow if needed
#[default]
2020-07-26 19:27:09 +00:00
NoWrap,
/// Multiple lines, if needed
2020-07-26 19:27:09 +00:00
Wrap,
/// Same as [`FlexWrap::Wrap`] but new lines will appear before the previous one
2020-07-26 19:27:09 +00:00
WrapReverse,
}
/// The calculated size of the node
#[derive(Component, Default, Copy, Clone, Debug, Reflect)]
#[reflect(Component)]
pub struct CalculatedSize {
/// The size of the node
pub size: Size,
}
/// The background color of the node
///
/// This serves as the "fill" color.
/// When combined with [`UiImage`], tints the provided texture.
#[derive(Component, Default, Copy, Clone, Debug, Reflect)]
add `#[reflect(Default)]` to create default value for reflected types (#3733) ### Problem It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be. ### Solution 1. add `ReflectDefault` type ```rust #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box<dyn Reflect>, } impl ReflectDefault { pub fn default(&self) -> Box<dyn Reflect> { (self.default)() } } impl<T: Reflect + Default> FromType<T> for ReflectDefault { fn from_type() -> Self { ReflectDefault { default: || Box::new(T::default()), } } } ``` 2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.) This makes it possible to add the default value of a component to an entity without any compile-time information: ```rust fn main() { let mut app = App::new(); app.register_type::<Camera>(); let type_registry = app.world.get_resource::<TypeRegistry>().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap(); let reflect_default = camera_registration.data::<ReflectDefault>().unwrap(); let reflect_component = camera_registration .data::<ReflectComponent>() .unwrap() .clone(); let default = reflect_default.default(); drop(type_registry); let entity = app.world.spawn().id(); reflect_component.add_component(&mut app.world, entity, &*default); let camera = app.world.entity(entity).get::<Camera>().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both?
2022-05-03 19:20:13 +00:00
#[reflect(Component, Default)]
pub struct BackgroundColor(pub Color);
impl From<Color> for BackgroundColor {
fn from(color: Color) -> Self {
Self(color)
}
}
/// The 2D texture displayed for this UI node
Enforce type safe usage of Handle::get (#4794) # Objective - Sometimes, people might load an asset as one type, then use it with an `Asset`s for a different type. - See e.g. #4784. - This is especially likely with the Gltf types, since users may not have a clear conceptual model of what types the assets will be. - We had an instance of this ourselves, in the `scene_viewer` example ## Solution - Make `Assets::get` require a type safe handle. --- ## Changelog ### Changed - `Assets::<T>::get` and `Assets::<T>::get_mut` now require that the passed handles are `Handle<T>`, improving the type safety of handles. ### Added - `HandleUntyped::typed_weak`, a helper function for creating a weak typed version of an exisitng `HandleUntyped`. ## Migration Guide `Assets::<T>::get` and `Assets::<T>::get_mut` now require that the passed handles are `Handle<T>`, improving the type safety of handles. If you were previously passing in: - a `HandleId`, use `&Handle::weak(id)` instead, to create a weak handle. You may have been able to store a type safe `Handle` instead. - a `HandleUntyped`, use `&handle_untyped.typed_weak()` to create a weak handle of the specified type. This is most likely to be the useful when using [load_folder](https://docs.rs/bevy_asset/latest/bevy_asset/struct.AssetServer.html#method.load_folder) - a `Handle<U>` of of a different type, consider whether this is the correct handle type to store. If it is (i.e. the same handle id is used for multiple different Asset types) use `Handle::weak(handle.id)` to cast to a different type.
2022-05-30 16:59:44 +00:00
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
add `#[reflect(Default)]` to create default value for reflected types (#3733) ### Problem It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be. ### Solution 1. add `ReflectDefault` type ```rust #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box<dyn Reflect>, } impl ReflectDefault { pub fn default(&self) -> Box<dyn Reflect> { (self.default)() } } impl<T: Reflect + Default> FromType<T> for ReflectDefault { fn from_type() -> Self { ReflectDefault { default: || Box::new(T::default()), } } } ``` 2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.) This makes it possible to add the default value of a component to an entity without any compile-time information: ```rust fn main() { let mut app = App::new(); app.register_type::<Camera>(); let type_registry = app.world.get_resource::<TypeRegistry>().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap(); let reflect_default = camera_registration.data::<ReflectDefault>().unwrap(); let reflect_component = camera_registration .data::<ReflectComponent>() .unwrap() .clone(); let default = reflect_default.default(); drop(type_registry); let entity = app.world.spawn().id(); reflect_component.add_component(&mut app.world, entity, &*default); let camera = app.world.entity(entity).get::<Camera>().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both?
2022-05-03 19:20:13 +00:00
#[reflect(Component, Default)]
pub struct UiImage(pub Handle<Image>);
impl Default for UiImage {
fn default() -> Self {
Self(DEFAULT_IMAGE_HANDLE.typed())
}
}
impl From<Handle<Image>> for UiImage {
fn from(handle: Handle<Image>) -> Self {
Self(handle)
}
}
/// The calculated clip of the node
#[derive(Component, Default, Copy, Clone, Debug, Reflect)]
#[reflect(Component)]
pub struct CalculatedClip {
/// The rect of the clip
Move `sprite::Rect` into `bevy_math` (#5686) # Objective Promote the `Rect` utility of `sprite::Rect`, which defines a rectangle by its minimum and maximum corners, to the `bevy_math` crate to make it available as a general math type to all crates without the need to depend on the `bevy_sprite` crate. Fixes #5575 ## Solution Move `sprite::Rect` into `bevy_math` and fix all uses. Implement `Reflect` for `Rect` directly into the `bevy_reflect` crate by having `bevy_reflect` depend on `bevy_math`. This looks like a new dependency, but the `bevy_reflect` was "cheating" for other math types by directly depending on `glam` to reflect other math types, thereby giving the illusion that there was no dependency on `bevy_math`. In practice conceptually Bevy's math types are reflected into the `bevy_reflect` crate to avoid a dependency of that crate to a "lower level" utility crate like `bevy_math` (which in turn would make `bevy_reflect` be a dependency of most other crates, and increase the risk of circular dependencies). So this change simply formalizes that dependency in `Cargo.toml`. The `Rect` struct is also augmented in this change with a collection of utility methods to improve its usability. A few uses cases are updated to use those new methods, resulting is more clear and concise syntax. --- ## Changelog ### Changed - Moved the `sprite::Rect` type into `bevy_math`. ### Added - Added several utility methods to the `math::Rect` type. ## Migration Guide The `bevy::sprite::Rect` type moved to the math utility crate as `bevy::math::Rect`. You should change your imports from `use bevy::sprite::Rect` to `use bevy::math::Rect`.
2022-09-02 12:35:23 +00:00
pub clip: Rect,
}