use crate::prelude::*; use anyhow::Result; use utilities::prelude::*; #[cfg(feature = "audio")] use assetpath::AssetPath; use super::gridinfo::GridInfo; use super::mandatory::Mandatory; use std::convert::TryFrom; use std::str::from_utf8; use std::sync::{Arc, RwLock, Weak}; use super::validator::{ cow_to_button_select_mode, cow_to_fill_type, cow_to_str, cow_to_text_alignment, str_into, }; #[cfg(feature = "audio")] use super::validator::cow_to_path; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum NeighbourDirection { East, West, North, South, } #[derive(Debug, Clone)] pub struct NeighbourInfo { pub direction: NeighbourDirection, pub id: String, } pub struct ButtonInfo { // global unique id, if set pub id: String, // slots inside grid pub x_slot: Mandatory, pub y_slot: Mandatory, pub x_dim: u32, pub y_dim: u32, // texturing pub normal: Option, pub selected: Option, #[cfg(feature = "audio")] pub click_sound: AssetPath, #[cfg(feature = "audio")] pub hover_sound: AssetPath, pub text: RwLock, pub text_color: Color, pub text_ratio: Option, pub text_alignment: TextAlignment, pub icon: Option, pub margin: u32, pub select_mode: ButtonSelectMode, pub neighbour_infos: Vec, // the chosen element for controller input pub select: bool, pub parent: Weak, } impl ButtonInfo { pub fn new<'a>( #[cfg(feature = "audio")] gui_handler: &Arc, attributes: quick_xml::events::attributes::Attributes<'a>, grid: &Arc, ) -> Result { let mut button_info = ButtonInfo { id: String::new(), x_slot: Mandatory::default(), y_slot: Mandatory::default(), x_dim: 1, y_dim: 1, normal: Self::find_menu_button(grid), selected: Self::find_menu_button_selected(grid), #[cfg(feature = "audio")] click_sound: match Self::find_click_sound(grid) { Some(sound) => sound, None => gui_handler.click_sound().clone(), }, #[cfg(feature = "audio")] hover_sound: match Self::find_hover_sound(grid) { Some(sound) => sound, None => gui_handler.hover_sound().clone(), }, text: RwLock::default(), text_color: Color::Black, text_ratio: None, text_alignment: TextAlignment::Center, icon: None, margin: 0, select_mode: ButtonSelectMode::Bigger, neighbour_infos: Vec::new(), select: false, parent: Arc::downgrade(grid), }; for attribute_res in attributes { let attribute = attribute_res?; match attribute.key.into_inner() { b"id" => button_info.id = cow_to_str(attribute.value), b"x_slot" => button_info.x_slot.set(str_into(attribute.value)?), b"y_slot" => button_info.y_slot.set(str_into(attribute.value)?), b"x_size" => button_info.x_dim = str_into(attribute.value)?, b"y_size" => button_info.y_dim = str_into(attribute.value)?, b"normal" => button_info.normal = Some(cow_to_fill_type(attribute.value)), b"selected" => button_info.selected = Some(cow_to_fill_type(attribute.value)), #[cfg(feature = "audio")] b"click_sound" => button_info.click_sound = cow_to_path(attribute.value), #[cfg(feature = "audio")] b"hover_sound" => button_info.hover_sound = cow_to_path(attribute.value), b"select_mode" => { button_info.select_mode = cow_to_button_select_mode(attribute.value)? } b"icon" => button_info.icon = Some(cow_to_str(attribute.value)), b"icon_margin" => button_info.margin = str_into(attribute.value)?, b"text_color" => { button_info.text_color = Color::try_from(cow_to_str(attribute.value).as_str())? } b"text_ratio" => button_info.text_ratio = Some(str_into(attribute.value)?), b"text_alignment" => { button_info.text_alignment = cow_to_text_alignment(attribute.value)? } b"select" => button_info.select = str_into(attribute.value)?, b"west_neighbour" => { button_info.add_neighbour(NeighbourDirection::West, cow_to_str(attribute.value)) } b"east_neighbour" => { button_info.add_neighbour(NeighbourDirection::East, cow_to_str(attribute.value)) } b"north_neighbour" => button_info .add_neighbour(NeighbourDirection::North, cow_to_str(attribute.value)), b"south_neighbour" => button_info .add_neighbour(NeighbourDirection::South, cow_to_str(attribute.value)), _ => { return Err(anyhow::Error::msg(format!( "Unsupported attribute in Button: {}", from_utf8(attribute.key.into_inner())? ))) } } } Ok(button_info) } fn add_neighbour(&mut self, direction: NeighbourDirection, id: String) { match self .neighbour_infos .iter_mut() .find(|info| info.direction == direction) { Some(info) => info.id = id, None => self.neighbour_infos.push(NeighbourInfo { direction, id }), } } fn find_menu_button(grid: &GridInfo) -> Option { // return immediately if present if let Some(menu_button) = &grid.button_normal { return Some(menu_button.clone()); } // check for parent if let Some(weak_parent) = &grid.parent { if let Some(parent) = weak_parent.upgrade() { return Self::find_menu_button(&parent); } } None } fn find_menu_button_selected(grid: &GridInfo) -> Option { // return immediately if present if let Some(menu_button_selected) = &grid.button_selected { return Some(menu_button_selected.clone()); } // check for parent if let Some(weak_parent) = &grid.parent { if let Some(parent) = weak_parent.upgrade() { return Self::find_menu_button_selected(&parent); } } None } #[cfg(feature = "audio")] fn find_click_sound(grid: &GridInfo) -> Option { // return immediately if present if let Some(click_sound) = &grid.click_sound { return Some(click_sound.clone()); } // check for parent if let Some(weak_parent) = &grid.parent { if let Some(parent) = weak_parent.upgrade() { return Self::find_click_sound(&parent); } } None } #[cfg(feature = "audio")] fn find_hover_sound(grid: &GridInfo) -> Option { // return immediately if present if let Some(hover_sound) = &grid.hover_sound { return Some(hover_sound.clone()); } // check for parent if let Some(weak_parent) = &grid.parent { if let Some(parent) = weak_parent.upgrade() { return Self::find_hover_sound(&parent); } } None } }