use std::collections::HashSet;
use nalgebra_glm::{Vec2, Vec4};
use crate::ecs::text::components::{TextAlignment, VerticalAlignment};
use crate::ecs::ui::builder::UiTreeBuilder;
use crate::ecs::ui::components::*;
use crate::ecs::ui::layout_types::FlowDirection;
use crate::ecs::ui::state::{UiBase, UiHover};
use crate::ecs::ui::types::Anchor;
use crate::ecs::ui::units::{Ab, Rl};
use crate::render::wgpu::passes::geometry::UiLayer;
use super::date_utils::{format_month_year, populate_calendar_grid};
impl<'a> UiTreeBuilder<'a> {
pub fn add_dropdown(&mut self, options: &[&str], initial: usize) -> freecs::Entity {
let theme = self
.world_mut()
.resources
.retained_ui
.theme_state
.active_theme();
let font_size = theme.font_size;
let corner_radius = theme.corner_radius;
let border_color = theme.border_color;
let button_height = theme.button_height;
let accent_color = theme.accent_color;
let bg_color = theme.input_background_color;
let selected_text = options.get(initial).copied().unwrap_or("");
let header_text_slot = self
.world_mut()
.resources
.text_cache
.add_text(selected_text);
let arrow_slot = self.world_mut().resources.text_cache.add_text("\u{25BC}");
let mut popup_entities = Vec::new();
let option_strings: Vec<String> = options.iter().map(|s| s.to_string()).collect();
let popup_height = options.len() as f32 * button_height;
let wrapper_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.without_pointer_events()
.entity();
self.push_parent(wrapper_entity);
let header_entity = self
.add_node()
.boundary(Ab(Vec2::new(0.0, 0.0)), Rl(Vec2::new(100.0, 100.0)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.flow(FlowDirection::Horizontal, 8.0, 0.0)
.with_children(|tree| {
tree.add_node()
.flow_child(Rl(Vec2::new(0.0, 100.0)))
.flex_grow(1.0)
.with_text_slot(header_text_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
tree.add_node()
.flow_child(Ab(Vec2::new(20.0, 0.0)) + Rl(Vec2::new(0.0, 100.0)))
.with_text_slot(arrow_slot, font_size * 0.8)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
let popup_container_entity = self
.add_node()
.window(
Rl(Vec2::new(0.0, 100.0)),
Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, popup_height)),
Anchor::TopLeft,
)
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_layer(UiLayer::Popups)
.with_depth(UiDepthMode::Set(30.0))
.with_visible(false)
.flow(FlowDirection::Vertical, 0.0, 0.0)
.entity();
self.push_parent(popup_container_entity);
for (index, option) in options.iter().enumerate() {
let option_slot = self.world_mut().resources.text_cache.add_text(*option);
let is_selected = index == initial;
let option_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.with_rect(corner_radius, 0.0, Vec4::new(0.0, 0.0, 0.0, 0.0))
.with_color::<UiBase>(if is_selected { accent_color } else { bg_color })
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.with_text_slot(option_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
popup_entities.push(option_entity);
}
self.pop_parent();
self.pop_parent();
self.world_mut().ui.set_ui_widget_state(
header_entity,
UiWidgetState::Dropdown(UiDropdownData {
options: option_strings,
selected_index: initial,
changed: false,
open: false,
header_text_slot,
popup_entities,
popup_container_entity,
hovered_index: None,
is_theme_dropdown: false,
searchable: false,
filter_text: String::new(),
filter_input_entity: None,
filtered_indices: Vec::new(),
}),
);
if let Some(interaction) = self
.world_mut()
.ui
.get_ui_node_interaction_mut(header_entity)
{
interaction.accessible_role = Some(AccessibleRole::Dropdown);
}
self.assign_tab_index(header_entity);
header_entity
}
pub fn add_dropdown_searchable(&mut self, options: &[&str], initial: usize) -> freecs::Entity {
let entity = self.add_dropdown(options, initial);
let theme = self
.world_mut()
.resources
.retained_ui
.theme_state
.active_theme();
let font_size = theme.font_size;
let button_height = theme.button_height;
let corner_radius = theme.corner_radius;
let border_color = theme.border_color;
let popup_container = {
let widget = self.world_mut().ui.get_ui_widget_state(entity).cloned();
if let Some(UiWidgetState::Dropdown(data)) = widget {
data.popup_container_entity
} else {
return entity;
}
};
let filter_text_slot = self.world_mut().resources.text_cache.add_text("");
let placeholder_slot = self.world_mut().resources.text_cache.add_text("Search...");
self.push_parent(popup_container);
let filter_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_interaction()
.with_cursor_icon(winit::window::CursorIcon::Text)
.with_children(|tree| {
tree.add_node()
.boundary(
Ab(Vec2::new(8.0, 0.0)),
Ab(Vec2::new(0.0, button_height)) + Rl(Vec2::new(100.0, 0.0)),
)
.with_text_slot(filter_text_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
tree.add_node()
.boundary(
Ab(Vec2::new(8.0, 0.0)),
Ab(Vec2::new(0.0, button_height)) + Rl(Vec2::new(100.0, 0.0)),
)
.with_text_slot(placeholder_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::TextDisabled)
.without_pointer_events()
.done();
})
.done();
self.pop_parent();
self.world_mut().resources.children_cache_valid = false;
if let Some(children) = self
.world_mut()
.resources
.children_cache
.get_mut(&popup_container)
&& let Some(pos) = children.iter().position(|e| *e == filter_entity)
{
children.remove(pos);
children.insert(0, filter_entity);
}
let all_indices: Vec<usize> = (0..options.len()).collect();
if let Some(UiWidgetState::Dropdown(data)) =
self.world_mut().ui.get_ui_widget_state_mut(entity)
{
data.searchable = true;
data.filter_input_entity = Some(filter_entity);
data.filtered_indices = all_indices;
}
self.world_mut().ui.set_ui_widget_state(
filter_entity,
UiWidgetState::TextInput(UiTextInputData {
text: String::new(),
cursor_position: 0,
selection_start: None,
changed: false,
text_slot: filter_text_slot,
cursor_entity: freecs::Entity::default(),
selection_entity: freecs::Entity::default(),
scroll_offset: 0.0,
cursor_blink_timer: 0.0,
placeholder_entity: None,
undo_stack: UndoStack::new(50),
input_mask: crate::ecs::ui::components::InputMask::None,
max_length: None,
}),
);
entity
}
pub fn add_multi_select(&mut self, options: &[&str]) -> freecs::Entity {
let theme = self
.world_mut()
.resources
.retained_ui
.theme_state
.active_theme();
let font_size = theme.font_size;
let corner_radius = theme.corner_radius;
let border_color = theme.border_color;
let button_height = theme.button_height;
let bg_color = theme.input_background_color;
let header_text_slot = self.world_mut().resources.text_cache.add_text("0 selected");
let arrow_slot = self.world_mut().resources.text_cache.add_text("\u{25BC}");
let mut popup_entities = Vec::new();
let mut check_entities = Vec::new();
let option_strings: Vec<String> = options.iter().map(|s| s.to_string()).collect();
let popup_height = options.len() as f32 * button_height;
let wrapper_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.without_pointer_events()
.entity();
self.push_parent(wrapper_entity);
let header_entity = self
.add_node()
.boundary(Ab(Vec2::new(0.0, 0.0)), Rl(Vec2::new(100.0, 100.0)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.flow(FlowDirection::Horizontal, 8.0, 0.0)
.with_children(|tree| {
tree.add_node()
.flow_child(Rl(Vec2::new(0.0, 100.0)))
.flex_grow(1.0)
.with_text_slot(header_text_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
tree.add_node()
.flow_child(Ab(Vec2::new(20.0, 0.0)) + Rl(Vec2::new(0.0, 100.0)))
.with_text_slot(arrow_slot, font_size * 0.8)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
let popup_container_entity = self
.add_node()
.window(
Rl(Vec2::new(0.0, 100.0)),
Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, popup_height)),
Anchor::TopLeft,
)
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_layer(UiLayer::Popups)
.with_depth(UiDepthMode::Set(30.0))
.with_visible(false)
.flow(FlowDirection::Vertical, 0.0, 0.0)
.entity();
self.push_parent(popup_container_entity);
for option in options.iter() {
let option_slot = self.world_mut().resources.text_cache.add_text(*option);
let check_slot = self.world_mut().resources.text_cache.add_text(" ");
let mut check_entity = freecs::Entity::default();
let option_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.with_rect(corner_radius, 0.0, Vec4::new(0.0, 0.0, 0.0, 0.0))
.with_color::<UiBase>(bg_color)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.flow(FlowDirection::Horizontal, 4.0, 0.0)
.with_children(|tree| {
check_entity = tree
.add_node()
.flow_child(Ab(Vec2::new(20.0, 0.0)) + Rl(Vec2::new(0.0, 100.0)))
.with_text_slot(check_slot, font_size)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
tree.add_node()
.flow_child(Rl(Vec2::new(0.0, 100.0)))
.flex_grow(1.0)
.with_text_slot(option_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
popup_entities.push(option_entity);
check_entities.push(check_entity);
}
self.pop_parent();
self.pop_parent();
self.world_mut().ui.set_ui_widget_state(
header_entity,
UiWidgetState::MultiSelect(UiMultiSelectData {
options: option_strings,
selected_indices: HashSet::new(),
changed: false,
open: false,
header_text_slot,
popup_entities,
popup_container_entity,
hovered_index: None,
check_entities,
}),
);
self.assign_tab_index(header_entity);
header_entity
}
pub fn add_date_picker(&mut self, year: i32, month: u32, day: u32) -> freecs::Entity {
let theme = self
.world_mut()
.resources
.retained_ui
.theme_state
.active_theme();
let font_size = theme.font_size;
let corner_radius = theme.corner_radius;
let border_color = theme.border_color;
let button_height = theme.button_height;
let accent_color = theme.accent_color;
let header_text = format!("{year:04}-{month:02}-{day:02}");
let header_text_slot = self.world_mut().resources.text_cache.add_text(&header_text);
let arrow_slot = self.world_mut().resources.text_cache.add_text("\u{1F4C5}");
let month_label = format_month_year(year, month);
let month_label_slot = self.world_mut().resources.text_cache.add_text(&month_label);
let cell_size = 30.0;
let grid_width = cell_size * 7.0;
let nav_height = button_height;
let grid_height = cell_size * 6.0;
let popup_height = nav_height + grid_height;
let wrapper_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.without_pointer_events()
.entity();
self.push_parent(wrapper_entity);
let header_entity = self
.add_node()
.boundary(Ab(Vec2::new(0.0, 0.0)), Rl(Vec2::new(100.0, 100.0)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.flow(FlowDirection::Horizontal, 8.0, 0.0)
.with_children(|tree| {
tree.add_node()
.flow_child(Rl(Vec2::new(0.0, 100.0)))
.flex_grow(1.0)
.with_text_slot(header_text_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
tree.add_node()
.flow_child(Ab(Vec2::new(24.0, 0.0)) + Rl(Vec2::new(0.0, 100.0)))
.with_text_slot(arrow_slot, font_size * 0.8)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
let popup_entity = self
.add_node()
.window(
Rl(Vec2::new(0.0, 100.0)),
Ab(Vec2::new(grid_width + 8.0, popup_height + 8.0)),
Anchor::TopLeft,
)
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_layer(UiLayer::Popups)
.with_depth(UiDepthMode::Set(30.0))
.with_visible(false)
.flow(FlowDirection::Vertical, 4.0, 4.0)
.entity();
self.push_parent(popup_entity);
let nav_row = self
.add_node()
.flow_child(Ab(Vec2::new(grid_width, nav_height)))
.flow(FlowDirection::Horizontal, 0.0, 0.0)
.without_pointer_events()
.entity();
self.push_parent(nav_row);
let prev_slot = self.world_mut().resources.text_cache.add_text("\u{25C0}");
let prev_month_entity = self
.add_node()
.flow_child(Ab(Vec2::new(cell_size, nav_height)))
.with_rect(corner_radius, 0.0, Vec4::zeros())
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.boundary(Ab(Vec2::zeros()), Rl(Vec2::new(100.0, 100.0)))
.with_text_slot(prev_slot, font_size)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
self.add_node()
.flow_child(Rl(Vec2::new(0.0, 100.0)))
.flex_grow(1.0)
.with_text_slot(month_label_slot, font_size)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
let next_slot = self.world_mut().resources.text_cache.add_text("\u{25B6}");
let next_month_entity = self
.add_node()
.flow_child(Ab(Vec2::new(cell_size, nav_height)))
.with_rect(corner_radius, 0.0, Vec4::zeros())
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.boundary(Ab(Vec2::zeros()), Rl(Vec2::new(100.0, 100.0)))
.with_text_slot(next_slot, font_size)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
self.pop_parent();
let mut day_entities = Vec::with_capacity(42);
let mut day_text_slots = Vec::with_capacity(42);
let grid_entity = self
.add_node()
.flow_child(Ab(Vec2::new(grid_width, grid_height)))
.flow(FlowDirection::Horizontal, 0.0, 0.0)
.flow_wrap()
.without_pointer_events()
.entity();
self.push_parent(grid_entity);
for _ in 0..42 {
let slot = self.world_mut().resources.text_cache.add_text("");
day_text_slots.push(slot);
let cell = self
.add_node()
.flow_child(Ab(Vec2::new(cell_size, cell_size)))
.with_rect(corner_radius, 0.0, Vec4::zeros())
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.boundary(Ab(Vec2::zeros()), Rl(Vec2::new(100.0, 100.0)))
.with_text_slot(slot, font_size * 0.85)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
day_entities.push(cell);
}
self.pop_parent();
self.pop_parent();
self.pop_parent();
populate_calendar_grid(
self.world_mut(),
year,
month,
day,
&day_text_slots,
&day_entities,
accent_color,
);
self.world_mut().ui.set_ui_widget_state(
header_entity,
UiWidgetState::DatePicker(UiDatePickerData {
year,
month,
day,
changed: false,
open: false,
header_text_slot,
popup_entity,
day_entities,
day_text_slots,
month_label_slot,
prev_month_entity,
next_month_entity,
selected_day_entity: None,
}),
);
self.assign_tab_index(header_entity);
header_entity
}
pub fn add_menu(&mut self, label: &str, items: &[&str]) -> freecs::Entity {
let theme = self
.world_mut()
.resources
.retained_ui
.theme_state
.active_theme();
let font_size = theme.font_size;
let corner_radius = theme.corner_radius;
let button_height = theme.button_height;
let border_color = theme.border_color;
let label_slot = self.world_mut().resources.text_cache.add_text(label);
let mut popup_entities = Vec::new();
let mut popup_container_entity = freecs::Entity::default();
let item_strings: Vec<String> = items.iter().map(|s| s.to_string()).collect();
let popup_height = items.len() as f32 * button_height;
let menu_button = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::Background)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.with_text_slot(label_slot, font_size)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
popup_container_entity = tree
.add_node()
.window(
Rl(Vec2::new(0.0, 100.0)),
Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, popup_height)),
Anchor::TopLeft,
)
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::Background)
.with_layer(UiLayer::Popups)
.with_depth(UiDepthMode::Set(30.0))
.with_visible(false)
.flow(FlowDirection::Vertical, 0.0, 0.0)
.entity();
tree.push_parent(popup_container_entity);
for item in items {
let item_slot = tree.world_mut().resources.text_cache.add_text(*item);
let item_entity = tree
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, button_height)))
.with_rect(corner_radius, 0.0, Vec4::new(0.0, 0.0, 0.0, 0.0))
.with_theme_color::<UiBase>(ThemeColor::Background)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.with_text_slot(item_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done();
popup_entities.push(item_entity);
}
tree.pop_parent();
})
.done();
self.world_mut().ui.set_ui_widget_state(
menu_button,
UiWidgetState::Menu(UiMenuData {
items: item_strings,
clicked_item: None,
open: false,
label_text_slot: label_slot,
popup_entities,
popup_container_entity,
}),
);
menu_button
}
pub fn add_theme_dropdown(&mut self) -> freecs::Entity {
let preset_names: Vec<String> = self
.world_mut()
.resources
.retained_ui
.theme_state
.presets
.iter()
.map(|theme| theme.name.clone())
.collect();
let selected = self
.world_mut()
.resources
.retained_ui
.theme_state
.selected_preset_index;
let labels: Vec<&str> = preset_names.iter().map(|s| s.as_str()).collect();
let entity = self.add_dropdown(&labels, selected.unwrap_or(0));
if let Some(UiWidgetState::Dropdown(data)) =
self.world_mut().ui.get_ui_widget_state_mut(entity)
{
data.is_theme_dropdown = true;
}
entity
}
}