Compare commits

...

5 commits

Author SHA1 Message Date
87893d2973 Update Rust crate quick-xml to 0.37.0
Some checks failed
Gavania Merge Build / build (pull_request) Failing after 2m18s
2025-03-04 15:05:35 +00:00
d4997dff39 improve click callback builder 2025-03-04 16:03:57 +01:00
Michael Hübner
22994c97f6 Remove double ref 2025-03-04 14:55:30 +01:00
Michael Hübner
c8b0c46d0e Fix audio feature 2025-03-04 14:37:56 +01:00
Michael Hübner
b09ec887ab Finish un-arc-ing GuiHandler 2025-03-04 14:25:35 +01:00
14 changed files with 234 additions and 184 deletions

View file

@ -5,7 +5,7 @@ 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"

View file

@ -1,12 +1,12 @@
use crate::prelude::*; use crate::prelude::*;
use anyhow::{bail, Context, Result}; use anyhow::{Context, Result, bail};
use assetpath::AssetPath; use assetpath::AssetPath;
use super::validator::buttoninfo::{NeighbourDirection, NeighbourInfo}; use super::validator::buttoninfo::{NeighbourDirection, NeighbourInfo};
use super::validator::gridinfo::GridInfo; use super::validator::gridinfo::GridInfo;
use super::validator::uiinfoelement::UiInfoElement; use super::validator::uiinfoelement::UiInfoElement;
use super::validator::validator::{handle_function_suffix, Validator}; use super::validator::validator::{Validator, handle_function_suffix};
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
@ -22,7 +22,7 @@ pub struct GuiBuilder {
} }
impl GuiBuilder { impl GuiBuilder {
pub fn new(gui_handler: &Arc<GuiHandler>, path: &AssetPath) -> Result<Arc<Self>> { pub fn new(gui_handler: &mut GuiHandler, path: &AssetPath) -> Result<Arc<Self>> {
let validator = Validator::new( let validator = Validator::new(
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
gui_handler, gui_handler,
@ -35,7 +35,7 @@ impl GuiBuilder {
)?)) )?))
} }
pub fn from_str(gui_handler: &Arc<GuiHandler>, s: &str) -> Result<Arc<Self>> { pub fn from_str(gui_handler: &mut GuiHandler, s: &str) -> Result<Arc<Self>> {
let validator = Validator::from_str( let validator = Validator::from_str(
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
gui_handler, gui_handler,
@ -46,7 +46,7 @@ impl GuiBuilder {
} }
pub fn merge<'a>( pub fn merge<'a>(
gui_handler: &Arc<GuiHandler>, gui_handler: &mut GuiHandler,
pathes: impl IntoIterator<Item = &'a AssetPath>, pathes: impl IntoIterator<Item = &'a AssetPath>,
) -> Result<Arc<Self>> { ) -> Result<Arc<Self>> {
let mut me = Self { let mut me = Self {
@ -85,7 +85,7 @@ impl GuiBuilder {
} }
#[inline] #[inline]
fn _new(gui_handler: &Arc<GuiHandler>, validator: Validator) -> Result<Self> { fn _new(gui_handler: &mut GuiHandler, validator: Validator) -> Result<Self> {
let root = validator.root(); let root = validator.root();
let mut ids = HashMap::new(); let mut ids = HashMap::new();
@ -178,7 +178,10 @@ impl GuiBuilder {
impl Functionality for GuiBuilder { impl Functionality for GuiBuilder {
fn set_click_callbacks( fn set_click_callbacks(
&self, &self,
functions: Vec<(&str, Box<dyn Fn() -> Result<()> + Send + Sync>)>, functions: Vec<(
&str,
Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
)>,
) -> Result<()> { ) -> Result<()> {
for (function_name, callback) in functions { for (function_name, callback) in functions {
let suffix_less_function_name = handle_function_suffix(function_name); let suffix_less_function_name = handle_function_suffix(function_name);
@ -235,9 +238,9 @@ impl Visibility for GuiBuilder {
.unwrap_or(false) .unwrap_or(false)
} }
fn set_visibility(&self, visibility: bool) -> Result<()> { fn set_visibility(&self, gui_handler: &mut GuiHandler, visibility: bool) -> Result<()> {
for grid in &self.grids { for grid in &self.grids {
grid.set_visibility(visibility)?; grid.set_visibility(gui_handler, visibility)?;
} }
Ok(()) Ok(())
@ -259,7 +262,7 @@ impl GuiElementTraits for GuiBuilder {
} }
impl TopGui for GuiBuilder { impl TopGui for GuiBuilder {
fn decline(&self) -> Result<()> { fn decline(&self, _gui_handler: &mut GuiHandler) -> Result<()> {
if let Some(decline_callback) = self.decline_callback.read().unwrap().as_ref() { if let Some(decline_callback) = self.decline_callback.read().unwrap().as_ref() {
decline_callback()?; decline_callback()?;
} }
@ -267,11 +270,11 @@ impl TopGui for GuiBuilder {
Ok(()) Ok(())
} }
fn next_tab(&self, _: bool) -> Result<()> { fn next_tab(&self, _gui_handler: &mut GuiHandler, _: bool) -> Result<()> {
Ok(()) Ok(())
} }
fn previous_tab(&self, _: bool) -> Result<()> { fn previous_tab(&self, _gui_handler: &mut GuiHandler, _: bool) -> Result<()> {
Ok(()) Ok(())
} }
} }
@ -293,18 +296,18 @@ impl TopLevelGui for GuiBuilder {
Some(self) Some(self)
} }
fn enable(&self) -> Result<()> { fn enable(&self, gui_handler: &mut GuiHandler) -> Result<()> {
self.set_visibility(true)?; self.set_visibility(gui_handler, true)?;
if let Some(button) = &self.default_select { if let Some(button) = &self.default_select {
Button::select(button)?; button.select(gui_handler)?;
} }
Ok(()) Ok(())
} }
fn disable(&self) -> Result<()> { fn disable(&self, gui_handler: &mut GuiHandler) -> Result<()> {
self.set_visibility(false)?; self.set_visibility(gui_handler, false)?;
Ok(()) Ok(())
} }
@ -332,7 +335,7 @@ impl_element!(MultiLineTextField);
// private // private
impl GuiBuilder { impl GuiBuilder {
fn create_tree( fn create_tree(
gui_handler: &Arc<GuiHandler>, gui_handler: &mut GuiHandler,
ids: &mut HashMap<String, UiElement>, ids: &mut HashMap<String, UiElement>,
root_grid_info: &Arc<GridInfo>, root_grid_info: &Arc<GridInfo>,
default_button: &mut Option<Arc<Button>>, default_button: &mut Option<Arc<Button>>,
@ -340,7 +343,7 @@ impl GuiBuilder {
(reference_width, reference_height): (Option<u32>, Option<u32>), (reference_width, reference_height): (Option<u32>, Option<u32>),
layer: i32, layer: i32,
) -> Result<Arc<Grid>> { ) -> Result<Arc<Grid>> {
let root_grid = Grid::try_from(root_grid_info, gui_handler, true)?; let root_grid = Grid::try_from(gui_handler, root_grid_info, true)?;
let root_layer = root_grid_info.layer.unwrap_or(layer); let root_layer = root_grid_info.layer.unwrap_or(layer);
root_grid.set_layer(root_layer)?; root_grid.set_layer(root_layer)?;
@ -348,11 +351,12 @@ impl GuiBuilder {
if let Some(ref_height) = reference_height { if let Some(ref_height) = reference_height {
root_grid root_grid
.framable .framable
.set_reference_size(ref_width, ref_height)?; .set_reference_size(gui_handler, ref_width, ref_height)?;
} }
} }
root_grid.set_frame( root_grid.set_frame(
gui_handler,
root_grid_info root_grid_info
.x_offset .x_offset
.get() .get()
@ -397,7 +401,7 @@ impl GuiBuilder {
} }
fn create_child( fn create_child(
gui_handler: &Arc<GuiHandler>, gui_handler: &mut GuiHandler,
child: &UiInfoElement, child: &UiInfoElement,
grid: &Grid, grid: &Grid,
ids: &mut HashMap<String, UiElement>, ids: &mut HashMap<String, UiElement>,
@ -407,11 +411,12 @@ impl GuiBuilder {
) -> Result<()> { ) -> Result<()> {
match child { match child {
UiInfoElement::Button(button_info) => { UiInfoElement::Button(button_info) => {
let button = Button::try_from(button_info, gui_handler)?; let button = Button::try_from(gui_handler, button_info)?;
Self::insert_id(ids, &button_info.id, &button)?; Self::insert_id(ids, &button_info.id, &button)?;
grid.attach( grid.attach(
gui_handler,
button.clone(), button.clone(),
button_info button_info
.x_slot .x_slot
@ -434,7 +439,7 @@ impl GuiBuilder {
Some(_) => { Some(_) => {
return Err(anyhow::Error::msg( return Err(anyhow::Error::msg(
"It is not allowed to select multiple UI elements", "It is not allowed to select multiple UI elements",
)) ));
} }
None => *default_button = Some(button.clone()), None => *default_button = Some(button.clone()),
} }
@ -446,6 +451,7 @@ impl GuiBuilder {
Self::insert_id(ids, &label_info.id, &label)?; Self::insert_id(ids, &label_info.id, &label)?;
grid.attach( grid.attach(
gui_handler,
label.clone(), label.clone(),
label_info.x_slot.get().with_context(|| "x_slot of label")?, label_info.x_slot.get().with_context(|| "x_slot of label")?,
label_info.y_slot.get().with_context(|| "y_slot of label")?, label_info.y_slot.get().with_context(|| "y_slot of label")?,
@ -462,6 +468,7 @@ impl GuiBuilder {
GuiBuilder::insert_id(ids, &multi_line_label_info.id, &multi_line_label)?; GuiBuilder::insert_id(ids, &multi_line_label_info.id, &multi_line_label)?;
grid.attach( grid.attach(
gui_handler,
multi_line_label.clone(), multi_line_label.clone(),
multi_line_label_info multi_line_label_info
.x_slot .x_slot
@ -484,6 +491,7 @@ impl GuiBuilder {
GuiBuilder::insert_id(ids, &multi_line_text_field_info.id, &multi_line_text_field)?; GuiBuilder::insert_id(ids, &multi_line_text_field_info.id, &multi_line_text_field)?;
grid.attach( grid.attach(
gui_handler,
multi_line_text_field.clone(), multi_line_text_field.clone(),
multi_line_text_field_info multi_line_text_field_info
.x_slot .x_slot
@ -505,6 +513,7 @@ impl GuiBuilder {
Self::insert_id(ids, &text_field_info.id, &text_field)?; Self::insert_id(ids, &text_field_info.id, &text_field)?;
grid.attach( grid.attach(
gui_handler,
text_field.clone(), text_field.clone(),
text_field_info text_field_info
.x_slot .x_slot
@ -526,6 +535,7 @@ impl GuiBuilder {
Self::insert_id(ids, &icon_info.id, UiElement::Icon(Arc::downgrade(&icon)))?; Self::insert_id(ids, &icon_info.id, UiElement::Icon(Arc::downgrade(&icon)))?;
grid.attach( grid.attach(
gui_handler,
icon.clone(), icon.clone(),
icon_info.x_slot.get().with_context(|| "x_slot of icon")?, icon_info.x_slot.get().with_context(|| "x_slot of icon")?,
icon_info.y_slot.get().with_context(|| "y_slot of icon")?, icon_info.y_slot.get().with_context(|| "y_slot of icon")?,
@ -541,6 +551,7 @@ impl GuiBuilder {
Self::insert_id(ids, &progress_bar_info.id, &progress_bar)?; Self::insert_id(ids, &progress_bar_info.id, &progress_bar)?;
grid.attach( grid.attach(
gui_handler,
progress_bar.clone(), progress_bar.clone(),
progress_bar_info progress_bar_info
.x_slot .x_slot
@ -557,11 +568,12 @@ impl GuiBuilder {
progress_bar.set_layer(layer)?; progress_bar.set_layer(layer)?;
} }
UiInfoElement::Grid(grid_info) => { UiInfoElement::Grid(grid_info) => {
let sub_grid = Grid::try_from(grid_info, gui_handler, false)?; let sub_grid = Grid::try_from(gui_handler, grid_info, false)?;
Self::insert_id(ids, &grid_info.id, &sub_grid)?; Self::insert_id(ids, &grid_info.id, &sub_grid)?;
grid.attach( grid.attach(
gui_handler,
sub_grid.clone(), sub_grid.clone(),
grid_info.x_slot.get().with_context(|| "x_slot of grid")?, grid_info.x_slot.get().with_context(|| "x_slot of grid")?,
grid_info.y_slot.get().with_context(|| "y_slot of grid")?, grid_info.y_slot.get().with_context(|| "y_slot of grid")?,

View file

@ -5,7 +5,7 @@ use assetpath::AssetPath;
use super::validator::{ use super::validator::{
buttoninfo::NeighbourInfo, buttoninfo::NeighbourInfo,
uiinfoelement::UiInfoElement, uiinfoelement::UiInfoElement,
validator::{handle_function_suffix, Validator}, validator::{Validator, handle_function_suffix},
}; };
use crate::prelude::*; use crate::prelude::*;
use anyhow::Result; use anyhow::Result;
@ -17,17 +17,17 @@ pub struct GuiSnippet {
} }
impl GuiSnippet { impl GuiSnippet {
pub fn new(gui_handler: &Arc<GuiHandler>, path: &AssetPath) -> Result<Arc<Self>> { pub fn new(gui_handler: &mut GuiHandler, path: &AssetPath) -> Result<Arc<Self>> {
let validator = Validator::new( let validator = Validator::new(
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
&gui_handler, gui_handler,
path, path,
)?; )?;
Self::_new(gui_handler, validator) Self::_new(gui_handler, validator)
} }
pub fn from_str(gui_handler: &Arc<GuiHandler>, s: &str) -> Result<Arc<Self>> { pub fn from_str(gui_handler: &mut GuiHandler, s: &str) -> Result<Arc<Self>> {
let validator = Validator::from_str( let validator = Validator::from_str(
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
gui_handler, gui_handler,
@ -37,7 +37,7 @@ impl GuiSnippet {
Self::_new(gui_handler, validator) Self::_new(gui_handler, validator)
} }
fn _new(gui_handler: &Arc<GuiHandler>, validator: Validator) -> Result<Arc<Self>> { fn _new(gui_handler: &mut GuiHandler, validator: Validator) -> Result<Arc<Self>> {
let root = validator.root(); let root = validator.root();
let mut ids = HashMap::new(); let mut ids = HashMap::new();
@ -51,12 +51,12 @@ impl GuiSnippet {
} }
let grid_info = &root.children[0]; let grid_info = &root.children[0];
let grid = Grid::try_from(grid_info, &gui_handler, false)?; let grid = Grid::try_from(gui_handler, grid_info, false)?;
GuiBuilder::insert_id(&mut ids, &grid_info.id, &grid)?; GuiBuilder::insert_id(&mut ids, &grid_info.id, &grid)?;
for child in grid_info.children.read().unwrap().iter() { for child in grid_info.children.read().unwrap().iter() {
Self::create_child(&gui_handler, child, &grid, &mut ids, &mut custom_neighbours)?; Self::create_child(gui_handler, child, &grid, &mut ids, &mut custom_neighbours)?;
} }
GuiBuilder::connect_custom_neighbours(&ids, custom_neighbours)?; GuiBuilder::connect_custom_neighbours(&ids, custom_neighbours)?;
@ -93,8 +93,8 @@ impl Visibility for GuiSnippet {
self.grid.visible() self.grid.visible()
} }
fn set_visibility(&self, visibility: bool) -> Result<()> { fn set_visibility(&self, gui_handler: &mut GuiHandler, visibility: bool) -> Result<()> {
self.grid.set_visibility(visibility) self.grid.set_visibility(gui_handler, visibility)
} }
} }
@ -115,6 +115,7 @@ impl GuiElementTraits for GuiSnippet {
impl Gridable for GuiSnippet { impl Gridable for GuiSnippet {
fn set_frame( fn set_frame(
&self, &self,
gui_handler: &mut GuiHandler,
x: i32, x: i32,
y: i32, y: i32,
w: u32, w: u32,
@ -122,7 +123,8 @@ impl Gridable for GuiSnippet {
vert_align: VerticalAlign, vert_align: VerticalAlign,
hori_align: HorizontalAlign, hori_align: HorizontalAlign,
) -> Result<()> { ) -> Result<()> {
self.grid.set_frame(x, y, w, h, vert_align, hori_align) self.grid
.set_frame(gui_handler, x, y, w, h, vert_align, hori_align)
} }
fn selectable(&self) -> Option<&Arc<Selectable>> { fn selectable(&self) -> Option<&Arc<Selectable>> {
@ -145,7 +147,10 @@ impl Gridable for GuiSnippet {
impl Functionality for GuiSnippet { impl Functionality for GuiSnippet {
fn set_click_callbacks( fn set_click_callbacks(
&self, &self,
functions: Vec<(&str, Box<dyn Fn() -> Result<()> + Send + Sync>)>, functions: Vec<(
&str,
Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
)>,
) -> Result<()> { ) -> Result<()> {
for (function_name, callback) in functions { for (function_name, callback) in functions {
let suffix_less_function_name = handle_function_suffix(function_name); let suffix_less_function_name = handle_function_suffix(function_name);
@ -195,7 +200,7 @@ impl Functionality for GuiSnippet {
impl GuiSnippet { impl GuiSnippet {
fn create_child( fn create_child(
gui_handler: &Arc<GuiHandler>, gui_handler: &mut GuiHandler,
child: &UiInfoElement, child: &UiInfoElement,
grid: &Grid, grid: &Grid,
ids: &mut HashMap<String, UiElement>, ids: &mut HashMap<String, UiElement>,
@ -203,11 +208,12 @@ impl GuiSnippet {
) -> Result<()> { ) -> Result<()> {
match child { match child {
UiInfoElement::Button(button_info) => { UiInfoElement::Button(button_info) => {
let button = Button::try_from(button_info, gui_handler)?; let button = Button::try_from(gui_handler, button_info)?;
GuiBuilder::insert_id(ids, &button_info.id, &button)?; GuiBuilder::insert_id(ids, &button_info.id, &button)?;
grid.attach( grid.attach(
gui_handler,
button.clone(), button.clone(),
button_info.x_slot.get()?, button_info.x_slot.get()?,
button_info.y_slot.get()?, button_info.y_slot.get()?,
@ -223,6 +229,7 @@ impl GuiSnippet {
GuiBuilder::insert_id(ids, &label_info.id, &label)?; GuiBuilder::insert_id(ids, &label_info.id, &label)?;
grid.attach( grid.attach(
gui_handler,
label, label,
label_info.x_slot.get()?, label_info.x_slot.get()?,
label_info.y_slot.get()?, label_info.y_slot.get()?,
@ -237,6 +244,7 @@ impl GuiSnippet {
GuiBuilder::insert_id(ids, &multi_line_label_info.id, &multi_line_label)?; GuiBuilder::insert_id(ids, &multi_line_label_info.id, &multi_line_label)?;
grid.attach( grid.attach(
gui_handler,
multi_line_label, multi_line_label,
multi_line_label_info.x_slot.get()?, multi_line_label_info.x_slot.get()?,
multi_line_label_info.y_slot.get()?, multi_line_label_info.y_slot.get()?,
@ -251,6 +259,7 @@ impl GuiSnippet {
GuiBuilder::insert_id(ids, &multi_line_text_field_info.id, &multi_line_text_field)?; GuiBuilder::insert_id(ids, &multi_line_text_field_info.id, &multi_line_text_field)?;
grid.attach( grid.attach(
gui_handler,
multi_line_text_field, multi_line_text_field,
multi_line_text_field_info.x_slot.get()?, multi_line_text_field_info.x_slot.get()?,
multi_line_text_field_info.y_slot.get()?, multi_line_text_field_info.y_slot.get()?,
@ -264,6 +273,7 @@ impl GuiSnippet {
GuiBuilder::insert_id(ids, &text_field_info.id, &text_field)?; GuiBuilder::insert_id(ids, &text_field_info.id, &text_field)?;
grid.attach( grid.attach(
gui_handler,
text_field, text_field,
text_field_info.x_slot.get()?, text_field_info.x_slot.get()?,
text_field_info.y_slot.get()?, text_field_info.y_slot.get()?,
@ -277,6 +287,7 @@ impl GuiSnippet {
GuiBuilder::insert_id(ids, &icon_info.id, UiElement::Icon(Arc::downgrade(&icon)))?; GuiBuilder::insert_id(ids, &icon_info.id, UiElement::Icon(Arc::downgrade(&icon)))?;
grid.attach( grid.attach(
gui_handler,
icon, icon,
icon_info.x_slot.get()?, icon_info.x_slot.get()?,
icon_info.y_slot.get()?, icon_info.y_slot.get()?,
@ -290,6 +301,7 @@ impl GuiSnippet {
GuiBuilder::insert_id(ids, &progress_bar_info.id, &progress_bar)?; GuiBuilder::insert_id(ids, &progress_bar_info.id, &progress_bar)?;
grid.attach( grid.attach(
gui_handler,
progress_bar, progress_bar,
progress_bar_info.x_slot.get()?, progress_bar_info.x_slot.get()?,
progress_bar_info.y_slot.get()?, progress_bar_info.y_slot.get()?,
@ -298,11 +310,12 @@ impl GuiSnippet {
)?; )?;
} }
UiInfoElement::Grid(grid_info) => { UiInfoElement::Grid(grid_info) => {
let sub_grid = Grid::try_from(grid_info, gui_handler, false)?; let sub_grid = Grid::try_from(gui_handler, grid_info, false)?;
GuiBuilder::insert_id(ids, &grid_info.id, &sub_grid)?; GuiBuilder::insert_id(ids, &grid_info.id, &sub_grid)?;
grid.attach( grid.attach(
gui_handler,
sub_grid.clone(), sub_grid.clone(),
grid_info.x_slot.get()?, grid_info.x_slot.get()?,
grid_info.y_slot.get()?, grid_info.y_slot.get()?,

View file

@ -80,7 +80,7 @@ pub struct ButtonInfo {
impl ButtonInfo { impl ButtonInfo {
pub fn new<'a>( pub fn new<'a>(
#[cfg(feature = "audio")] gui_handler: &Arc<GuiHandler>, #[cfg(feature = "audio")] gui_handler: &GuiHandler,
attributes: quick_xml::events::attributes::Attributes<'a>, attributes: quick_xml::events::attributes::Attributes<'a>,
grid: &Arc<GridInfo>, grid: &Arc<GridInfo>,
) -> Result<ButtonInfo> { ) -> Result<ButtonInfo> {

View file

@ -6,11 +6,11 @@ use assetpath::AssetPath;
use serde_json::from_str; use serde_json::from_str;
use utilities::prelude::*; use utilities::prelude::*;
use quick_xml::{events::Event, Reader}; use quick_xml::{Reader, events::Event};
use std::borrow::Cow; use std::borrow::Cow;
use std::str::from_utf8;
use std::str::FromStr; use std::str::FromStr;
use std::str::from_utf8;
use std::{convert::TryFrom, io::BufRead, sync::Arc}; use std::{convert::TryFrom, io::BufRead, sync::Arc};
use super::buttoninfo::ButtonInfo; use super::buttoninfo::ButtonInfo;
@ -63,7 +63,7 @@ enum CurrentElement {
impl Validator { impl Validator {
pub fn from_str( pub fn from_str(
#[cfg(feature = "audio")] gui_handler: &Arc<GuiHandler>, #[cfg(feature = "audio")] gui_handler: &GuiHandler,
s: &str, s: &str,
) -> Result<Validator> { ) -> Result<Validator> {
Self::_new( Self::_new(
@ -74,7 +74,7 @@ impl Validator {
} }
pub fn new( pub fn new(
#[cfg(feature = "audio")] gui_handler: &Arc<GuiHandler>, #[cfg(feature = "audio")] gui_handler: &GuiHandler,
path: &AssetPath, path: &AssetPath,
) -> Result<Validator> { ) -> Result<Validator> {
Self::_new( Self::_new(
@ -86,7 +86,7 @@ impl Validator {
#[inline] #[inline]
fn _new<T: BufRead>( fn _new<T: BufRead>(
#[cfg(feature = "audio")] gui_handler: &Arc<GuiHandler>, #[cfg(feature = "audio")] gui_handler: &GuiHandler,
mut reader: Reader<T>, mut reader: Reader<T>,
) -> Result<Validator> { ) -> Result<Validator> {
// removes white spaces in texts // removes white spaces in texts
@ -312,13 +312,13 @@ impl Validator {
} }
Ok(Event::Text(ref e)) => match current_element { Ok(Event::Text(ref e)) => match current_element {
CurrentElement::Root => { CurrentElement::Root => {
return Err(anyhow::Error::msg("Text inside root not allowed")) return Err(anyhow::Error::msg("Text inside root not allowed"));
} }
CurrentElement::None => { CurrentElement::None => {
return Err(anyhow::Error::msg("Text outside root not allowed")) return Err(anyhow::Error::msg("Text outside root not allowed"));
} }
CurrentElement::Grid(_) => { CurrentElement::Grid(_) => {
return Err(anyhow::Error::msg("Text inside grid not allowed")) return Err(anyhow::Error::msg("Text inside grid not allowed"));
} }
CurrentElement::Icon(ref icon) => { CurrentElement::Icon(ref icon) => {
*icon.text.write().unwrap() = e.unescape()?.to_string(); *icon.text.write().unwrap() = e.unescape()?.to_string();
@ -365,7 +365,7 @@ impl Validator {
} }
fn process_start<'a>( fn process_start<'a>(
#[cfg(feature = "audio")] gui_handler: &Arc<GuiHandler>, #[cfg(feature = "audio")] gui_handler: &GuiHandler,
element: &quick_xml::events::BytesStart<'a>, element: &quick_xml::events::BytesStart<'a>,
handle: &CurrentElement, handle: &CurrentElement,
) -> Result<StartResult> { ) -> Result<StartResult> {
@ -479,7 +479,7 @@ impl Validator {
return Err(anyhow::Error::msg(format!( return Err(anyhow::Error::msg(format!(
"Unexpected tag: {}", "Unexpected tag: {}",
from_utf8(element.name().into_inner())? from_utf8(element.name().into_inner())?
))) )));
} }
}) })
} }

View file

@ -140,13 +140,13 @@ impl ButtonBuilder {
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
let click_sound = self let click_sound = self
.click_sound .click_sound
.map(|path| Audible::new(gui_handler.clone(), path)) .map(|path| Audible::new(gui_handler, path))
.transpose()?; .transpose()?;
#[cfg(feature = "audio")] #[cfg(feature = "audio")]
let hover_sound = self let hover_sound = self
.hover_sound .hover_sound
.map(|path| Audible::new(gui_handler.clone(), path)) .map(|path| Audible::new(gui_handler, path))
.transpose()?; .transpose()?;
let clickable = Clickable::new(framable.clone(), click_executable.clone()); let clickable = Clickable::new(framable.clone(), click_executable.clone());
@ -314,9 +314,10 @@ impl Button {
pub fn set_callback<F>(&self, callback: F) pub fn set_callback<F>(&self, callback: F)
where where
F: Fn() -> Result<()> + Send + Sync + 'static, F: Fn(&mut GuiHandler) -> Result<()> + Send + Sync + 'static,
{ {
self.click_executable.set_callback(move |_, _| callback()); self.click_executable
.set_callback(move |gui_handler: &mut GuiHandler, _: ()| callback(gui_handler));
} }
pub fn set_select_callback<F>(&self, callback: F) pub fn set_select_callback<F>(&self, callback: F)
@ -324,7 +325,7 @@ impl Button {
F: Fn(bool) -> Result<()> + Send + Sync + 'static, F: Fn(bool) -> Result<()> + Send + Sync + 'static,
{ {
self.on_select_executable self.on_select_executable
.set_callback(|_m, select| callback(select)); .set_callback(move |_: &mut GuiHandler, select: bool| callback(select));
} }
pub fn set_custom_callback<F>(&self, callback: F) pub fn set_custom_callback<F>(&self, callback: F)
@ -555,7 +556,7 @@ impl Button {
fn create_clicked_changed_callback(button: Arc<Button>) { fn create_clicked_changed_callback(button: Arc<Button>) {
let button_weak = Arc::downgrade(&button); let button_weak = Arc::downgrade(&button);
let clicked_changed = Box::new(move |gui_handler| { let clicked_changed = Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(button) = button_weak.upgrade() { if let Some(button) = button_weak.upgrade() {
if button.clickable.clicked() { if button.clickable.clicked() {
button.hoverable.set_hovered(gui_handler, false)?; button.hoverable.set_hovered(gui_handler, false)?;
@ -577,7 +578,7 @@ 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 = move |(gui_handler, selected)| { let selected_changed = move |gui_handler: &mut GuiHandler, selected: bool| {
if let Some(button) = button_weak.upgrade() { if let Some(button) = button_weak.upgrade() {
if selected { if selected {
button.set_button_state(gui_handler, ButtonState::Selected)?; button.set_button_state(gui_handler, ButtonState::Selected)?;

View file

@ -3,6 +3,7 @@ use std::any::Any;
use anyhow::Result; use anyhow::Result;
use super::ControllerButton; use super::ControllerButton;
use crate::prelude::*;
macro_rules! callbacks { macro_rules! callbacks {
($name:ident, $($cb:tt)*) => { ($name:ident, $($cb:tt)*) => {
@ -26,7 +27,7 @@ macro_rules! callbacks {
}; };
} }
callbacks!(ClickCallbacks, Fn() -> Result<()> + Send + Sync); callbacks!(ClickCallbacks, Fn(&mut GuiHandler) -> Result<()> + Send + Sync);
callbacks!(SelectCallbacks, Fn(bool) -> anyhow::Result<()> + Send + Sync); callbacks!(SelectCallbacks, Fn(bool) -> anyhow::Result<()> + Send + Sync);
callbacks!(CustomCallbacks, Fn(ControllerButton) -> anyhow::Result<bool> + Send + Sync); callbacks!(CustomCallbacks, Fn(ControllerButton) -> anyhow::Result<bool> + Send + Sync);
callbacks!(VecCallbacks, Fn(&dyn Any) -> Result<()> + Send + Sync); callbacks!(VecCallbacks, Fn(&dyn Any) -> Result<()> + Send + Sync);
@ -36,8 +37,8 @@ mod test {
use super::*; use super::*;
use anyhow::Result; use anyhow::Result;
fn normal_fn() -> impl Fn() -> Result<()> + Send + Sync { fn normal_fn() -> impl Fn(&mut GuiHandler) -> Result<()> + Send + Sync {
|| Ok(()) |_| Ok(())
} }
#[test] #[test]
@ -47,7 +48,10 @@ mod test {
impl Test { impl Test {
fn set_click_callbacks( fn set_click_callbacks(
&self, &self,
_callbacks: Vec<(&str, Box<dyn Fn() -> Result<()> + Send + Sync>)>, _callbacks: Vec<(
&str,
Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
)>,
) -> Result<()> { ) -> Result<()> {
Ok(()) Ok(())
} }

View file

@ -337,10 +337,10 @@ impl Grid {
self.framable.allow_size_scale(gui_handler, false) self.framable.allow_size_scale(gui_handler, false)
} }
pub fn connect( pub fn connect<'a>(
&self, &self,
direction: ConnectDirection, direction: ConnectDirection,
elements: impl IntoIterator<Item = (usize, &Arc<Selectable>)>, elements: impl IntoIterator<Item = (usize, &'a Arc<Selectable>)>,
) -> Result<()> { ) -> Result<()> {
for (index, selectable) in elements { for (index, selectable) in elements {
match direction { match direction {
@ -499,8 +499,8 @@ impl Grid {
} }
pub fn try_from( pub fn try_from(
grid_info: &GridInfo,
gui_handler: &mut GuiHandler, gui_handler: &mut GuiHandler,
grid_info: &GridInfo,
top_level: bool, top_level: bool,
) -> Result<Arc<Self>> { ) -> Result<Arc<Self>> {
let grid = Grid::new( let grid = Grid::new(

View file

@ -9,8 +9,8 @@ pub trait TopLevelGui: Send + Sync {
fn top_gui(&self) -> Option<&dyn TopGui>; fn top_gui(&self) -> Option<&dyn TopGui>;
fn elements(&self) -> Option<&HashMap<String, UiElement>>; fn elements(&self) -> Option<&HashMap<String, UiElement>>;
fn functionality(&self) -> Option<&dyn Functionality>; fn functionality(&self) -> Option<&dyn Functionality>;
fn enable(&self) -> Result<()>; fn enable(&self, gui_handler: &mut GuiHandler) -> Result<()>;
fn disable(&self) -> Result<()>; fn disable(&self, gui_handler: &mut GuiHandler) -> Result<()>;
} }
pub fn any_to<T>(any: &dyn Any) -> Result<&T> pub fn any_to<T>(any: &dyn Any) -> Result<&T>
@ -26,7 +26,10 @@ where
pub trait Functionality { pub trait Functionality {
fn set_click_callbacks( fn set_click_callbacks(
&self, &self,
callbacks: Vec<(&str, Box<dyn Fn() -> Result<()> + Send + Sync>)>, callbacks: Vec<(
&str,
Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
)>,
) -> Result<()>; ) -> Result<()>;
fn set_select_callbacks( fn set_select_callbacks(

View file

@ -16,7 +16,7 @@ pub struct Audible {
} }
impl Audible { impl Audible {
pub fn new(gui_handler: Arc<GuiHandler>, mut path: AssetPath) -> Result<Arc<Self>> { pub fn new(gui_handler: &GuiHandler, mut path: AssetPath) -> Result<Arc<Self>> {
if !path.has_prefix() { if !path.has_prefix() {
path.set_prefix( path.set_prefix(
&gui_handler &gui_handler

View file

@ -1,19 +1,21 @@
/// A trait that is used by the gui handler as the target for input /// A trait that is used by the gui handler as the target for input
use anyhow::Result; use anyhow::Result;
use crate::prelude::*;
pub trait TopGui: Send + Sync { pub trait TopGui: Send + Sync {
/// Decline method which is executed on `InputMap::B` press /// Decline method which is executed on `InputMap::B` press
fn decline(&self) -> Result<()>; fn decline(&self, gui_handler: &mut GuiHandler) -> Result<()>;
/// Method which is executed on `InputMap::RightButton` press /// Method which is executed on `InputMap::RightButton` press
/// ///
/// # Arguments /// # Arguments
/// * `second_level` adds support for multiple tab layers, e.g. RB and RT press on controller /// * `second_level` adds support for multiple tab layers, e.g. RB and RT press on controller
fn next_tab(&self, second_level: bool) -> Result<()>; fn next_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()>;
/// Method which is executed on `InputMap::LeftButton` press /// Method which is executed on `InputMap::LeftButton` press
/// /// /// ///
/// # Arguments /// # Arguments
/// * `second_level` adds support for multiple tab layers, e.g. RB and RT press on controller /// * `second_level` adds support for multiple tab layers, e.g. RB and RT press on controller
fn previous_tab(&self, second_level: bool) -> Result<()>; fn previous_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()>;
} }

View file

@ -736,36 +736,36 @@ impl GuiHandler {
Ok(false) Ok(false)
} }
pub fn decline_topgui(&self) -> Result<bool> { pub fn decline_topgui(&mut self) -> Result<bool> {
// workaround for unwanted borrowing behaviour inside decline function // workaround for unwanted borrowing behaviour inside decline function
let opt_topgui = self.top_ui.as_ref().cloned(); let opt_topgui = self.top_ui.as_ref().cloned();
if let Some(topgui) = opt_topgui { if let Some(topgui) = opt_topgui {
topgui.decline()?; topgui.decline(self)?;
return Ok(true); return Ok(true);
} }
Ok(false) Ok(false)
} }
pub fn next_tab_topgui(&self, second_level: bool) -> Result<bool> { pub fn next_tab_topgui(&mut self, second_level: bool) -> Result<bool> {
// workaround for unwanted borrowing behaviour inside decline function // workaround for unwanted borrowing behaviour inside decline function
let opt_topgui = self.top_ui.as_ref().cloned(); let opt_topgui = self.top_ui.as_ref().cloned();
if let Some(topgui) = opt_topgui { if let Some(topgui) = opt_topgui {
topgui.next_tab(second_level)?; topgui.next_tab(self, second_level)?;
return Ok(true); return Ok(true);
} }
Ok(false) Ok(false)
} }
pub fn previous_tab_topgui(&self, second_level: bool) -> Result<bool> { pub fn previous_tab_topgui(&mut self, second_level: bool) -> Result<bool> {
// workaround for unwanted borrowing behaviour inside decline function // workaround for unwanted borrowing behaviour inside decline function
let opt_topgui = self.top_ui.as_ref().cloned(); let opt_topgui = self.top_ui.as_ref().cloned();
if let Some(topgui) = opt_topgui { if let Some(topgui) = opt_topgui {
topgui.previous_tab(second_level)?; topgui.previous_tab(self, second_level)?;
return Ok(true); return Ok(true);
} }
@ -852,12 +852,12 @@ impl GuiHandler {
self.needs_update = true; self.needs_update = true;
} }
pub fn set_top_gui(&mut self, top_gui: impl Into<Option<Arc<dyn TopGui>>>) { pub fn set_top_gui(&mut self, top_gui: Option<Arc<dyn TopGui>>) {
self.top_ui = top_gui.into(); self.top_ui = top_gui;
} }
pub fn set_tooltip(&mut self, tooltip: impl Into<Option<Arc<dyn TopGui>>>) { pub fn set_tooltip(&mut self, tooltip: Option<Arc<dyn TopGui>>) {
self.tooltip_ui = tooltip.into(); self.tooltip_ui = tooltip;
} }
pub(crate) fn add_callback<F: FnOnce(&mut Self) -> Result<()> + Send + Sync + 'static>( pub(crate) fn add_callback<F: FnOnce(&mut Self) -> Result<()> + Send + Sync + 'static>(

View file

@ -25,21 +25,22 @@ pub struct Keyboard {
mode: Arc<RwLock<KeyboardMode>>, mode: Arc<RwLock<KeyboardMode>>,
decline_callback: Arc<RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>>, decline_callback: Arc<RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>>,
accept_callback: Arc<RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>>, accept_callback: Arc<RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>>,
elements: HashMap<String, UiElement>, elements: HashMap<String, UiElement>,
} }
impl Keyboard { impl Keyboard {
pub fn new(gui_handler: &GuiHandler) -> Result<Arc<Self>> { pub fn new(gui_handler: &mut GuiHandler) -> Result<Arc<Self>> {
let text_field_gui: Arc<GuiBuilder> = let text_field_gui: Arc<GuiBuilder> =
GuiBuilder::from_str(gui_handler, include_str!("text_field.xml"))?; GuiBuilder::from_str(gui_handler, include_str!("text_field.xml"))?;
let text_field: Arc<TextField> = text_field_gui.element("field")?; let text_field: Arc<TextField> = text_field_gui.element("field")?;
let decline_callback: Arc<RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>> = let decline_callback: Arc<
Arc::new(RwLock::new(None)); RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
> = Arc::new(RwLock::new(None));
let accept_callback: Arc< let accept_callback: Arc<
RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>, RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>,
@ -80,10 +81,12 @@ impl Keyboard {
} }
fn setup( fn setup(
gui_handler: &Arc<GuiHandler>, gui_handler: &mut GuiHandler,
textfield: Arc<TextField>, textfield: Arc<TextField>,
mode: &Arc<RwLock<KeyboardMode>>, mode: &Arc<RwLock<KeyboardMode>>,
decline_callback: Arc<RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>>, decline_callback: Arc<
RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
>,
accept_callback: Arc<RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>>, accept_callback: Arc<RwLock<Option<Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>>>>,
) -> Result<(Arc<GuiBuilder>, Arc<GuiBuilder>, Arc<GuiBuilder>)> { ) -> Result<(Arc<GuiBuilder>, Arc<GuiBuilder>, Arc<GuiBuilder>)> {
let lower_case = GuiBuilder::from_str(gui_handler, include_str!("lower_case.xml"))?; let lower_case = GuiBuilder::from_str(gui_handler, include_str!("lower_case.xml"))?;
@ -190,9 +193,9 @@ impl Keyboard {
Self::set_text_callback(&specials, ".", textfield.clone())?; Self::set_text_callback(&specials, ".", textfield.clone())?;
Self::set_text_callback(&specials, "_", textfield.clone())?; Self::set_text_callback(&specials, "_", textfield.clone())?;
let back = Box::new(move || { let back = Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(callback) = decline_callback.read().unwrap().as_ref() { if let Some(callback) = decline_callback.read().unwrap().as_ref() {
(callback)()?; (callback)(gui_handler)?;
} }
Ok(()) Ok(())
@ -202,7 +205,7 @@ impl Keyboard {
let weak_textfield = Arc::downgrade(&textfield); let weak_textfield = Arc::downgrade(&textfield);
let weak_accept = Arc::downgrade(&accept_callback); let weak_accept = Arc::downgrade(&accept_callback);
Box::new(move || { Box::new(move |_: &mut GuiHandler| {
if let Some(textfield) = weak_textfield.upgrade() { if let Some(textfield) = weak_textfield.upgrade() {
if let Some(accept_callback) = weak_accept.upgrade() { if let Some(accept_callback) = weak_accept.upgrade() {
if let Some(text) = textfield.text() { if let Some(text) = textfield.text() {
@ -222,15 +225,15 @@ impl Keyboard {
let weak_lower = Arc::downgrade(&lower_case); let weak_lower = Arc::downgrade(&lower_case);
let weak_upper = Arc::downgrade(&upper_case); let weak_upper = Arc::downgrade(&upper_case);
Box::new(move || { Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(lower) = weak_lower.upgrade() { if let Some(lower) = weak_lower.upgrade() {
if let Some(upper) = weak_upper.upgrade() { if let Some(upper) = weak_upper.upgrade() {
let mut mode = mode.write().unwrap(); let mut mode = mode.write().unwrap();
if let KeyboardMode::LowerCase = mode.deref() { if let KeyboardMode::LowerCase = mode.deref() {
*mode = KeyboardMode::UpperCase; *mode = KeyboardMode::UpperCase;
lower.disable()?; lower.disable(gui_handler)?;
upper.enable()?; upper.enable(gui_handler)?;
} }
} }
} }
@ -244,15 +247,15 @@ impl Keyboard {
let weak_upper = Arc::downgrade(&upper_case); let weak_upper = Arc::downgrade(&upper_case);
let weak_specials = Arc::downgrade(&specials); let weak_specials = Arc::downgrade(&specials);
Box::new(move || { Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(specials) = weak_specials.upgrade() { if let Some(specials) = weak_specials.upgrade() {
if let Some(upper) = weak_upper.upgrade() { if let Some(upper) = weak_upper.upgrade() {
let mut mode = mode.write().unwrap(); let mut mode = mode.write().unwrap();
if let KeyboardMode::UpperCase = mode.deref() { if let KeyboardMode::UpperCase = mode.deref() {
*mode = KeyboardMode::Specials; *mode = KeyboardMode::Specials;
upper.disable()?; upper.disable(gui_handler)?;
specials.enable()?; specials.enable(gui_handler)?;
} }
} }
} }
@ -266,15 +269,15 @@ impl Keyboard {
let weak_lower = Arc::downgrade(&lower_case); let weak_lower = Arc::downgrade(&lower_case);
let weak_specials = Arc::downgrade(&specials); let weak_specials = Arc::downgrade(&specials);
Box::new(move || { Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(lower) = weak_lower.upgrade() { if let Some(lower) = weak_lower.upgrade() {
if let Some(specials) = weak_specials.upgrade() { if let Some(specials) = weak_specials.upgrade() {
let mut mode = mode.write().unwrap(); let mut mode = mode.write().unwrap();
if let KeyboardMode::Specials = mode.deref() { if let KeyboardMode::Specials = mode.deref() {
*mode = KeyboardMode::LowerCase; *mode = KeyboardMode::LowerCase;
specials.disable()?; specials.disable(gui_handler)?;
lower.enable()?; lower.enable(gui_handler)?;
} }
} }
} }
@ -286,9 +289,9 @@ impl Keyboard {
let space_bar = { let space_bar = {
let weak_textfield = Arc::downgrade(&textfield); let weak_textfield = Arc::downgrade(&textfield);
Box::new(move || { Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(text_field) = weak_textfield.upgrade() { if let Some(text_field) = weak_textfield.upgrade() {
text_field.add_letter(' ')?; text_field.add_letter(gui_handler, ' ')?;
} }
Ok(()) Ok(())
@ -327,11 +330,11 @@ 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(move || { button_ref.set_callback(Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(textfield) = weak_textfield.upgrade() { if let Some(textfield) = weak_textfield.upgrade() {
if let Some(button) = weak_button.upgrade() { if let Some(button) = weak_button.upgrade() {
if let Some(text) = button.text()? { if let Some(text) = button.text()? {
textfield.add_letter(text.as_bytes()[0] as char)?; textfield.add_letter(gui_handler, text.as_bytes()[0] as char)?;
} }
} }
} }
@ -344,22 +347,22 @@ impl Keyboard {
} }
impl TopGui for Keyboard { impl TopGui for Keyboard {
fn decline(&self) -> Result<()> { fn decline(&self, gui_handler: &mut GuiHandler) -> Result<()> {
if let Some(callback) = self.decline_callback.read().unwrap().as_ref() { if let Some(callback) = self.decline_callback.read().unwrap().as_ref() {
(callback)()?; (callback)(gui_handler)?;
} }
Ok(()) Ok(())
} }
fn next_tab(&self, _: bool) -> Result<()> { fn next_tab(&self, _gui_handler: &mut GuiHandler, _: bool) -> Result<()> {
Ok(()) Ok(())
} }
fn previous_tab(&self, second_level: bool) -> Result<()> { fn previous_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()> {
// abuse event // abuse event
if !second_level { if !second_level {
self.text_field.remove_last()?; self.text_field.remove_last(gui_handler)?;
} }
Ok(()) Ok(())
@ -377,7 +380,7 @@ impl Visibility for Keyboard {
} }
} }
fn set_visibility(&self, visibility: bool) -> Result<()> { fn set_visibility(&self, gui_handler: &mut GuiHandler, visibility: bool) -> Result<()> {
let mode = self.mode.read().unwrap(); let mode = self.mode.read().unwrap();
let gui = match mode.deref() { let gui = match mode.deref() {
@ -387,11 +390,11 @@ impl Visibility for Keyboard {
}; };
if visibility { if visibility {
gui.enable()?; gui.enable(gui_handler)?;
self.text_field_gui.enable()?; self.text_field_gui.enable(gui_handler)?;
} else { } else {
gui.disable()?; gui.disable(gui_handler)?;
self.text_field_gui.disable()?; self.text_field_gui.disable(gui_handler)?;
} }
Ok(()) Ok(())
@ -429,15 +432,15 @@ impl TopLevelGui for Keyboard {
Some(self) Some(self)
} }
fn enable(&self) -> Result<()> { fn enable(&self, gui_handler: &mut GuiHandler) -> Result<()> {
self.set_visibility(true)?; self.set_visibility(gui_handler, true)?;
self.text_field.focus_input()?; self.text_field.focus_input(gui_handler)?;
Ok(()) Ok(())
} }
fn disable(&self) -> Result<()> { fn disable(&self, gui_handler: &mut GuiHandler) -> Result<()> {
self.set_visibility(false)?; self.set_visibility(gui_handler, false)?;
Ok(()) Ok(())
} }
@ -446,7 +449,10 @@ impl TopLevelGui for Keyboard {
impl Functionality for Keyboard { impl Functionality for Keyboard {
fn set_click_callbacks( fn set_click_callbacks(
&self, &self,
callbacks: Vec<(&str, Box<dyn Fn() -> Result<()> + Send + Sync>)>, callbacks: Vec<(
&str,
Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
)>,
) -> Result<()> { ) -> Result<()> {
for (name, callback) in callbacks { for (name, callback) in callbacks {
if name == "decline" { if name == "decline" {

View file

@ -7,19 +7,21 @@ use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock, Weak}; use std::sync::{Arc, Mutex, RwLock, Weak};
pub trait FutureStateChange: Fn() -> Result<()> + Send + Sync { pub trait FutureStateChange: Fn(&mut GuiHandler) -> Result<()> + Send + Sync {
fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange> fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange>
where where
Self: 'a; Self: 'a;
fn as_fn(&self) -> &(dyn Fn() -> Result<()> + Send + Sync) fn as_fn(&self) -> &(dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync)
where where
Self: Sized, Self: Sized,
{ {
self self
} }
fn as_static(&'static self) -> &'static (dyn Fn() -> Result<()> + Send + Sync + 'static) fn as_static(
&'static self,
) -> &'static (dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync + 'static)
where where
Self: Sized, Self: Sized,
{ {
@ -27,7 +29,7 @@ pub trait FutureStateChange: Fn() -> Result<()> + Send + Sync {
} }
} }
impl<F: Fn() -> Result<()> + Clone + Send + Sync> FutureStateChange for F { impl<F: Fn(&mut GuiHandler) -> Result<()> + Clone + Send + Sync> FutureStateChange for F {
fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange> fn clone_box<'a>(&self) -> Box<dyn 'a + FutureStateChange>
where where
Self: 'a, Self: 'a,
@ -47,12 +49,12 @@ struct State {
top_level_gui: Arc<dyn TopLevelGui>, top_level_gui: Arc<dyn TopLevelGui>,
on_activate: RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>, on_activate: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
on_deactivate: RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>, on_deactivate: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
next_tab: RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>, next_tab: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
previous_tab: RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>, previous_tab: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
decline: RwLock<Option<Box<dyn Fn() -> Result<()> + Send + Sync>>>, decline: RwLock<Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>>,
} }
/// Opaque handle for a State /// Opaque handle for a State
@ -148,16 +150,21 @@ impl GetElement<ProgressBar> for StateHandle {
/// Update type /// Update type
pub enum StateUpdateType<'a> { pub enum StateUpdateType<'a> {
/// Updates the callback which is executed on next tab event /// Updates the callback which is executed on next tab event
NextTab(Option<Box<dyn Fn() -> Result<()> + Send + Sync>>), NextTab(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
/// Updates the callback which is executed on previous tab event /// Updates the callback which is executed on previous tab event
PreviousTab(Option<Box<dyn Fn() -> Result<()> + Send + Sync>>), PreviousTab(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
/// Updates the callback which is executed on decline event /// Updates the callback which is executed on decline event
Decline(Option<Box<dyn Fn() -> Result<()> + Send + Sync>>), Decline(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
/// Updates callbacks by identifier /// Updates callbacks by identifier
ClickCallbacks(Vec<(&'a str, Box<dyn Fn() -> Result<()> + Send + Sync>)>), ClickCallbacks(
Vec<(
&'a str,
Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>,
)>,
),
/// Updates callbacks by identifier /// Updates callbacks by identifier
SelectCallbacks(Vec<(&'a str, Box<CustomCallback<bool, ()>>)>), SelectCallbacks(Vec<(&'a str, Box<CustomCallback<bool, ()>>)>),
@ -169,10 +176,10 @@ pub enum StateUpdateType<'a> {
VecCallbacks(Vec<(&'a str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>), VecCallbacks(Vec<(&'a str, Box<dyn Fn(&dyn Any) -> Result<()> + Send + Sync>)>),
/// Updates the callback which is executed when this state gets activated on state change /// Updates the callback which is executed when this state gets activated on state change
OnActivate(Option<Box<dyn Fn() -> Result<()> + Send + Sync>>), OnActivate(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
/// Updates the callback which is executed when this state gets deactivated on state change /// Updates the callback which is executed when this state gets deactivated on state change
OnDeactivate(Option<Box<dyn Fn() -> Result<()> + Send + Sync>>), OnDeactivate(Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>),
} }
/// Type of the state to be created /// Type of the state to be created
@ -204,8 +211,6 @@ impl<'a, T: TopLevelGui + 'static> From<T> for CreationType<'a> {
/// Collection and handler for your UI (basically a state machine) /// Collection and handler for your UI (basically a state machine)
pub struct States { pub struct States {
gui_handler: Arc<GuiHandler>,
states: HashMap<String, Arc<State>>, states: HashMap<String, Arc<State>>,
current_state: Arc<Mutex<Option<Arc<State>>>>, current_state: Arc<Mutex<Option<Arc<State>>>>,
@ -215,10 +220,8 @@ pub struct States {
impl States { impl States {
/// Creates an empty States struct /// Creates an empty States struct
pub fn new(gui_handler: Arc<GuiHandler>) -> Result<Self> { pub fn new() -> Result<Self> {
Ok(States { Ok(States {
gui_handler,
states: HashMap::new(), states: HashMap::new(),
current_state: Arc::new(Mutex::new(None)), current_state: Arc::new(Mutex::new(None)),
@ -246,12 +249,13 @@ impl States {
/// Adds a single state /// Adds a single state
pub fn add_state<'a>( pub fn add_state<'a>(
&mut self, &mut self,
gui_handler: &mut GuiHandler,
id: &str, id: &str,
creation_type: impl Into<CreationType<'a>>, creation_type: impl Into<CreationType<'a>>,
) -> Result<()> { ) -> Result<()> {
self.states.insert( self.states.insert(
id.to_string(), id.to_string(),
State::new(&self.gui_handler, id, creation_type.into())?, State::new(gui_handler, id, creation_type.into())?,
); );
Ok(()) Ok(())
@ -270,15 +274,15 @@ impl States {
/// # Arguments /// # Arguments
/// ///
/// * `id` - Set state with the given identifier or None /// * `id` - Set state with the given identifier or None
pub fn set_state<'b>(&self, id: impl Into<Option<&'b str>>) -> Result<()> { pub fn set_state<'b>(
&self,
gui_handler: &mut GuiHandler,
id: impl Into<Option<&'b str>>,
) -> Result<()> {
Self::_set_state( Self::_set_state(
id.into().map(|id| self.get_state(id)).transpose()?, id.into().map(|id| self.get_state(id)).transpose()?,
&mut *self.current_state.lock().unwrap(), &mut *self.current_state.lock().unwrap(),
if self.control_top_gui { gui_handler,
Some(self.gui_handler.clone())
} else {
None
},
self.log_state_change, self.log_state_change,
) )
} }
@ -286,7 +290,7 @@ impl States {
fn _set_state( fn _set_state(
state: Option<Arc<State>>, state: Option<Arc<State>>,
current: &mut Option<Arc<State>>, current: &mut Option<Arc<State>>,
gui_handler: Option<Arc<GuiHandler>>, gui_handler: &mut GuiHandler,
logging: bool, logging: bool,
) -> Result<()> { ) -> Result<()> {
if let Some(old_state) = current { if let Some(old_state) = current {
@ -298,17 +302,14 @@ impl States {
} }
// execute deactivate on old state // execute deactivate on old state
old_state.deactivate()?; old_state.deactivate(gui_handler)?;
} }
// set new state, either no state or requested state // set new state, either no state or requested state
match state { match state {
Some(state) => { Some(state) => {
state.activate()?; state.activate(gui_handler)?;
gui_handler.set_top_gui(Some(state.clone()));
if let Some(gui_handler) = gui_handler {
gui_handler.set_top_gui(Some(state.clone()));
}
if logging { if logging {
println!("Change UI State to {}", state.name); println!("Change UI State to {}", state.name);
@ -317,9 +318,7 @@ impl States {
*current = Some(state); *current = Some(state);
} }
None => { None => {
if let Some(gui_handler) = gui_handler { gui_handler.set_top_gui(None);
gui_handler.set_top_gui(None);
}
if logging { if logging {
println!("Change UI State to None"); println!("Change UI State to None");
@ -353,19 +352,14 @@ impl States {
let state: Option<Arc<State>> = id.into().map(|id| self.get_state(id)).transpose()?; let state: Option<Arc<State>> = id.into().map(|id| self.get_state(id)).transpose()?;
let weak_state = state.map(|s| Arc::downgrade(&s)); let weak_state = state.map(|s| Arc::downgrade(&s));
let weak_current_state = Arc::downgrade(&self.current_state); let weak_current_state = Arc::downgrade(&self.current_state);
let gui_handler = if self.control_top_gui {
Some(Arc::downgrade(&self.gui_handler))
} else {
None
};
let logging = self.log_state_change; let logging = self.log_state_change;
Ok(Box::new(move || { Ok(Box::new(move |gui_handler: &mut GuiHandler| {
if let Some(current) = weak_current_state.upgrade() { if let Some(current) = weak_current_state.upgrade() {
Self::_set_state( Self::_set_state(
weak_state.as_ref().map(|w| w.upgrade()).flatten(), weak_state.as_ref().map(|w| w.upgrade()).flatten(),
&mut *current.lock().unwrap(), &mut *current.lock().unwrap(),
gui_handler.as_ref().map(|h| h.upgrade()).flatten(), gui_handler,
logging, logging,
)?; )?;
} }
@ -377,7 +371,7 @@ impl States {
impl State { impl State {
fn new<'a>( fn new<'a>(
gui_handler: &Arc<GuiHandler>, gui_handler: &mut GuiHandler,
name: &str, name: &str,
creation_type: CreationType<'a>, creation_type: CreationType<'a>,
) -> Result<Arc<Self>> { ) -> Result<Arc<Self>> {
@ -435,56 +429,71 @@ impl State {
} }
} }
fn activate(&self) -> Result<()> { fn activate(&self, gui_handler: &mut GuiHandler) -> Result<()> {
self.top_level_gui.enable()?; self.top_level_gui.enable(gui_handler)?;
if let Some(activate) = self.on_activate.read().unwrap().as_ref() { if let Some(activate) = self.on_activate.read().unwrap().as_ref() {
(activate)()?; (activate)(gui_handler)?;
} }
Ok(()) Ok(())
} }
fn deactivate(&self) -> Result<()> { fn deactivate(&self, gui_handler: &mut GuiHandler) -> Result<()> {
self.top_level_gui.disable()?; self.top_level_gui.disable(gui_handler)?;
if let Some(deactivate) = self.on_deactivate.read().unwrap().as_ref() { if let Some(deactivate) = self.on_deactivate.read().unwrap().as_ref() {
(deactivate)()?; (deactivate)(gui_handler)?;
} }
Ok(()) Ok(())
} }
fn set_on_activate(&self, on_activate: Option<Box<dyn Fn() -> Result<()> + Send + Sync>>) { fn set_on_activate(
&self,
on_activate: Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>,
) {
*self.on_activate.write().unwrap() = on_activate; *self.on_activate.write().unwrap() = on_activate;
} }
fn set_on_deactivate(&self, on_deactivate: Option<Box<dyn Fn() -> Result<()> + Send + Sync>>) { fn set_on_deactivate(
&self,
on_deactivate: Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>,
) {
*self.on_deactivate.write().unwrap() = on_deactivate; *self.on_deactivate.write().unwrap() = on_deactivate;
} }
fn set_previous_tab(&self, previous_tab: Option<Box<dyn Fn() -> Result<()> + Send + Sync>>) { fn set_previous_tab(
&self,
previous_tab: Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>,
) {
*self.previous_tab.write().unwrap() = previous_tab; *self.previous_tab.write().unwrap() = previous_tab;
} }
fn set_next_tab(&self, next_tab: Option<Box<dyn Fn() -> Result<()> + Send + Sync>>) { fn set_next_tab(
&self,
next_tab: Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>,
) {
*self.next_tab.write().unwrap() = next_tab; *self.next_tab.write().unwrap() = next_tab;
} }
fn set_decline(&self, decline: Option<Box<dyn Fn() -> Result<()> + Send + Sync>>) { fn set_decline(
&self,
decline: Option<Box<dyn Fn(&mut GuiHandler) -> Result<()> + Send + Sync>>,
) {
*self.decline.write().unwrap() = decline; *self.decline.write().unwrap() = decline;
} }
} }
impl TopGui for State { impl TopGui for State {
fn decline(&self) -> Result<()> { fn decline(&self, gui_handler: &mut GuiHandler) -> Result<()> {
match self.decline.read().unwrap().as_ref() { match self.decline.read().unwrap().as_ref() {
Some(decline) => { Some(decline) => {
(decline)()?; (decline)(gui_handler)?;
} }
None => { None => {
if let Some(top_gui) = self.top_level_gui.top_gui() { if let Some(top_gui) = self.top_level_gui.top_gui() {
top_gui.decline()?; top_gui.decline(gui_handler)?;
} }
} }
} }
@ -492,14 +501,14 @@ impl TopGui for State {
Ok(()) Ok(())
} }
fn next_tab(&self, second_level: bool) -> Result<()> { fn next_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()> {
match self.next_tab.read().unwrap().as_ref() { match self.next_tab.read().unwrap().as_ref() {
Some(next_tab) => { Some(next_tab) => {
(next_tab)()?; (next_tab)(gui_handler)?;
} }
None => { None => {
if let Some(top_gui) = self.top_level_gui.top_gui() { if let Some(top_gui) = self.top_level_gui.top_gui() {
top_gui.next_tab(second_level)?; top_gui.next_tab(gui_handler, second_level)?;
} }
} }
} }
@ -507,14 +516,14 @@ impl TopGui for State {
Ok(()) Ok(())
} }
fn previous_tab(&self, second_level: bool) -> Result<()> { fn previous_tab(&self, gui_handler: &mut GuiHandler, second_level: bool) -> Result<()> {
match self.previous_tab.read().unwrap().as_ref() { match self.previous_tab.read().unwrap().as_ref() {
Some(previous_tab) => { Some(previous_tab) => {
(previous_tab)()?; (previous_tab)(gui_handler)?;
} }
None => { None => {
if let Some(top_gui) = self.top_level_gui.top_gui() { if let Some(top_gui) = self.top_level_gui.top_gui() {
top_gui.previous_tab(second_level)?; top_gui.previous_tab(gui_handler, second_level)?;
} }
} }
} }