Compare commits

...

2 commits

Author SHA1 Message Date
492d57b856 Update Rust crate quick-xml to 0.37.0
Some checks failed
Gavania Merge Build / build (pull_request) Has been cancelled
2025-04-17 09:05:14 +00:00
b0a9d66db3 First impl attempt of callback handling 2025-04-17 10:36:25 +02:00
13 changed files with 170 additions and 77 deletions

View file

@ -5,17 +5,20 @@ authors = ["hodasemi <michaelh.95@t-online.de>"]
edition = "2024" edition = "2024"
[dependencies] [dependencies]
quick-xml = "0.31.0" quick-xml = "0.37.0"
serde = { version = "1.0.203", features = ["derive"] } serde = { version = "1.0.203", features = ["derive"] }
serde_json = { version = "1.0.120" } serde_json = { version = "1.0.120" }
paste = "1.0.15" paste = "1.0.15"
anyhow = { version = "1.0.86", features = ["backtrace"] } anyhow = { version = "1.0.86", features = ["backtrace"] }
itertools = "0.14.0"
vulkan-rs = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } vulkan-rs = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }
utilities = { git = "https://gavania.de/hodasemi/utilities.git" } utilities = { git = "https://gavania.de/hodasemi/utilities.git" }
assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }
ecs = { git = "https://gavania.de/hodasemi/ecs.git" } ecs = { git = "https://gavania.de/hodasemi/ecs.git" }
ui_proc_macro = { path = "../ui_proc_macro" }
# optional # optional
audio = { git = "https://gavania.de/hodasemi/audio.git", optional = true } audio = { git = "https://gavania.de/hodasemi/audio.git", optional = true }

View file

@ -203,7 +203,8 @@ impl Functionality for GuiBuilder {
let suffix_less_function_name = handle_function_suffix(function_name); let suffix_less_function_name = handle_function_suffix(function_name);
let button: Arc<Button> = self.element(&suffix_less_function_name)?; let button: Arc<Button> = self.element(&suffix_less_function_name)?;
button.set_callback(callback); todo!()
// button.set_callback(callback);
} }
Ok(()) Ok(())

View file

@ -181,7 +181,8 @@ impl Functionality for GuiSnippet {
let suffix_less_function_name = handle_function_suffix(function_name); let suffix_less_function_name = handle_function_suffix(function_name);
let button: Arc<Button> = self.element(&suffix_less_function_name)?; let button: Arc<Button> = self.element(&suffix_less_function_name)?;
button.set_callback(callback); todo!()
// button.set_callback(callback);
} }
Ok(()) Ok(())

View file

