diff --git a/editor/src/lib.rs b/editor/src/lib.rs index 5a44806b9..4dcf22576 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -170,6 +170,7 @@ use crate::{ utils::doc::DocWindow, world::{graph::menu::SceneNodeContextMenu, graph::EditorSceneWrapper, WorldViewer}, }; +use fyrox::gui::constructor::new_widget_constructor_container; pub use message::Message; use std::{ cell::RefCell, @@ -610,7 +611,7 @@ impl Editor { resource_manager: ResourceManager::new(task_pool.clone()), serialization_context, task_pool, - widget_constructors: Arc::new(Default::default()), + widget_constructors: Arc::new(new_widget_constructor_container()), }) .unwrap(); @@ -639,9 +640,13 @@ impl Editor { let navmesh_panel = NavmeshPanel::new(scene_viewer.frame(), ctx, message_sender.clone()); let scene_node_context_menu = Rc::new(RefCell::new(SceneNodeContextMenu::new( &engine.serialization_context, + &engine.widget_constructors, + ctx, + ))); + let widget_context_menu = Rc::new(RefCell::new(WidgetContextMenu::new( + &engine.widget_constructors, ctx, ))); - let widget_context_menu = Rc::new(RefCell::new(WidgetContextMenu::new(ctx))); let world_outliner = WorldViewer::new(ctx, message_sender.clone(), &settings); let command_stack_viewer = CommandStackViewer::new(ctx, message_sender.clone()); let log = LogPanel::new(ctx, log_message_receiver); diff --git a/editor/src/menu/create.rs b/editor/src/menu/create.rs index 1a8e96e62..16ec4f24a 100644 --- a/editor/src/menu/create.rs +++ b/editor/src/menu/create.rs @@ -28,7 +28,7 @@ use crate::{ menu::MenuItemMessage, message::MessageDirection, message::UiMessage, widget::WidgetMessage, BuildContext, UiNode, UserInterface, }, - scene::{node::constructor::Constructor, node::Node}, + scene::node::Node, }, menu::{create_menu_item, create_root_menu_item, ui::UiMenu}, message::MessageSender, @@ -40,6 +40,10 @@ use crate::{ ui_scene::UiScene, Mode, }; +use fyrox::core::log::Log; +use fyrox::graph::constructor::{VariantConstructor, VariantResult}; +use fyrox::gui::constructor::WidgetConstructorContainer; +use fyrox::scene::graph::Graph; pub struct CreateEntityRootMenu { pub menu: Handle, @@ -47,8 +51,13 @@ pub struct CreateEntityRootMenu { } impl CreateEntityRootMenu { - pub fn new(serialization_context: &SerializationContext, ctx: &mut BuildContext) -> Self { - let sub_menus = CreateEntityMenu::new(serialization_context, ctx); + 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", sub_menus.root_items.clone(), ctx); @@ -61,11 +70,11 @@ impl CreateEntityRootMenu { sender: &MessageSender, controller: &mut dyn SceneController, selection: &Selection, - engine: &Engine, + engine: &mut Engine, ) { if let Some(node) = self .sub_menus - .handle_ui_message(message, sender, controller, selection) + .handle_ui_message(message, sender, controller, selection, engine) { if let Some(game_scene) = controller.downcast_ref::() { let scene = &engine.scenes[game_scene.scene]; @@ -103,12 +112,16 @@ impl CreateEntityRootMenu { pub struct CreateEntityMenu { ui_menu: UiMenu, pub root_items: Vec>, - constructor_views: FxHashMap, Constructor>, + constructor_views: FxHashMap, VariantConstructor>, } impl CreateEntityMenu { - pub fn new(serialization_context: &SerializationContext, ctx: &mut BuildContext) -> Self { - let ui_menu = UiMenu::new(UiMenu::default_entries(), "UI", ctx); + 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(); @@ -116,7 +129,7 @@ impl CreateEntityMenu { 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, vec![], ctx); + let item = create_menu_item(&variant.name, vec![], ctx); constructor_views.insert(item, variant.constructor.clone()); if constructor.group.is_empty() { root_items.push(item); @@ -154,6 +167,10 @@ impl CreateEntityMenu { )); for widget in self.root_items.iter() { + if *widget == self.ui_menu.menu { + continue; + } + ui.send_message(WidgetMessage::enabled( *widget, MessageDirection::ToWidget, @@ -168,15 +185,21 @@ impl CreateEntityMenu { sender: &MessageSender, controller: &mut dyn SceneController, selection: &Selection, + engine: &mut Engine, ) -> Option { if let Some(ui_scene) = controller.downcast_mut::() { self.ui_menu .handle_ui_message(sender, message, ui_scene, selection); - } - - if let Some(MenuItemMessage::Click) = message.data::() { - if let Some(constructor) = self.constructor_views.get(&message.destination()) { - return Some(constructor()); + } else if let Some(game_scene) = controller.downcast_mut::() { + let graph = &mut engine.scenes[game_scene.scene].graph; + if let Some(MenuItemMessage::Click) = message.data::() { + if let Some(constructor) = self.constructor_views.get(&message.destination()) { + if let VariantResult::Owned(node) = constructor(graph) { + return Some(node); + } else { + Log::err("Unsupported"); + } + } } } diff --git a/editor/src/menu/mod.rs b/editor/src/menu/mod.rs index c0dfb5988..ca6e43f8b 100644 --- a/editor/src/menu/mod.rs +++ b/editor/src/menu/mod.rs @@ -122,7 +122,11 @@ impl Menu { pub fn new(engine: &mut Engine, message_sender: MessageSender, settings: &Settings) -> Self { let file_menu = FileMenu::new(engine, settings); let ctx = &mut engine.user_interfaces.first_mut().build_ctx(); - let create_entity_menu = CreateEntityRootMenu::new(&engine.serialization_context, ctx); + let create_entity_menu = CreateEntityRootMenu::new( + &engine.serialization_context, + &engine.widget_constructors, + ctx, + ); let edit_menu = EditMenu::new(ctx); let view_menu = ViewMenu::new(ctx); let utils_menu = UtilsMenu::new(ctx); diff --git a/editor/src/menu/ui.rs b/editor/src/menu/ui.rs index 71c3490d1..bab7cbf2a 100644 --- a/editor/src/menu/ui.rs +++ b/editor/src/menu/ui.rs @@ -1,3 +1,4 @@ +use fyrox::core::log::Log; // Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors. // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -17,49 +18,10 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - -use crate::fyrox::gui::selector::SelectorBuilder; use crate::fyrox::{ core::pool::Handle, fxhash::FxHashMap, - gui::{ - absm::{AbsmEventProviderBuilder, AnimationBlendingStateMachineBuilder}, - animation::AnimationPlayerBuilder, - border::BorderBuilder, - button::ButtonBuilder, - canvas::CanvasBuilder, - check_box::CheckBoxBuilder, - decorator::DecoratorBuilder, - dropdown_list::DropdownListBuilder, - expander::ExpanderBuilder, - grid::GridBuilder, - image::ImageBuilder, - list_view::ListViewBuilder, - menu::MenuItemMessage, - menu::{MenuBuilder, MenuItemBuilder}, - message::UiMessage, - messagebox::MessageBoxBuilder, - nine_patch::NinePatchBuilder, - numeric::NumericUpDownBuilder, - path::PathEditorBuilder, - popup::PopupBuilder, - progress_bar::ProgressBarBuilder, - screen::ScreenBuilder, - scroll_bar::ScrollBarBuilder, - scroll_viewer::ScrollViewerBuilder, - searchbar::SearchBarBuilder, - stack_panel::StackPanelBuilder, - tab_control::TabControlBuilder, - text::TextBuilder, - text_box::TextBoxBuilder, - tree::{TreeBuilder, TreeRootBuilder}, - uuid::UuidEditorBuilder, - vector_image::VectorImageBuilder, - widget::WidgetBuilder, - window::WindowBuilder, - wrap_panel::WrapPanelBuilder, - BuildContext, UiNode, - }, + gui::{menu::MenuItemMessage, message::UiMessage, BuildContext, UiNode}, }; use crate::{ menu::create_menu_item, @@ -67,182 +29,55 @@ use crate::{ scene::Selection, ui_scene::{commands::graph::AddWidgetCommand, UiScene}, }; +use fyrox::graph::constructor::{VariantConstructor, VariantResult}; +use fyrox::gui::constructor::WidgetConstructorContainer; +use fyrox::gui::message::MessageDirection; +use fyrox::gui::UserInterface; pub struct UiMenu { pub menu: Handle, - constructors: FxHashMap, UiMenuEntry>, -} - -#[allow(clippy::type_complexity)] -pub struct UiMenuEntry { - pub name: String, - pub constructor: Box Handle>, -} - -impl UiMenuEntry { - pub fn new(name: P, constructor: F) -> Self - where - P: AsRef, - F: FnMut(&str, &mut BuildContext) -> Handle + 'static, - { - Self { - name: name.as_ref().to_owned(), - constructor: Box::new(constructor), - } - } + constructor_views: FxHashMap, VariantConstructor>, } impl UiMenu { - pub fn default_entries() -> Vec { - vec![ - UiMenuEntry::new("Screen", |name, ctx| { - ScreenBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Button", |name, ctx| { - ButtonBuilder::new( - WidgetBuilder::new() - .with_width(100.0) - .with_height(20.0) - .with_name(name), - ) - .build(ctx) - }), - UiMenuEntry::new("Border", |name, ctx| { - BorderBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Image", |name, ctx| { - ImageBuilder::new( - WidgetBuilder::new() - .with_height(32.0) - .with_width(32.0) - .with_name(name), - ) - .build(ctx) - }), - UiMenuEntry::new("Canvas", |name, ctx| { - CanvasBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Grid", |name, ctx| { - GridBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("CheckBox", |name, ctx| { - CheckBoxBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Decorator", |name, ctx| { - DecoratorBuilder::new(BorderBuilder::new(WidgetBuilder::new().with_name(name))) - .build(ctx) - }), - UiMenuEntry::new("DropdownList", |name, ctx| { - DropdownListBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Expander", |name, ctx| { - ExpanderBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("ListView", |name, ctx| { - ListViewBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Menu", |name, ctx| { - MenuBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("MenuItem", |name, ctx| { - MenuItemBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("MessageBox", |name, ctx| { - MessageBoxBuilder::new(WindowBuilder::new(WidgetBuilder::new().with_name(name))) - .build(ctx) - }), - UiMenuEntry::new("NinePatch", |name, ctx| { - NinePatchBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("NumericUpDownF32", |name, ctx| { - NumericUpDownBuilder::::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("NumericUpDownI32", |name, ctx| { - NumericUpDownBuilder::::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("PathEditor", |name, ctx| { - PathEditorBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Popup", |name, ctx| { - PopupBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("ProgressBar", |name, ctx| { - ProgressBarBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("ScrollBar", |name, ctx| { - ScrollBarBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("ScrollViewer", |name, ctx| { - ScrollViewerBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("SearchBar", |name, ctx| { - SearchBarBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("StackPanel", |name, ctx| { - StackPanelBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("TabControl", |name, ctx| { - TabControlBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Text", |name, ctx| { - TextBuilder::new(WidgetBuilder::new().with_name(name)) - .with_text("Text") - .build(ctx) - }), - UiMenuEntry::new("TextBox", |name, ctx| { - TextBoxBuilder::new(WidgetBuilder::new().with_name(name)) - .with_text("Text") - .build(ctx) - }), - UiMenuEntry::new("Tree", |name, ctx| { - TreeBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("TreeRoot", |name, ctx| { - TreeRootBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("UuidEditor", |name, ctx| { - UuidEditorBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("VectorImage", |name, ctx| { - VectorImageBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Window", |name, ctx| { - WindowBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("WrapPanel", |name, ctx| { - WrapPanelBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("AnimationPlayer", |name, ctx| { - AnimationPlayerBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("AnimationBlendingStateMachine", |name, ctx| { - AnimationBlendingStateMachineBuilder::new(WidgetBuilder::new().with_name(name)) - .build(ctx) - }), - UiMenuEntry::new("AbsmEventProvider", |name, ctx| { - AbsmEventProviderBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - UiMenuEntry::new("Selector", |name, ctx| { - SelectorBuilder::new(WidgetBuilder::new().with_name(name)).build(ctx) - }), - ] - } + pub fn new( + constructors: &WidgetConstructorContainer, + name: &str, + ctx: &mut BuildContext, + ) -> Self { + let mut root_items = vec![]; + let mut groups = FxHashMap::default(); + let mut constructor_views = FxHashMap::default(); + let constructors = constructors.map(); + for constructor in constructors.values() { + for variant in constructor.variants.iter() { + let item = create_menu_item(&variant.name, 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, vec![], ctx); + root_items.push(group); + group + }); + ctx.sender() + .send(MenuItemMessage::add_item( + group, + MessageDirection::ToWidget, + item, + )) + .unwrap() + } + } + } - pub fn new(entries: Vec, name: &str, ctx: &mut BuildContext) -> Self { - let items = entries - .iter() - .map(|e| create_menu_item(&e.name, Default::default(), ctx)) - .collect::>(); + let menu = create_menu_item(name, root_items, ctx); - let constructors = entries - .into_iter() - .zip(items.iter().cloned()) - .map(|(entry, node)| (node, entry)) - .collect::>(); - - let menu = create_menu_item(name, items, ctx); - - Self { menu, constructors } + Self { + menu, + constructor_views, + } } pub fn handle_ui_message( @@ -253,15 +88,18 @@ impl UiMenu { selection: &Selection, ) { if let Some(MenuItemMessage::Click) = message.data::() { - if let Some(entry) = self.constructors.get_mut(&message.destination()) { - let ui_node_handle = (entry.constructor)(&entry.name, &mut scene.ui.build_ctx()); - let sub_graph = scene.ui.take_reserve_sub_graph(ui_node_handle); - let parent = if let Some(selection) = selection.as_ui() { - selection.widgets.first().cloned().unwrap_or_default() + if let Some(constructor) = self.constructor_views.get_mut(&message.destination()) { + if let VariantResult::Handle(ui_node_handle) = constructor(&mut scene.ui) { + let sub_graph = scene.ui.take_reserve_sub_graph(ui_node_handle); + let parent = if let Some(selection) = selection.as_ui() { + selection.widgets.first().cloned().unwrap_or_default() + } else { + Handle::NONE + }; + sender.do_command(AddWidgetCommand::new(sub_graph, parent, true)); } else { - Handle::NONE - }; - sender.do_command(AddWidgetCommand::new(sub_graph, parent, true)); + Log::err("Unsupported"); + } } } } diff --git a/editor/src/ui_scene/menu.rs b/editor/src/ui_scene/menu.rs index 7f94d6ff8..a50f8c410 100644 --- a/editor/src/ui_scene/menu.rs +++ b/editor/src/ui_scene/menu.rs @@ -42,6 +42,7 @@ use crate::{ world::WorldViewerItemContextMenu, Engine, Message, MessageDirection, }; +use fyrox::gui::constructor::WidgetConstructorContainer; use fyrox::gui::menu::ContextMenuBuilder; use std::path::PathBuf; @@ -77,14 +78,17 @@ fn resource_path_of_first_selected_node( } impl WidgetContextMenu { - pub fn new(ctx: &mut BuildContext) -> Self { + pub fn new( + widget_constructors_container: &WidgetConstructorContainer, + ctx: &mut BuildContext, + ) -> Self { let delete_selection; let copy_selection; let paste; let make_root; let open_asset; - let widgets_menu = UiMenu::new(UiMenu::default_entries(), "Create Child Widget", ctx); + let widgets_menu = UiMenu::new(widget_constructors_container, "Create Child Widget", ctx); let menu = ContextMenuBuilder::new( PopupBuilder::new(WidgetBuilder::new().with_visibility(false)).with_content( diff --git a/editor/src/world/graph/menu.rs b/editor/src/world/graph/menu.rs index f03120f6d..c0767dff2 100644 --- a/editor/src/world/graph/menu.rs +++ b/editor/src/world/graph/menu.rs @@ -55,6 +55,7 @@ use crate::{ Engine, Message, MessageDirection, PasteCommand, }; use fyrox::engine::SerializationContext; +use fyrox::gui::constructor::WidgetConstructorContainer; use std::{any::TypeId, path::PathBuf}; pub struct SceneNodeContextMenu { @@ -96,7 +97,11 @@ fn resource_path_of_first_selected_node( } impl SceneNodeContextMenu { - pub fn new(serialization_context: &SerializationContext, ctx: &mut BuildContext) -> Self { + pub fn new( + serialization_context: &SerializationContext, + widget_constructors_container: &WidgetConstructorContainer, + ctx: &mut BuildContext, + ) -> Self { let delete_selection; let copy_selection; let save_as_prefab; @@ -105,9 +110,12 @@ impl SceneNodeContextMenu { let open_asset; let reset_inheritable_properties; - let create_child_entity_menu = CreateEntityMenu::new(serialization_context, ctx); - let create_parent_entity_menu = CreateEntityMenu::new(serialization_context, ctx); - let replace_with_menu = CreateEntityMenu::new(serialization_context, ctx); + let create_child_entity_menu = + CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx); + let create_parent_entity_menu = + CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx); + let replace_with_menu = + CreateEntityMenu::new(serialization_context, widget_constructors_container, ctx); let menu = ContextMenuBuilder::new( PopupBuilder::new(WidgetBuilder::new().with_visibility(false)).with_content( @@ -206,6 +214,7 @@ impl SceneNodeContextMenu { sender, controller, editor_selection, + engine, ) { if let Some(graph_selection) = editor_selection.as_graph() { if let Some(parent) = graph_selection.nodes().first() { @@ -217,6 +226,7 @@ impl SceneNodeContextMenu { sender, controller, editor_selection, + engine, ) { if let Some(graph_selection) = editor_selection.as_graph() { if let Some(first) = graph_selection.nodes().first() { @@ -258,10 +268,13 @@ impl SceneNodeContextMenu { } } } - } else if let Some(replacement) = - self.replace_with_menu - .handle_ui_message(message, sender, controller, editor_selection) - { + } else if let Some(replacement) = self.replace_with_menu.handle_ui_message( + message, + sender, + controller, + editor_selection, + engine, + ) { if let Some(graph_selection) = editor_selection.as_graph() { if let Some(first) = graph_selection.nodes().first() { sender.do_command(ReplaceNodeCommand { diff --git a/fyrox-graph/src/constructor.rs b/fyrox-graph/src/constructor.rs new file mode 100644 index 000000000..9985d6b6b --- /dev/null +++ b/fyrox-graph/src/constructor.rs @@ -0,0 +1,176 @@ +// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +use fxhash::FxHashMap; +use fyrox_core::pool::Handle; +use fyrox_core::{ + parking_lot::{Mutex, MutexGuard}, + reflect::prelude::*, + TypeUuidProvider, Uuid, +}; +use std::sync::Arc; + +pub trait ConstructorProvider: TypeUuidProvider + Default + Reflect { + fn constructor() -> GraphNodeConstructor; +} + +pub enum VariantResult { + Owned(Node), + Handle(Handle), +} + +impl From for VariantResult { + fn from(node: Node) -> Self { + VariantResult::Owned(node) + } +} + +impl From> for VariantResult { + fn from(value: Handle) -> Self { + VariantResult::Handle(value) + } +} + +/// Shared closure that creates a node of some type. +pub type Constructor = Arc Node + Send + Sync>; + +pub type VariantConstructor = Arc VariantResult + Send + Sync>; + +/// Constructor variant. +pub struct Variant { + /// Name of the variant. + pub name: String, + /// Boxed type constructor. + pub constructor: VariantConstructor, +} + +/// Node constructor creates scene nodes in various states. +pub struct GraphNodeConstructor { + /// A boxed type constructor that returns a node in default state. This constructor is used at + /// deserialization stage. + pub default: Constructor, + + /// A set of node constructors that returns specific variants of the same node type. Could be + /// used to pre-define specific variations of nodes, for example a [`Mesh`] node could have + /// different surfaces (sphere, cube, cone, etc.). It is used by the editor, this collection must + /// have at least one item to be shown in the editor. + pub variants: Vec>, + + /// Name of the group the type belongs to. + pub group: &'static str, + + /// A name of the assembly this node constructor is from. + pub assembly_name: &'static str, +} + +impl GraphNodeConstructor { + /// Creates a new node constructor with default values for the given scene node type. This method + /// automatically creates default constructor, but leaves potential variants empty (nothing will + /// be shown in the editor, use [`Self::with_variant`] to add potential variant of the constructor). + pub fn new() -> Self + where + Node: From, + Inner: ConstructorProvider, + { + Self { + default: Arc::new(|| Node::from(Inner::default())), + variants: vec![], + group: "", + assembly_name: Inner::type_assembly_name(), + } + } + + /// Sets a desired group for the constructor. See [`NodeTrait::constructor`] docs for examples. + pub fn with_group(mut self, group: &'static str) -> Self { + self.group = group; + self + } + + /// Adds a new constructor variant. See [`NodeTrait::constructor`] docs for examples. + pub fn with_variant(mut self, name: impl AsRef, variant: F) -> Self + where + F: Fn(&mut Ctx) -> VariantResult + Send + Sync + 'static, + { + self.variants.push(Variant { + name: name.as_ref().to_string(), + constructor: Arc::new(variant), + }); + self + } +} + +/// A special container that is able to create nodes by their type UUID. +pub struct GraphNodeConstructorContainer { + map: Mutex>>, +} + +impl Default for GraphNodeConstructorContainer { + fn default() -> Self { + Self { + map: Default::default(), + } + } +} + +impl GraphNodeConstructorContainer { + /// Adds new type constructor for a given type and return previous constructor for the type + /// (if any). + pub fn add(&self) + where + Inner: ConstructorProvider, + { + let previous = self + .map + .lock() + .insert(Inner::type_uuid(), Inner::constructor()); + assert!(previous.is_none()); + } + + /// Adds custom type constructor. + pub fn add_custom(&self, type_uuid: Uuid, constructor: GraphNodeConstructor) { + self.map.lock().insert(type_uuid, constructor); + } + + /// Unregisters type constructor. + pub fn remove(&self, type_uuid: Uuid) { + self.map.lock().remove(&type_uuid); + } + + /// Makes an attempt to create a node using provided type UUID. It may fail if there is no + /// node constructor for specified type UUID. + pub fn try_create(&self, type_uuid: &Uuid) -> Option { + self.map.lock().get_mut(type_uuid).map(|c| (c.default)()) + } + + /// Returns total amount of constructors. + pub fn len(&self) -> usize { + self.map.lock().len() + } + + /// Returns true if the container is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the inner map of the node constructors. + pub fn map(&self) -> MutexGuard<'_, FxHashMap>> { + self.map.lock() + } +} diff --git a/fyrox-graph/src/lib.rs b/fyrox-graph/src/lib.rs index 6df13c87e..529dc627c 100644 --- a/fyrox-graph/src/lib.rs +++ b/fyrox-graph/src/lib.rs @@ -22,6 +22,8 @@ //! Graph utilities and common algorithms. +pub mod constructor; + use fxhash::FxHashMap; use fyrox_core::pool::ErasedHandle; use fyrox_core::{ diff --git a/fyrox-impl/src/engine/executor.rs b/fyrox-impl/src/engine/executor.rs index f98374d53..8459e5c3e 100644 --- a/fyrox-impl/src/engine/executor.rs +++ b/fyrox-impl/src/engine/executor.rs @@ -32,12 +32,12 @@ use crate::{ }, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, - gui::constructor::WidgetConstructorContainer, plugin::Plugin, utils::translate_event, window::WindowAttributes, }; use clap::Parser; +use fyrox_ui::constructor::new_widget_constructor_container; use std::{ ops::{Deref, DerefMut}, sync::Arc, @@ -100,7 +100,7 @@ impl Executor { resource_manager: ResourceManager::new(task_pool.clone()), serialization_context, task_pool, - widget_constructors: Arc::new(WidgetConstructorContainer::new()), + widget_constructors: Arc::new(new_widget_constructor_container()), }) .unwrap(); diff --git a/fyrox-impl/src/engine/mod.rs b/fyrox-impl/src/engine/mod.rs index 023e940b0..113b1ce01 100644 --- a/fyrox-impl/src/engine/mod.rs +++ b/fyrox-impl/src/engine/mod.rs @@ -29,6 +29,7 @@ pub mod task; mod hotreload; +use crate::scene::node::constructor::new_node_constructor_container; use crate::{ asset::{ event::ResourceEvent, @@ -138,7 +139,7 @@ impl SerializationContext { /// Creates default serialization context. pub fn new() -> Self { Self { - node_constructors: NodeConstructorContainer::new(), + node_constructors: new_node_constructor_container(), script_constructors: ScriptConstructorContainer::new(), } } @@ -1259,6 +1260,7 @@ impl Engine { /// # }; /// # use std::sync::Arc; /// # use fyrox_core::task::TaskPool; + /// use fyrox_ui::constructor::new_widget_constructor_container; /// /// let mut window_attributes = WindowAttributes::default(); /// window_attributes.title = "Some title".to_string(); @@ -1274,7 +1276,7 @@ impl Engine { /// resource_manager: ResourceManager::new(task_pool.clone()), /// serialization_context: Arc::new(SerializationContext::new()), /// task_pool, - /// widget_constructors: Arc::new(Default::default()), + /// widget_constructors: Arc::new(new_widget_constructor_container()), /// }) /// .unwrap(); /// ``` @@ -2283,7 +2285,6 @@ impl Engine { resource_manager: &ResourceManager, plugin: &dyn Plugin, ) { - *widget_constructors.context_type_id.lock() = plugin.type_id(); plugin.register(PluginRegistrationContext { serialization_context, widget_constructors, diff --git a/fyrox-impl/src/scene/animation/absm.rs b/fyrox-impl/src/scene/animation/absm.rs index 0818bc53d..9447b1892 100644 --- a/fyrox-impl/src/scene/animation/absm.rs +++ b/fyrox-impl/src/scene/animation/absm.rs @@ -40,6 +40,7 @@ use crate::{ Scene, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraph, SceneGraphNode}; use std::ops::{Deref, DerefMut}; @@ -274,13 +275,10 @@ impl DerefMut for AnimationBlendingStateMachine { } } -impl NodeTrait for AnimationBlendingStateMachine { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for AnimationBlendingStateMachine { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Animation Blending State Machine", || { + .with_variant("Animation Blending State Machine", |_| { let mut machine = Machine::default(); let mut layer = MachineLayer::new(); @@ -293,10 +291,13 @@ impl NodeTrait for AnimationBlendingStateMachine { ) .with_machine(machine) .build_node() + .into() }) .with_group("Animation") } +} +impl NodeTrait for AnimationBlendingStateMachine { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/animation/mod.rs b/fyrox-impl/src/scene/animation/mod.rs index b04c11e5b..3e2ddee99 100644 --- a/fyrox-impl/src/scene/animation/mod.rs +++ b/fyrox-impl/src/scene/animation/mod.rs @@ -40,6 +40,7 @@ use crate::{ node::{Node, NodeTrait, UpdateContext}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -319,18 +320,19 @@ impl DerefMut for AnimationPlayer { } } -impl NodeTrait for AnimationPlayer { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for AnimationPlayer { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Animation Player", || { - AnimationPlayerBuilder::new(BaseBuilder::new()).build_node() + .with_variant("Animation Player", |_| { + AnimationPlayerBuilder::new(BaseBuilder::new()) + .build_node() + .into() }) .with_group("Animation") } +} +impl NodeTrait for AnimationPlayer { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/camera.rs b/fyrox-impl/src/scene/camera.rs index 2b48a4594..51a20c074 100644 --- a/fyrox-impl/src/scene/camera.rs +++ b/fyrox-impl/src/scene/camera.rs @@ -50,6 +50,7 @@ use crate::{ node::{Node, NodeTrait, UpdateContext}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use std::{ @@ -735,16 +736,17 @@ impl Camera { } } -impl NodeTrait for Camera { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Camera", || { - CameraBuilder::new(BaseBuilder::new().with_name("Camera")).build_node() +impl ConstructorProvider for Camera { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Camera", |_| { + CameraBuilder::new(BaseBuilder::new().with_name("Camera")) + .build_node() + .into() }) } +} +impl NodeTrait for Camera { /// Returns current **local-space** bounding box. #[inline] fn local_bounding_box(&self) -> AxisAlignedBoundingBox { diff --git a/fyrox-impl/src/scene/collider.rs b/fyrox-impl/src/scene/collider.rs index cf53911a2..830d73327 100644 --- a/fyrox-impl/src/scene/collider.rs +++ b/fyrox-impl/src/scene/collider.rs @@ -48,6 +48,7 @@ use crate::{ }; use fyrox_core::algebra::{Isometry3, Translation3}; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraphNode}; use rapier3d::geometry::{self, ColliderHandle}; use std::{ @@ -851,20 +852,20 @@ impl Collider { } } -impl NodeTrait for Collider { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Collider { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Collider", || { + .with_variant("Collider", |_| { ColliderBuilder::new(BaseBuilder::new().with_name("Collider")) .with_shape(ColliderShape::Cuboid(Default::default())) .build_node() + .into() }) .with_group("Physics") } +} +impl NodeTrait for Collider { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/decal.rs b/fyrox-impl/src/scene/decal.rs index 20626097a..3d1f818be 100644 --- a/fyrox-impl/src/scene/decal.rs +++ b/fyrox-impl/src/scene/decal.rs @@ -22,7 +22,6 @@ //! //! For more info see [`Decal`] -use crate::scene::node::constructor::NodeConstructor; use crate::{ core::{ color::Color, @@ -35,12 +34,14 @@ use crate::{ visitor::prelude::*, }, resource::texture::TextureResource, + scene::node::constructor::NodeConstructor, scene::{ base::{Base, BaseBuilder}, graph::Graph, node::{Node, NodeTrait}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -211,16 +212,17 @@ impl Decal { } } -impl NodeTrait for Decal { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Decal", || { - DecalBuilder::new(BaseBuilder::new().with_name("Decal")).build_node() +impl ConstructorProvider for Decal { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Decal", |_| { + DecalBuilder::new(BaseBuilder::new().with_name("Decal")) + .build_node() + .into() }) } +} +impl NodeTrait for Decal { /// Returns current **local-space** bounding box. #[inline] fn local_bounding_box(&self) -> AxisAlignedBoundingBox { diff --git a/fyrox-impl/src/scene/dim2/collider.rs b/fyrox-impl/src/scene/dim2/collider.rs index 0d0e31899..634241870 100644 --- a/fyrox-impl/src/scene/dim2/collider.rs +++ b/fyrox-impl/src/scene/dim2/collider.rs @@ -48,6 +48,7 @@ use crate::{ }; use fyrox_core::algebra::{Isometry2, Translation2, UnitComplex}; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraphNode}; use rapier2d::geometry::ColliderHandle; use std::{ @@ -568,20 +569,20 @@ impl Collider { } } -impl NodeTrait for Collider { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Collider { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Collider", || { + .with_variant("Collider", |_| { ColliderBuilder::new(BaseBuilder::new().with_name("Collider 2D")) .with_shape(ColliderShape::Cuboid(Default::default())) .build_node() + .into() }) .with_group("Physics 2D") } +} +impl NodeTrait for Collider { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/dim2/joint.rs b/fyrox-impl/src/scene/dim2/joint.rs index 933c677a4..90b240102 100644 --- a/fyrox-impl/src/scene/dim2/joint.rs +++ b/fyrox-impl/src/scene/dim2/joint.rs @@ -42,6 +42,7 @@ use crate::{ }, }; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraphNode}; use rapier2d::dynamics::ImpulseJointHandle; use std::{ @@ -282,30 +283,32 @@ impl Joint { } } -impl NodeTrait for Joint { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Joint { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Ball Joint 2D", || { + .with_variant("Ball Joint 2D", |_| { JointBuilder::new(BaseBuilder::new().with_name("Ball Joint 2D")) .with_params(JointParams::BallJoint(Default::default())) .build_node() + .into() }) - .with_variant("Prismatic Joint 2D", || { + .with_variant("Prismatic Joint 2D", |_| { JointBuilder::new(BaseBuilder::new().with_name("Prismatic Joint 2D")) .with_params(JointParams::PrismaticJoint(Default::default())) .build_node() + .into() }) - .with_variant("Fixed Joint 2D", || { + .with_variant("Fixed Joint 2D", |_| { JointBuilder::new(BaseBuilder::new().with_name("Fixed Joint 2D")) .with_params(JointParams::FixedJoint(Default::default())) .build_node() + .into() }) .with_group("Physics 2D") } +} +impl NodeTrait for Joint { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/dim2/rectangle.rs b/fyrox-impl/src/scene/dim2/rectangle.rs index e86968ad5..4110d241d 100644 --- a/fyrox-impl/src/scene/dim2/rectangle.rs +++ b/fyrox-impl/src/scene/dim2/rectangle.rs @@ -50,6 +50,7 @@ use crate::{ }; use bytemuck::{Pod, Zeroable}; use fyrox_core::value_as_u8_slice; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::{ hash::{Hash, Hasher}, @@ -275,18 +276,19 @@ impl Rectangle { } } -impl NodeTrait for Rectangle { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Rectangle { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Rectangle (2D Sprite)", || { - RectangleBuilder::new(BaseBuilder::new().with_name("Sprite (2D)")).build_node() + .with_variant("Rectangle (2D Sprite)", |_| { + RectangleBuilder::new(BaseBuilder::new().with_name("Sprite (2D)")) + .build_node() + .into() }) .with_group("2D") } +} +impl NodeTrait for Rectangle { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::unit() } diff --git a/fyrox-impl/src/scene/dim2/rigidbody.rs b/fyrox-impl/src/scene/dim2/rigidbody.rs index ecd044215..27c2e04b7 100644 --- a/fyrox-impl/src/scene/dim2/rigidbody.rs +++ b/fyrox-impl/src/scene/dim2/rigidbody.rs @@ -51,6 +51,7 @@ use crate::{ Scene, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraph}; use rapier2d::prelude::RigidBodyHandle; use std::{ @@ -423,18 +424,19 @@ impl RigidBody { } } -impl NodeTrait for RigidBody { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for RigidBody { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Rigid Body", || { - RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body 2D")).build_node() + .with_variant("Rigid Body", |_| { + RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body 2D")) + .build_node() + .into() }) .with_group("Physics 2D") } +} +impl NodeTrait for RigidBody { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/joint.rs b/fyrox-impl/src/scene/joint.rs index e21562f55..ca689da99 100644 --- a/fyrox-impl/src/scene/joint.rs +++ b/fyrox-impl/src/scene/joint.rs @@ -43,6 +43,7 @@ use crate::{ }; use fyrox_core::algebra::{Isometry3, Vector3}; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraphNode}; use rapier2d::na::UnitQuaternion; use rapier3d::dynamics::ImpulseJointHandle; @@ -355,35 +356,38 @@ impl Joint { } } -impl NodeTrait for Joint { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Joint { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Revolute Joint", || { + .with_variant("Revolute Joint", |_| { JointBuilder::new(BaseBuilder::new().with_name("Revolute Joint")) .with_params(JointParams::RevoluteJoint(Default::default())) .build_node() + .into() }) - .with_variant("Ball Joint", || { + .with_variant("Ball Joint", |_| { JointBuilder::new(BaseBuilder::new().with_name("Ball Joint")) .with_params(JointParams::BallJoint(Default::default())) .build_node() + .into() }) - .with_variant("Prismatic Joint", || { + .with_variant("Prismatic Joint", |_| { JointBuilder::new(BaseBuilder::new().with_name("Prismatic Joint")) .with_params(JointParams::PrismaticJoint(Default::default())) .build_node() + .into() }) - .with_variant("Fixed Joint", || { + .with_variant("Fixed Joint", |_| { JointBuilder::new(BaseBuilder::new().with_name("Fixed Joint")) .with_params(JointParams::FixedJoint(Default::default())) .build_node() + .into() }) .with_group("Physics") } +} +impl NodeTrait for Joint { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/light/directional.rs b/fyrox-impl/src/scene/light/directional.rs index 562e286cb..9ca428de0 100644 --- a/fyrox-impl/src/scene/light/directional.rs +++ b/fyrox-impl/src/scene/light/directional.rs @@ -48,6 +48,7 @@ use crate::{ node::{Node, NodeTrait}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; use strum_macros::{AsRefStr, EnumString, VariantNames}; @@ -175,21 +176,21 @@ impl DirectionalLight { } } -impl NodeTrait for DirectionalLight { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for DirectionalLight { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Directional Light", || { + .with_variant("Directional Light", |_| { DirectionalLightBuilder::new(BaseLightBuilder::new( BaseBuilder::new().with_name("DirectionalLight"), )) .build_node() + .into() }) .with_group("Light") } +} +impl NodeTrait for DirectionalLight { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::default() } diff --git a/fyrox-impl/src/scene/light/point.rs b/fyrox-impl/src/scene/light/point.rs index 4009fa45d..7dce207ff 100644 --- a/fyrox-impl/src/scene/light/point.rs +++ b/fyrox-impl/src/scene/light/point.rs @@ -58,6 +58,7 @@ use crate::{ node::{Node, NodeTrait}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -132,22 +133,22 @@ impl PointLight { } } -impl NodeTrait for PointLight { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for PointLight { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Point Light", || { + .with_variant("Point Light", |_| { PointLightBuilder::new(BaseLightBuilder::new( BaseBuilder::new().with_name("PointLight"), )) .with_radius(10.0) .build_node() + .into() }) .with_group("Light") } +} +impl NodeTrait for PointLight { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::from_radius(*self.radius) } diff --git a/fyrox-impl/src/scene/light/spot.rs b/fyrox-impl/src/scene/light/spot.rs index 4527cf16f..0e898a0af 100644 --- a/fyrox-impl/src/scene/light/spot.rs +++ b/fyrox-impl/src/scene/light/spot.rs @@ -65,6 +65,7 @@ use crate::{ node::{Node, NodeTrait}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -218,13 +219,10 @@ impl SpotLight { } } -impl NodeTrait for SpotLight { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for SpotLight { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Spot Light", || { + .with_variant("Spot Light", |_| { SpotLightBuilder::new(BaseLightBuilder::new( BaseBuilder::new().with_name("SpotLight"), )) @@ -232,10 +230,13 @@ impl NodeTrait for SpotLight { .with_hotspot_cone_angle(45.0f32.to_radians()) .with_falloff_angle_delta(2.0f32.to_radians()) .build_node() + .into() }) .with_group("Light") } +} +impl NodeTrait for SpotLight { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::from_radius(self.distance()) } diff --git a/fyrox-impl/src/scene/mesh/mod.rs b/fyrox-impl/src/scene/mesh/mod.rs index de5756715..b3ad0a816 100644 --- a/fyrox-impl/src/scene/mesh/mod.rs +++ b/fyrox-impl/src/scene/mesh/mod.rs @@ -62,6 +62,7 @@ use crate::{ }, }; use fxhash::{FxHashMap, FxHasher}; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_resource::untyped::ResourceKind; use std::{ cell::Cell, @@ -550,30 +551,29 @@ fn placeholder_material() -> MaterialResource { MaterialResource::new_ok(ResourceKind::Embedded, material) } -impl NodeTrait for Mesh { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Mesh { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Empty", || { - MeshBuilder::new(BaseBuilder::new()).build_node() + .with_variant("Empty", |_| { + MeshBuilder::new(BaseBuilder::new()).build_node().into() }) - .with_variant("Cube", || { + .with_variant("Cube", |_| { MeshBuilder::new(BaseBuilder::new().with_name("Cube")) .with_surfaces(vec![SurfaceBuilder::new(surface::CUBE.resource.clone()) .with_material(placeholder_material()) .build()]) .build_node() + .into() }) - .with_variant("Cone", || { + .with_variant("Cone", |_| { MeshBuilder::new(BaseBuilder::new().with_name("Cone")) .with_surfaces(vec![SurfaceBuilder::new(surface::CONE.resource.clone()) .with_material(placeholder_material()) .build()]) .build_node() + .into() }) - .with_variant("Cylinder", || { + .with_variant("Cylinder", |_| { MeshBuilder::new(BaseBuilder::new().with_name("Cylinder")) .with_surfaces(vec![SurfaceBuilder::new( surface::CYLINDER.resource.clone(), @@ -581,24 +581,29 @@ impl NodeTrait for Mesh { .with_material(placeholder_material()) .build()]) .build_node() + .into() }) - .with_variant("Sphere", || { + .with_variant("Sphere", |_| { MeshBuilder::new(BaseBuilder::new().with_name("Sphere")) .with_surfaces(vec![SurfaceBuilder::new(surface::SPHERE.resource.clone()) .with_material(placeholder_material()) .build()]) .build_node() + .into() }) - .with_variant("Quad", || { + .with_variant("Quad", |_| { MeshBuilder::new(BaseBuilder::new().with_name("Quad")) .with_surfaces(vec![SurfaceBuilder::new(surface::QUAD.resource.clone()) .with_material(placeholder_material()) .build()]) .build_node() + .into() }) .with_group("Mesh") } +} +impl NodeTrait for Mesh { /// Returns current bounding box. Bounding box presented in *local coordinates* /// WARNING: This method does *not* includes bounds of bones! fn local_bounding_box(&self) -> AxisAlignedBoundingBox { diff --git a/fyrox-impl/src/scene/navmesh.rs b/fyrox-impl/src/scene/navmesh.rs index e033f5d0d..05a4e27cb 100644 --- a/fyrox-impl/src/scene/navmesh.rs +++ b/fyrox-impl/src/scene/navmesh.rs @@ -45,6 +45,7 @@ use crate::{ use fyrox_core::algebra::Vector3; use fyrox_core::math::TriangleDefinition; use fyrox_core::parking_lot::{RwLockReadGuard, RwLockWriteGuard}; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::{ ops::{Deref, DerefMut}, @@ -180,12 +181,9 @@ impl DerefMut for NavigationalMesh { } } -impl NodeTrait for NavigationalMesh { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Navmesh", || { +impl ConstructorProvider for NavigationalMesh { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Navmesh", |_| { let navmesh = Navmesh::new( vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])], vec![ @@ -199,9 +197,12 @@ impl NodeTrait for NavigationalMesh { NavigationalMeshBuilder::new(BaseBuilder::new().with_name("Navmesh")) .with_navmesh(navmesh) .build_node() + .into() }) } +} +impl NodeTrait for NavigationalMesh { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/node/constructor.rs b/fyrox-impl/src/scene/node/constructor.rs index 2c9b79cd1..80726813e 100644 --- a/fyrox-impl/src/scene/node/constructor.rs +++ b/fyrox-impl/src/scene/node/constructor.rs @@ -20,176 +20,61 @@ //! A special container that is able to create nodes by their type UUID. -use crate::{ - core::{ - parking_lot::{Mutex, MutexGuard}, - uuid::Uuid, - TypeUuidProvider, - }, - scene::{ - self, - animation::{absm::AnimationBlendingStateMachine, AnimationPlayer}, - camera::Camera, - decal::Decal, - dim2::{self, rectangle::Rectangle}, - light::{directional::DirectionalLight, point::PointLight, spot::SpotLight}, - mesh::Mesh, - navmesh::NavigationalMesh, - node::{Node, NodeTrait}, - particle_system::ParticleSystem, - pivot::Pivot, - ragdoll::Ragdoll, - sound::{listener::Listener, Sound}, - sprite::Sprite, - terrain::Terrain, - tilemap::TileMap, - }, +use crate::scene::graph::Graph; +use crate::scene::{ + self, + animation::{absm::AnimationBlendingStateMachine, AnimationPlayer}, + camera::Camera, + decal::Decal, + dim2::{self, rectangle::Rectangle}, + light::{directional::DirectionalLight, point::PointLight, spot::SpotLight}, + mesh::Mesh, + navmesh::NavigationalMesh, + node::Node, + particle_system::ParticleSystem, + pivot::Pivot, + ragdoll::Ragdoll, + sound::{listener::Listener, Sound}, + sprite::Sprite, + terrain::Terrain, + tilemap::TileMap, }; -use fxhash::FxHashMap; -use std::sync::Arc; - -/// Shared closure that creates a node of some type. -pub type Constructor = Arc Node + Send + Sync>; - -/// Constructor variant. -pub struct Variant { - /// Name of the variant. - pub name: &'static str, - /// Boxed type constructor. - pub constructor: Constructor, -} +use fyrox_graph::constructor::{GraphNodeConstructor, GraphNodeConstructorContainer}; /// Node constructor creates scene nodes in various states. -pub struct NodeConstructor { - /// A boxed type constructor that returns a node in default state. This constructor is used at - /// deserialization stage. - pub default: Constructor, - - /// A set of node constructors that returns specific variants of the same node type. Could be - /// used to pre-define specific variations of nodes, for example a [`Mesh`] node could have - /// different surfaces (sphere, cube, cone, etc.). It is used by the editor, this collection must - /// have at least one item to be shown in the editor. - pub variants: Vec, - - /// Name of the group the type belongs to. - pub group: &'static str, - - /// A name of the assembly this node constructor is from. - pub assembly_name: &'static str, -} - -impl NodeConstructor { - /// Creates a new node constructor with default values for the given scene node type. This method - /// automatically creates default constructor, but leaves potential variants empty (nothing will - /// be shown in the editor, use [`Self::with_variant`] to add potential variant of the constructor). - pub fn new() -> Self - where - T: NodeTrait + Default, - { - Self { - default: Arc::new(|| Node::new(T::default())), - variants: vec![], - group: "", - assembly_name: T::type_assembly_name(), - } - } - - /// Sets a desired group for the constructor. See [`NodeTrait::constructor`] docs for examples. - pub fn with_group(mut self, group: &'static str) -> Self { - self.group = group; - self - } - - /// Adds a new constructor variant. See [`NodeTrait::constructor`] docs for examples. - pub fn with_variant(mut self, name: &'static str, variant: F) -> Self - where - F: Fn() -> Node + Send + Sync + 'static, - { - self.variants.push(Variant { - name, - constructor: Arc::new(variant), - }); - self - } -} +pub type NodeConstructor = GraphNodeConstructor; /// A special container that is able to create nodes by their type UUID. -#[derive(Default)] -pub struct NodeConstructorContainer { - map: Mutex>, -} - -impl NodeConstructorContainer { - /// Creates default node constructor container with constructors for built-in engine nodes. - pub fn new() -> Self { - let container = NodeConstructorContainer::default(); - - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - container.add::(); - - container - } - - /// Adds new type constructor for a given type and return previous constructor for the type - /// (if any). - pub fn add(&self) - where - T: TypeUuidProvider + NodeTrait + Default, - { - let previous = self.map.lock().insert(T::type_uuid(), T::constructor()); - assert!(previous.is_none()); - } - - /// Adds custom type constructor. - pub fn add_custom(&self, type_uuid: Uuid, constructor: NodeConstructor) { - self.map.lock().insert(type_uuid, constructor); - } - - /// Unregisters type constructor. - pub fn remove(&self, type_uuid: Uuid) { - self.map.lock().remove(&type_uuid); - } - - /// Makes an attempt to create a node using provided type UUID. It may fail if there is no - /// node constructor for specified type UUID. - pub fn try_create(&self, type_uuid: &Uuid) -> Option { - self.map.lock().get_mut(type_uuid).map(|c| (c.default)()) - } - - /// Returns total amount of constructors. - pub fn len(&self) -> usize { - self.map.lock().len() - } - - /// Returns true if the container is empty. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the inner map of the node constructors. - pub fn map(&self) -> MutexGuard<'_, FxHashMap> { - self.map.lock() - } +pub type NodeConstructorContainer = GraphNodeConstructorContainer; + +/// Creates default node constructor container with constructors for built-in engine nodes. +pub fn new_node_constructor_container() -> NodeConstructorContainer { + let container = NodeConstructorContainer::default(); + + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + container.add::(); + + container } diff --git a/fyrox-impl/src/scene/node/mod.rs b/fyrox-impl/src/scene/node/mod.rs index 3d6d64c08..aea594412 100644 --- a/fyrox-impl/src/scene/node/mod.rs +++ b/fyrox-impl/src/scene/node/mod.rs @@ -25,7 +25,6 @@ #![warn(missing_docs)] use crate::resource::model::Model; -use crate::scene::node::constructor::NodeConstructor; use crate::{ asset::untyped::UntypedResource, core::{ @@ -146,57 +145,6 @@ pub enum RdcControlFlow { /// A main trait for any scene graph node. pub trait NodeTrait: BaseNodeTrait + Reflect + Visit + ComponentProvider { - /// A method that returns node constructor for a particular node type. See [`NodeConstructor`] - /// docs for more info. - /// - /// ## Examples - /// - /// ```rust - /// # use fyrox_impl::{ - /// # core::{ - /// # math::aabb::AxisAlignedBoundingBox, reflect::prelude::*, type_traits::prelude::*, - /// # visitor::prelude::*, - /// # }, - /// # scene::{ - /// # base::Base, - /// # node::{constructor::NodeConstructor, Node, NodeTrait}, - /// # }, - /// # }; - /// # - /// #[derive(Visit, Reflect, Clone, Debug, Default, ComponentProvider)] - /// struct MyNode { - /// base: Base, - /// } - /// - /// impl NodeTrait for MyNode { - /// fn constructor() -> NodeConstructor - /// where - /// Self: Sized + Default, - /// { - /// NodeConstructor::new::() - /// // Provide variants for the editor. It will be shown in the `Create` menu. - /// .with_variant("My Node", || { - /// Node::new(MyNode { - /// base: Default::default(), - /// }) - /// }) - /// .with_group("Custom Nodes") - /// } - /// # fn local_bounding_box(&self) -> AxisAlignedBoundingBox { - /// # todo!() - /// # } - /// # fn world_bounding_box(&self) -> AxisAlignedBoundingBox { - /// # todo!() - /// # } - /// # fn id(&self) -> Uuid { - /// # todo!() - /// # } - /// } - /// ``` - fn constructor() -> NodeConstructor - where - Self: Sized + Default; - /// Returns axis-aligned bounding box in **local space** of the node. fn local_bounding_box(&self) -> AxisAlignedBoundingBox; @@ -378,6 +326,12 @@ pub trait NodeTrait: BaseNodeTrait + Reflect + Visit + ComponentProvider { #[derive(Debug)] pub struct Node(Box); +impl From for Node { + fn from(value: T) -> Self { + Self(Box::new(value)) + } +} + impl Clone for Node { fn clone(&self) -> Self { self.0.clone_box() diff --git a/fyrox-impl/src/scene/particle_system/mod.rs b/fyrox-impl/src/scene/particle_system/mod.rs index c79924881..bc58695b1 100644 --- a/fyrox-impl/src/scene/particle_system/mod.rs +++ b/fyrox-impl/src/scene/particle_system/mod.rs @@ -53,6 +53,7 @@ use crate::{ }, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::{ cmp::Ordering, @@ -545,12 +546,9 @@ impl Default for ParticleSystem { } } -impl NodeTrait for ParticleSystem { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Particle System", || { +impl ConstructorProvider for ParticleSystem { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Particle System", |_| { ParticleSystemBuilder::new(BaseBuilder::new().with_name("ParticleSystem")) .with_emitters(vec![SphereEmitterBuilder::new( BaseEmitterBuilder::new() @@ -560,9 +558,12 @@ impl NodeTrait for ParticleSystem { .with_radius(1.0) .build()]) .build_node() + .into() }) } +} +impl NodeTrait for ParticleSystem { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::unit() } diff --git a/fyrox-impl/src/scene/pivot.rs b/fyrox-impl/src/scene/pivot.rs index dd09b2e66..b4941ee80 100644 --- a/fyrox-impl/src/scene/pivot.rs +++ b/fyrox-impl/src/scene/pivot.rs @@ -35,6 +35,7 @@ use crate::{ node::{Node, NodeTrait}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -70,16 +71,17 @@ impl DerefMut for Pivot { } } -impl NodeTrait for Pivot { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Pivot", || { - PivotBuilder::new(BaseBuilder::new().with_name("Pivot")).build_node() +impl ConstructorProvider for Pivot { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Pivot", |_| { + PivotBuilder::new(BaseBuilder::new().with_name("Pivot")) + .build_node() + .into() }) } +} +impl NodeTrait for Pivot { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/ragdoll.rs b/fyrox-impl/src/scene/ragdoll.rs index 92cee1037..f579f507e 100644 --- a/fyrox-impl/src/scene/ragdoll.rs +++ b/fyrox-impl/src/scene/ragdoll.rs @@ -44,6 +44,7 @@ use crate::{ rigidbody::{RigidBody, RigidBodyType}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::SceneGraphNode; use std::{ any::{type_name, Any, TypeId}, @@ -268,18 +269,19 @@ impl TypeUuidProvider for Ragdoll { } } -impl NodeTrait for Ragdoll { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Ragdoll { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Ragdoll", || { - RagdollBuilder::new(BaseBuilder::new().with_name("Ragdoll")).build_node() + .with_variant("Ragdoll", |_| { + RagdollBuilder::new(BaseBuilder::new().with_name("Ragdoll")) + .build_node() + .into() }) .with_group("Physics") } +} +impl NodeTrait for Ragdoll { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/rigidbody.rs b/fyrox-impl/src/scene/rigidbody.rs index 2187d6954..28d313d1f 100644 --- a/fyrox-impl/src/scene/rigidbody.rs +++ b/fyrox-impl/src/scene/rigidbody.rs @@ -51,6 +51,7 @@ use crate::{ }, }; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::{BaseSceneGraph, SceneGraph}; use rapier3d::{dynamics, prelude::RigidBodyHandle}; use std::{ @@ -527,18 +528,19 @@ impl RigidBody { } } -impl NodeTrait for RigidBody { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for RigidBody { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Rigid Body", || { - RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body")).build_node() + .with_variant("Rigid Body", |_| { + RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body")) + .build_node() + .into() }) .with_group("Physics") } +} +impl NodeTrait for RigidBody { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { self.base.local_bounding_box() } diff --git a/fyrox-impl/src/scene/sound/listener.rs b/fyrox-impl/src/scene/sound/listener.rs index a6f40a858..c012f2989 100644 --- a/fyrox-impl/src/scene/sound/listener.rs +++ b/fyrox-impl/src/scene/sound/listener.rs @@ -39,6 +39,7 @@ use crate::{ node::{Node, NodeTrait, SyncContext}, }, }; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -81,18 +82,19 @@ impl TypeUuidProvider for Listener { } } -impl NodeTrait for Listener { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Listener { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Listener", || { - ListenerBuilder::new(BaseBuilder::new().with_name("Listener")).build_node() + .with_variant("Listener", |_| { + ListenerBuilder::new(BaseBuilder::new().with_name("Listener")) + .build_node() + .into() }) .with_group("Sound") } +} +impl NodeTrait for Listener { /// Returns local bounding box of the listener, since listener cannot have any bounds - /// returned bounding box is collapsed into a point. fn local_bounding_box(&self) -> AxisAlignedBoundingBox { diff --git a/fyrox-impl/src/scene/sound/mod.rs b/fyrox-impl/src/scene/sound/mod.rs index ffe0e6e75..a83ac1ed9 100644 --- a/fyrox-impl/src/scene/sound/mod.rs +++ b/fyrox-impl/src/scene/sound/mod.rs @@ -59,6 +59,7 @@ pub use fyrox_sound::{ use crate::scene::node::constructor::NodeConstructor; use crate::scene::Scene; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use fyrox_resource::state::ResourceState; use fyrox_sound::source::SoundSource; @@ -387,18 +388,19 @@ impl Sound { } } -impl NodeTrait for Sound { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for Sound { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Sound Source", || { - SoundBuilder::new(BaseBuilder::new().with_name("Sound Source")).build_node() + .with_variant("Sound Source", |_| { + SoundBuilder::new(BaseBuilder::new().with_name("Sound Source")) + .build_node() + .into() }) .with_group("Sound") } +} +impl NodeTrait for Sound { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::unit() } diff --git a/fyrox-impl/src/scene/sprite.rs b/fyrox-impl/src/scene/sprite.rs index 873cc203a..36459adde 100644 --- a/fyrox-impl/src/scene/sprite.rs +++ b/fyrox-impl/src/scene/sprite.rs @@ -54,6 +54,7 @@ use crate::{ }; use bytemuck::{Pod, Zeroable}; use fyrox_core::value_as_u8_slice; +use fyrox_graph::constructor::ConstructorProvider; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -293,16 +294,17 @@ impl Sprite { } } -impl NodeTrait for Sprite { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Sprite (3D)", || { - SpriteBuilder::new(BaseBuilder::new().with_name("Sprite")).build_node() +impl ConstructorProvider for Sprite { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Sprite (3D)", |_| { + SpriteBuilder::new(BaseBuilder::new().with_name("Sprite")) + .build_node() + .into() }) } +} +impl NodeTrait for Sprite { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { AxisAlignedBoundingBox::from_radius(*self.size) } diff --git a/fyrox-impl/src/scene/terrain/mod.rs b/fyrox-impl/src/scene/terrain/mod.rs index 3d7d38029..3c9854bfc 100644 --- a/fyrox-impl/src/scene/terrain/mod.rs +++ b/fyrox-impl/src/scene/terrain/mod.rs @@ -78,6 +78,7 @@ mod quadtree; use crate::scene::node::constructor::NodeConstructor; pub use brushstroke::*; +use fyrox_graph::constructor::ConstructorProvider; /// Current implementation version marker. pub const VERSION: u8 = 2; @@ -2514,21 +2515,21 @@ fn create_terrain_layer_material() -> MaterialResource { MaterialResource::new_ok(Default::default(), material) } -impl NodeTrait for Terrain { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { - NodeConstructor::new::().with_variant("Terrain", || { +impl ConstructorProvider for Terrain { + fn constructor() -> NodeConstructor { + NodeConstructor::new::().with_variant("Terrain", |_| { TerrainBuilder::new(BaseBuilder::new().with_name("Terrain")) .with_layers(vec![Layer { material: create_terrain_layer_material(), ..Default::default() }]) .build_node() + .into() }) } +} +impl NodeTrait for Terrain { /// Returns pre-cached bounding axis-aligned bounding box of the terrain. Keep in mind that /// if you're modified terrain, bounding box will be recalculated and it is not fast. fn local_bounding_box(&self) -> AxisAlignedBoundingBox { diff --git a/fyrox-impl/src/scene/tilemap/mod.rs b/fyrox-impl/src/scene/tilemap/mod.rs index d49d92033..2d408521d 100644 --- a/fyrox-impl/src/scene/tilemap/mod.rs +++ b/fyrox-impl/src/scene/tilemap/mod.rs @@ -52,6 +52,7 @@ use crate::{ }, }; use fxhash::{FxHashMap, FxHashSet}; +use fyrox_graph::constructor::ConstructorProvider; use std::ops::{Deref, DerefMut}; struct BresenhamLineIter { @@ -648,18 +649,19 @@ impl DerefMut for TileMap { } } -impl NodeTrait for TileMap { - fn constructor() -> NodeConstructor - where - Self: Sized + Default, - { +impl ConstructorProvider for TileMap { + fn constructor() -> NodeConstructor { NodeConstructor::new::() - .with_variant("Tile Map", || { - TileMapBuilder::new(BaseBuilder::new().with_name("Tile Map")).build_node() + .with_variant("Tile Map", |_| { + TileMapBuilder::new(BaseBuilder::new().with_name("Tile Map")) + .build_node() + .into() }) .with_group("2D") } +} +impl NodeTrait for TileMap { fn local_bounding_box(&self) -> AxisAlignedBoundingBox { let rect = self.bounding_rect(); diff --git a/fyrox-ui/src/absm.rs b/fyrox-ui/src/absm.rs index 977a9fd7f..0e142ddb6 100644 --- a/fyrox-ui/src/absm.rs +++ b/fyrox-ui/src/absm.rs @@ -33,6 +33,7 @@ use crate::{ BuildContext, Control, UiNode, UserInterface, }; use fyrox_animation::machine::Parameter; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::{SceneGraph, SceneGraphNode}; use std::ops::{Deref, DerefMut}; use strum_macros::{AsRefStr, EnumString, VariantNames}; @@ -131,6 +132,20 @@ pub struct AnimationBlendingStateMachine { animation_player: InheritableVariable>, } +impl ConstructorProvider for AnimationBlendingStateMachine { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Animation Blending State Machine", |ui| { + AnimationBlendingStateMachineBuilder::new( + WidgetBuilder::new().with_name("Animation Blending State Machine"), + ) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Animation") + } +} + impl AnimationBlendingStateMachine { /// Sets new state machine to the node. pub fn set_machine(&mut self, machine: Machine) { @@ -280,6 +295,18 @@ pub struct AbsmEventProvider { absm: InheritableVariable>, } +impl ConstructorProvider for AbsmEventProvider { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Absm Event Provider", |ui| { + AbsmEventProviderBuilder::new(WidgetBuilder::new().with_name("Absm Event Provider")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Animation") + } +} + define_widget_deref!(AbsmEventProvider); impl AbsmEventProvider { diff --git a/fyrox-ui/src/animation.rs b/fyrox-ui/src/animation.rs index deba52f7f..24d525645 100644 --- a/fyrox-ui/src/animation.rs +++ b/fyrox-ui/src/animation.rs @@ -37,6 +37,7 @@ use crate::{ widget::{Widget, WidgetBuilder}, BuildContext, Control, UiNode, UserInterface, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -167,6 +168,16 @@ pub struct AnimationPlayer { auto_apply: bool, } +impl ConstructorProvider for AnimationPlayer { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::().with_variant("Animation Player", |ui| { + AnimationPlayerBuilder::new(WidgetBuilder::new().with_name("Animation Player")) + .build(&mut ui.build_ctx()) + .into() + }) + } +} + impl Default for AnimationPlayer { fn default() -> Self { Self { diff --git a/fyrox-ui/src/bit.rs b/fyrox-ui/src/bit.rs index 6aaae47c7..8ac0059b3 100644 --- a/fyrox-ui/src/bit.rs +++ b/fyrox-ui/src/bit.rs @@ -37,6 +37,7 @@ use crate::{ BuildContext, Control, MessageDirection, MouseButton, Orientation, Thickness, UiNode, UserInterface, WidgetMessage, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ fmt::Debug, @@ -95,6 +96,18 @@ impl BitFieldMessage { define_constructor!(BitFieldMessage:Value => fn value(T), layout: false); } +impl ConstructorProvider for BitField { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant(format!("Bit Field<{}>", std::any::type_name::()), |ui| { + BitFieldBuilder::::new(WidgetBuilder::new()) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Bit") + } +} + #[derive(Default, Clone, Reflect, Visit, Debug, ComponentProvider)] pub struct BitField where diff --git a/fyrox-ui/src/border.rs b/fyrox-ui/src/border.rs index b1f638115..bafd05730 100644 --- a/fyrox-ui/src/border.rs +++ b/fyrox-ui/src/border.rs @@ -34,6 +34,7 @@ use crate::{ widget::{Widget, WidgetBuilder}, BuildContext, Control, MessageDirection, Thickness, UiNode, UserInterface, BRUSH_PRIMARY, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::ops::{Deref, DerefMut}; /// The Border widget provides a stylized, static border around its child widget. Below is an example of creating a 1 pixel @@ -114,6 +115,18 @@ pub struct Border { pub pad_by_corner_radius: InheritableVariable, } +impl ConstructorProvider for Border { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Border", |ui| { + BorderBuilder::new(WidgetBuilder::new().with_name("Border")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Visual") + } +} + crate::define_widget_deref!(Border); /// Supported border-specific messages. diff --git a/fyrox-ui/src/button.rs b/fyrox-ui/src/button.rs index 666f46264..afa158aa1 100644 --- a/fyrox-ui/src/button.rs +++ b/fyrox-ui/src/button.rs @@ -37,6 +37,7 @@ use crate::{ BuildContext, Control, HorizontalAlignment, Thickness, UiNode, UserInterface, VerticalAlignment, BRUSH_DARKER, BRUSH_LIGHT, BRUSH_LIGHTER, BRUSH_LIGHTEST, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::{ cell::RefCell, ops::{Deref, DerefMut}, @@ -133,6 +134,23 @@ pub struct Button { pub repeat_clicks_on_hold: InheritableVariable, } +impl ConstructorProvider for Button { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Button", |ui| { + ButtonBuilder::new( + WidgetBuilder::new() + .with_width(100.0) + .with_height(20.0) + .with_name("Button"), + ) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(Button); impl Control for Button { diff --git a/fyrox-ui/src/canvas.rs b/fyrox-ui/src/canvas.rs index 7a26bbcf5..ca3ad8b6f 100644 --- a/fyrox-ui/src/canvas.rs +++ b/fyrox-ui/src/canvas.rs @@ -33,6 +33,7 @@ use crate::{ widget::{Widget, WidgetBuilder}, BuildContext, Control, UiNode, UserInterface, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::ops::{Deref, DerefMut}; /// Canvas widget allows its children to have an arbitrary position on an imaginable infinite plane, it also @@ -75,6 +76,18 @@ pub struct Canvas { pub widget: Widget, } +impl ConstructorProvider for Canvas { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Canvas", |ui| { + CanvasBuilder::new(WidgetBuilder::new().with_name("Canvas")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Layout") + } +} + crate::define_widget_deref!(Canvas); impl Control for Canvas { diff --git a/fyrox-ui/src/check_box.rs b/fyrox-ui/src/check_box.rs index 55f39bcdd..dde19d4e6 100644 --- a/fyrox-ui/src/check_box.rs +++ b/fyrox-ui/src/check_box.rs @@ -39,6 +39,7 @@ use crate::{ BuildContext, Control, HorizontalAlignment, MouseButton, Thickness, UiNode, UserInterface, VerticalAlignment, BRUSH_BRIGHT, BRUSH_BRIGHT_BLUE, BRUSH_DARKEST, BRUSH_LIGHT, BRUSH_TEXT, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::ops::{Deref, DerefMut}; /// A set of possible check box messages. @@ -162,6 +163,18 @@ pub struct CheckBox { pub undefined_mark: InheritableVariable>, } +impl ConstructorProvider for CheckBox { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("CheckBox", |ui| { + CheckBoxBuilder::new(WidgetBuilder::new().with_name("CheckBox")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(CheckBox); impl Control for CheckBox { diff --git a/fyrox-ui/src/color/gradient.rs b/fyrox-ui/src/color/gradient.rs index b2c2df6df..8320eb63d 100644 --- a/fyrox-ui/src/color/gradient.rs +++ b/fyrox-ui/src/color/gradient.rs @@ -42,6 +42,7 @@ use crate::{ widget::{Widget, WidgetBuilder, WidgetMessage}, BuildContext, Control, RcUiNodeHandle, UiNode, UserInterface, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ cell::Cell, @@ -65,6 +66,20 @@ pub struct ColorGradientField { color_gradient: ColorGradient, } +impl ConstructorProvider for ColorGradientField { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Color Gradient Field", |ui| { + ColorGradientFieldBuilder::new( + WidgetBuilder::new().with_name("Color Gradient Field"), + ) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + define_widget_deref!(ColorGradientField); const SYNC_FLAG: u64 = 1; @@ -182,6 +197,20 @@ pub struct ColorGradientEditor { context_menu_open_position: Cell>, } +impl ConstructorProvider for ColorGradientEditor { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Color Gradient Editor", |ui| { + ColorGradientEditorBuilder::new( + WidgetBuilder::new().with_name("Color Gradient Editor"), + ) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + define_widget_deref!(ColorGradientEditor); impl Control for ColorGradientEditor { @@ -487,6 +516,18 @@ pub struct ColorPoint { pub dragging: bool, } +impl ConstructorProvider for ColorPoint { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Color Point", |ui| { + ColorPointBuilder::new(WidgetBuilder::new().with_name("Color Point")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + define_widget_deref!(ColorPoint); impl Control for ColorPoint { diff --git a/fyrox-ui/src/color/mod.rs b/fyrox-ui/src/color/mod.rs index 191d21e77..d7def4796 100644 --- a/fyrox-ui/src/color/mod.rs +++ b/fyrox-ui/src/color/mod.rs @@ -41,6 +41,7 @@ use crate::{ BuildContext, Control, Orientation, Thickness, UiNode, UserInterface, VerticalAlignment, }; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ ops::{Deref, DerefMut}, @@ -130,6 +131,18 @@ pub struct AlphaBar { pub is_picking: bool, } +impl ConstructorProvider for AlphaBar { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Alpha Bar", |ui| { + AlphaBarBuilder::new(WidgetBuilder::new().with_name("Alpha Bar")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + crate::define_widget_deref!(AlphaBar); impl AlphaBar { @@ -393,6 +406,18 @@ pub struct HueBar { pub hue: f32, } +impl ConstructorProvider for HueBar { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Hue Bar", |ui| { + HueBarBuilder::new(WidgetBuilder::new().with_name("Hue Bar")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + crate::define_widget_deref!(HueBar); impl HueBar { @@ -545,6 +570,20 @@ pub struct SaturationBrightnessField { pub brightness: f32, } +impl ConstructorProvider for SaturationBrightnessField { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Saturation Brightness Field", |ui| { + SaturationBrightnessFieldBuilder::new( + WidgetBuilder::new().with_name("Saturation Brightness Field"), + ) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + crate::define_widget_deref!(SaturationBrightnessField); impl SaturationBrightnessField { @@ -754,6 +793,18 @@ pub struct ColorPicker { pub hsv: Hsv, } +impl ConstructorProvider for ColorPicker { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Color Picker", |ui| { + ColorPickerBuilder::new(WidgetBuilder::new().with_name("Color Picker")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + crate::define_widget_deref!(ColorPicker); fn mark_handled(message: UiMessage) -> UiMessage { @@ -1159,6 +1210,18 @@ pub struct ColorField { pub color: Color, } +impl ConstructorProvider for ColorField { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Color Field", |ui| { + ColorFieldBuilder::new(WidgetBuilder::new().with_name("Color Field")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Color") + } +} + crate::define_widget_deref!(ColorField); uuid_provider!(ColorField = "68dec1ac-23c6-41df-bc85-499f2a82e908"); diff --git a/fyrox-ui/src/curve/mod.rs b/fyrox-ui/src/curve/mod.rs index 297c7442b..b196d5a4b 100644 --- a/fyrox-ui/src/curve/mod.rs +++ b/fyrox-ui/src/curve/mod.rs @@ -52,6 +52,7 @@ use crate::{ BRUSH_BRIGHT, BRUSH_LIGHT, }; use fxhash::FxHashSet; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ cell::{Cell, RefCell}, @@ -456,6 +457,18 @@ pub struct CurveEditor { clipboard: Vec<(Vector2, CurveKeyKind)>, } +impl ConstructorProvider for CurveEditor { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Curve Editor", |ui| { + CurveEditorBuilder::new(WidgetBuilder::new().with_name("Curve Editor")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(CurveEditor); #[derive(Default, Clone, Visit, Reflect, Debug)] diff --git a/fyrox-ui/src/decorator.rs b/fyrox-ui/src/decorator.rs index a00a08866..ed65a133a 100644 --- a/fyrox-ui/src/decorator.rs +++ b/fyrox-ui/src/decorator.rs @@ -23,6 +23,7 @@ #![warn(missing_docs)] +use crate::widget::WidgetBuilder; use crate::{ border::{Border, BorderBuilder}, brush::Brush, @@ -39,6 +40,7 @@ use crate::{ }; use fyrox_core::uuid_provider; use fyrox_core::variable::InheritableVariable; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::ops::{Deref, DerefMut}; /// A set of messages that is used to modify [`Decorator`] widgets state. @@ -127,6 +129,20 @@ pub struct Decorator { pub is_pressable: InheritableVariable, } +impl ConstructorProvider for Decorator { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Decorator", |ui| { + DecoratorBuilder::new(BorderBuilder::new( + WidgetBuilder::new().with_name("Decorator"), + )) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Visual") + } +} + impl Deref for Decorator { type Target = Widget; diff --git a/fyrox-ui/src/dock/mod.rs b/fyrox-ui/src/dock/mod.rs index 0c7e2b7a6..08cc57b11 100644 --- a/fyrox-ui/src/dock/mod.rs +++ b/fyrox-ui/src/dock/mod.rs @@ -36,6 +36,7 @@ use crate::{ widget::{Widget, WidgetBuilder, WidgetMessage}, BuildContext, Control, UiNode, UserInterface, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::{BaseSceneGraph, SceneGraph}; use std::{ cell::RefCell, @@ -76,6 +77,18 @@ pub struct DockingManager { pub floating_windows: RefCell>>, } +impl ConstructorProvider for DockingManager { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Docking Manager", |ui| { + DockingManagerBuilder::new(WidgetBuilder::new().with_name("Docking Manager")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Layout") + } +} + crate::define_widget_deref!(DockingManager); uuid_provider!(DockingManager = "b04299f7-3f6b-45f1-89a6-0dce4ad929e1"); diff --git a/fyrox-ui/src/dock/tile.rs b/fyrox-ui/src/dock/tile.rs index 2156c579a..88842f2e1 100644 --- a/fyrox-ui/src/dock/tile.rs +++ b/fyrox-ui/src/dock/tile.rs @@ -32,6 +32,7 @@ use crate::{ BuildContext, Control, Thickness, UiNode, UserInterface, }; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::{BaseSceneGraph, SceneGraph}; use std::{ cell::Cell, @@ -126,6 +127,18 @@ pub struct Tile { pub drop_anchor: Cell>, } +impl ConstructorProvider for Tile { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Tile", |ui| { + TileBuilder::new(WidgetBuilder::new().with_name("Tile")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Layout") + } +} + crate::define_widget_deref!(Tile); uuid_provider!(Tile = "8ed17fa9-890e-4dd7-b4f9-a24660882234"); diff --git a/fyrox-ui/src/dropdown_list.rs b/fyrox-ui/src/dropdown_list.rs index 58c81a9e4..ebaa4aa8c 100644 --- a/fyrox-ui/src/dropdown_list.rs +++ b/fyrox-ui/src/dropdown_list.rs @@ -39,6 +39,7 @@ use crate::{ widget::{Widget, WidgetBuilder, WidgetMessage}, BuildContext, Control, Thickness, UiNode, UserInterface, BRUSH_DARKER, BRUSH_LIGHT, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ ops::{Deref, DerefMut}, @@ -204,6 +205,18 @@ pub struct DropdownList { pub main_grid: InheritableVariable>, } +impl ConstructorProvider for DropdownList { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Dropdown List", |ui| { + DropdownListBuilder::new(WidgetBuilder::new().with_name("Dropdown List")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(DropdownList); uuid_provider!(DropdownList = "1da2f69a-c8b4-4ae2-a2ad-4afe61ee2a32"); diff --git a/fyrox-ui/src/expander.rs b/fyrox-ui/src/expander.rs index 822b57c00..93eb6a565 100644 --- a/fyrox-ui/src/expander.rs +++ b/fyrox-ui/src/expander.rs @@ -36,6 +36,7 @@ use crate::{ }; use fyrox_core::uuid_provider; use fyrox_core::variable::InheritableVariable; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::ops::{Deref, DerefMut}; /// A set messages that can be used to either alternate the state of an [`Expander`] widget, or to listen for @@ -165,6 +166,18 @@ pub struct Expander { pub is_expanded: InheritableVariable, } +impl ConstructorProvider for Expander { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Expander", |ui| { + ExpanderBuilder::new(WidgetBuilder::new().with_name("Expander")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Visual") + } +} + crate::define_widget_deref!(Expander); uuid_provider!(Expander = "24976179-b338-4c55-84c3-72d21663efd2"); diff --git a/fyrox-ui/src/file_browser/mod.rs b/fyrox-ui/src/file_browser/mod.rs index 64852c10f..62730d1dc 100644 --- a/fyrox-ui/src/file_browser/mod.rs +++ b/fyrox-ui/src/file_browser/mod.rs @@ -57,6 +57,7 @@ mod selector; use fyrox_core::parking_lot::Mutex; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use notify::Watcher; pub use selector::*; @@ -153,6 +154,18 @@ pub struct FileBrowser { pub watcher: Option<(notify::RecommendedWatcher, thread::JoinHandle<()>)>, } +impl ConstructorProvider for FileBrowser { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("File Browser", |ui| { + FileBrowserBuilder::new(WidgetBuilder::new().with_name("File Browser")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("File System") + } +} + impl Clone for FileBrowser { fn clone(&self) -> Self { Self { diff --git a/fyrox-ui/src/file_browser/selector.rs b/fyrox-ui/src/file_browser/selector.rs index e037f3eaa..a2af8483b 100644 --- a/fyrox-ui/src/file_browser/selector.rs +++ b/fyrox-ui/src/file_browser/selector.rs @@ -38,6 +38,7 @@ use crate::{ VerticalAlignment, }; use fyrox_core::uuid_provider; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ ops::{Deref, DerefMut}, @@ -72,6 +73,20 @@ pub struct FileSelector { pub cancel: Handle, } +impl ConstructorProvider for FileSelector { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("File Selector", |ui| { + FileSelectorBuilder::new(WindowBuilder::new( + WidgetBuilder::new().with_name("File Selector"), + )) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("File System") + } +} + impl Deref for FileSelector { type Target = Widget; @@ -315,6 +330,18 @@ pub struct FileSelectorField { file_selector: Handle, } +impl ConstructorProvider for FileSelectorField { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("File Selector Field", |ui| { + FileSelectorFieldBuilder::new(WidgetBuilder::new().with_name("File Selector Field")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("File System") + } +} + define_widget_deref!(FileSelectorField); uuid_provider!(FileSelectorField = "2dbda730-8a60-4f62-aee8-2ff0ccd15bf2"); diff --git a/fyrox-ui/src/grid.rs b/fyrox-ui/src/grid.rs index 21a2ff792..c1883637e 100644 --- a/fyrox-ui/src/grid.rs +++ b/fyrox-ui/src/grid.rs @@ -35,6 +35,7 @@ use crate::{ BuildContext, Control, UiNode, UserInterface, }; use core::f32; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::{ cell::RefCell, @@ -261,6 +262,18 @@ pub struct Grid { pub groups: RefCell<[Vec; 4]>, } +impl ConstructorProvider for Grid { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Grid", |ui| { + GridBuilder::new(WidgetBuilder::new().with_name("Grid")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Layout") + } +} + crate::define_widget_deref!(Grid); /// Cell of the grid, that contains additional information for layout purposes. It does not have any diff --git a/fyrox-ui/src/image.rs b/fyrox-ui/src/image.rs index 4025be5cb..1c3c1569f 100644 --- a/fyrox-ui/src/image.rs +++ b/fyrox-ui/src/image.rs @@ -36,6 +36,7 @@ use crate::{ }; use fyrox_core::uuid_provider; use fyrox_core::variable::InheritableVariable; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_resource::untyped::UntypedResource; use std::ops::{Deref, DerefMut}; @@ -190,6 +191,23 @@ pub struct Image { pub checkerboard_background: InheritableVariable, } +impl ConstructorProvider for Image { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Image", |ui| { + ImageBuilder::new( + WidgetBuilder::new() + .with_height(32.0) + .with_width(32.0) + .with_name("Image"), + ) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Visual") + } +} + crate::define_widget_deref!(Image); uuid_provider!(Image = "18e18d0f-cb84-4ac1-8050-3480a2ec3de5"); diff --git a/fyrox-ui/src/inspector/mod.rs b/fyrox-ui/src/inspector/mod.rs index c2fc22581..fc0c80d45 100644 --- a/fyrox-ui/src/inspector/mod.rs +++ b/fyrox-ui/src/inspector/mod.rs @@ -51,6 +51,7 @@ use crate::{ BuildContext, Control, RcUiNodeHandle, Thickness, UiNode, UserInterface, VerticalAlignment, }; use copypasta::ClipboardProvider; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::{BaseSceneGraph, SceneGraph}; use std::{ any::{Any, TypeId}, @@ -481,6 +482,16 @@ pub struct Inspector { pub context: InspectorContext, } +impl ConstructorProvider for Inspector { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::().with_variant("Inspector", |ui| { + InspectorBuilder::new(WidgetBuilder::new().with_name("Inspector")) + .build(&mut ui.build_ctx()) + .into() + }) + } +} + crate::define_widget_deref!(Inspector); impl Inspector { diff --git a/fyrox-ui/src/key.rs b/fyrox-ui/src/key.rs index 2432efef6..f1ad484ef 100644 --- a/fyrox-ui/src/key.rs +++ b/fyrox-ui/src/key.rs @@ -38,6 +38,7 @@ use crate::{ }; use fyrox_core::uuid_provider; use fyrox_core::variable::InheritableVariable; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use serde::{Deserialize, Serialize}; use std::{ fmt::{Display, Formatter}, @@ -183,6 +184,18 @@ pub struct HotKeyEditor { editing: InheritableVariable, } +impl ConstructorProvider for HotKeyEditor { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Hot Key Editor", |ui| { + HotKeyEditorBuilder::new(WidgetBuilder::new().with_name("Hot Key Editor")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + define_widget_deref!(HotKeyEditor); impl HotKeyEditor { @@ -400,6 +413,18 @@ pub struct KeyBindingEditor { editing: InheritableVariable, } +impl ConstructorProvider for KeyBindingEditor { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Key Binding Editor", |ui| { + KeyBindingEditorBuilder::new(WidgetBuilder::new().with_name("Key Binding Editor")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + define_widget_deref!(KeyBindingEditor); impl KeyBindingEditor { diff --git a/fyrox-ui/src/lib.rs b/fyrox-ui/src/lib.rs index 875b7640c..fe946560d 100644 --- a/fyrox-ui/src/lib.rs +++ b/fyrox-ui/src/lib.rs @@ -327,6 +327,7 @@ use fyrox_graph::{ pub use node::*; pub use thickness::*; +use crate::constructor::new_widget_constructor_container; pub use fyrox_animation as generic_animation; use fyrox_core::pool::ErasedHandle; @@ -2942,7 +2943,7 @@ impl UserInterface { ) -> Result { Self::load_from_file_ex( path, - Arc::new(WidgetConstructorContainer::new()), + Arc::new(new_widget_constructor_container()), resource_manager, &FsResourceIo, ) diff --git a/fyrox-ui/src/list_view.rs b/fyrox-ui/src/list_view.rs index 645ce376b..c5a73204e 100644 --- a/fyrox-ui/src/list_view.rs +++ b/fyrox-ui/src/list_view.rs @@ -39,6 +39,7 @@ use crate::{ widget::{Widget, WidgetBuilder, WidgetMessage}, BuildContext, Control, Thickness, UiNode, UserInterface, BRUSH_DARK, BRUSH_LIGHT, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use std::ops::{Deref, DerefMut}; @@ -250,6 +251,18 @@ pub struct ListView { pub scroll_viewer: InheritableVariable>, } +impl ConstructorProvider for ListView { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("List View", |ui| { + ListViewBuilder::new(WidgetBuilder::new().with_name("List View")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(ListView); impl ListView { @@ -321,6 +334,19 @@ pub struct ListViewItem { pub widget: Widget, } +impl ConstructorProvider for ListViewItem { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("List View Item", |ui: &mut UserInterface| { + ui.add_node(UiNode::new(ListViewItem { + widget: WidgetBuilder::new().with_name("List View Item").build(), + })) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(ListViewItem); uuid_provider!(ListViewItem = "02f21415-5843-42f5-a3e4-b4a21e7739ad"); diff --git a/fyrox-ui/src/loader.rs b/fyrox-ui/src/loader.rs index 7175e010a..afe52088c 100644 --- a/fyrox-ui/src/loader.rs +++ b/fyrox-ui/src/loader.rs @@ -20,8 +20,8 @@ //! User Interface loader. +use crate::constructor::new_widget_constructor_container; use crate::{ - constructor::WidgetConstructorContainer, core::{uuid::Uuid, TypeUuidProvider}, UserInterface, }; @@ -53,7 +53,7 @@ impl ResourceLoader for UserInterfaceLoader { let io = io.as_ref(); let ui = UserInterface::load_from_file_ex( &path, - Arc::new(WidgetConstructorContainer::new()), + Arc::new(new_widget_constructor_container()), resource_manager, io, ) diff --git a/fyrox-ui/src/menu.rs b/fyrox-ui/src/menu.rs index 998711cfb..94f900838 100644 --- a/fyrox-ui/src/menu.rs +++ b/fyrox-ui/src/menu.rs @@ -44,6 +44,7 @@ use crate::{ BuildContext, Control, HorizontalAlignment, Orientation, RestrictionEntry, Thickness, UiNode, UserInterface, VerticalAlignment, BRUSH_BRIGHT, BRUSH_BRIGHT_BLUE, BRUSH_PRIMARY, }; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::{BaseSceneGraph, SceneGraph, SceneGraphNode}; use std::any::TypeId; use std::{ @@ -184,6 +185,18 @@ pub struct Menu { items: ItemsContainer, } +impl ConstructorProvider for Menu { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Menu", |ui| { + MenuBuilder::new(WidgetBuilder::new().with_name("Menu")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(Menu); uuid_provider!(Menu = "582a04f3-a7fd-4e70-bbd1-eb95e2275b75"); @@ -395,6 +408,18 @@ pub struct MenuItem { pub arrow: InheritableVariable>, } +impl ConstructorProvider for MenuItem { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Menu Item", |ui| { + MenuItemBuilder::new(WidgetBuilder::new().with_name("Menu Item")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + crate::define_widget_deref!(MenuItem); impl MenuItem { @@ -1084,6 +1109,20 @@ pub struct ContextMenu { pub parent_menu_item: Handle, } +impl ConstructorProvider for ContextMenu { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Context Menu", |ui| { + ContextMenuBuilder::new(PopupBuilder::new( + WidgetBuilder::new().with_name("Context Menu"), + )) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + impl Deref for ContextMenu { type Target = Widget; diff --git a/fyrox-ui/src/messagebox.rs b/fyrox-ui/src/messagebox.rs index 16bb2d966..87c64def3 100644 --- a/fyrox-ui/src/messagebox.rs +++ b/fyrox-ui/src/messagebox.rs @@ -44,6 +44,7 @@ use crate::{ }; use fyrox_core::uuid_provider; use fyrox_core::variable::InheritableVariable; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use std::ops::{Deref, DerefMut}; /// A set of messages that can be used to communicate with message boxes. @@ -189,6 +190,20 @@ pub struct MessageBox { pub text: InheritableVariable>, } +impl ConstructorProvider for MessageBox { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Message Box", |ui| { + MessageBoxBuilder::new(WindowBuilder::new( + WidgetBuilder::new().with_name("Message Box"), + )) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Input") + } +} + impl Deref for MessageBox { type Target = Widget; diff --git a/fyrox-ui/src/nine_patch.rs b/fyrox-ui/src/nine_patch.rs index f93e6b03f..0946a6319 100644 --- a/fyrox-ui/src/nine_patch.rs +++ b/fyrox-ui/src/nine_patch.rs @@ -32,6 +32,7 @@ use crate::{ BuildContext, Control, UiNode, UserInterface, }; use fyrox_core::variable::InheritableVariable; +use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor}; use fyrox_graph::BaseSceneGraph; use fyrox_resource::untyped::UntypedResource; use std::ops::{Deref, DerefMut}; @@ -52,6 +53,18 @@ pub struct NinePatch { pub top_margin_pixel: InheritableVariable, } +impl ConstructorProvider for NinePatch { + fn constructor() -> GraphNodeConstructor { + GraphNodeConstructor::new::() + .with_variant("Nine Patch", |ui| { + NinePatchBuilder::new(WidgetBuilder::new().with_name("Nine Patch")) + .build(&mut ui.build_ctx()) + .into() + }) + .with_group("Visual") + } +} + crate::define_widget_deref!(NinePatch); uuid_provider!(NinePatch = "c345033e-8c10-4186-b101-43f73b85981d"); diff --git a/fyrox-ui/src/node/constructor.rs b/fyrox-ui/src/node/constructor.rs index ead8d0531..6992323a0 100644 --- a/fyrox-ui/src/node/constructor.rs +++ b/fyrox-ui/src/node/constructor.rs @@ -29,7 +29,6 @@ use crate::{ check_box::CheckBox, color::gradient::{ColorGradientEditor, ColorGradientField, ColorPoint}, color::{AlphaBar, ColorField, ColorPicker, HueBar, SaturationBrightnessField}, - core::{parking_lot::Mutex, uuid::Uuid, TypeUuidProvider}, curve::CurveEditor, decorator::Decorator, dock::{DockingManager, Tile}, @@ -66,228 +65,158 @@ use crate::{ vector_image::VectorImage, window::Window, wrap_panel::WrapPanel, - Control, UiNode, + UiNode, UserInterface, }; -use fxhash::FxHashMap; -use fyrox_core::parking_lot::MutexGuard; -use std::any::{Any, TypeId}; +use fyrox_graph::constructor::{GraphNodeConstructor, GraphNodeConstructorContainer}; /// Node constructor. -pub struct WidgetConstructor { - /// A simple type alias for boxed widget constructor. - closure: Box UiNode + Send>, - - /// A name of the assembly this widget constructor belongs to. - pub assembly_name: &'static str, -} +pub type WidgetConstructor = GraphNodeConstructor; /// A special container that is able to create widgets by their type UUID. -pub struct WidgetConstructorContainer { - pub context_type_id: Mutex, - map: Mutex>, -} - -impl Default for WidgetConstructorContainer { - fn default() -> Self { - Self::new() - } -} - -impl WidgetConstructorContainer { - /// Creates default widget constructor container with constructors for built-in widgets. - pub fn new() -> Self { - let container = WidgetConstructorContainer { - context_type_id: Mutex::new(().type_id()), - map: Default::default(), - }; - - container.add::>(); - container.add::>(); - container.add::>(); - container.add::>(); - container.add::>(); - container.add::>(); - container.add::>(); - container.add::>(); - - container.add::(); - container.add::