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