use crate::{
command::{Command, CommandGroup},
fyrox::{
core::{algebra::Vector3, pool::Handle},
engine::{Engine, SerializationContext},
fxhash::FxHashMap,
gui::{
menu::MenuItemMessage, message::UiMessage, widget::WidgetMessage, BuildContext,
UserInterface,
},
scene::node::Node,
},
menu::{create_menu_item, create_root_menu_item, ui::UiMenu},
message::MessageSender,
scene::{
commands::graph::{AddNodeCommand, MoveNodeCommand},
controller::SceneController,
GameScene, Selection,
},
ui_scene::UiScene,
Mode,
};
use fyrox::core::log::Log;
use fyrox::core::{uuid, Uuid};
use fyrox::graph::constructor::{VariantConstructor, VariantResult};
use fyrox::gui::constructor::WidgetConstructorContainer;
use fyrox::gui::menu::{MenuItem, SortingPredicate};
use fyrox::scene::graph::Graph;
pub struct CreateEntityRootMenu {
pub menu: Handle<MenuItem>,
pub sub_menus: CreateEntityMenu,
}
impl CreateEntityRootMenu {
pub const CREATE: Uuid = uuid!("edc4d319-2e8e-4173-8b35-73ff4982f380");
pub fn new(
serialization_context: &SerializationContext,
widget_constructors_container: &WidgetConstructorContainer,
ctx: &mut BuildContext,
) -> Self {
let sub_menus =
CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx);
let menu = create_root_menu_item("Create", Self::CREATE, sub_menus.root_items.clone(), ctx);
ctx.inner().send(
menu,
MenuItemMessage::Sort(SortingPredicate::sort_by_text()),
);
Self { menu, sub_menus }
}
pub fn handle_ui_message(
&mut self,
message: &UiMessage,
sender: &MessageSender,
controller: &mut dyn SceneController,
selection: &Selection,
engine: &mut Engine,
) {
if let Some(node) = self
.sub_menus
.handle_ui_message(message, sender, controller, selection, engine)
{
if let Some(game_scene) = controller.downcast_ref::<GameScene>() {
let scene = &engine.scenes[game_scene.scene];
let position = game_scene
.camera_controller
.placement_position(&scene.graph, Default::default());
let node_handle = scene.graph.generate_free_handles(1)[0];
sender.do_command(CommandGroup::from(vec![
Command::new(AddNodeCommand::new(node, Handle::NONE, true)),
Command::new(MoveNodeCommand::new(
node_handle,
Vector3::default(),
position,
)),
]));
}
}
}
pub fn on_scene_changed(&self, controller: &dyn SceneController, ui: &UserInterface) {
self.sub_menus.on_scene_changed(controller, ui);
}
pub fn on_mode_changed(&mut self, ui: &UserInterface, mode: &Mode) {
ui.send(self.menu, WidgetMessage::Enabled(mode.is_edit()));
}
}
pub struct CreateEntityMenu {
ui_menu: UiMenu,
pub root_items: Vec<Handle<MenuItem>>,
constructor_views: FxHashMap<Handle<MenuItem>, VariantConstructor<Node, Graph>>,
}
impl CreateEntityMenu {
pub fn new(
serialization_context: &SerializationContext,
widget_constructor_container: &WidgetConstructorContainer,
ctx: &mut BuildContext,
) -> Self {
let ui_menu = UiMenu::new(widget_constructor_container, "UI", ctx);
let mut root_items = vec![ui_menu.menu];
let mut groups = FxHashMap::default();
let mut constructor_views = FxHashMap::default();
let constructors = serialization_context.node_constructors.map();
for constructor in constructors.values() {
for variant in constructor.variants.iter() {
let item = create_menu_item(&variant.name, Uuid::new_v4(), vec![], ctx);
constructor_views.insert(item, variant.constructor.clone());
if constructor.group.is_empty() {
root_items.push(item);
} else {
let group = *groups.entry(constructor.group).or_insert_with(|| {
let group =
create_menu_item(constructor.group, Uuid::new_v4(), vec![], ctx);
root_items.push(group);
group
});
ctx.inner().send(group, MenuItemMessage::AddItem(item))
}
}
}
for root_item in root_items.iter() {
ctx.inner().send(
*root_item,
MenuItemMessage::Sort(SortingPredicate::sort_by_text()),
)
}
Self {
ui_menu,
constructor_views,
root_items,
}
}
pub fn on_scene_changed(&self, controller: &dyn SceneController, ui: &UserInterface) {
let is_ui_scene = controller.downcast_ref::<UiScene>().is_some();
ui.send(self.ui_menu.menu, WidgetMessage::Enabled(is_ui_scene));
for widget in self.root_items.iter() {
if *widget == self.ui_menu.menu {
continue;
}
ui.send(*widget, WidgetMessage::Enabled(!is_ui_scene));
}
}
pub fn handle_ui_message(
&mut self,
message: &UiMessage,
sender: &MessageSender,
controller: &mut dyn SceneController,
selection: &Selection,
engine: &mut Engine,
) -> Option<Node> {
if let Some(ui_scene) = controller.downcast_mut::<UiScene>() {
self.ui_menu
.handle_ui_message(sender, message, ui_scene, selection);
} else if let Some(game_scene) = controller.downcast_mut::<GameScene>() {
let graph = &mut engine.scenes[game_scene.scene].graph;
if let Some(MenuItemMessage::Click) = message.data::<MenuItemMessage>() {
if let Some(constructor) = self
.constructor_views
.get(&message.destination().to_variant())
{
if let VariantResult::Owned(node) = constructor(graph) {
return Some(node);
} else {
Log::err("Unsupported");
}
}
}
}
None
}
}