Skip to main content

bevy_feathers/controls/
listview.rs

1use accesskit::Role;
2use bevy_a11y::AccessibilityNode;
3use bevy_app::{Plugin, PostUpdate, PreUpdate};
4use bevy_ecs::{
5    change_detection::DetectChanges,
6    component::Component,
7    entity::Entity,
8    hierarchy::{ChildOf, Children},
9    lifecycle::RemovedComponents,
10    query::{Added, Changed, Has, Or, With},
11    reflect::ReflectComponent,
12    schedule::IntoScheduleConfigs as _,
13    system::{Commands, Query, Res},
14};
15use bevy_input_focus::{tab_navigation::TabIndex, InputFocus, InputFocusVisible};
16use bevy_picking::{hover::Hovered, PickingSystems};
17use bevy_reflect::{prelude::ReflectDefault, Reflect};
18use bevy_scene::{bsn, bsn_list, Scene, SceneComponent, SceneList};
19use bevy_text::{FontSize, FontWeight};
20use bevy_ui::{
21    px, AlignItems, BorderRadius, Display, FlexDirection, InteractionDisabled, JustifyContent,
22    Node, Overflow, PositionType, Selected, UiRect,
23};
24use bevy_ui_widgets::{ActiveDescendant, ControlOrientation, ListBox, ListItem, ScrollArea};
25
26use crate::{
27    constants::{fonts, size},
28    controls::FeathersScrollbar,
29    cursor::EntityCursor,
30    font_styles::InheritableFont,
31    theme::{InheritableThemeTextColor, ThemeBackgroundColor, ThemeBorderColor},
32    tokens,
33};
34
35/// A container that displays a scrolling list of items
36#[derive(impl bevy_scene::SceneComponent for FeathersListView where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    type Props = FeathersListViewProps;
    fn scene(props: Self::Props) -> impl bevy_scene::Scene {
        (Self::scene(props),
            <bevy_scene::InitTemplate<<FeathersListView as
                    bevy_ecs::template::FromTemplate>::Template> as
                    ::core::default::Default>::default(),
            bevy_scene::template_value(bevy_scene::SceneComponentInfo::new::<FeathersListView>(true)))
    }
}SceneComponent, #[automatically_derived]
impl ::core::default::Default for FeathersListView {
    #[inline]
    fn default() -> FeathersListView { FeathersListView {} }
}Default, #[automatically_derived]
impl ::core::clone::Clone for FeathersListView {
    #[inline]
    fn clone(&self) -> FeathersListView { FeathersListView }
}Clone, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for FeathersListView where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectComponent, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for FeathersListView where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            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 FeathersListView where  {
            fn type_path() -> &'static str {
                "bevy_feathers::controls::listview::FeathersListView"
            }
            fn short_type_path() -> &'static str { "FeathersListView" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("FeathersListView")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::listview".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::listview")
            }
        }
        impl bevy_reflect::Reflect for FeathersListView 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(<FeathersListView
                                        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 FeathersListView 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)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for FeathersListView 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 FeathersListView 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)]
