Partially document bevy_ui (#3526)

# Objective

Updated the docs for bevy_ui as requested by #3492 

## Solution

I have documented the parts I understand. anchors.rs is not in use and should be removed, thus I haven't documented that, and some of the more renderer-heavy code is beyond me and needs input from either cart or someone familiar with bevy rendering

Co-authored-by: Troels Jessen <kairyuka@gmail.com>
This commit is contained in:
Troels Jessen 2022-01-07 22:20:34 +00:00
parent d34ecd7584
commit 32f7997c56
11 changed files with 186 additions and 4 deletions

View File

@ -1,3 +1,5 @@
//! This module contains the bundles used in Bevy's UI
use crate::{
widget::{Button, ImageMode},
CalculatedSize, FocusPolicy, Interaction, Node, Style, UiColor, UiImage, CAMERA_UI,
@ -10,39 +12,66 @@ use bevy_render::{
use bevy_text::Text;
use bevy_transform::prelude::{GlobalTransform, Transform};
/// The basic UI node
#[derive(Bundle, Clone, Debug, Default)]
pub struct NodeBundle {
/// Describes the size of the node
pub node: Node,
/// Describes the style including flexbox settings
pub style: Style,
/// Describes the color of the node
pub color: UiColor,
/// Describes the image of the node
pub image: UiImage,
/// The transform of the node
pub transform: Transform,
/// The global transform of the node
pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node
pub visibility: Visibility,
}
/// A UI node that is an image
#[derive(Bundle, Clone, Debug, Default)]
pub struct ImageBundle {
/// Describes the size of the node
pub node: Node,
/// Describes the style including flexbox settings
pub style: Style,
/// Configures how the image should scale
pub image_mode: ImageMode,
/// The calculated size based on the given image
pub calculated_size: CalculatedSize,
/// The color of the node
pub color: UiColor,
/// The image of the node
pub image: UiImage,
/// The transform of the node
pub transform: Transform,
/// The global transform of the node
pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node
pub visibility: Visibility,
}
/// A UI node that is text
#[derive(Bundle, Clone, Debug)]
pub struct TextBundle {
/// Describes the size of the node
pub node: Node,
/// Describes the style including flexbox settings
pub style: Style,
/// Contains the text of the node
pub text: Text,
/// The calculated size based on the given image
pub calculated_size: CalculatedSize,
/// Whether this node should block interaction with lower nodes
pub focus_policy: FocusPolicy,
/// The transform of the node
pub transform: Transform,
/// The global transform of the node
pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node
pub visibility: Visibility,
}
@ -61,17 +90,28 @@ impl Default for TextBundle {
}
}
/// A UI node that is a button
#[derive(Bundle, Clone, Debug)]
pub struct ButtonBundle {
/// Describes the size of the node
pub node: Node,
/// Marker component that signals this node is a button
pub button: Button,
/// Describes the style including flexbox settings
pub style: Style,
/// Describes whether and how the button has been interacted with by the input
pub interaction: Interaction,
/// Whether this node should block interaction with lower nodes
pub focus_policy: FocusPolicy,
/// The color of the node
pub color: UiColor,
/// The image of the node
pub image: UiImage,
/// The transform of the node
pub transform: Transform,
/// The global transform of the node
pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node
pub visibility: Visibility,
}
@ -92,12 +132,18 @@ impl Default for ButtonBundle {
}
}
/// The camera that is needed to see UI elements
#[derive(Bundle, Debug)]
pub struct UiCameraBundle {
/// The camera component
pub camera: Camera,
/// The orthographic projection settings
pub orthographic_projection: OrthographicProjection,
/// The transform of the camera
pub transform: Transform,
/// The global transform of the camera
pub global_transform: GlobalTransform,
/// Contains visible entities
// FIXME there is no frustrum culling for UI
pub visible_entities: VisibleEntities,
}

View File

@ -14,11 +14,17 @@ use bevy_window::Windows;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
/// Describes what type of input interaction has occurred for a UI node.
///
/// This is commonly queried with a `Changed<Interaction>` filter.
#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)]
#[reflect_value(Component, Serialize, Deserialize, PartialEq)]
pub enum Interaction {
/// The node has been clicked
Clicked,
/// The node has been hovered over
Hovered,
/// Nothing has happened
None,
}
@ -28,10 +34,13 @@ impl Default for Interaction {
}
}
/// Describes whether the node should block interactions with lower nodes
#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)]
#[reflect_value(Component, Serialize, Deserialize, PartialEq)]
pub enum FocusPolicy {
/// Blocks interaction
Block,
/// Lets interaction pass through
Pass,
}
@ -41,11 +50,13 @@ impl Default for FocusPolicy {
}
}
/// Contains entities whose Interaction should be set to None
#[derive(Default)]
pub struct State {
entities_to_reset: SmallVec<[Entity; 1]>,
}
/// The system that sets Interaction for all UI elements based on the mouse cursor activity
#[allow(clippy::type_complexity)]
pub fn ui_focus_system(
mut state: Local<State>,

View File

@ -1,3 +1,7 @@
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
//! # Basic usage
//! Spawn [`entity::UiCameraBundle`] and spawn UI elements with [`entity::ButtonBundle`], [`entity::ImageBundle`], [`entity::TextBundle`] and [`entity::NodeBundle`]
//! This UI is laid out with the Flexbox paradigm (see <https://cssreference.io/flexbox/> ) except the vertical axis is inverted
mod flex;
mod focus;
mod margins;
@ -14,6 +18,7 @@ pub use margins::*;
pub use render::*;
pub use ui_node::*;
#[doc(hidden)]
pub mod prelude {
#[doc(hidden)]
pub use crate::{entity::*, ui_node::*, widget::Button, Interaction, Margins};
@ -26,13 +31,16 @@ use bevy_math::{Rect, Size};
use bevy_transform::TransformSystem;
use update::{ui_z_system, update_clipping_system};
/// The basic plugin for Bevy UI
#[derive(Default)]
pub struct UiPlugin;
/// The label enum labeling the types of systems in the Bevy UI
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]
pub enum UiSystem {
/// After this label, the ui flex state has been updated
Flex,
/// After this label, input interactions with UI entities have been updated for this frame
Focus,
}

View File

@ -1,12 +1,18 @@
/// Defines the margins of a UI node
#[derive(Debug, Clone)]
pub struct Margins {
/// Left margin size in pixels
pub left: f32,
/// Right margin size in pixels
pub right: f32,
/// Bottom margin size in pixels
pub bottom: f32,
/// Top margin size in pixels
pub top: f32,
}
impl Margins {
/// Creates a new Margins based on the input
pub fn new(left: f32, right: f32, bottom: f32, top: f32) -> Self {
Margins {
left,

View File

@ -1,8 +1,10 @@
use bevy_ecs::prelude::*;
use bevy_render::{camera::ActiveCameras, render_phase::RenderPhase};
/// The name of the UI camera
pub const CAMERA_UI: &str = "camera_ui";
/// Inserts the [`RenderPhase`] into the UI camera
pub fn extract_ui_camera_phases(mut commands: Commands, active_cameras: Res<ActiveCameras>) {
if let Some(camera_ui) = active_cameras.get(CAMERA_UI) {
if let Some(entity) = camera_ui.entity {

View File

@ -9,18 +9,25 @@ use bevy_render::{
use serde::{Deserialize, Serialize};
use std::ops::{Add, AddAssign};
/// Describes the size of a UI node
#[derive(Component, Debug, Clone, Default, Reflect)]
#[reflect(Component)]
pub struct Node {
/// The size of the node as width and height in pixels
pub size: Vec2,
}
/// An enum that describes possible types of value in flexbox layout options
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum Val {
/// No value defined
Undefined,
/// Automatically determine this value
Auto,
/// Set this value in pixels
Px(f32),
/// Set this value in percent
Percent(f32),
}
@ -53,29 +60,57 @@ impl AddAssign<f32> for Val {
}
}
/// 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)]
#[reflect(Component, PartialEq)]
pub struct Style {
/// Whether to arrange this node and its children with flexbox layout
pub display: Display,
/// Whether to arrange this node relative to other nodes, or positioned absolutely
pub position_type: PositionType,
/// Which direction the content of this node should go
pub direction: Direction,
/// Whether to use column or row layout
pub flex_direction: FlexDirection,
/// How to wrap nodes
pub flex_wrap: FlexWrap,
/// How items are aligned according to the cross axis
pub align_items: AlignItems,
/// Like align_items but for only this item
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
pub align_content: AlignContent,
/// How items align according to the main axis
pub justify_content: JustifyContent,
/// The position of the node as descrided by its Rect
pub position: Rect<Val>,
/// The margin of the node
pub margin: Rect<Val>,
/// The padding of the node
pub padding: Rect<Val>,
/// The border of the node
pub border: Rect<Val>,
/// Defines how much a flexbox item should grow if there's space available
pub flex_grow: f32,
/// How to shrink if there's not enough space available
pub flex_shrink: f32,
/// The initial size of the item
pub flex_basis: Val,
/// The size of the flexbox
pub size: Size<Val>,
/// The minimum size of the flexbox
pub min_size: Size<Val>,
/// The maximum size of the flexbox
pub max_size: Size<Val>,
/// The aspect ratio of the flexbox
pub aspect_ratio: Option<f32>,
/// How to handle overflow
pub overflow: Overflow,
}
@ -107,13 +142,19 @@ impl Default for Style {
}
}
/// How items are aligned according to the cross axis
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum AlignItems {
/// Items are aligned at the start
FlexStart,
/// Items are aligned at the end
FlexEnd,
/// Items are aligned at the center
Center,
/// Items are aligned at the baseline
Baseline,
/// Items are stretched across the whole cross axis
Stretch,
}
@ -123,14 +164,21 @@ impl Default for AlignItems {
}
}
/// Works like [`AlignItems`] but applies only to a single item
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum AlignSelf {
/// Use the value of [`AlignItems`]
Auto,
/// If the parent has [`AlignItems::Center`] only this item will be at the start
FlexStart,
/// If the parent has [`AlignItems::Center`] only this item will be at the end
FlexEnd,
/// If the parent has [`AlignItems::FlexStart`] only this item will be at the center
Center,
/// If the parent has [`AlignItems::Center`] only this item will be at the baseline
Baseline,
/// If the parent has [`AlignItems::Center`] only this item will stretch along the whole cross axis
Stretch,
}
@ -140,14 +188,25 @@ impl Default for AlignSelf {
}
}
/// 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, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum AlignContent {
/// Each line moves towards the start of the cross axis
FlexStart,
/// Each line moves towards the end of the cross axis
FlexEnd,
/// Each line moves towards the center of the cross axis
Center,
/// Each line will stretch to fill the remaining space
Stretch,
/// Each line fills the space it needs, putting the remaining space, if any
/// inbetween the lines
SpaceBetween,
/// Each line fills the space it needs, putting the remaining space, if any
/// around the lines
SpaceAround,
}
@ -157,11 +216,17 @@ impl Default for AlignContent {
}
}
/// 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, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum Direction {
/// Inherit from parent node
Inherit,
/// Text is written left to right
LeftToRight,
/// Text is written right to left
RightToLeft,
}
@ -171,10 +236,13 @@ impl Default for Direction {
}
}
/// Whether to use Flexbox layout
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum Display {
/// Use flexbox
Flex,
/// Use no layout, don't render this node and its children
None,
}
@ -184,12 +252,17 @@ impl Default for Display {
}
}
/// Defines how flexbox items are ordered within a flexbox
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum FlexDirection {
/// Same way as text direction along the main axis
Row,
/// Flex from bottom to top
Column,
/// Opposite way as text direction along the main axis
RowReverse,
/// Flex from top to bottom
ColumnReverse,
}
@ -199,14 +272,21 @@ impl Default for FlexDirection {
}
}
/// Defines how items are aligned according to the main axis
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum JustifyContent {
/// Pushed towards the start
FlexStart,
/// Pushed towards the end
FlexEnd,
/// Centered along the main axis
Center,
/// Remaining space is distributed between the items
SpaceBetween,
/// Remaining space is distributed around the items
SpaceAround,
/// Like [`JustifyContent::SpaceAround`] but with even spacing between items
SpaceEvenly,
}
@ -216,12 +296,14 @@ impl Default for JustifyContent {
}
}
/// 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,
// Scroll,
}
impl Default for Overflow {
@ -230,10 +312,15 @@ impl Default for Overflow {
}
}
/// The strategy used to position this node
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum PositionType {
/// Relative to all other nodes with the [`PositionType::Relative`] value
Relative,
/// Independent of all other nodes
///
/// As usual, the `Style.position` field of this node is specified relative to its parent node
Absolute,
}
@ -243,11 +330,15 @@ impl Default for PositionType {
}
}
/// Defines if flexbox items appear on a single line or on multiple lines
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum FlexWrap {
/// Single line, will overflow if needed
NoWrap,
/// Multiple lines, if needed
Wrap,
/// Same as [`FlexWrap::Wrap`] but new lines will appear before the previous one
WrapReverse,
}
@ -257,12 +348,15 @@ impl Default for FlexWrap {
}
}
/// 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)]
#[reflect(Component)]
pub struct UiColor(pub Color);
@ -273,6 +367,7 @@ impl From<Color> for UiColor {
}
}
/// The image of the node
#[derive(Component, Clone, Debug, Reflect)]
#[reflect(Component)]
pub struct UiImage(pub Handle<Image>);
@ -289,8 +384,10 @@ impl From<Handle<Image>> for UiImage {
}
}
/// 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,
}

