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