fyrox_ui/
dropdown_menu.rs1use crate::popup::Popup;
25use crate::{
26 core::{pool::Handle, reflect::prelude::*, type_traits::prelude::*, visitor::prelude::*},
27 message::{MouseButton, UiMessage},
28 popup::{Placement, PopupBuilder, PopupMessage},
29 widget::{Widget, WidgetBuilder, WidgetMessage},
30 BuildContext, Control, UiNode, UserInterface,
31};
32use fyrox_core::pool::ObjectOrVariant;
33use std::sync::mpsc::Sender;
34
35#[derive(Default, Clone, Visit, Reflect, Debug, TypeUuidProvider, ComponentProvider)]
38#[type_uuid(id = "c0a4c51b-f041-453b-a89d-7ceb5394e321")]
39#[reflect(derived_type = "UiNode")]
40pub struct DropdownMenu {
41 pub widget: Widget,
43 pub popup: Handle<Popup>,
45}
46
47crate::define_widget_deref!(DropdownMenu);
48
49impl Control for DropdownMenu {
50 fn on_remove(&self, sender: &Sender<UiMessage>) {
51 sender
52 .send(UiMessage::for_widget(self.popup, WidgetMessage::Remove))
53 .unwrap()
54 }
55
56 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
57 self.widget.handle_routed_message(ui, message);
58
59 if let Some(WidgetMessage::MouseDown { button, .. }) = message.data() {
60 if *button == MouseButton::Left {
61 ui.send(
62 self.popup,
63 PopupMessage::Placement(Placement::LeftBottom(self.handle)),
64 );
65 ui.send(self.popup, PopupMessage::Open);
66 }
67 }
68 }
69}
70
71pub struct DropdownMenuBuilder {
74 widget_builder: WidgetBuilder,
75 header: Handle<UiNode>,
76 content: Handle<UiNode>,
77}
78
79impl DropdownMenuBuilder {
80 pub fn new(widget_builder: WidgetBuilder) -> Self {
82 Self {
83 widget_builder,
84 header: Handle::NONE,
85 content: Handle::NONE,
86 }
87 }
88
89 pub fn with_header(mut self, header: Handle<UiNode>) -> Self {
91 self.header = header;
92 self
93 }
94
95 pub fn with_content(mut self, content: Handle<impl ObjectOrVariant<UiNode>>) -> Self {
97 self.content = content.to_base();
98 self
99 }
100
101 pub fn build(self, ctx: &mut BuildContext) -> Handle<DropdownMenu> {
104 let popup = PopupBuilder::new(WidgetBuilder::new())
105 .stays_open(false)
106 .with_content(self.content)
107 .build(ctx);
108
109 let dropdown_menu = DropdownMenu {
110 widget: self.widget_builder.with_child(self.header).build(ctx),
111 popup,
112 };
113 ctx.add(dropdown_menu)
114 }
115}
116
117#[cfg(test)]
118mod test {
119 use crate::dropdown_menu::DropdownMenuBuilder;
120 use crate::{test::test_widget_deletion, widget::WidgetBuilder};
121
122 #[test]
123 fn test_deletion() {
124 test_widget_deletion(|ctx| DropdownMenuBuilder::new(WidgetBuilder::new()).build(ctx));
125 }
126}