1use crate::{
22 command::{Command, CommandGroup},
23 fyrox::{
24 core::{algebra::Vector3, pool::Handle},
25 engine::{Engine, SerializationContext},
26 fxhash::FxHashMap,
27 gui::{
28 menu::MenuItemMessage, message::MessageDirection, message::UiMessage,
29 widget::WidgetMessage, BuildContext, UiNode, UserInterface,
30 },
31 scene::node::Node,
32 },
33 menu::{create_menu_item, create_root_menu_item, ui::UiMenu},
34 message::MessageSender,
35 scene::{
36 commands::graph::{AddNodeCommand, MoveNodeCommand},
37 controller::SceneController,
38 GameScene, Selection,
39 },
40 ui_scene::UiScene,
41 Mode,
42};
43use fyrox::core::log::Log;
44use fyrox::graph::constructor::{VariantConstructor, VariantResult};
45use fyrox::gui::constructor::WidgetConstructorContainer;
46use fyrox::gui::menu::SortingPredicate;
47use fyrox::scene::graph::Graph;
48
49pub struct CreateEntityRootMenu {
50 pub menu: Handle<UiNode>,
51 pub sub_menus: CreateEntityMenu,
52}
53
54impl CreateEntityRootMenu {
55 pub fn new(
56 serialization_context: &SerializationContext,
57 widget_constructors_container: &WidgetConstructorContainer,
58 ctx: &mut BuildContext,
59 ) -> Self {
60 let sub_menus =
61 CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx);
62
63 let menu = create_root_menu_item("Create", sub_menus.root_items.clone(), ctx);
64
65 ctx.inner().send_message(MenuItemMessage::sort(
66 menu,
67 MessageDirection::ToWidget,
68 SortingPredicate::sort_by_text(),
69 ));
70
71 Self { menu, sub_menus }
72 }
73
74 pub fn handle_ui_message(
75 &mut self,
76 message: &UiMessage,
77 sender: &MessageSender,
78 controller: &mut dyn SceneController,
79 selection: &Selection,
80 engine: &mut Engine,
81 ) {
82 if let Some(node) = self
83 .sub_menus
84 .handle_ui_message(message, sender, controller, selection, engine)
85 {
86 if let Some(game_scene) = controller.downcast_ref::<GameScene>() {
87 let scene = &engine.scenes[game_scene.scene];
88
89 let position = game_scene
90 .camera_controller
91 .placement_position(&scene.graph, Default::default());
92
93 let node_handle = scene.graph.generate_free_handles(1)[0];
94 sender.do_command(CommandGroup::from(vec![
95 Command::new(AddNodeCommand::new(node, Handle::NONE, true)),
96 Command::new(MoveNodeCommand::new(
97 node_handle,
98 Vector3::default(),
99 position,
100 )),
101 ]));
102 }
103 }
104 }
105
106 pub fn on_scene_changed(&self, controller: &dyn SceneController, ui: &UserInterface) {
107 self.sub_menus.on_scene_changed(controller, ui);
108 }
109
110 pub fn on_mode_changed(&mut self, ui: &UserInterface, mode: &Mode) {
111 ui.send_message(WidgetMessage::enabled(
112 self.menu,
113 MessageDirection::ToWidget,
114 mode.is_edit(),
115 ));
116 }
117}
118
119pub struct CreateEntityMenu {
120 ui_menu: UiMenu,
121 pub root_items: Vec<Handle<UiNode>>,
122 constructor_views: FxHashMap<Handle<UiNode>, VariantConstructor<Node, Graph>>,
123}
124
125impl CreateEntityMenu {
126 pub fn new(
127 serialization_context: &SerializationContext,
128 widget_constructor_container: &WidgetConstructorContainer,
129 ctx: &mut BuildContext,
130 ) -> Self {
131 let ui_menu = UiMenu::new(widget_constructor_container, "UI", ctx);
132
133 let mut root_items = vec![ui_menu.menu];
134 let mut groups = FxHashMap::default();
135 let mut constructor_views = FxHashMap::default();
136 let constructors = serialization_context.node_constructors.map();
137 for constructor in constructors.values() {
138 for variant in constructor.variants.iter() {
139 let item = create_menu_item(&variant.name, vec![], ctx);
140 constructor_views.insert(item, variant.constructor.clone());
141 if constructor.group.is_empty() {
142 root_items.push(item);
143 } else {
144 let group = *groups.entry(constructor.group).or_insert_with(|| {
145 let group = create_menu_item(constructor.group, vec![], ctx);
146 root_items.push(group);
147 group
148 });
149 ctx.send_message(MenuItemMessage::add_item(
150 group,
151 MessageDirection::ToWidget,
152 item,
153 ))
154 }
155 }
156 }
157
158 for root_item in root_items.iter() {
159 ctx.inner().send_message(MenuItemMessage::sort(
160 *root_item,
161 MessageDirection::ToWidget,
162 SortingPredicate::sort_by_text(),
163 ))
164 }
165
166 Self {
167 ui_menu,
168 constructor_views,
169 root_items,
170 }
171 }
172
173 pub fn on_scene_changed(&self, controller: &dyn SceneController, ui: &UserInterface) {
174 let is_ui_scene = controller.downcast_ref::<UiScene>().is_some();
175
176 ui.send_message(WidgetMessage::enabled(
177 self.ui_menu.menu,
178 MessageDirection::ToWidget,
179 is_ui_scene,
180 ));
181
182 for widget in self.root_items.iter() {
183 if *widget == self.ui_menu.menu {
184 continue;
185 }
186
187 ui.send_message(WidgetMessage::enabled(
188 *widget,
189 MessageDirection::ToWidget,
190 !is_ui_scene,
191 ));
192 }
193 }
194
195 pub fn handle_ui_message(
196 &mut self,
197 message: &UiMessage,
198 sender: &MessageSender,
199 controller: &mut dyn SceneController,
200 selection: &Selection,
201 engine: &mut Engine,
202 ) -> Option<Node> {
203 if let Some(ui_scene) = controller.downcast_mut::<UiScene>() {
204 self.ui_menu
205 .handle_ui_message(sender, message, ui_scene, selection);
206 } else if let Some(game_scene) = controller.downcast_mut::<GameScene>() {
207 let graph = &mut engine.scenes[game_scene.scene].graph;
208 if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
209 if let Some(constructor) = self.constructor_views.get(&message.destination()) {
210 if let VariantResult::Owned(node) = constructor(graph) {
211 return Some(node);
212 } else {
213 Log::err("Unsupported");
214 }
215 }
216 }
217 }
218
219 None
220 }
221}