Cleaning up NodeBundle, and some slight UI module re-organization (#6473)

# Objective

`NodeBundle` contains an `image` field, which can be misleading, because if you do supply an image there, nothing will be shown to screen. You need to use an `ImageBundle` instead.

## Solution

* `image` (`UiImage`) field is removed from `NodeBundle`, 
* extraction stage queries now make an optional query for `UiImage`, if one is not found, use the image handle that is used as a default by `UiImage`: c019a60b39/crates/bevy_ui/src/ui_node.rs (L464)
* touching up docs for `NodeBundle` to help guide what `NodeBundle` should be used for
* renamed `entity.rs` to `node_bundle.rs` as that gives more of a hint regarding the module's purpose
* separating `camera_config` stuff from the pre-made UI node bundles so that `node_bundle.rs` makes more sense as a module name.
This commit is contained in:
Brian Merchant 2022-11-05 20:48:15 +00:00
parent 5ae94750a1
commit 66f495c44e
5 changed files with 62 additions and 47 deletions

View file

@ -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<Camera>;
fn extract_component(item: QueryItem<'_, Self::Query>) -> Self {
item.clone()
}
}

View file

@ -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,

View file

@ -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 <https://cssreference.io/flexbox/>)
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::*;

View file

@ -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<Camera>;
fn extract_component(item: QueryItem<'_, Self::Query>) -> Self {
item.clone()
}
}

View file

@ -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(),