@ -271,9 +271,9 @@ pub struct Button {
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
_hover_sound: Option<Arc<Audible>>, _hover_sound: Option<Arc<Audible>>,
click_executable: Arc<Executable<()>>, pub(crate) click_executable: Arc<Executable<()>>,
select_executable: Arc<Executable<bool>>, pub(crate) select_executable: Arc<Executable<bool>>,
on_select_executable: Arc<Executable<bool>>, pub(crate) on_select_executable: Arc<Executable<bool>>,
normal: FillType, normal: FillType,
selected: FillType, selected: FillType,
@ -313,26 +313,23 @@ impl Button {
self.selectable.select(gui_handler) self.selectable.select(gui_handler)
} }
pub fn set_callback<F>(&self, callback: F) // pub fn set_callback<F>(&self, callback: F)
where // where
F: Fn(&mut Commands, &mut GuiHandler) -> Result<()> + Send + Sync + 'static, // F: Fn(&mut Commands, &mut GuiHandler) -> Result<()> + Send + Sync + 'static,
{ // {
self.click_executable.set_callback( // self.click_executable.set_callback(
move |commands: &mut Commands, gui_handler: &mut GuiHandler, _: ()| { // move |commands: &mut Commands, gui_handler: &mut GuiHandler, _: ()| {
callback(commands, gui_handler) // callback(commands, gui_handler)
}, // },
); // );
} // }
pub fn set_select_callback<F>(&self, callback: F) pub fn set_select_callback<F>(&self, callback: F)
where where
F: Fn(&mut Commands, &mut GuiHandler, bool) -> Result<()> + Send + Sync + 'static, F: Fn(&mut Commands, &mut GuiHandler, bool) -> Result<()> + Send + Sync + 'static,
{ {
self.on_select_executable.set_callback( todo!()
move |commands: &mut Commands, gui_handler: &mut GuiHandler, select: bool| { // self.on_select_executable.set_callback(callback);
callback(commands, gui_handler, select)
},
);
} }
pub fn set_custom_callback<F>(&self, callback: F) pub fn set_custom_callback<F>(&self, callback: F)
@ -593,18 +590,20 @@ impl Button {
fn create_selected_changed_callback(button: Arc<Button>) { fn create_selected_changed_callback(button: Arc<Button>) {
let button_weak = Arc::downgrade(&button); let button_weak = Arc::downgrade(&button);
let selected_changed = let selected_changed = move |_world: &mut World,
move |_commands: &mut Commands, gui_handler: &mut GuiHandler, selected: bool| { _commands: &mut Commands,
if let Some(button) = button_weak.upgrade() { gui_handler: &mut GuiHandler,
if selected { selected: bool| {
button.set_button_state(gui_handler, ButtonState::Selected)?; if let Some(button) = button_weak.upgrade() {
} else { if selected {
button.set_button_state(gui_handler, ButtonState::Normal)?; button.set_button_state(gui_handler, ButtonState::Selected)?;
} } else {
button.set_button_state(gui_handler, ButtonState::Normal)?;
} }
}
Ok(()) Ok(())
}; };
button.select_executable.set_callback(selected_changed); button.select_executable.set_callback(selected_changed);
} }

View file

@ -0,0 +1,22 @@
use anyhow::Result;
use ecs::{resources::Resource as ResourceTrait, *};
use itertools::Itertools;
use ui_proc_macro::implement_callbacks;
use crate::prelude::*;
use std::marker::PhantomData;
pub trait SetCallback<T, R, Func, Filter> {
fn set_callback(&self, func: Func);
}
pub trait SetSelectCallback<T, R, Func, Filter> {
fn set_select_callback(&self, func: Func);
}
pub trait SetCustomCallback<T, R, Func, Filter> {
fn set_custom_callback(&self, func: Func);
}
implement_callbacks!(2, 0);

View file

@ -18,6 +18,7 @@ pub mod ui_element;
pub mod traits; pub mod traits;
mod callback_builder; mod callback_builder;
pub mod callback_impl;
pub mod prelude; pub mod prelude;
mod wrapper; mod wrapper;

View file

@ -101,7 +101,10 @@ impl MultiLineTextFieldBuilder {
multi_line_text_field.text_changed_exec.set_callback({ multi_line_text_field.text_changed_exec.set_callback({
let weak_tf = Arc::downgrade(&multi_line_text_field); let weak_tf = Arc::downgrade(&multi_line_text_field);
move |_commands: &mut Commands, gui_handler: &mut GuiHandler, _text| { move |_world: &mut World,
_commands: &mut Commands,
gui_handler: &mut GuiHandler,
_text| {
if let Some(tf) = weak_tf.upgrade() { if let Some(tf) = weak_tf.upgrade() {
tf.update_text(gui_handler)?; tf.update_text(gui_handler)?;
} }

View file

@ -172,7 +172,8 @@ impl TextField {
where where
F: Fn(&mut Commands, &mut GuiHandler, Option<String>) -> Result<()> + Send + Sync + 'static, F: Fn(&mut Commands, &mut GuiHandler, Option<String>) -> Result<()> + Send + Sync + 'static,
{ {
self.text_changed_executable.set_callback(f); todo!()
// self.text_changed_executable.set_callback(f);
} }
pub fn set_text_color(&self, gui_handler: &mut GuiHandler, text_color: Color) -> Result<()> { pub fn set_text_color(&self, gui_handler: &mut GuiHandler, text_color: Color) -> Result<()> {

View file

@ -9,8 +9,11 @@ use crate::prelude::*;
/// `Executable` holds a closure which can be executed /// `Executable` holds a closure which can be executed
pub struct Executable<I: Send + Sync> { pub struct Executable<I: Send + Sync> {
callback: callback: RwLock<
RwLock<Option<Arc<dyn Fn(&mut Commands, &mut GuiHandler, I) -> Result<()> + Send + Sync>>>, Option<
Arc<dyn Fn(&mut World, &mut Commands, &mut GuiHandler, I) -> Result<()> + Send + Sync>,
>,
>,
} }
impl<I: Send + Sync + 'static> Executable<I> { impl<I: Send + Sync + 'static> Executable<I> {
@ -28,7 +31,7 @@ impl<I: Send + Sync + 'static> Executable<I> {
/// * `callback` is a `Option<Callback>` closure /// * `callback` is a `Option<Callback>` closure
pub fn set_callback<F>(&self, callback: impl Into<Option<F>>) pub fn set_callback<F>(&self, callback: impl Into<Option<F>>)
where where
F: Fn(&mut Commands, &mut GuiHandler, I) -> Result<()> + Send + Sync + 'static, F: Fn(&mut World, &mut Commands, &mut GuiHandler, I) -> Result<()> + Send + Sync + 'static,
{ {
let mut function = self.callback.write().unwrap(); let mut function = self.callback.write().unwrap();
@ -43,8 +46,8 @@ impl<I: Send + Sync + 'static> Executable<I> {
if let Some(callback) = self.callback.read().unwrap().as_ref() { if let Some(callback) = self.callback.read().unwrap().as_ref() {
let callback = callback.clone(); let callback = callback.clone();
gui_handler.add_callback(move |commands, gui_handler| { gui_handler.add_callback(move |world, commands, gui_handler| {
(callback)(commands, gui_handler, input) (callback)(world, commands, gui_handler, input)
}); });
} }

View file

@ -245,7 +245,9 @@ pub struct GuiHandler {
text_sample_count: VkSampleCountFlags, text_sample_count: VkSampleCountFlags,
callback_list: Vec<Box<dyn FnOnce(&mut Commands, &mut GuiHandler) -> Result<()> + Send + Sync>>, callback_list: Vec<
Box<dyn FnOnce(&mut World, &mut Commands, &mut GuiHandler) -> Result<()> + Send + Sync>,
>,
} }
impl GuiHandler { impl GuiHandler {
@ -927,7 +929,7 @@ impl GuiHandler {
} }
pub(crate) fn add_callback< pub(crate) fn add_callback<
F: FnOnce(&mut Commands, &mut GuiHandler) -> Result<()> + Send + Sync + 'static, F: FnOnce(&mut World, &mut Commands, &mut GuiHandler) -> Result<()> + Send + Sync + 'static,
>( >(
&mut self, &mut self,
f: F, f: F,
@ -935,12 +937,17 @@ impl GuiHandler {
self.callback_list.push(Box::new(f)); self.callback_list.push(Box::new(f));
} }
pub fn process_callbacks(&mut self, commands: &mut Commands) -> Result<()> { pub fn process_callbacks(&mut self, world: &mut World) -> Result<()> {
let callbacks = mem::take(&mut self.callback_list); let callbacks = mem::take(&mut self.callback_list);
let mut commands = Commands::new(world.now());
callbacks callbacks
.into_iter() .into_iter()
.try_for_each(|callback| callback(commands, self)) .try_for_each(|callback| callback(world, &mut commands, self))?;
commands.apply_deferred(world);
Ok(())
} }
fn render( fn render(

View file

@ -376,19 +376,20 @@ impl Keyboard {
let weak_textfield = Arc::downgrade(&textfield); let weak_textfield = Arc::downgrade(&textfield);
let weak_button = Arc::downgrade(&button_ref); let weak_button = Arc::downgrade(&button_ref);
button_ref.set_callback(Box::new( todo!();
move |_commands: &mut Commands, gui_handler: &mut GuiHandler| { // button_ref.set_callback(Box::new(
if let Some(textfield) = weak_textfield.upgrade() { // move |_world: &mut World, _commands: &mut Commands, gui_handler: &mut GuiHandler| {
if let Some(button) = weak_button.upgrade() { // if let Some(textfield) = weak_textfield.upgrade() {
if let Some(text) = button.text()? { // if let Some(button) = weak_button.upgrade() {
textfield.add_letter(gui_handler, text.as_bytes()[0] as char)?; // if let Some(text) = button.text()? {
} // textfield.add_letter(gui_handler, text.as_bytes()[0] as char)?;
} // }
} // }
// }
Ok(()) // Ok(())
}, // },
)); // ));
Ok(()) Ok(())
} }

View file

@ -3,9 +3,8 @@ mod update;
use update::update; use update::update;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote;
use syn::{ use syn::{
DeriveInput, LitInt, Result, LitInt, Result,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
parse_macro_input, parse_macro_input,
token::Comma, token::Comma,
@ -30,7 +29,7 @@ impl Parse for UpdateInfo {
} }
#[proc_macro] #[proc_macro]
pub fn implement_updates(input: TokenStream) -> TokenStream { pub fn implement_callbacks(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as UpdateInfo); let input = parse_macro_input!(input as UpdateInfo);
update(input.max_components, input.max_resources) update(input.max_components, input.max_resources)

View file

@ -1,4 +1,6 @@
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use update_macro_base::*; use update_macro_base::*;
fn resource_only_events_and_systems(update: &Update) -> TokenStream2 { fn resource_only_events_and_systems(update: &Update) -> TokenStream2 {
@ -11,7 +13,7 @@ fn resource_only_events_and_systems(update: &Update) -> TokenStream2 {
let resource_store = &resource_tokens.resource_store; let resource_store = &resource_tokens.resource_store;
let resource_idents = &resource_tokens.resource_idents; let resource_idents = &resource_tokens.resource_idents;
todo!() quote! {}
} }
fn events_and_systems(update: &Update) -> TokenStream2 { fn events_and_systems(update: &Update) -> TokenStream2 {
@ -40,29 +42,77 @@ fn events_and_systems(update: &Update) -> TokenStream2 {
let resource_store = &resource_tokens.resource_store; let resource_store = &resource_tokens.resource_store;
let resource_idents = &resource_tokens.resource_idents; let resource_idents = &resource_tokens.resource_idents;
todo!() quote! {
impl<Func, #filter_type_impls #query_type_impls #resource_type_impls> SetCallback<#query_types, #resource_types, Func, #filter_types> for Button
where
Func: Fn(&mut Commands, &mut GuiHandler, #( #queries, )* #resources ) -> Result<()> + Send + Sync + 'static,
#filter_requirements
#component_requirements
#resource_requirement
{
fn set_callback(&self, func: Func) {
#( #verify_dedup )*
self.click_executable.set_callback(
move |world: &mut World, commands: &mut Commands, gui_handler: &mut GuiHandler, _: ()| -> Result<()> {
let mut complying_entities: Vec<Vec<&EntityObject>> = vec![Vec::new(); #query_count];
for entity in unsafe { utilities::prelude::remove_life_time(world).entities() } {
let mut comply_queries = Vec::new();
#( #check_entities )*
if !comply_queries.is_empty() {
comply_queries
.into_iter()
.for_each(|q| complying_entities[q].push(entity));
}
}
// check if one of the queries could not be fullfilled
for queryable_entities in complying_entities.iter() {
if queryable_entities.is_empty() {
return Ok(());
}
}
#resource_store
for entities in complying_entities.into_iter().multi_cartesian_product() {
#( #component_stores )*
#( #query_structs )*
func(commands, gui_handler, #( #query_idents, )* #( #resource_idents, )*)?;
}
Ok(())
}
)
}
}
}
} }
fn update(max_components: usize, max_resources: usize) -> TokenStream2 { pub fn update(max_components: usize, max_resources: usize) -> TokenStream {
let mut queries: Vec<Vec<usize>> = Vec::new(); let mut queries: Vec<Vec<usize>> = Vec::new();
for c in Update::MIN_COMPONENTS..=max_components { for c in Update::MIN_COMPONENTS..=max_components {
queries.push(vec![c]); queries.push(vec![c]);
} }
for x in Update::MIN_COMPONENTS..=max_components { // for x in Update::MIN_COMPONENTS..=max_components {
for y in Update::MIN_COMPONENTS..=max_components { // for y in Update::MIN_COMPONENTS..=max_components {
queries.push(vec![x, y]); // queries.push(vec![x, y]);
} // }
} // }
for x in Update::MIN_COMPONENTS..=max_components { // for x in Update::MIN_COMPONENTS..=max_components {
for y in Update::MIN_COMPONENTS..=max_components { // for y in Update::MIN_COMPONENTS..=max_components {
for z in Update::MIN_COMPONENTS..=max_components { // for z in Update::MIN_COMPONENTS..=max_components {
queries.push(vec![x, y, z]); // queries.push(vec![x, y, z]);
} // }
} // }
} // }
let mut resources = Vec::new(); let mut resources = Vec::new();
@ -90,16 +140,18 @@ fn update(max_components: usize, max_resources: usize) -> TokenStream2 {
events.push(q); events.push(q);
} }
// updates.push(Update::new(vec![1].into_iter(), 0)); // updates.push(events_and_systems(&Update::new(vec![2].into_iter(), 0)));
// let q = quote! { // let q = quote! {
// #( #updates )* // #( #updates )*
// }; // };
// panic!("{q}"); let q = quote! {
TokenStream::from(quote! {
#( #updates )* #( #updates )*
#( #events )* #( #events )*
}) };
panic!("{q}");
TokenStream::from(q)
} }