use crate::{ builder::validator::labelinfo::LabelInfo, guihandler::gui::iconizable::IconizablePositioning, prelude::*, }; use super::{ fill_type::FillType, wrapper::{IconizableWrapper, TextableWrapper}, }; use vulkan_rs::prelude::*; use std::sync::{ atomic::{AtomicBool, Ordering::SeqCst}, Arc, RwLock, }; use anyhow::Result; pub struct LabelBuilder { text_alignment: TextAlignment, text_ratio: f32, text_color: Color, text: Option, background: Option, } impl LabelBuilder { pub fn set_text(mut self, text: impl Into) -> Self { self.text = Some(text.into()); self } pub fn set_ratio(mut self, ratio: f32) -> Self { self.text_ratio = ratio; self } pub fn set_text_color(mut self, text_color: impl Into) -> Self { self.text_color = text_color.into(); self } pub fn set_text_alignment(mut self, text_alignment: TextAlignment) -> Self { self.text_alignment = text_alignment; self } pub fn set_background(mut self, background: impl Into) -> Self { self.background = Some(background.into()); self } pub fn build(self, gui_handler: Arc) -> Result> { let framable = Framable::new(gui_handler, false)?; let textable_wrapper = TextableWrapper::new( framable.clone(), self.text_color, self.text_ratio, self.text_alignment, ); if let Some(text) = &self.text { textable_wrapper.set_text(text, false)?; } let background = self .background .map(|info| FillType::new(framable.clone(), info)) .transpose()?; let info_icon = IconizableWrapper::new( framable.clone(), None, Some(IconizablePositioning { left: 1.2, right: 0.0, top: 1.2, bottom: 0.0, }), 0, )?; Ok(Arc::new(Label { framable, background: RwLock::new(background), textable_wrapper, info_icon, visible: AtomicBool::new(false), })) } } pub struct Label { pub(crate) framable: Arc, background: RwLock>, textable_wrapper: TextableWrapper, info_icon: IconizableWrapper, visible: AtomicBool, } impl Label { pub fn builder() -> LabelBuilder { LabelBuilder { text_alignment: TextAlignment::Center, text_ratio: 0.7, text_color: Color::Black, text: None, background: None, } } pub fn set_text(&self, text: impl ToString) -> Result<()> { self.textable_wrapper.set_text(text, self.visible()) } pub fn text(&self) -> Result> { self.textable_wrapper.text() } pub fn set_text_color(&self, text_color: Color) -> Result<()> { self.textable_wrapper.set_text_color(text_color) } pub fn set_alignment(&self, alignment: TextAlignment) -> Result<()> { self.textable_wrapper.set_alignment(alignment) } pub fn set_text_ratio(&self, ratio: f32) -> Result<()> { self.textable_wrapper.set_height_ratio(ratio) } pub fn text_ratio(&self) -> f32 { self.textable_wrapper.height_ratio() } pub fn set_info_icon(&self, button: &Arc) -> Result<()> { self.info_icon.set_icon(button, self.visible()) } pub fn clear_info_icon(&self) -> Result<()> { self.info_icon.clear_icon(self.visible()) } pub fn set_background(&self, background: impl Into) -> Result<()> { super::set_background(self.visible(), &self.framable, &self.background, background) } pub fn try_from(label_info: &LabelInfo, gui_handler: &Arc) -> Result> { let text = label_info.text.read().unwrap().clone(); let color = label_info.text_color; let mut label_builder = Label::builder() .set_text_color(color) .set_text_alignment(label_info.text_alignment); if let Some(background_type) = &label_info.background_type { label_builder = label_builder.set_background(background_type.clone()); } if let Some(ratio) = label_info.text_ratio { label_builder = label_builder.set_ratio(ratio); } if !text.is_empty() { label_builder = label_builder.set_text(text); } label_builder.build(gui_handler.clone()) } fn disable_base(&self) -> Result<()> { self.framable.delete()?; self.textable_wrapper.disable()?; self.info_icon.disable()?; if let Some(background) = self.background.read().unwrap().as_ref() { background.disable()?; } Ok(()) } } impl GuiElementTraits for Label { fn gridable(&self) -> Option<&dyn Gridable> { Some(self) } fn visibility(&self) -> Option<&dyn Visibility> { Some(self) } fn downcast<'a>(&'a self) -> Option> { Some(GuiElement::Label(self)) } } impl Visibility for Label { fn visible(&self) -> bool { self.visible.load(SeqCst) } fn set_visibility(&self, visibility: bool) -> Result<()> { if visibility != self.visible() { self.visible.store(visibility, SeqCst); if visibility { self.framable.add()?; self.textable_wrapper.enable()?; self.info_icon.enable()?; if let Some(background) = self.background.read().unwrap().as_ref() { background.enable()?; } } else { self.disable_base()?; } } Ok(()) } } impl Gridable for Label { 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.textable_wrapper.update()?; self.info_icon.update_frame()?; 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 { "Label" } fn set_layer(&self, layer: i32) -> Result<()> { self.framable.set_ui_layer(layer); self.textable_wrapper.set_ui_layer(layer)?; self.info_icon.set_ui_layer(layer)?; if let Some(background) = self.background.read().unwrap().as_ref() { background.set_ui_layer(layer); } Ok(()) } fn position_extent(&self) -> (i32, i32, u32, u32) { self.framable.position() } } impl Drop for Label { fn drop(&mut self) { if self.visible.load(SeqCst) { self.disable_base().unwrap(); } } }