Skip to main content

bevy_feathers/controls/
slider.rs

1use core::f32::consts::PI;
2
3use bevy_app::{Plugin, PreUpdate};
4use bevy_color::Color;
5use bevy_ecs::{
6    change_detection::DetectChanges,
7    component::Component,
8    entity::Entity,
9    hierarchy::Children,
10    lifecycle::RemovedComponents,
11    query::{Added, Changed, Has, Or, Spawned, With},
12    reflect::ReflectComponent,
13    schedule::IntoScheduleConfigs,
14    system::{Commands, Query, Res},
15};
16use bevy_input_focus::tab_navigation::TabIndex;
17use bevy_picking::{cursor::EntityCursor, hover::Hovered, PickingSystems};
18use bevy_reflect::{prelude::ReflectDefault, Reflect};
19use bevy_scene::prelude::*;
20use bevy_text::{FontWeight, TextLayout};
21use bevy_ui::{
22    percent, px, widget::Text, AlignItems, BackgroundGradient, ColorStop, Display, FlexDirection,
23    Gradient, InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node,
24    PositionType, Pressed, UiRect,
25};
26use bevy_ui_widgets::{
27    Slider, SliderOrientation, SliderPrecision, SliderRange, SliderValue, TrackClick,
28};
29
30use crate::{
31    constants::{fonts, size},
32    display::caption,
33    focus::FocusIndicator,
34    font_styles::InheritableFont,
35    rounded_corners::RoundedCorners,
36    theme::{InheritableThemeTextColor, SurfaceLevel, ThemeContext, UiTheme},
37    tokens,
38};
39
40/// A slider widget.
41///
42/// This is spawnable by inheriting it as a "scene component" with optional [`FeathersSliderProps`].
43///
44/// # Emitted events
45///
46/// * [`bevy_ui_widgets::ValueChange<f32>`] when the slider value is changed.
47///
48/// These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
49///
50/// A more complete explanation of how to control this widget can be found in the documentation
51/// for [`Slider`] and [`bevy_ui_widgets`].
52#[derive(#[doc =
"**Required Components**: [`Slider`]. \n\n A component's Required Components are inserted whenever it is inserted. Note that this will also insert the required components _of_ the required components, recursively, in depth-first order."]
impl bevy_ecs::component::Component for FeathersSlider where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {
        required_components.register_required::<Slider>(<Slider as
                ::core::default::Default>::default);
        required_components.register_required(||
                bevy_scene::SceneComponentInfo::new::<FeathersSlider>(false));
    }
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}
impl bevy_scene::SceneComponent for FeathersSlider where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    type Props = FeathersSliderProps;
    fn scene(props: Self::Props) -> impl bevy_scene::Scene {
        (Self::scene(props),
            <bevy_scene::InitTemplate<<FeathersSlider as
                    bevy_ecs::template::FromTemplate>::Template> as
                    ::core::default::Default>::default(),
            bevy_scene::template_value(bevy_scene::SceneComponentInfo::new::<FeathersSlider>(true)))
    }
}SceneComponent, #[automatically_derived]
impl ::core::default::Default for FeathersSlider {
    #[inline]
    fn default() -> Self { Self }
}Default, #[automatically_derived]
impl ::core::clone::Clone for FeathersSlider {
    #[inline]
    fn clone(&self) -> Self { Self }
}Clone, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for FeathersSlider where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert(<bevy_reflect::ReflectFromPtr as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.insert(<bevy_reflect::ReflectFromReflect as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.register_type_data_with::<ReflectComponent, Self,
                    _>(());
                registration.register_type_data_with::<ReflectDefault, Self,
                    _>(());
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for FeathersSlider where  {
            #[inline(never)]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(#[inline(never)] ||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for FeathersSlider where  {
            fn type_path() -> &'static str {
                "bevy_feathers::controls::slider::FeathersSlider"
            }
            fn short_type_path() -> &'static str { "FeathersSlider" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("FeathersSlider")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::slider".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::slider")
            }
        }
        impl bevy_reflect::Reflect for FeathersSlider where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        #[allow(non_upper_case_globals)]
        const _: () =
            {
                static __INVENTORY: ::inventory::Node =
                    ::inventory::Node {
                        value: &{
                                bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<FeathersSlider
                                        as
                                        bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
                            },
                        next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
                    };
                #[link_section = ".text.startup"]
                unsafe extern "C" fn __ctor() {
                    unsafe {
                        ::inventory::ErasedNode::submit(__INVENTORY.value,
                            &__INVENTORY)
                    }
                }
                #[used]
                #[link_section = ".init_array"]
                static __CTOR: unsafe extern "C" fn() = __ctor;
            };
        impl bevy_reflect::structs::Struct for FeathersSlider where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index { _ => ::core::option::Option::None, }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index { _ => ::core::option::Option::None, }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index { _ => ::core::option::Option::None, }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_len(&self) -> usize { 0usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                ->
                    ::core::result::Result<bevy_reflect::structs::DynamicStruct,
                    bevy_reflect::ReflectCloneError> {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                ::core::result::Result::Ok(dynamic)
            }
        }
        impl bevy_reflect::PartialReflect for FeathersSlider where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for FeathersSlider where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let mut __this =
                        <Self as ::core::default::Default>::default();
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
53#[scene(FeathersSliderProps)]
54#[require(Slider)]
55#[reflect(Component, Clone, Default)]
56pub struct FeathersSlider;
57
58/// Props used to construct the [`FeathersSlider`] scene.
59pub struct FeathersSliderProps {
60    /// Slider minimum value
61    pub min: f32,
62    /// Slider maximum value
63    pub max: f32,
64}
65
66impl Default for FeathersSliderProps {
67    fn default() -> Self {
68        Self { min: 0.0, max: 1.0 }
69    }
70}
71
72impl FeathersSlider {
73    fn scene(props: FeathersSliderProps) -> impl Scene {
74        bevy_scene::SceneScope({
        let _expr0 = { size::ROW_HEIGHT }.into();
        let _expr1 = { UiRect::horizontal(px(8)) }.into();
        let _expr2 = { RoundedCorners::All.to_border_radius(6.0) }.into();
        let _expr3 = { props.min }.into();
        let _expr4 = { tokens::SLIDER_TEXT }.into();
        let _expr5 =
            {
                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                            [Gradient::Linear(LinearGradient {
                                            angle: PI * 0.5,
                                            stops: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                                                    [ColorStop::new(Color::NONE, percent(0)),
                                                            ColorStop::new(Color::NONE, percent(50)),
                                                            ColorStop::new(Color::NONE, percent(50)),
                                                            ColorStop::new(Color::NONE, percent(100))])),
                                            color_space: InterpolationColorSpace::Srgba,
                                        })]))
                }.into();
        let _expr6 = { fonts::MONO }.into();
        let _expr7 = { size::SMALL_FONT }.into();
        (bevy_scene::SceneFunction(move |_context, _scene|
                    {
                        let __value =
                            _scene.get_or_insert_from_template::<Node>(_context);
                        __value.height = _expr0;
                        __value.justify_content = JustifyContent::Center.into();
                        __value.align_items = AlignItems::Center.into();
                        __value.padding = _expr1;
                        __value.flex_grow = 1.0;
                        __value.border_radius = _expr2;
                        let _ =
                            _scene.get_or_insert_from_template::<Hovered>(_context);
                        let __value =
                            _scene.get_or_insert_from_template::<Slider>(_context);
                        __value.track_click = TrackClick::Drag.into();
                        __value.orientation = SliderOrientation::Horizontal.into();
                        let _ =
                            _scene.get_or_insert_from_template::<FeathersSlider>(_context);
                        let __value =
                            _scene.get_or_insert_from_template::<SliderValue>(_context);
                        __value.0 = _expr3;
                        _scene.insert_template(<SliderRange as
                                    bevy_ecs::template::FromTemplate>::Template::new(props.min,
                                props.max));
                        _scene.insert_template(bevy_scene::macro_utils::PathResolveHelper::<<EntityCursor
                                    as
                                    bevy_ecs::template::FromTemplate>::Template>::System(bevy_window::SystemCursorIcon::EwResize));
                        let __value =
                            _scene.get_or_insert_from_template::<TabIndex>(_context);
                        __value.0 = 0;
                        let _ =
                            _scene.get_or_insert_from_template::<FocusIndicator>(_context);
                        let __value =
                            _scene.get_or_insert_from_template::<InheritableThemeTextColor>(_context);
                        __value.0 = _expr4;
                        let __value =
                            _scene.get_or_insert_from_template::<BackgroundGradient>(_context);
                        __value.0 = _expr5;
                    }),
            bevy_scene::RelatedScenes::<Children>::new(bevy_scene::EntityScene((bevy_scene::SceneFunction(move
                                |_context, _scene|
                                {
                                    let __value =
                                        _scene.get_or_insert_from_template::<Node>(_context);
                                    __value.display = Display::Flex.into();
                                    __value.position_type = PositionType::Absolute.into();
                                    __value.flex_direction = FlexDirection::Row.into();
                                    __value.align_items = AlignItems::Center.into();
                                    __value.justify_content = JustifyContent::Center.into();
                                    let __value =
                                        _scene.get_or_insert_from_template::<InheritableFont>(_context);
                                    __value.font = _expr6;
                                    __value.font_size = _expr7;
                                    __value.weight = FontWeight::NORMAL.into();
                                }),
                        bevy_scene::RelatedScenes::<Children>::new(bevy_scene::EntityScene((bevy_scene::SceneScope(caption("10.0")),
                                    bevy_scene::SceneFunction(move |_context, _scene|
                                            {
                                                _scene.insert_template(<TextLayout as
                                                            bevy_ecs::template::FromTemplate>::Template::no_wrap());
                                                let _ =
                                                    _scene.get_or_insert_from_template::<SliderValueText>(_context);
                                            }))))))))
    });bsn! {
75            Node {
76                height: size::ROW_HEIGHT,
77                justify_content: JustifyContent::Center,
78                align_items: AlignItems::Center,
79                padding: UiRect::horizontal(px(8)),
80                flex_grow: 1.0,
81                border_radius: {RoundedCorners::All.to_border_radius(6.0)},
82            }
83            Hovered
84            Slider {
85                track_click: TrackClick::Drag,
86                orientation: SliderOrientation::Horizontal,
87            }
88            FeathersSlider
89            SliderValue({props.min})
90            SliderRange::new(props.min, props.max)
91            EntityCursor::System(bevy_window::SystemCursorIcon::EwResize)
92            TabIndex(0)
93            FocusIndicator
94            InheritableThemeTextColor(tokens::SLIDER_TEXT)
95            // Use a gradient to draw the moving bar
96            BackgroundGradient(vec![Gradient::Linear(LinearGradient {
97                angle: PI * 0.5,
98                stops: vec![
99                    ColorStop::new(Color::NONE, percent(0)),
100                    ColorStop::new(Color::NONE, percent(50)),
101                    ColorStop::new(Color::NONE, percent(50)),
102                    ColorStop::new(Color::NONE, percent(100)),
103                ],
104                color_space: InterpolationColorSpace::Srgba,
105            })])
106            Children [
107                // Text container
108                Node {
109                    display: Display::Flex,
110                    position_type: PositionType::Absolute,
111                    flex_direction: FlexDirection::Row,
112                    align_items: AlignItems::Center,
113                    justify_content: JustifyContent::Center,
114                }
115                InheritableFont {
116                    font: fonts::MONO,
117                    font_size: size::SMALL_FONT,
118                    weight: FontWeight::NORMAL,
119                }
120                Children [@caption("10.0") TextLayout::no_wrap() SliderValueText]
121            ]
122        }
123    }
124}
125
126/// Marker for the text
127#[derive(impl bevy_ecs::component::Component for SliderValueText where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component, #[automatically_derived]
impl ::core::default::Default for SliderValueText {
    #[inline]
    fn default() -> Self { Self }
}Default, #[automatically_derived]
impl ::core::clone::Clone for SliderValueText {
    #[inline]
    fn clone(&self) -> Self { Self }
}Clone, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for SliderValueText where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert(<bevy_reflect::ReflectFromPtr as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.insert(<bevy_reflect::ReflectFromReflect as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.register_type_data_with::<ReflectComponent, Self,
                    _>(());
                registration.register_type_data_with::<ReflectDefault, Self,
                    _>(());
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for SliderValueText where  {
            #[inline(never)]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(#[inline(never)] ||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for SliderValueText where  {
            fn type_path() -> &'static str {
                "bevy_feathers::controls::slider::SliderValueText"
            }
            fn short_type_path() -> &'static str { "SliderValueText" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("SliderValueText")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::slider".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::slider")
            }
        }
        impl bevy_reflect::Reflect for SliderValueText where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        #[allow(non_upper_case_globals)]
        const _: () =
            {
                static __INVENTORY: ::inventory::Node =
                    ::inventory::Node {
                        value: &{
                                bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<SliderValueText
                                        as
                                        bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
                            },
                        next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
                    };
                #[link_section = ".text.startup"]
                unsafe extern "C" fn __ctor() {
                    unsafe {
                        ::inventory::ErasedNode::submit(__INVENTORY.value,
                            &__INVENTORY)
                    }
                }
                #[used]
                #[link_section = ".init_array"]
                static __CTOR: unsafe extern "C" fn() = __ctor;
            };
        impl bevy_reflect::structs::Struct for SliderValueText where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index { _ => ::core::option::Option::None, }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index { _ => ::core::option::Option::None, }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index { _ => ::core::option::Option::None, }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_len(&self) -> usize { 0usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                ->
                    ::core::result::Result<bevy_reflect::structs::DynamicStruct,
                    bevy_reflect::ReflectCloneError> {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                ::core::result::Result::Ok(dynamic)
            }
        }
        impl bevy_reflect::PartialReflect for SliderValueText where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for SliderValueText where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let mut __this =
                        <Self as ::core::default::Default>::default();
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
128#[reflect(Component, Clone, Default)]
129struct SliderValueText;
130
131fn update_slider_styles(
132    mut q_sliders: Query<
133        (
134            Entity,
135            Has<InteractionDisabled>,
136            Has<Pressed>,
137            &Hovered,
138            &mut BackgroundGradient,
139            &InheritableThemeTextColor,
140            Option<&ThemeContext>,
141        ),
142        (
143            With<FeathersSlider>,
144            Or<(
145                Spawned,
146                Added<InteractionDisabled>,
147                Changed<Hovered>,
148                Changed<ThemeContext>,
149                Added<Pressed>,
150            )>,
151        ),
152    >,
153    theme: Res<UiTheme>,
154    mut commands: Commands,
155) {
156    for (slider_ent, disabled, pressed, hovered, mut gradient, font_color, theme_context) in
157        q_sliders.iter_mut()
158    {
159        set_slider_styles(
160            slider_ent,
161            &theme,
162            theme_context.map(|tc| tc.0).unwrap_or(SurfaceLevel::Base),
163            disabled,
164            pressed,
165            hovered.0,
166            gradient.as_mut(),
167            font_color,
168            &mut commands,
169        );
170    }
171}
172
173fn update_slider_styles_remove(
174    mut q_sliders: Query<
175        (
176            Entity,
177            Has<InteractionDisabled>,
178            Has<Pressed>,
179            &Hovered,
180            &mut BackgroundGradient,
181            &InheritableThemeTextColor,
182            Option<&ThemeContext>,
183        ),
184        With<FeathersSlider>,
185    >,
186    mut removed_disabled: RemovedComponents<InteractionDisabled>,
187    mut remove_pressed: RemovedComponents<Pressed>,
188    theme: Res<UiTheme>,
189    mut commands: Commands,
190) {
191    removed_disabled
192        .read()
193        .chain(remove_pressed.read())
194        .for_each(|ent| {
195            if let Ok((
196                slider_ent,
197                disabled,
198                pressed,
199                hovered,
200                mut gradient,
201                font_color,
202                theme_context,
203            )) = q_sliders.get_mut(ent)
204            {
205                set_slider_styles(
206                    slider_ent,
207                    &theme,
208                    theme_context.map(|tc| tc.0).unwrap_or(SurfaceLevel::Base),
209                    disabled,
210                    pressed,
211                    hovered.0,
212                    gradient.as_mut(),
213                    font_color,
214                    &mut commands,
215                );
216            }
217        });
218}
219
220/// Re-apply slider styles to every slider when the theme changes.
221fn update_slider_styles_theme(
222    mut q_sliders: Query<
223        (
224            Entity,
225            Has<InteractionDisabled>,
226            Has<Pressed>,
227            &Hovered,
228            &mut BackgroundGradient,
229            &InheritableThemeTextColor,
230            Option<&ThemeContext>,
231        ),
232        With<FeathersSlider>,
233    >,
234    theme: Res<UiTheme>,
235    mut commands: Commands,
236) {
237    if !theme.is_changed() {
238        return;
239    }
240    for (slider_ent, disabled, pressed, hovered, mut gradient, font_color, theme_context) in
241        q_sliders.iter_mut()
242    {
243        set_slider_styles(
244            slider_ent,
245            &theme,
246            theme_context.map(|tc| tc.0).unwrap_or(SurfaceLevel::Base),
247            disabled,
248            pressed,
249            hovered.0,
250            gradient.as_mut(),
251            font_color,
252            &mut commands,
253        );
254    }
255}
256
257fn set_slider_styles(
258    slider_ent: Entity,
259    theme: &Res<'_, UiTheme>,
260    context: SurfaceLevel,
261    disabled: bool,
262    pressed: bool,
263    hovered: bool,
264    gradient: &mut BackgroundGradient,
265    font_color: &InheritableThemeTextColor,
266    commands: &mut Commands,
267) {
268    let bar_color = theme.context_color(
269        &if disabled {
270            tokens::SLIDER_BAR_DISABLED
271        } else if pressed {
272            tokens::SLIDER_BAR_PRESSED
273        } else if hovered {
274            tokens::SLIDER_BAR_HOVER
275        } else {
276            tokens::SLIDER_BAR
277        },
278        context,
279    );
280
281    let bg_color = theme.context_color(
282        &if disabled {
283            tokens::SLIDER_BG_DISABLED
284        } else if pressed {
285            tokens::SLIDER_BG_PRESSED
286        } else if hovered {
287            tokens::SLIDER_BG_HOVER
288        } else {
289            tokens::SLIDER_BG
290        },
291        context,
292    );
293
294    let text_token = if disabled {
295        tokens::SLIDER_TEXT_DISABLED
296    } else {
297        tokens::SLIDER_TEXT
298    };
299
300    let cursor_shape = match disabled {
301        true => bevy_window::SystemCursorIcon::NotAllowed,
302        false => bevy_window::SystemCursorIcon::EwResize,
303    };
304
305    if let [Gradient::Linear(linear_gradient)] = &mut gradient.0[..] {
306        linear_gradient.stops[0].color = bar_color;
307        linear_gradient.stops[1].color = bar_color;
308        linear_gradient.stops[2].color = bg_color;
309        linear_gradient.stops[3].color = bg_color;
310    }
311
312    // Change value-text color (dim when disabled)
313    if font_color.0 != text_token {
314        commands
315            .entity(slider_ent)
316            .insert(InheritableThemeTextColor(text_token));
317    }
318
319    // Change cursor shape
320    commands
321        .entity(slider_ent)
322        .insert(EntityCursor::System(cursor_shape));
323}
324
325fn update_slider_pos(
326    mut q_sliders: Query<
327        (
328            Entity,
329            &SliderValue,
330            &SliderRange,
331            Option<&SliderPrecision>,
332            &mut BackgroundGradient,
333        ),
334        (
335            With<FeathersSlider>,
336            Or<(
337                Changed<SliderValue>,
338                Changed<SliderRange>,
339                Changed<Children>,
340            )>,
341        ),
342    >,
343    q_children: Query<&Children>,
344    mut q_slider_text: Query<&mut Text, With<SliderValueText>>,
345) {
346    for (slider_ent, value, range, precision, mut gradient) in q_sliders.iter_mut() {
347        if let [Gradient::Linear(linear_gradient)] = &mut gradient.0[..] {
348            let percent_value = (range.thumb_position(value.0) * 100.0).clamp(0.0, 100.0);
349            linear_gradient.stops[1].point = percent(percent_value);
350            linear_gradient.stops[2].point = percent(percent_value);
351        }
352
353        // Find slider text child entity and update its text with the formatted value
354        let precision = precision.cloned().unwrap_or_default().0;
355
356        q_children.iter_descendants(slider_ent).for_each(|child| {
357            if let Ok(mut text) = q_slider_text.get_mut(child) {
358                let label = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", value.0))
    })format!("{}", value.0);
359                let decimals_len = label
360                    .split_once('.')
361                    .map(|(_, decimals)| decimals.len() as i32)
362                    .unwrap_or(precision);
363
364                // Don't format with precision if the value has more decimals than the precision
365                text.0 = if precision >= 0 && decimals_len <= precision {
366                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:.1$}", value.0,
                precision as usize))
    })format!("{:.precision$}", value.0, precision = precision as usize)
367                } else {
368                    label
369                };
370            }
371        });
372    }
373}
374
375/// Plugin which registers the systems for updating the slider styles.
376pub struct SliderPlugin;
377
378impl Plugin for SliderPlugin {
379    fn build(&self, app: &mut bevy_app::App) {
380        app.add_systems(
381            PreUpdate,
382            (
383                update_slider_styles,
384                update_slider_styles_remove,
385                update_slider_styles_theme,
386                update_slider_pos,
387            )
388                .chain()
389                .in_set(PickingSystems::Last),
390        );
391    }
392}