//! Helper functions for creating common widgets. use std::borrow::Cow; use bevy::{ ecs::{spawn::SpawnWith, system::IntoObserverSystem}, prelude::*, ui::Val::*, }; use crate::theme::{interaction::InteractionPalette, palette::*}; /// A root UI node that fills the window and centers its content. pub fn ui_root(name: impl Into>) -> impl Bundle { ( Name::new(name), Node { position_type: PositionType::Absolute, width: Percent(100.0), height: Percent(100.0), align_items: AlignItems::Center, justify_content: JustifyContent::Center, flex_direction: FlexDirection::Column, row_gap: Px(20.0), ..default() }, // Don't block picking events for other UI roots. Pickable::IGNORE, ) } /// A simple header label. Bigger than [`label`]. pub fn header(text: impl Into) -> impl Bundle { ( Name::new("Header"), Text(text.into()), TextFont::from_font_size(40.0), TextColor(HEADER_TEXT), ) } /// A simple text label. pub fn label(text: impl Into) -> impl Bundle { ( Name::new("Label"), Text(text.into()), TextFont::from_font_size(24.0), TextColor(LABEL_TEXT), ) } /// A large rounded button with text and an action defined as an [`Observer`]. pub fn button(text: impl Into, action: I) -> impl Bundle where E: Event, B: Bundle, I: IntoObserverSystem, { button_base( text, action, ( Node { width: Px(380.0), height: Px(80.0), align_items: AlignItems::Center, justify_content: JustifyContent::Center, ..default() }, BorderRadius::MAX, ), ) } /// A small square button with text and an action defined as an [`Observer`]. pub fn button_small(text: impl Into, action: I) -> impl Bundle where E: Event, B: Bundle, I: IntoObserverSystem, { button_base( text, action, Node { width: Px(30.0), height: Px(30.0), align_items: AlignItems::Center, justify_content: JustifyContent::Center, ..default() }, ) } /// A simple button with text and an action defined as an [`Observer`]. The button's layout is provided by `button_bundle`. fn button_base( text: impl Into, action: I, button_bundle: impl Bundle, ) -> impl Bundle where E: Event, B: Bundle, I: IntoObserverSystem, { let text = text.into(); let action = IntoObserverSystem::into_system(action); ( Name::new("Button"), Node::default(), Children::spawn(SpawnWith(|parent: &mut ChildSpawner| { parent .spawn(( Name::new("Button Inner"), Button, BackgroundColor(BUTTON_BACKGROUND), InteractionPalette { none: BUTTON_BACKGROUND, hovered: BUTTON_HOVERED_BACKGROUND, pressed: BUTTON_PRESSED_BACKGROUND, }, children![( Name::new("Button Text"), Text(text), TextFont::from_font_size(40.0), TextColor(BUTTON_TEXT), // Don't bubble picking events from the text up to the button. Pickable::IGNORE, )], )) .insert(button_bundle) .observe(action); })), ) }