37#[scene(FeathersListViewProps)]
38#[reflect(Component, Clone, Default)]
39pub struct FeathersListView;
40
41/// Props used to construct a [`FeathersListView`] scene.
42pub struct FeathersListViewProps {
43    /// The list of items to be displayed in the list view.
44    pub rows: Box<dyn SceneList>,
45}
46
47impl Default for FeathersListViewProps {
48    fn default() -> Self {
49        Self {
50            rows: Box::new({ let _res = bevy_scene::SceneListScope(()); _res }bsn_list!()),
51        }
52    }
53}
54
55impl FeathersListView {
56    /// Scene function for list view.
57    pub fn scene(props: FeathersListViewProps) -> impl Scene {
58        bevy_scene::SceneScope({
        static _CALL_ID: bevy_scene::macro_utils::CallCounter =
            bevy_scene::macro_utils::CallCounter::new();
        let _call_id = _CALL_ID.increment();
        let _expr0 = { px(10) }.into();
        let _expr1 = { accesskit::Node::new(Role::ListBox) }.into();
        let _expr2 = { Overflow::scroll_y() }.into();
        let _expr3 = { ControlOrientation::Vertical }.into();
        let _expr4 = { px(0) }.into();
        let _expr5 = { px(0) }.into();
        let _expr6 = { px(0) }.into();
        let _expr7 = { px(6) }.into();
        let _res =
            (bevy_scene::SceneFunction(move |_context, _scene|
                        {
                            let __value =
                                _scene.get_or_insert_template::<<Node as
                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                            __value.display = (Display::Flex {}).into();
                            __value.flex_direction = (FlexDirection::Column {}).into();
                            __value.align_items = (AlignItems::Stretch {}).into();
                            __value.justify_content = (JustifyContent::Start {}).into();
                            bevy_scene::macro_utils::touch_type::<UiRect>();
                            __value.padding.right = _expr0;
                            let _ =
                                _scene.get_or_insert_template::<<ListBox as
                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                            let __value =
                                _scene.get_or_insert_template::<<AccessibilityNode as
                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                            __value.0 = _expr1;
                            let __value =
                                _scene.get_or_insert_template::<<TabIndex as
                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                            __value.0 = 0;
                        }),
                bevy_scene::RelatedScenes::<<Children as
                        bevy_ecs::relationship::RelationshipTarget>::Relationship,
                        _>::new((bevy_scene::EntityScene((bevy_scene::SceneFunction(move
                                        |_context, _scene|
                                        {
                                            bevy_scene::NameEntityReference {
                                                    name: bevy_ecs::name::Name("inner".into()),
                                                    reference: bevy_ecs::template::SceneEntityReference::new(("src/controls/listview.rs",
                                                            58usize, 9usize), 0usize, _call_id),
                                                }.resolve_inline(_context, _scene);
                                            let __value =
                                                _scene.get_or_insert_template::<<Node as
                                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                                            __value.display = (Display::Flex {}).into();
                                            __value.flex_direction = (FlexDirection::Column {}).into();
                                            __value.align_items = (AlignItems::Stretch {}).into();
                                            __value.justify_content = (JustifyContent::Start {}).into();
                                            __value.overflow = _expr2;
                                            let _ =
                                                _scene.get_or_insert_template::<<ScrollArea as
                                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                                        }),
                                bevy_scene::RelatedScenes::<<Children as
                                        bevy_ecs::relationship::RelationshipTarget>::Relationship,
                                        _>::new(props.rows))),
                        bevy_scene::EntityScene(({
                                    let mut __props =
                                        <<FeathersScrollbar as bevy_scene::SceneComponent>::Props as
                                                ::core::default::Default>::default();
                                    let __props_ref = &mut __props;
                                    bevy_scene::macro_utils::touch_type::<FeathersScrollbar>();
                                    __props.target =
                                        bevy_ecs::template::EntityTemplate::from_reference(("src/controls/listview.rs",
                                                58usize, 9usize), 0usize, _call_id);
                                    __props.orientation = _expr3;
                                    (<FeathersScrollbar as
                                                bevy_scene::SceneComponent>::scene(__props),
                                        <FeathersScrollbar as
                                                bevy_scene::PatchFromTemplate>::patch(move
                                                |__value, _context| {}))
                                },
                                bevy_scene::SceneFunction(move |_context, _scene|
                                        {
                                            let __value =
                                                _scene.get_or_insert_template::<<Node as
                                                    bevy_ecs::template::FromTemplate>::Template>(_context);
                                            __value.position_type = (PositionType::Absolute {}).into();
                                            __value.right = _expr4;
                                            __value.top = _expr5;
                                            __value.bottom = _expr6;
                                            __value.width = _expr7;
                                        }))))));
        _res
    });bsn! {
59            // Outer frame that holds the scrollbar
60            Node {
61                display: Display::Flex,
62                flex_direction: FlexDirection::Column,
63                align_items: AlignItems::Stretch,
64                justify_content: JustifyContent::Start,
65                padding: UiRect {
66                    right: px(10) // Room for scrollbar
67                }
68            }
69            ListBox
70            AccessibilityNode(accesskit::Node::new(Role::ListBox))
71            TabIndex(0)
72            Children [
73                // Inner part that scrolls
74                (
75                    #inner
76                    Node {
77                        display: Display::Flex,
78                        flex_direction: FlexDirection::Column,
79                        align_items: AlignItems::Stretch,
80                        justify_content: JustifyContent::Start,
81                        overflow: Overflow::scroll_y(),
82                    }
83                    ScrollArea
84                    Children [
85                        {props.rows}
86                    ]
87                ),
88
89                @FeathersScrollbar {
90                    @target: #inner,
91                    @orientation: {ControlOrientation::Vertical}
92                }
93                Node {
94                    position_type: PositionType::Absolute,
95                    right: px(0),
96                    top: px(0),
97                    bottom: px(0),
98                    width: px(6),
99                }
100            ]
101        }
102    }
103}
104
105/// A selectable row in a list of items
106#[derive(impl bevy_scene::SceneComponent for FeathersListRow where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    type Props = ();
    fn scene(props: Self::Props) -> impl bevy_scene::Scene {
        (Self::scene(),
            <bevy_scene::InitTemplate<<FeathersListRow as
                    bevy_ecs::template::FromTemplate>::Template> as
                    ::core::default::Default>::default(),
            bevy_scene::template_value(bevy_scene::SceneComponentInfo::new::<FeathersListRow>(true)))
    }
}SceneComponent, #[automatically_derived]
impl ::core::default::Default for FeathersListRow {
    #[inline]
    fn default() -> FeathersListRow { FeathersListRow {} }
}Default, #[automatically_derived]
impl ::core::clone::Clone for FeathersListRow {
    #[inline]
    fn clone(&self) -> FeathersListRow { FeathersListRow }
}Clone, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for FeathersListRow where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectComponent, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for FeathersListRow where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            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 FeathersListRow where  {
            fn type_path() -> &'static str {
                "bevy_feathers::controls::listview::FeathersListRow"
            }
            fn short_type_path() -> &'static str { "FeathersListRow" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("FeathersListRow")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::listview".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::listview")
            }
        }
        impl bevy_reflect::Reflect for FeathersListRow 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(<FeathersListRow
                                        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 FeathersListRow 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)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for FeathersListRow 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 FeathersListRow 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)]
