bevy/crates/bevy_ui/src/ui_node.rs

395 lines
12 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};
use bevy_math::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};
2020-07-28 21:24:03 +00:00
use std::ops::{Add, AddAssign};
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
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum Val {
/// No value defined
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 Default for Val {
fn default() -> Self {
Val::Undefined
}
}
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
}
}
}
/// 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
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 descrided by its Rect
pub position: UiRect<Val>,
/// The margin of the node
pub margin: UiRect<Val>,
/// The padding of the node
pub padding: UiRect<Val>,
/// The border of the node
pub border: UiRect<Val>,
/// 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
2020-07-26 19:27:09 +00:00
pub size: Size<Val>,
/// The minimum size of the flexbox
2020-07-26 19:27:09 +00:00
pub min_size: Size<Val>,
/// The maximum size of the flexbox
2020-07-26 19:27:09 +00:00
pub max_size: Size<Val>,
/// 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::new(Val::Auto, Val::Auto),
min_size: Size::new(Val::Auto, Val::Auto),
max_size: Size::new(Val::Auto, Val::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
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(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
2020-07-26 19:27:09 +00:00
Stretch,
}
impl Default for AlignItems {
fn default() -> AlignItems {
AlignItems::Stretch
}
}
/// Works like [`AlignItems`] but applies only to a single item
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum AlignSelf {
/// Use the value of [`AlignItems`]
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,
}
impl Default for AlignSelf {
fn default() -> AlignSelf {
AlignSelf::Auto
}
}
/// 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.
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(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
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,
}
impl Default for AlignContent {
fn default() -> AlignContent {
AlignContent::Stretch
}
}
/// Defines the text direction
///
/// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left).
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum Direction {
/// Inherit from parent node
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
}
impl Default for Direction {
fn default() -> Direction {
Direction::Inherit
}
}
/// Whether to use Flexbox layout
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum Display {
/// Use flexbox
2020-07-26 19:27:09 +00:00
Flex,
/// Use no layout, don't render this node and its children
2020-07-26 19:27:09 +00:00
None,
}
impl Default for Display {
fn default() -> Display {
Display::Flex
}
}
/// Defines how flexbox items are ordered within a flexbox
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum FlexDirection {
/// Same way as text direction along the main axis
2020-07-26 19:27:09 +00:00
Row,
/// Flex from bottom to top
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,
/// Flex from top to bottom
2020-07-26 19:27:09 +00:00
ColumnReverse,
}
impl Default for FlexDirection {
fn default() -> FlexDirection {
FlexDirection::Row
}
}
/// Defines how items are aligned according to the main axis
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum JustifyContent {
/// Pushed towards the start
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,
}
impl Default for JustifyContent {
fn default() -> JustifyContent {
JustifyContent::FlexStart
}
}
/// Whether to show or hide overflowing items
#[derive(Copy, Clone, PartialEq, Debug, Reflect, Serialize, Deserialize)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum Overflow {
/// Show overflowing items
Visible,
/// Hide overflowing items
Hidden,
}
2020-07-26 19:27:09 +00:00
impl Default for Overflow {
fn default() -> Overflow {
Overflow::Visible
}
}
2020-07-26 19:27:09 +00:00
/// The strategy used to position this node
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum PositionType {
/// Relative to all other nodes with the [`PositionType::Relative`] value
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,
}
impl Default for PositionType {
fn default() -> PositionType {
PositionType::Relative
}
}
/// Defines if flexbox items appear on a single line or on multiple lines
2020-11-28 00:39:59 +00:00
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
2020-07-26 19:27:09 +00:00
pub enum FlexWrap {
/// Single line, will overflow if needed
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,
}
impl Default for FlexWrap {
fn default() -> FlexWrap {
FlexWrap::NoWrap
}
2020-07-28 21:24:03 +00:00
}
/// 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 color of the node
#[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 UiColor(pub Color);
impl From<Color> for UiColor {
fn from(color: Color) -> Self {
Self(color)
}
}
/// The image of the 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
pub clip: bevy_sprite::Rect,
}