diff --git a/crates/bevy_ui/src/camera_config.rs b/crates/bevy_ui/src/camera_config.rs new file mode 100644 index 0000000000000..da903e513787e --- /dev/null +++ b/crates/bevy_ui/src/camera_config.rs @@ -0,0 +1,37 @@ +//! Configuration for cameras related to UI. + +use bevy_ecs::component::Component; +use bevy_ecs::prelude::With; +use bevy_ecs::query::QueryItem; +use bevy_render::camera::Camera; +use bevy_render::extract_component::ExtractComponent; + +/// Configuration for cameras related to UI. +/// +/// When a [`Camera`] doesn't have the [`UiCameraConfig`] component, +/// it will display the UI by default. +/// +/// [`Camera`]: bevy_render::camera::Camera +#[derive(Component, Clone)] +pub struct UiCameraConfig { + /// Whether to output UI to this camera view. + /// + /// When a `Camera` doesn't have the [`UiCameraConfig`] component, + /// it will display the UI by default. + pub show_ui: bool, +} + +impl Default for UiCameraConfig { + fn default() -> Self { + Self { show_ui: true } + } +} + +impl ExtractComponent for UiCameraConfig { + type Query = &'static Self; + type Filter = With; + + fn extract_component(item: QueryItem<'_, Self::Query>) -> Self { + item.clone() + } +} diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index 423711d6e39ff..07d865de61be1 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -1,4 +1,4 @@ -use crate::{entity::UiCameraConfig, CalculatedClip, Node, UiStack}; +use crate::{camera_config::UiCameraConfig, CalculatedClip, Node, UiStack}; use bevy_ecs::{ entity::Entity, prelude::Component, diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 39fae6f1761bf..8b9e1b2564b81 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -1,6 +1,6 @@ //! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games //! # Basic usage -//! Spawn UI elements with [`entity::ButtonBundle`], [`entity::ImageBundle`], [`entity::TextBundle`] and [`entity::NodeBundle`] +//! Spawn UI elements with [`node_bundles::ButtonBundle`], [`node_bundles::ImageBundle`], [`node_bundles::TextBundle`] and [`node_bundles::NodeBundle`] //! This UI is laid out with the Flexbox paradigm (see ) mod flex; mod focus; @@ -9,7 +9,8 @@ mod render; mod stack; mod ui_node; -pub mod entity; +pub mod camera_config; +pub mod node_bundles; pub mod update; pub mod widget; @@ -23,7 +24,10 @@ pub use ui_node::*; #[doc(hidden)] pub mod prelude { #[doc(hidden)] - pub use crate::{entity::*, geometry::*, ui_node::*, widget::Button, Interaction, UiScale}; + pub use crate::{ + camera_config::*, geometry::*, node_bundles::*, ui_node::*, widget::Button, Interaction, + UiScale, + }; } use bevy_app::prelude::*; diff --git a/crates/bevy_ui/src/entity.rs b/crates/bevy_ui/src/node_bundles.rs similarity index 89% rename from crates/bevy_ui/src/entity.rs rename to crates/bevy_ui/src/node_bundles.rs index 05ede7d7e0700..938a740a48e76 100644 --- a/crates/bevy_ui/src/entity.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -1,17 +1,11 @@ -//! This module contains the bundles used in Bevy's UI +//! This module contains basic node bundles used to build UIs use crate::{ widget::{Button, ImageMode}, BackgroundColor, CalculatedSize, FocusPolicy, Interaction, Node, Style, UiImage, ZIndex, }; -use bevy_ecs::{ - bundle::Bundle, - prelude::{Component, With}, - query::QueryItem, -}; +use bevy_ecs::bundle::Bundle; use bevy_render::{ - camera::Camera, - extract_component::ExtractComponent, prelude::{Color, ComputedVisibility}, view::Visibility, }; @@ -19,6 +13,8 @@ use bevy_text::{Text, TextAlignment, TextSection, TextStyle}; use bevy_transform::prelude::{GlobalTransform, Transform}; /// The basic UI node +/// +/// Useful as a container for a variety of child nodes. #[derive(Bundle, Clone, Debug)] pub struct NodeBundle { /// Describes the size of the node @@ -27,8 +23,6 @@ pub struct NodeBundle { pub style: Style, /// The background color, which serves as a "fill" for this node pub background_color: BackgroundColor, - /// Describes the image of the node - pub image: UiImage, /// Whether this node should block interaction with lower nodes pub focus_policy: FocusPolicy, /// The transform of the node @@ -56,7 +50,6 @@ impl Default for NodeBundle { background_color: Color::NONE.into(), node: Default::default(), style: Default::default(), - image: Default::default(), focus_policy: Default::default(), transform: Default::default(), global_transform: Default::default(), @@ -241,32 +234,3 @@ impl Default for ButtonBundle { } } } -/// Configuration for cameras related to UI. -/// -/// When a [`Camera`] doesn't have the [`UiCameraConfig`] component, -/// it will display the UI by default. -/// -/// [`Camera`]: bevy_render::camera::Camera -#[derive(Component, Clone)] -pub struct UiCameraConfig { - /// Whether to output UI to this camera view. - /// - /// When a `Camera` doesn't have the [`UiCameraConfig`] component, - /// it will display the UI by default. - pub show_ui: bool, -} - -impl Default for UiCameraConfig { - fn default() -> Self { - Self { show_ui: true } - } -} - -impl ExtractComponent for UiCameraConfig { - type Query = &'static Self; - type Filter = With; - - fn extract_component(item: QueryItem<'_, Self::Query>) -> Self { - item.clone() - } -} diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f7484fe76fc16..4f6a1b2d7a019 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -11,6 +11,7 @@ use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped} use bevy_ecs::prelude::*; use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles}; use bevy_reflect::TypeUuid; +use bevy_render::texture::DEFAULT_IMAGE_HANDLE; use bevy_render::{ camera::Camera, color::Color, @@ -209,7 +210,7 @@ pub fn extract_uinodes( &Node, &GlobalTransform, &BackgroundColor, - &UiImage, + Option<&UiImage>, &ComputedVisibility, Option<&CalculatedClip>, )>, @@ -218,11 +219,19 @@ pub fn extract_uinodes( let scale_factor = windows.scale_factor(WindowId::primary()) as f32; extracted_uinodes.uinodes.clear(); for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() { - if let Ok((uinode, transform, color, image, visibility, clip)) = uinode_query.get(*entity) { + if let Ok((uinode, transform, color, maybe_image, visibility, clip)) = + uinode_query.get(*entity) + { if !visibility.is_visible() { continue; } - let image = image.0.clone_weak(); + + let image = if let Some(image) = maybe_image { + image.0.clone_weak() + } else { + DEFAULT_IMAGE_HANDLE.typed().clone_weak() + }; + // Skip loading images if !images.contains(&image) { continue; @@ -231,6 +240,7 @@ pub fn extract_uinodes( if color.0.a() == 0.0 { continue; } + extracted_uinodes.uinodes.push(ExtractedUiNode { stack_index, transform: transform.compute_matrix(),