107#[reflect(Component, Clone, Default)]
108pub struct FeathersListRow;
109
110impl FeathersListRow {
111    /// Scene function for list row.
112    pub fn scene() -> impl Scene {
113        bevy_scene::SceneScope({
        let _expr0 = { size::ROW_HEIGHT }.into();
        let _expr1 = { size::ROW_HEIGHT }.into();
        let _expr2 = { UiRect::axes(px(8), px(2)) }.into();
        let _expr3 = { accesskit::Node::new(Role::ListItem) }.into();
        let _expr4 = { tokens::LISTROW_TEXT }.into();
        let _expr5 = { tokens::LISTROW_BG }.into();
        let _expr6 = { fonts::REGULAR }.into();
        let _expr7 = { FontWeight::NORMAL }.into();
        let _res =
            bevy_scene::SceneFunction(move |_context, _scene|
                    {
                        let __value =
                            _scene.get_or_insert_template::<<Node as
                                bevy_ecs::template::FromTemplate>::Template>(_context);
                        __value.min_height = _expr0;
                        __value.min_width = _expr1;
                        __value.display = (Display::Flex {}).into();
                        __value.flex_direction = (FlexDirection::Row {}).into();
                        __value.justify_content = (JustifyContent::Start {}).into();
                        __value.align_items = (AlignItems::Center {}).into();
                        __value.padding = _expr2;
                        let __value =
                            _scene.get_or_insert_template::<<AccessibilityNode as
                                bevy_ecs::template::FromTemplate>::Template>(_context);
                        __value.0 = _expr3;
                        let __value =
                            _scene.get_or_insert_template::<<InheritableThemeTextColor
                                as bevy_ecs::template::FromTemplate>::Template>(_context);
                        __value.0 = _expr4;
                        let __value =
                            _scene.get_or_insert_template::<<ThemeBackgroundColor as
                                bevy_ecs::template::FromTemplate>::Template>(_context);
                        __value.0 = _expr5;
                        let __value =
                            _scene.get_or_insert_template::<<InheritableFont as
                                bevy_ecs::template::FromTemplate>::Template>(_context);
                        __value.font = _expr6;
                        __value.font_size = (FontSize::Px(14.0)).into();
                        __value.weight = _expr7;
                        let _ =
                            _scene.get_or_insert_template::<<Hovered as
                                bevy_ecs::template::FromTemplate>::Template>(_context);
                        let _ =
                            _scene.get_or_insert_template::<<ListItem as
                                bevy_ecs::template::FromTemplate>::Template>(_context);
                    });
        _res
    });bsn! {
114            Node {
115                min_height: size::ROW_HEIGHT,
116                min_width: size::ROW_HEIGHT,
117                display: Display::Flex,
118                flex_direction: FlexDirection::Row,
119                justify_content: JustifyContent::Start,
120                align_items: AlignItems::Center,
121                padding: UiRect::axes(px(8), px(2)),
122            }
123            AccessibilityNode(accesskit::Node::new(Role::ListItem))
124            InheritableThemeTextColor(tokens::LISTROW_TEXT)
125            ThemeBackgroundColor(tokens::LISTROW_BG)
126            InheritableFont {
127                font: fonts::REGULAR,
128                font_size: FontSize::Px(14.0),
129                weight: FontWeight::NORMAL,
130            }
131            Hovered
132            ListItem
133        }
134    }
135}
136
137/// Marker for the listrow check mark
138#[derive(impl bevy_ecs::component::Component for ActiveRowOutline 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 ActiveRowOutline {
    #[inline]
    fn default() -> ActiveRowOutline { ActiveRowOutline {} }
}Default, #[automatically_derived]
impl ::core::clone::Clone for ActiveRowOutline {
    #[inline]
    fn clone(&self) -> ActiveRowOutline { ActiveRowOutline }
}Clone, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for ActiveRowOutline where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectComponent, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for ActiveRowOutline where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            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 ActiveRowOutline where  {
            fn type_path() -> &'static str {
                "bevy_feathers::controls::listview::ActiveRowOutline"
            }
            fn short_type_path() -> &'static str { "ActiveRowOutline" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("ActiveRowOutline")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::listview".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_feathers::controls::listview")
            }
        }
        impl bevy_reflect::Reflect for ActiveRowOutline 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(<ActiveRowOutline
                                        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 ActiveRowOutline 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)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for ActiveRowOutline 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 ActiveRowOutline 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)]
