From f7c60f8ed9167c131493c2023e11ca6224bf7ea7 Mon Sep 17 00:00:00 2001 From: StarArawn <toasterthegamer@gmail.com> Date: Mon, 13 Dec 2021 09:46:02 -0500 Subject: [PATCH] Global bindings. --- Cargo.lock | 6 +-- examples/global_counter.rs | 90 ++++++++++++++++++++++++++++++++++++++ kayak_core/Cargo.toml | 2 +- kayak_core/src/context.rs | 42 ++++++++++++++++++ 4 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 examples/global_counter.rs diff --git a/Cargo.lock b/Cargo.lock index e220fcd..0298c92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1482,13 +1482,13 @@ checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e" [[package]] name = "flo_binding" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711a65cd60b91114a1cecbf6a9d533c3fde6e38532506cde25bc5f7bc87d2fa0" +version = "2.0.2" +source = "git+https://github.com/StarArawn/flo_binding.git?rev=609883068c43dc897da2b277e91320a41892643d#609883068c43dc897da2b277e91320a41892643d" dependencies = [ "desync", "flo_rope", "futures", + "uuid", ] [[package]] diff --git a/examples/global_counter.rs b/examples/global_counter.rs new file mode 100644 index 0000000..7c12559 --- /dev/null +++ b/examples/global_counter.rs @@ -0,0 +1,90 @@ +use bevy::{ + math::Vec2, + prelude::{App as BevyApp, AssetServer, Commands, Res, ResMut, World}, + window::{WindowDescriptor, Windows}, + PipelinedDefaultPlugins, +}; +use bevy_kayak_ui::{BevyContext, BevyKayakUIPlugin, FontMapping, UICameraBundle}; +use kayak_components::{Text, Window}; +use kayak_core::{bind, Binding, Bound, Index, MutableBound}; +use kayak_ui::components::App; +use kayak_ui::core::{rsx, widget}; + +#[derive(Clone, PartialEq)] +struct GlobalCount(pub u32); + +#[widget] +fn Counter(context: &mut KayakContext) { + let global_count = { + if let Ok(world) = context.get_global_state::<World>() { + if let Some(global_count) = world.get_resource::<Binding<GlobalCount>>() { + global_count.clone() + } else { + return; + } + } else { + return; + } + }; + + context.bind(&global_count); + + let global_count = global_count.get().0; + + rsx! { + <> + <Window position={(50.0, 50.0)} size={(300.0, 300.0)} title={"Counter Example".to_string()}> + <Text size={32.0} content={format!("Current Count: {}", global_count).to_string()}>{}</Text> + </Window> + </> + } +} + +fn startup( + mut commands: Commands, + windows: Res<Windows>, + mut font_mapping: ResMut<FontMapping>, + asset_server: Res<AssetServer>, +) { + commands.spawn_bundle(UICameraBundle::new()); + + font_mapping.add(asset_server.load("roboto.kayak_font")); + + let window_size = if let Some(window) = windows.get_primary() { + Vec2::new(window.width(), window.height()) + } else { + panic!("Couldn't find primary window!"); + }; + + commands.insert_resource(bind(GlobalCount(0))); + + let context = BevyContext::new(window_size.x, window_size.y, |styles, context| { + // Hack to trick the proc macro for right now.. + let parent_id: Option<Index> = None; + rsx! { + <App styles={Some(styles.clone())}> + <Counter /> + </App> + } + }); + commands.insert_resource(context); +} + +fn count_up(global_count: Res<Binding<GlobalCount>>) { + global_count.set(GlobalCount(global_count.get().0 + 1)); +} + +fn main() { + BevyApp::new() + .insert_resource(WindowDescriptor { + width: 1270.0, + height: 720.0, + title: String::from("UI Example"), + ..Default::default() + }) + .add_plugins(PipelinedDefaultPlugins) + .add_plugin(BevyKayakUIPlugin) + .add_startup_system(startup) + .add_system(count_up) + .run(); +} diff --git a/kayak_core/Cargo.toml b/kayak_core/Cargo.toml index 10e71da..4a5cc1a 100644 --- a/kayak_core/Cargo.toml +++ b/kayak_core/Cargo.toml @@ -10,7 +10,7 @@ as-any = "0.2" dashmap = "4.0" diff-struct = "0.3" derivative = "2.2" -flo_binding = "2.0.1" +flo_binding = { git = "https://github.com/StarArawn/flo_binding.git", rev = "609883068c43dc897da2b277e91320a41892643d" } fontdue = "0.6" kayak_render_macros = { path = "../kayak_render_macros" } morphorm = { git = "https://github.com/geom3trik/morphorm" } diff --git a/kayak_core/src/context.rs b/kayak_core/src/context.rs index 582f365..b2a60ca 100644 --- a/kayak_core/src/context.rs +++ b/kayak_core/src/context.rs @@ -5,6 +5,7 @@ use crate::{node::NodeIndex, widget_manager::WidgetManager, Event, EventType, In pub struct KayakContext { component_states: HashMap<crate::Index, resources::Resources>, + global_bindings: HashMap<crate::Index, Vec<flo_binding::Uuid>>, // component_state_lifetimes: DashMap<crate::Index, Vec<Box<dyn crate::Releasable>>>, current_id: Index, pub widget_manager: WidgetManager, @@ -25,6 +26,7 @@ impl KayakContext { pub fn new() -> Self { Self { component_states: HashMap::new(), + global_bindings: HashMap::new(), // component_state_lifetimes: DashMap::new(), current_id: crate::Index::default(), widget_manager: WidgetManager::new(), @@ -34,6 +36,46 @@ impl KayakContext { } } + /// Binds some global state to the current widget. + pub fn bind<T: Clone + PartialEq + Send + 'static>( + &mut self, + global_state: &crate::Binding<T>, + ) { + if !self.global_bindings.contains_key(&self.current_id) { + self.global_bindings.insert(self.current_id, vec![]); + } + + let global_binding_ids = self.global_bindings.get_mut(&self.current_id).unwrap(); + + if !global_binding_ids.contains(&global_state.id) { + let cloned_id = self.current_id; + let dirty_nodes = self.widget_manager.dirty_nodes.clone(); + let mut lifetime = global_state.when_changed(crate::notify(move || { + if let Ok(mut dirty_nodes) = dirty_nodes.lock() { + dirty_nodes.insert(cloned_id); + } + })); + // TODO: Figure out how to store this so we can drop the lifetime on unbind. + lifetime.keep_alive(); + global_binding_ids.push(global_state.id); + } + } + + pub fn unbind<T: Clone + PartialEq + Send + 'static>( + &mut self, + global_state: &crate::Binding<T>, + ) { + if self.global_bindings.contains_key(&self.current_id) { + let global_binding_ids = self.global_bindings.get_mut(&self.current_id).unwrap(); + if let Some(index) = global_binding_ids + .iter() + .position(|id| *id == global_state.id) + { + global_binding_ids.remove(index); + } + } + } + pub fn set_current_id(&mut self, id: crate::Index) { self.current_id = id; } -- GitLab