bevy_ui_builders/dropdown/
builder.rs1use bevy::prelude::*;
4use super::types::*;
5use crate::styles::{colors, dimensions};
6use crate::relationships::BelongsToDropdown;
7
8pub struct DropdownBuilder {
22 options: Vec<String>,
23 selected_index: Option<usize>,
24 placeholder: String,
25 width: Val,
26}
27
28impl DropdownBuilder {
29 pub fn new(options: Vec<String>) -> Self {
31 Self {
32 options,
33 selected_index: None,
34 placeholder: "Select an option".to_string(),
35 width: Val::Px(200.0),
36 }
37 }
38
39 pub fn placeholder(mut self, placeholder: impl Into<String>) -> Self {
41 self.placeholder = placeholder.into();
42 self
43 }
44
45 pub fn selected_index(mut self, index: Option<usize>) -> Self {
47 self.selected_index = index;
48 self
49 }
50
51 pub fn width(mut self, width: Val) -> Self {
53 self.width = width;
54 self
55 }
56
57 pub fn build(self, parent: &mut ChildSpawnerCommands) -> Entity {
59 let data = DropdownData {
60 options: self.options.clone(),
61 selected_index: self.selected_index,
62 placeholder: self.placeholder.clone(),
63 };
64
65 let display_text = data.display_text().to_string();
66
67 let mut dropdown_entity = Entity::PLACEHOLDER;
69
70 let container_id = parent.spawn((
72 Node {
73 width: self.width,
74 flex_direction: FlexDirection::Column,
75 position_type: PositionType::Relative,
76 ..default()
77 },
78 Dropdown,
79 DropdownState::Closed,
80 data,
81 )).with_children(|dropdown| {
82 dropdown_entity = dropdown.target_entity();
83 dropdown.spawn((
85 Node {
86 width: Val::Percent(100.0),
87 height: Val::Px(dimensions::INPUT_HEIGHT),
88 padding: UiRect::all(Val::Px(dimensions::PADDING_SMALL)),
89 border: UiRect::all(Val::Px(dimensions::BORDER_WIDTH_THIN)),
90 justify_content: JustifyContent::SpaceBetween,
91 align_items: AlignItems::Center,
92 flex_direction: FlexDirection::Row,
93 ..default()
94 },
95 BackgroundColor(colors::BACKGROUND_TERTIARY),
96 BorderColor::all(colors::BORDER_DEFAULT),
97 BorderRadius::all(Val::Px(dimensions::BORDER_RADIUS_SMALL)),
98 DropdownButton,
99 Interaction::default(),
100 )).with_children(|button| {
101 button.spawn((
103 Text::new(display_text),
104 TextFont {
105 font_size: dimensions::FONT_SIZE_NORMAL,
106 ..default()
107 },
108 TextColor(colors::TEXT_PRIMARY),
109 ));
110
111 button.spawn((
113 Text::new("v"),
114 TextFont {
115 font_size: dimensions::FONT_SIZE_SMALL,
116 ..default()
117 },
118 TextColor(colors::TEXT_SECONDARY),
119 ));
120 });
121
122 let menu_id = dropdown.spawn((
124 Node {
125 width: Val::Percent(100.0),
126 max_height: Val::Px(200.0),
127 position_type: PositionType::Absolute,
128 top: Val::Px(dimensions::INPUT_HEIGHT + 4.0),
129 left: Val::Px(0.0),
130 flex_direction: FlexDirection::Column,
131 display: Display::None, overflow: Overflow::scroll_y(),
133 border: UiRect::all(Val::Px(2.0)),
134 ..default()
135 },
136 BackgroundColor(Color::srgb(0.08, 0.08, 0.1)), BorderColor::all(colors::BORDER_DEFAULT),
138 BorderRadius::all(Val::Px(dimensions::BORDER_RADIUS_SMALL)),
139 GlobalZIndex(dimensions::Z_INDEX_MODAL), DropdownMenu,
141 BelongsToDropdown(dropdown_entity),
142 )).with_children(|menu| {
143 for (index, option) in self.options.iter().enumerate() {
145 menu.spawn((
146 Node {
147 width: Val::Percent(100.0),
148 padding: UiRect::all(Val::Px(dimensions::PADDING_SMALL)),
149 ..default()
150 },
151 BackgroundColor(if Some(index) == self.selected_index {
152 Color::srgba(0.3, 0.5, 0.8, 0.3)
153 } else {
154 Color::NONE
155 }),
156 DropdownOption { index },
157 Interaction::default(),
158 BelongsToDropdown(dropdown_entity),
159 )).with_children(|option_container| {
160 option_container.spawn((
161 Text::new(option.clone()),
162 TextFont {
163 font_size: dimensions::FONT_SIZE_NORMAL,
164 ..default()
165 },
166 TextColor(colors::TEXT_PRIMARY),
167 ));
168 });
169 }
170 }).id();
171 }).id();
172
173 container_id
174 }
175}