139#[reflect(Component, Clone, Default)]
140struct ActiveRowOutline;
141
142fn update_listrow_styles(
143    q_listrows: Query<
144        (
145            Entity,
146            Has<InteractionDisabled>,
147            Has<Selected>,
148            &Hovered,
149            &ThemeBackgroundColor,
150            &InheritableThemeTextColor,
151        ),
152        (
153            With<FeathersListRow>,
154            Or<(
155                Changed<Hovered>,
156                Added<Selected>,
157                Added<InteractionDisabled>,
158            )>,
159        ),
160    >,
161    mut commands: Commands,
162) {
163    for (listrow_ent, disabled, selected, hovered, bg_color, font_color) in q_listrows.iter() {
164        set_listrow_styles(
165            listrow_ent,
166            disabled,
167            selected,
168            hovered.0,
169            bg_color,
170            font_color,
171            &mut commands,
172        );
173    }
174}
175
176fn update_listrow_styles_remove(
177    q_listrows: Query<
178        (
179            Entity,
180            Has<InteractionDisabled>,
181            Has<Selected>,
182            &Hovered,
183            &ThemeBackgroundColor,
184            &InheritableThemeTextColor,
185        ),
186        With<FeathersListRow>,
187    >,
188    mut removed_disabled: RemovedComponents<InteractionDisabled>,
189    mut removed_selected: RemovedComponents<Selected>,
190    mut commands: Commands,
191) {
192    removed_disabled
193        .read()
194        .chain(removed_selected.read())
195        .for_each(|ent| {
196            if let Ok((listrow_ent, disabled, selected, hovered, bg_color, font_color)) =
197                q_listrows.get(ent)
198            {
199                set_listrow_styles(
200                    listrow_ent,
201                    disabled,
202                    selected,
203                    hovered.0,
204                    bg_color,
205                    font_color,
206                    &mut commands,
207                );
208            }
209        });
210}
211
212fn set_listrow_styles(
213    listrow_ent: Entity,
214    disabled: bool,
215    selected: bool,
216    hovered: bool,
217    bg_color: &ThemeBackgroundColor,
218    font_color: &InheritableThemeTextColor,
219    commands: &mut Commands,
220) {
221    let outline_bg_token = match (disabled, selected, hovered) {
222        (false, true, _) => tokens::LISTROW_BG_SELECTED,
223        (false, false, true) => tokens::LISTROW_BG_HOVER,
224        _ => tokens::LISTROW_BG,
225    };
226
227    let font_color_token = match disabled {
228        true => tokens::LISTROW_TEXT_DISABLED,
229        false => tokens::LISTROW_TEXT,
230    };
231
232    let cursor_shape = match disabled {
233        true => bevy_window::SystemCursorIcon::NotAllowed,
234        false => bevy_window::SystemCursorIcon::Pointer,
235    };
236
237    // Change outline background
238    if bg_color.0 != outline_bg_token {
239        commands
240            .entity(listrow_ent)
241            .insert(ThemeBackgroundColor(outline_bg_token));
242    }
243
244    // Change font color
245    if font_color.0 != font_color_token {
246        commands
247            .entity(listrow_ent)
248            .insert(InheritableThemeTextColor(font_color_token));
249    }
250
251    // Change cursor shape
252    commands
253        .entity(listrow_ent)
254        .insert(EntityCursor::System(cursor_shape));
255}
256
257fn on_change_focus(
258    focus: Res<InputFocus>,
259    focus_visible: Res<InputFocusVisible>,
260    q_listbox: Query<&ActiveDescendant, With<ListBox>>,
261    q_row_outline: Query<(Entity, &ChildOf), With<ActiveRowOutline>>,
262    mut commands: Commands,
263) {
264    if focus.is_changed() || focus_visible.is_changed() {
265        if let Some(focus_entity) = focus.get()
266            && let Ok(active_descendant) = q_listbox.get(focus_entity)
267        {
268            // Highlight the active descendant of the current focused listbox, clear all others.
269            highlight_active(
270                &q_row_outline,
271                &mut commands,
272                active_descendant.0,
273                focus_visible.0,
274            );
275        } else {
276            // Clear all highlights
277            highlight_active(&q_row_outline, &mut commands, None, focus_visible.0);
278        }
279    }
280}
281
282fn highlight_active(
283    q_row_outline: &Query<'_, '_, (Entity, &ChildOf), With<ActiveRowOutline>>,
284    commands: &mut Commands<'_, '_>,
285    active_row: Option<Entity>,
286    show_highlight: bool,
287) {
288    // Despawn all active outlines that aren't the current active descendant.
289    let mut needs_spawn = show_highlight;
290    for (outline_id, ChildOf(outline_parent)) in q_row_outline.iter() {
291        let is_active = Some(*outline_parent) == active_row;
292        if is_active && show_highlight {
293            // If we already have a highlight for the active element, then do nothing.
294            needs_spawn = false;
295        } else if !is_active || !show_highlight {
296            // If this isn't the active highlight, or we are not showing highlights, then
297            // despawn any highlight entities.
298            commands.entity(outline_id).despawn();
299        }
300    }
301
302    if let Some(active_item) = active_row
303        && needs_spawn
304    {
305        commands.entity(active_item).with_child((
306            Node {
307                position_type: PositionType::Absolute,
308                left: px(0),
309                right: px(0),
310                top: px(0),
311                bottom: px(0),
312                border: UiRect::all(px(2)),
313                border_radius: BorderRadius::all(px(3)),
314                ..Default::default()
315            },
316            ThemeBorderColor(tokens::FOCUS_RING),
317            ActiveRowOutline,
318        ));
319    }
320}
321
322/// Plugin which registers the systems for updating the listrow styles.
323pub struct ListViewPlugin;
324
325impl Plugin for ListViewPlugin {
326    fn build(&self, app: &mut bevy_app::App) {
327        app.add_systems(
328            PreUpdate,
329            (update_listrow_styles, update_listrow_styles_remove).in_set(PickingSystems::Last),
330        );
331        app.add_systems(PostUpdate, on_change_focus);
332    }
333}