use crate::{builder::validator::iconinfo::IconInfo, prelude::*}; use anyhow::Result; use utilities::prelude::*; use vulkan_rs::prelude::*; use std::sync::{ atomic::{AtomicBool, Ordering::SeqCst}, Arc, RwLock, }; use super::{fill_type::FillType, IconBuilderType, IconizableWrapper, TextableWrapper}; pub struct IconBuilder { content: Option, background: Option, margin: u32, text: Option, text_color: Color, text_ratio: f32, } impl IconBuilder { pub fn set_margin(mut self, margin: u32) -> Self { self.margin = margin; self } pub fn set_content(mut self, content: impl Into) -> Self { self.content = Some(content.into()); self } pub fn set_background(mut self, background: FillTypeInfo) -> Self { self.background = Some(background); self } pub fn set_text(mut self, text: &str) -> Self { self.text = Some(text.to_string()); self } pub fn set_text_color(mut self, color: Color) -> Self { self.text_color = color; self } pub fn set_text_ratio(mut self, ratio: f32) -> Self { self.text_ratio = ratio; self } pub fn build(self, gui_handler: Arc) -> Result> { let framable = Framable::new(gui_handler, false)?; let iconizable_wrapper = IconizableWrapper::new(framable.clone(), self.content, self.margin)?; let background = RwLock::new( self.background .map(|info| FillType::new(framable.clone(), info)) .transpose()?, ); let textable_wrapper = TextableWrapper::new( framable.clone(), self.text_color, self.text_ratio, TextAlignment::Center, ); if let Some(text) = self.text { textable_wrapper.set_text(&text, false)?; } Ok(Arc::new(Icon { framable, background, iconizable_wrapper, textable_wrapper, visible: AtomicBool::new(false), })) } } pub struct Icon { framable: Arc, background: RwLock>, iconizable_wrapper: IconizableWrapper, textable_wrapper: TextableWrapper, visible: AtomicBool, } impl Icon { pub fn builder() -> IconBuilder { IconBuilder { content: None, background: None, margin: 0, text: None, text_color: Color::Black, text_ratio: 0.7, } } pub fn clear_icon(&self) -> Result<()> { self.iconizable_wrapper.clear_icon(self.visible()) } pub fn set_icon(&self, icon: &Arc) -> Result<()> { self.iconizable_wrapper.set_icon(icon, self.visible()) } pub fn set_margin(&self, margin: u32) -> Result<()> { self.iconizable_wrapper.set_margin(margin) } pub fn set_background(&self, background: impl Into) -> Result<()> { let background = FillType::new(self.framable.clone(), background.into())?; if self.framable.is_framed() { background.update_frame()?; } if self.visible() { background.enable()?; } *self.background.write().unwrap() = Some(background); Ok(()) } pub fn clear_background(&self) { *self.background.write().unwrap() = None; } pub fn set_text(&self, text: impl ToString) -> Result<()> { self.textable_wrapper.set_text(text, self.visible()) } pub fn clear_text(&self) -> Result<()> { self.textable_wrapper.set_text("", self.visible()) } pub fn set_text_color(&self, color: Color) -> Result<()> { self.textable_wrapper.set_text_color(color) } pub fn try_from(icon_info: &IconInfo, gui_handler: &Arc) -> Result> { let mut icon_builder = Icon::builder().set_text_color(icon_info.text_color); if let Some(text_ratio) = icon_info.text_ratio { icon_builder = icon_builder.set_text_ratio(text_ratio); } if let Some(margin) = icon_info.margin { icon_builder = icon_builder.set_margin(margin); } if let Some(icon) = &icon_info.icon { icon_builder = icon_builder.set_content(icon.clone()); } if let Some(fill_type_info) = icon_info.background_type.clone() { icon_builder = icon_builder.set_background(fill_type_info); } { let t = icon_info.text.read().unwrap(); let text = t.as_str(); if !text.is_empty() { icon_builder = icon_builder.set_text(text); } } icon_builder.build(gui_handler.clone()) } pub fn icon(&self) -> Result>> { self.iconizable_wrapper.icon() } pub fn extent(&self) -> (i32, i32) { ( self.framable.right() - self.framable.left(), self.framable.bottom() - self.framable.top(), ) } fn disable_base(&self) -> Result<()> { self.framable.delete()?; self.iconizable_wrapper.disable()?; self.textable_wrapper.disable()?; if let Some(background) = self.background.read().unwrap().as_ref() { background.disable()?; } Ok(()) } } impl GuiElementTraits for Icon { fn gridable(&self) -> Option<&dyn Gridable> { Some(self) } fn visibility(&self) -> Option<&dyn Visibility> { Some(self) } fn downcast<'a>(&'a self) -> Option> { Some(GuiElement::Icon(self)) } } impl Visibility for Icon { fn visible(&self) -> bool { self.visible.load(SeqCst) } fn set_visibility(&self, visibility: bool) -> Result<()> { if visibility != self.visible.load(SeqCst) { self.visible.store(visibility, SeqCst); if visibility { self.framable.add()?; self.iconizable_wrapper.enable()?; self.textable_wrapper.enable()?; if let Some(background) = self.background.read().unwrap().as_ref() { background.enable()?; } } else { self.disable_base()?; } } Ok(()) } } impl Gridable for Icon { fn set_frame( &self, x: i32, y: i32, w: u32, h: u32, vert_align: VerticalAlign, hori_align: HorizontalAlign, ) -> Result<()> { self.framable.set_frame(x, y, w, h, vert_align, hori_align); self.iconizable_wrapper.update_frame()?; self.textable_wrapper.update()?; if let Some(background) = self.background.read().unwrap().as_ref() { background.update_frame()?; } Ok(()) } fn selectable(&self) -> Option<&Arc> { None } fn type_name(&self) -> &str { "Icon" } fn set_layer(&self, layer: i32) -> Result<()> { self.framable.set_ui_layer(layer); self.iconizable_wrapper.set_ui_layer(layer)?; self.textable_wrapper.set_ui_layer(layer)?; if let Some(background) = self.background.read().unwrap().as_ref() { background.set_ui_layer(layer); } Ok(()) } } impl Drop for Icon { fn drop(&mut self) { if self.visible.load(SeqCst) { self.disable_base().unwrap(); } } }