Start of custom elements

This commit is contained in:
JMS55 2023-12-18 21:24:06 -08:00
parent 9d5b0408c0
commit d8a08b56cc
7 changed files with 106 additions and 31 deletions

1
Cargo.lock generated
View file

@ -1631,7 +1631,6 @@ dependencies = [
"dioxus-core-macro", "dioxus-core-macro",
"dioxus-hooks", "dioxus-hooks",
"dioxus-hot-reload", "dioxus-hot-reload",
"dioxus-html",
"dioxus-rsx", "dioxus-rsx",
] ]

View file

@ -5,7 +5,11 @@ edition = "2021"
[dependencies] [dependencies]
bevy = { git = "https://github.com/JMS55/bevy", branch = "query_new_12" } bevy = { git = "https://github.com/JMS55/bevy", branch = "query_new_12" }
dioxus = "0.4" dioxus = { version = "0.4", default-features = false, features = [
"macro",
"hooks",
"hot-reload",
] }
bevy_mod_picking = { version = "0.17", default-features = false, features = [ bevy_mod_picking = { version = "0.17", default-features = false, features = [
"backend_bevy_ui", "backend_bevy_ui",
] } ] }

View file

@ -6,10 +6,8 @@ use bevy::{
ui::{node_bundles::NodeBundle, Node}, ui::{node_bundles::NodeBundle, Node},
DefaultPlugins, DefaultPlugins,
}; };
use bevy_dioxus::{ use bevy_dioxus::{colors::*, prelude::*};
bevy_mod_picking::DefaultPickingPlugins, colors::*, dioxus::prelude::*, hooks::*, use bevy_mod_picking::DefaultPickingPlugins;
DioxusUiBundle, DioxusUiPlugin, DioxusUiRoot,
};
fn main() { fn main() {
App::new() App::new()
@ -30,7 +28,7 @@ fn Editor(cx: Scope) -> Element {
let selected_entity = use_state(cx, || Option::<Entity>::None); let selected_entity = use_state(cx, || Option::<Entity>::None);
render! { render! {
div { node {
width: "100vw", width: "100vw",
height: "100vh", height: "100vh",
justify_content: "space-between", justify_content: "space-between",
@ -52,7 +50,7 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> El
}); });
render! { render! {
div { node {
onclick: move |_| selected_entity.set(None), onclick: move |_| selected_entity.set(None),
flex_direction: "column", flex_direction: "column",
if entities.is_empty() { if entities.is_empty() {
@ -60,7 +58,7 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> El
} else { } else {
rsx! { rsx! {
for (entity, name) in entities { for (entity, name) in entities {
div { node {
onclick: move |_| { onclick: move |_| {
if Some(entity) == ***selected_entity { if Some(entity) == ***selected_entity {
selected_entity.set(None); selected_entity.set(None);
@ -78,7 +76,7 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> El
} }
} }
} }
div { node {
onclick: move |_| spawn_entity(), onclick: move |_| spawn_entity(),
padding: "8", padding: "8",
background_color: NEUTRAL_800, background_color: NEUTRAL_800,
@ -117,14 +115,14 @@ fn EntityInspector<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>)
} }
} else { } else {
rsx! { rsx! {
div { node {
flex_direction: "column", flex_direction: "column",
for (name, _component_id, _type_id, _size) in components { for (name, _component_id, _type_id, _size) in components {
div { node {
padding: "8", padding: "8",
background_color: NEUTRAL_800, background_color: NEUTRAL_800,
div { node {
"Component: {name}" "Component: {name}"
} }
} }

View file

@ -221,21 +221,14 @@ impl BevyTemplateNode {
fn from_dioxus(node: &TemplateNode) -> Self { fn from_dioxus(node: &TemplateNode) -> Self {
match node { match node {
TemplateNode::Element { TemplateNode::Element {
tag, tag: "node",
namespace: _, namespace: Some("bevy_ui"),
attrs, attrs,
children, children,
} => { } => Self::Node {
if *tag != "div" { style: parse_style_attributes(attrs),
panic!( children: children.iter().map(Self::from_dioxus).collect(),
"Encountered unsupported bevy_dioxus tag `{tag}`. Only `div` is supported." },
);
}
Self::Node {
style: parse_style_attributes(attrs),
children: children.iter().map(Self::from_dioxus).collect(),
}
}
TemplateNode::Text { text } => { TemplateNode::Text { text } => {
Self::TextNode(Text::from_section(*text, TextStyle::default())) Self::TextNode(Text::from_section(*text, TextStyle::default()))
} }
@ -246,6 +239,20 @@ impl BevyTemplateNode {
TemplateNode::DynamicText { id: _ } => { TemplateNode::DynamicText { id: _ } => {
Self::TextNode(Text::from_section("", TextStyle::default())) Self::TextNode(Text::from_section("", TextStyle::default()))
} }
TemplateNode::Element {
tag,
namespace: None,
..
} => {
panic!("Encountered unsupported bevy_dioxus tag `{tag}`.")
}
TemplateNode::Element {
tag,
namespace: Some(namespace),
..
} => {
panic!("Encountered unsupported bevy_dioxus tag `{namespace}::{tag}`.")
}
} }
} }

20
src/elements.rs Normal file
View file

@ -0,0 +1,20 @@
#[allow(non_camel_case_types, non_upper_case_globals)]
pub mod dioxus_elements {
pub use crate::events::events;
pub type AttributeDescription = (&'static str, Option<&'static str>, bool);
pub struct node;
impl node {
pub const TAG_NAME: &'static str = "node";
pub const NAME_SPACE: Option<&'static str> = Some("bevy_ui");
// TODO: The rest of Style
pub const width: AttributeDescription = ("width", None, false);
pub const height: AttributeDescription = ("height", None, false);
pub const justify_content: AttributeDescription = ("justify-content", None, false);
pub const flex_direction: AttributeDescription = ("flex-direction", None, false);
pub const padding: AttributeDescription = ("padding", None, false);
pub const background_color: AttributeDescription = ("background-color", None, false);
}
}

View file

@ -4,7 +4,7 @@ use bevy::ecs::{
system::Resource, system::Resource,
}; };
use bevy_mod_picking::events::{Click, Pointer}; use bevy_mod_picking::events::{Click, Pointer};
use dioxus::html::MouseData; use dioxus::core::ScopeState;
use std::{any::Any, rc::Rc}; use std::{any::Any, rc::Rc};
// TODO: Other events // TODO: Other events
@ -22,7 +22,7 @@ impl EventReaders {
let mut events: Vec<(Entity, &'static str, Rc<dyn Any>)> = Vec::new(); let mut events: Vec<(Entity, &'static str, Rc<dyn Any>)> = Vec::new();
for event in self.clicks.read(clicks) { for event in self.clicks.read(clicks) {
events.push((event.target, "click", Rc::new(MouseData::default()))); events.push((event.target, "click", Rc::new(())));
} }
events events
@ -32,3 +32,43 @@ impl EventReaders {
pub fn is_supported_event(event: &str) -> bool { pub fn is_supported_event(event: &str) -> bool {
event == "click" event == "click"
} }
pub mod events {
super::impl_event! [
();
onclick
];
}
pub trait EventReturn<P>: Sized {
fn spawn(self, _cx: &ScopeState) {}
}
impl EventReturn<()> for () {}
macro_rules! impl_event {
(
$data:ty;
$(
$( #[$attr:meta] )*
$name:ident
)*
) => {
$(
$( #[$attr] )*
#[inline]
pub fn $name<'a, E: crate::events::EventReturn<T>, T>(_cx: &'a dioxus::core::ScopeState, mut _f: impl FnMut(dioxus::core::Event<$data>) -> E + 'a) -> dioxus::core::Attribute<'a> {
dioxus::core::Attribute::new(
stringify!($name),
_cx.listener(move |e: dioxus::core::Event<$data>| {
_f(e).spawn(_cx);
}),
None,
false,
)
}
)*
};
}
pub(self) use impl_event;

View file

@ -1,8 +1,10 @@
mod apply_mutations; mod apply_mutations;
pub mod colors; pub mod colors;
mod deferred_system; mod deferred_system;
mod elements;
#[macro_use]
mod events; mod events;
pub mod hooks; mod hooks;
mod tick; mod tick;
use self::{ use self::{
@ -18,8 +20,13 @@ use bevy::{
}; };
use dioxus::core::{Element, ElementId, Scope, VirtualDom}; use dioxus::core::{Element, ElementId, Scope, VirtualDom};
pub use bevy_mod_picking; pub mod prelude {
pub use dioxus; pub use super::elements::*;
pub use super::hooks::*;
pub use super::{DioxusUiBundle, DioxusUiPlugin, DioxusUiRoot};
pub use dioxus;
pub use dioxus::prelude::*;
}
pub struct DioxusUiPlugin; pub struct DioxusUiPlugin;