//! This example shows off the various Bevy Feathers widgets. use std::f32::consts::PI; use bevy::{ feathers::{ controls::*, dark_theme::create_dark_theme, display::label, theme::{ThemeBackgroundColor, UiTheme}, tokens, FeathersPlugins, }, input_focus::tab_navigation::TabGroup, prelude::*, ui::InteractionDisabled, ui_widgets::ValueChange, }; fn main() { App::new() .add_plugins((DefaultPlugins, FeathersPlugins)) .insert_resource(UiTheme(create_dark_theme())) .add_systems(Startup, scene.spawn()) // .add_systems(Update, update_colors) .run(); } fn scene() -> impl SceneList { bsn_list! { Camera2d -- @demo_root() } } fn demo_root() -> impl Scene { bsn! { Node { width: percent(100), height: percent(100), align_items: AlignItems::Start, justify_content: JustifyContent::Start, display: Display::Flex, flex_direction: FlexDirection::Column, flex_wrap: FlexWrap::Wrap, padding: px(8), row_gap: px(8), } TabGroup ThemeBackgroundColor(tokens::WINDOW_BG) Children[ @demo_field_f32("none (bare)", 1.0, bsn! {}) -- @demo_field_f32("soft limit", 2.0, bsn! { SoftLimit(NumberInputRange::F32(0.0..=10.0)) }) -- @demo_field_f32("hard limit", 3.0, bsn! { HardLimit(NumberInputRange::F32(-100.0..=100.0)) }) -- @demo_field_f32("soft + hard", 4.0, bsn! { SoftLimit(NumberInputRange::F32(0.0..=10.0)) HardLimit(NumberInputRange::F32(-100.0..=100.0)) }) -- @demo_field_f32("precision(0)", 5.0, bsn! { NumberInputPrecision(0) }) -- @demo_field_f32("precision(2)", 6.0, bsn! { NumberInputPrecision(2) }) -- @demo_field_f32("precision(4)", 7.0, bsn! { NumberInputPrecision(4) }) -- @demo_field_f32("step(1.0)", 8.0, bsn! { NumberInputStep(1.0f64) }) -- @demo_field_f64("f64: soft limit", 1.0f64, bsn! { SoftLimit(NumberInputRange::F64(0.0f64..=10.0f64)) }) -- @demo_field_f64("f64: soft limit + precision(2)", 1.0f64, bsn! { SoftLimit(NumberInputRange::F64(0.0f64..=10.0f64)) NumberInputPrecision(2) }) -- @demo_field_i32("i32: bare", 1, bsn! {}) -- @demo_field_i32("i32: soft limit", 1, bsn! { SoftLimit(NumberInputRange::I32(0..=10)) }) -- @demo_field_f32_with_sigil("precision(2) + sigil", 6.0, bsn! { NumberInputPrecision(2) }) -- @demo_field_f32("soft limit + disabled", 2.0, bsn! { InteractionDisabled SoftLimit(NumberInputRange::F32(0.0..=10.0)) }) -- @demo_field_f32("hard limit + wrap", 0.0, bsn! { HardLimit(NumberInputRange::F32(-180.0..=180.0)) NumberInputWrap::Wrap }) -- @demo_field_f32("in meters", 2.0, bsn! { NumberInputUnits::new(&LengthMeters) }) -- @demo_field_f32("in seconds", 2.0, bsn! { NumberInputUnits::new(&TimeSeconds) }) -- @demo_field_f32("in degrees", PI, bsn! { NumberInputUnits::new(&AngleDegrees) }) ] } } fn demo_field_f32(label_text: &str, value: f32, options: impl Scene) -> impl Scene { bsn! { Node { display: Display::Flex, flex_direction: FlexDirection::Column, align_items: AlignItems::Start, width: px(200), row_gap: px(4), } Children [ @label(label_text) -- Node { display: Display::Flex, flex_direction: FlexDirection::Row, align_items: AlignItems::Center, align_self: AlignSelf::Stretch, justify_content: JustifyContent::SpaceBetween, } Children [ @FeathersNumberInput NumberInputValue::F32(value) @{options} Node { flex_grow: 1.0, max_width: px(120), } on( |value_change: On>, mut commands: Commands| { commands.entity(value_change.event_target()) .insert(NumberInputValue::F32(value_change.value)); }) -- #Output @label("-") ] ] } } fn demo_field_f32_with_sigil(label_text: &str, value: f32, options: impl Scene) -> impl Scene { bsn! { Node { display: Display::Flex, flex_direction: FlexDirection::Column, align_items: AlignItems::Start, width: px(200), } Children [ @label(label_text) -- Node { display: Display::Flex, flex_direction: FlexDirection::Row, align_items: AlignItems::Center, align_self: AlignSelf::Stretch, justify_content: JustifyContent::SpaceBetween, } Children [ @FeathersNumberInput { @sigil_color: tokens::TEXT_INPUT_X_AXIS, @label_text: "X", } NumberInputValue::F32(value) @{options} Node { flex_grow: 1.0, max_width: px(120), } on( |value_change: On>, mut commands: Commands| { commands.entity(value_change.event_target()) .insert(NumberInputValue::F32(value_change.value)); }) -- #Output @label("-") ] ] } } fn demo_field_f64(label_text: &str, value: f64, options: impl Scene) -> impl Scene { bsn! { Node { display: Display::Flex, flex_direction: FlexDirection::Column, align_items: AlignItems::Start, width: px(200), } Children [ @label(label_text) -- Node { display: Display::Flex, flex_direction: FlexDirection::Row, align_items: AlignItems::Center, align_self: AlignSelf::Stretch, justify_content: JustifyContent::SpaceBetween, } Children [ @FeathersNumberInput NumberInputValue::F64(value) @{options} Node { flex_grow: 1.0, max_width: px(120), } on( |value_change: On>, mut commands: Commands| { commands.entity(value_change.event_target()) .insert(NumberInputValue::F64(value_change.value)); }) -- #Output @label("-") ] ] } } fn demo_field_i32(label_text: &str, value: i32, options: impl Scene) -> impl Scene { bsn! { Node { display: Display::Flex, flex_direction: FlexDirection::Column, align_items: AlignItems::Start, width: px(200), } Children [ @label(label_text) -- Node { display: Display::Flex, flex_direction: FlexDirection::Row, align_items: AlignItems::Center, align_self: AlignSelf::Stretch, justify_content: JustifyContent::SpaceBetween, } Children [ @FeathersNumberInput NumberInputValue::I32(value) @{options} Node { flex_grow: 1.0, max_width: px(120), } on( |value_change: On>, mut commands: Commands| { commands.entity(value_change.event_target()) .insert(NumberInputValue::I32(value_change.value)); }) -- #Output @label("-") ] ] } }