View File

@ -1,3 +1,5 @@
//! This module contains systems that update the UI when something changes
use crate::{CalculatedClip, Overflow, Style};
use super::Node;
@ -13,8 +15,10 @@ use bevy_transform::{
prelude::{Children, Parent, Transform},
};
/// The resolution of Z values for UI
pub const UI_Z_STEP: f32 = 0.001;
/// Updates transforms of nodes to fit with the z system
pub fn ui_z_system(
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
mut node_query: Query<&mut Transform, With<Node>>,
@ -58,6 +62,7 @@ fn update_hierarchy(
current_global_z
}
/// Updates clipping for all nodes
pub fn update_clipping_system(
mut commands: Commands,
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,

View File

@ -2,6 +2,7 @@ use bevy_ecs::prelude::Component;
use bevy_ecs::reflect::ReflectComponent;
use bevy_reflect::Reflect;
/// Marker struct for buttons
#[derive(Component, Debug, Default, Clone, Copy, Reflect)]
#[reflect(Component)]
pub struct Button;

View File

@ -11,9 +11,11 @@ use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_render::texture::Image;
use serde::{Deserialize, Serialize};
/// Describes how to resize the Image node
#[derive(Component, Debug, Clone, Reflect, Serialize, Deserialize)]
#[reflect_value(Component, Serialize, Deserialize)]
pub enum ImageMode {
/// Keep the aspect ratio of the image
KeepAspect,
}
@ -23,6 +25,7 @@ impl Default for ImageMode {
}
}
/// Updates calculated size of the node based on the image provided
pub fn image_node_system(
textures: Res<Assets<Image>>,
mut query: Query<(&mut CalculatedSize, &UiImage), With<ImageMode>>,

View File

@ -1,3 +1,5 @@
//! This module contains the basic building blocks of Bevy's UI
mod button;
mod image;
mod text;

View File

@ -21,7 +21,8 @@ fn scale_value(value: f32, factor: f64) -> f32 {
(value as f64 * factor) as f32
}
/// Defines how `min_size`, `size`, and `max_size` affects the bounds of a text block.
/// Defines how `min_size`, `size`, and `max_size` affects the bounds of a text
/// block.
pub fn text_constraint(min_size: Val, size: Val, max_size: Val, scale_factor: f64) -> f32 {
// Needs support for percentages
match (min_size, size, max_size) {
@ -33,8 +34,8 @@ pub fn text_constraint(min_size: Val, size: Val, max_size: Val, scale_factor: f6
}
}
/// Computes the size of a text block and updates the `TextGlyphs` with the new computed glyphs
/// from the layout
/// Computes the size of a text block and updates the Text Glyphs with the
/// new computed glyphs from the layout
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub fn text_system(
mut queued_text: Local<QueuedText>,