1use crate::{
22 border::BorderBuilder,
23 button::{ButtonBuilder, ButtonMessage},
24 core::{
25 pool::Handle, reflect::prelude::*, type_traits::prelude::*, variable::InheritableVariable,
26 visitor::prelude::*,
27 },
28 define_widget_deref,
29 grid::{Column, GridBuilder, Row},
30 message::{MessageDirection, UiMessage},
31 utils::{make_arrow, ArrowDirection},
32 widget::{Widget, WidgetBuilder, WidgetMessage},
33 BuildContext, Control, Thickness, UiNode, UserInterface,
34};
35
36use crate::button::Button;
37use crate::message::MessageData;
38use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
39
40#[derive(Debug, PartialEq, Clone)]
41pub enum SelectorMessage {
42 AddItem(Handle<UiNode>),
43 RemoveItem(Handle<UiNode>),
44 SetItems {
45 items: Vec<Handle<UiNode>>,
46 remove_previous: bool,
47 },
48 Current(Option<usize>),
49}
50impl MessageData for SelectorMessage {}
51
52#[derive(Default, Clone, Visit, Reflect, Debug, ComponentProvider, TypeUuidProvider)]
53#[reflect(derived_type = "UiNode")]
54#[type_uuid(id = "25118853-5c3c-4197-9e4b-2e3b9d92f4d2")]
55pub struct Selector {
56 widget: Widget,
57 items: InheritableVariable<Vec<Handle<UiNode>>>,
58 items_panel: InheritableVariable<Handle<UiNode>>,
59 current: InheritableVariable<Option<usize>>,
60 prev: InheritableVariable<Handle<Button>>,
61 next: InheritableVariable<Handle<Button>>,
62}
63
64impl ConstructorProvider<UiNode, UserInterface> for Selector {
65 fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
66 GraphNodeConstructor::new::<Self>()
67 .with_variant("Selector", |ui| {
68 SelectorBuilder::new(WidgetBuilder::new().with_name("Selector"))
69 .build(&mut ui.build_ctx())
70 .to_base()
71 .into()
72 })
73 .with_group("Input")
74 }
75}
76
77define_widget_deref!(Selector);
78
79impl Control for Selector {
80 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
81 self.widget.handle_routed_message(ui, message);
82
83 if let Some(msg) = message.data::<SelectorMessage>() {
84 match msg {
85 SelectorMessage::AddItem(item) => {
86 ui.send(*item, WidgetMessage::LinkWith(*self.items_panel));
87 self.items.push(*item);
88 }
89 SelectorMessage::RemoveItem(item) => {
90 if let Some(position) = self.items.iter().position(|i| i == item) {
91 ui.send(*item, WidgetMessage::Remove);
92 self.items.remove(position);
93 }
94 }
95 SelectorMessage::SetItems {
96 items,
97 remove_previous,
98 } => {
99 if *remove_previous {
100 for &item in &*self.items {
101 ui.send(item, WidgetMessage::Remove);
102 }
103 }
104
105 for &item in items {
106 ui.send(item, WidgetMessage::LinkWith(*self.items_panel));
107 }
108
109 self.items.set_value_and_mark_modified(items.clone());
110
111 for (i, item) in self.items.iter().enumerate() {
112 ui.send(*item, WidgetMessage::Visibility(*self.current == Some(i)));
113 }
114 }
115 SelectorMessage::Current(current) => {
116 if &*self.current != current
117 && message.direction() == MessageDirection::ToWidget
118 {
119 if let Some(current) = *self.current {
120 if let Some(current_item) = self.items.get(current) {
121 ui.send(*current_item, WidgetMessage::Visibility(false));
122 }
123 }
124
125 self.current.set_value_and_mark_modified(*current);
126
127 if let Some(new_current) = *self.current {
128 if let Some(new_current_item) = self.items.get(new_current) {
129 ui.send(*new_current_item, WidgetMessage::Visibility(true));
130 }
131 }
132
133 ui.send_message(message.reverse());
134 }
135 }
136 }
137 } else if let Some(ButtonMessage::Click) = message.data() {
138 if message.destination() == *self.prev {
139 if let Some(current) = *self.current {
140 let new_current = current.saturating_sub(1);
141 ui.send(self.handle, SelectorMessage::Current(Some(new_current)));
142 }
143 } else if message.destination() == *self.next {
144 if let Some(current) = *self.current {
145 let new_current = current
146 .saturating_add(1)
147 .min(self.items.len().saturating_sub(1));
148 ui.send(self.handle, SelectorMessage::Current(Some(new_current)));
149 }
150 }
151 }
152 }
153}
154
155pub struct SelectorBuilder {
156 widget_builder: WidgetBuilder,
157 items: Vec<Handle<UiNode>>,
158 current: Option<usize>,
159}
160
161impl SelectorBuilder {
162 pub fn new(widget_builder: WidgetBuilder) -> Self {
163 Self {
164 widget_builder,
165 items: Default::default(),
166 current: None,
167 }
168 }
169
170 pub fn build(self, ctx: &mut BuildContext) -> Handle<Selector> {
171 for (i, item) in self.items.iter().enumerate() {
172 ctx[*item].set_visibility(self.current == Some(i));
173 }
174
175 let prev;
176 let next;
177 let items_panel;
178 let grid = GridBuilder::new(
179 WidgetBuilder::new()
180 .with_child({
181 prev = ButtonBuilder::new(WidgetBuilder::new().on_column(0))
182 .with_content(make_arrow(ctx, ArrowDirection::Left, 24.0))
183 .build(ctx);
184 prev
185 })
186 .with_child({
187 items_panel = BorderBuilder::new(
188 WidgetBuilder::new()
189 .with_children(self.items.clone())
190 .on_column(1),
191 )
192 .with_stroke_thickness(Thickness::uniform(0.0).into())
193 .build(ctx);
194 items_panel
195 })
196 .with_child({
197 next = ButtonBuilder::new(WidgetBuilder::new().on_column(2))
198 .with_content(make_arrow(ctx, ArrowDirection::Right, 24.0))
199 .build(ctx);
200 next
201 }),
202 )
203 .add_row(Row::auto())
204 .add_column(Column::auto())
205 .add_column(Column::stretch())
206 .add_column(Column::auto())
207 .build(ctx);
208
209 let selector = Selector {
210 widget: self.widget_builder.with_child(grid).build(ctx),
211 items: self.items.into(),
212 items_panel: items_panel.to_base().into(),
213 prev: prev.into(),
214 next: next.into(),
215 current: self.current.into(),
216 };
217
218 ctx.add(selector)
219 }
220}
221
222#[cfg(test)]
223mod test {
224 use crate::selector::SelectorBuilder;
225 use crate::{test::test_widget_deletion, widget::WidgetBuilder};
226
227 #[test]
228 fn test_deletion() {
229 test_widget_deletion(|ctx| SelectorBuilder::new(WidgetBuilder::new()).build(ctx));
230 }
231}