diff --git a/src/elements/button.rs b/src/elements/button.rs index 32f0e3d..98cedf5 100644 --- a/src/elements/button.rs +++ b/src/elements/button.rs @@ -1,4 +1,7 @@ -use crate::{builder::validator::buttoninfo::ButtonInfo, prelude::*}; +use crate::{ + builder::validator::buttoninfo::ButtonInfo, guihandler::gui::iconizable::IconizablePositioning, + prelude::*, +}; use anyhow::Result; use assetpath::AssetPath; @@ -7,7 +10,8 @@ use vulkan_rs::prelude::*; use super::{ fill_type::{FillType, InnerFillType}, - IconBuilderType, IconizableWrapper, TextableWrapper, + wrapper::{IconizableWrapper, TextableWrapper}, + IconBuilderType, }; use cgmath::{vec2, vec4}; @@ -177,6 +181,19 @@ impl ButtonBuilder { let iconizable = IconizableWrapper::new( framable.clone(), self.icon.map(IconBuilderType::Image), + None, + self.margin, + )?; + + let button_info = IconizableWrapper::new( + framable.clone(), + None, + Some(IconizablePositioning { + left: 1.2, + right: 0.0, + top: 1.2, + bottom: 0.0, + }), self.margin, )?; @@ -187,6 +204,7 @@ impl ButtonBuilder { selectable, textable, iconizable, + button_info, #[cfg(feature = "audio")] _click_sound: click_sound, @@ -234,6 +252,7 @@ pub struct Button { framable: Arc, iconizable: IconizableWrapper, textable: TextableWrapper, + button_info: IconizableWrapper, #[cfg(feature = "audio")] _click_sound: Option>, @@ -321,6 +340,10 @@ impl Button { self.iconizable.icon() } + pub fn set_button_info(&self, button: &Arc) -> Result<()> { + self.button_info.set_icon(button, self.visible()) + } + pub fn text(&self) -> Result> { self.textable.text() } @@ -412,6 +435,7 @@ impl Visibility for Button { self.textable.enable()?; self.iconizable.enable()?; + self.button_info.enable()?; match *self.button_state.lock().unwrap() { ButtonState::Normal => self.normal.enable()?, @@ -442,6 +466,7 @@ impl Gridable for Button { self.selected.update_frame()?; self.textable.update()?; self.iconizable.update_frame()?; + self.button_info.update_frame()?; if self.select_mode == ButtonSelectMode::Bigger { self.modify_hovered_vbo()?; @@ -465,6 +490,7 @@ impl Gridable for Button { self.framable.set_ui_layer(layer); self.iconizable.set_ui_layer(layer)?; self.textable.set_ui_layer(layer)?; + self.button_info.set_ui_layer(layer)?; self.normal.set_ui_layer(layer); self.selected.set_ui_layer(layer); @@ -609,6 +635,7 @@ impl Button { self.textable.disable()?; self.iconizable.disable()?; + self.button_info.disable()?; self.normal.disable()?; self.selected.disable()?; diff --git a/src/elements/icon.rs b/src/elements/icon.rs index ef93291..2c6d134 100644 --- a/src/elements/icon.rs +++ b/src/elements/icon.rs @@ -8,7 +8,11 @@ use std::sync::{ Arc, RwLock, }; -use super::{fill_type::FillType, IconBuilderType, IconizableWrapper, TextableWrapper}; +use super::{ + fill_type::FillType, + wrapper::{IconizableWrapper, TextableWrapper}, + IconBuilderType, +}; pub struct IconBuilder { content: Option, @@ -61,7 +65,7 @@ impl IconBuilder { let framable = Framable::new(gui_handler, false)?; let iconizable_wrapper = - IconizableWrapper::new(framable.clone(), self.content, self.margin)?; + IconizableWrapper::new(framable.clone(), self.content, None, self.margin)?; let background = RwLock::new( self.background diff --git a/src/elements/label.rs b/src/elements/label.rs index 2f2b6ac..e108662 100644 --- a/src/elements/label.rs +++ b/src/elements/label.rs @@ -1,6 +1,6 @@ use crate::{builder::validator::labelinfo::LabelInfo, prelude::*}; -use super::{fill_type::FillType, TextableWrapper}; +use super::{fill_type::FillType, wrapper::TextableWrapper}; use std::sync::{ atomic::{AtomicBool, Ordering::SeqCst}, diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 6b8e4c1..aac80b3 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -1,11 +1,6 @@ use crate::{guihandler::gui::iconizable::IconBuilderType, prelude::*}; use anyhow::Result; -use std::sync::{ - atomic::{AtomicU32, Ordering::SeqCst}, - Arc, Mutex, RwLock, -}; -use utilities::prelude::*; -use vulkan_rs::prelude::*; +use std::sync::{Arc, RwLock}; use self::fill_type::FillType; @@ -24,307 +19,7 @@ pub mod traits; mod callback_builder; pub mod prelude; - -pub(crate) struct TextableWrapper { - framable: Arc, - - textable: Mutex>>, - - color: Mutex, - ratio: Mutex, - alignment: Mutex, -} - -impl TextableWrapper { - pub(crate) fn new( - framable: Arc, - color: Color, - ratio: f32, - alignment: TextAlignment, - ) -> Self { - TextableWrapper { - framable, - - textable: Mutex::new(None), - - color: Mutex::new(color), - ratio: Mutex::new(ratio), - alignment: Mutex::new(alignment), - } - } - - pub(crate) fn set_ui_layer(&self, layer: i32) -> Result<()> { - self.framable.set_ui_layer(layer); - - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.set_ui_layer(layer); - } - - Ok(()) - } - - pub(crate) fn set_text_color(&self, text_color: Color) -> Result<()> { - *self.color.lock().unwrap() = text_color; - - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.set_text_color(text_color)?; - } - - Ok(()) - } - - pub(crate) fn set_text(&self, text: impl ToString, is_visible: bool) -> Result<()> { - let text = text.to_string(); - let mut textable = self.textable.lock().unwrap(); - - match textable.as_ref() { - Some(current_textable) => { - if text.is_empty() { - current_textable.clear_callback(); - - if is_visible { - current_textable.delete()?; - } - - *textable = None; - } else { - current_textable.set_text(text)?; - } - } - None => { - if !text.is_empty() { - let new_textable = Textable::new( - self.framable.clone(), - text, - *self.ratio.lock().unwrap(), - *self.alignment.lock().unwrap(), - *self.color.lock().unwrap(), - )?; - - if self.framable.is_framed() { - new_textable.update_text()?; - } - - new_textable.set_ui_layer(self.framable.ui_layer()); - - if is_visible { - new_textable.add()?; - } - - *textable = Some(new_textable); - } - } - } - - Ok(()) - } - - pub(crate) fn text(&self) -> Result> { - Ok(self - .textable - .lock() - .unwrap() - .as_ref() - .map(|textable| textable.text())) - } - - pub(crate) fn set_height_ratio(&self, height_ratio: f32) -> Result<()> { - *self.ratio.lock().unwrap() = height_ratio; - - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.set_size(height_ratio)?; - } - - Ok(()) - } - - pub(crate) fn height_ratio(&self) -> f32 { - *self.ratio.lock().unwrap() - } - - pub(crate) fn set_alignment(&self, alignment: TextAlignment) -> Result<()> { - *self.alignment.lock().unwrap() = alignment; - - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.set_text_alignment(alignment)?; - } - - Ok(()) - } - - pub(crate) fn update(&self) -> Result<()> { - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.update_text()?; - } - - Ok(()) - } - - pub(crate) fn enable(&self) -> Result<()> { - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.add()?; - } - - Ok(()) - } - - pub(crate) fn disable(&self) -> Result<()> { - if let Some(textable) = self.textable.lock().unwrap().as_ref() { - textable.delete()?; - } - - Ok(()) - } -} - -impl Drop for TextableWrapper { - fn drop(&mut self) { - if let Some(current_textable) = self.textable.lock().unwrap().as_ref() { - current_textable.clear_callback(); - } - } -} - -pub(crate) struct IconizableWrapper { - framable: Arc, - - iconizable: Mutex>>, - margin: AtomicU32, -} - -impl IconizableWrapper { - pub(crate) fn new( - framable: Arc, - builder: Option, - margin: u32, - ) -> Result { - let iconizable: Option>> = builder.map(|content| { - let iconizable = Iconizable::new(framable.clone(), content)?; - - iconizable.set_margin(margin)?; - - Ok(iconizable) - }); - - let iconizable = iconizable.transpose()?; - - Ok(Self { - framable, - - iconizable: Mutex::new(iconizable), - margin: AtomicU32::new(margin), - }) - } - - pub(crate) fn set_ui_layer(&self, layer: i32) -> Result<()> { - self.framable.set_ui_layer(layer); - - if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { - iconizable.set_ui_layer(layer); - } - - Ok(()) - } - - pub(crate) fn clear_icon(&self, is_visible: bool) -> Result<()> { - let mut iconizable = self.iconizable.lock().unwrap(); - - if let Some(iconizable) = iconizable.as_ref() { - if is_visible { - iconizable.delete()?; - } - - iconizable.clear_callback(); - } - - *iconizable = None; - - Ok(()) - } - - pub(crate) fn set_icon( - &self, - icon_builder: impl Into, - is_visible: bool, - ) -> Result<()> { - let mut iconizable = self.iconizable.lock().unwrap(); - - match iconizable.as_ref() { - Some(iconizable) => iconizable.set_icon(icon_builder)?, - None => { - let new_iconizable = Iconizable::new(self.framable.clone(), icon_builder)?; - - new_iconizable.set_margin(self.margin.load(SeqCst))?; - - if self.framable.is_framed() { - new_iconizable.update_frame()?; - } - - new_iconizable.set_ui_layer(self.framable.ui_layer()); - - if is_visible { - new_iconizable.add()?; - } - - *iconizable = Some(new_iconizable); - } - } - - Ok(()) - } - - pub(crate) fn set_margin(&self, margin: u32) -> Result<()> { - if self.framable.is_framed() { - if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { - iconizable.set_margin(margin)?; - iconizable.update_frame()?; - } - } - - self.margin.store(margin, SeqCst); - - Ok(()) - } - - pub(crate) fn icon(&self) -> Result>> { - match self.iconizable.lock().unwrap().as_ref() { - Some(iconizable) => Ok(Some(iconizable.icon())), - None => Ok(None), - } - } - - pub(crate) fn enable(&self) -> Result<()> { - if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { - iconizable.add()?; - } - - Ok(()) - } - - pub(crate) fn disable(&self) -> Result<()> { - if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { - iconizable.delete()?; - } - - Ok(()) - } - - pub(crate) fn update_frame(&self) -> Result<()> { - if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { - iconizable.update_frame()?; - } - - Ok(()) - } -} - -impl Drop for IconizableWrapper { - fn drop(&mut self) { - if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { - iconizable.clear_callback(); - } - } -} +mod wrapper; pub(crate) fn set_background( visible: bool, diff --git a/src/elements/progress_bar.rs b/src/elements/progress_bar.rs index 80b5c61..e87f90b 100644 --- a/src/elements/progress_bar.rs +++ b/src/elements/progress_bar.rs @@ -9,7 +9,7 @@ use utilities::prelude::*; use super::{ fill_type::{FillType, InnerFillType}, - TextableWrapper, + wrapper::TextableWrapper, }; #[derive(Clone)] diff --git a/src/elements/wrapper.rs b/src/elements/wrapper.rs new file mode 100644 index 0000000..d6e663a --- /dev/null +++ b/src/elements/wrapper.rs @@ -0,0 +1,319 @@ +use crate::{ + guihandler::gui::iconizable::{IconBuilderType, IconizablePositioning}, + prelude::*, +}; +use anyhow::Result; +use std::sync::{ + atomic::{AtomicU32, Ordering::SeqCst}, + Arc, Mutex, +}; +use utilities::prelude::*; +use vulkan_rs::prelude::*; + +pub(crate) struct TextableWrapper { + framable: Arc, + + textable: Mutex>>, + + color: Mutex, + ratio: Mutex, + alignment: Mutex, +} + +impl TextableWrapper { + pub(crate) fn new( + framable: Arc, + color: Color, + ratio: f32, + alignment: TextAlignment, + ) -> Self { + TextableWrapper { + framable, + + textable: Mutex::new(None), + + color: Mutex::new(color), + ratio: Mutex::new(ratio), + alignment: Mutex::new(alignment), + } + } + + pub(crate) fn set_ui_layer(&self, layer: i32) -> Result<()> { + self.framable.set_ui_layer(layer); + + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.set_ui_layer(layer); + } + + Ok(()) + } + + pub(crate) fn set_text_color(&self, text_color: Color) -> Result<()> { + *self.color.lock().unwrap() = text_color; + + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.set_text_color(text_color)?; + } + + Ok(()) + } + + pub(crate) fn set_text(&self, text: impl ToString, is_visible: bool) -> Result<()> { + let text = text.to_string(); + let mut textable = self.textable.lock().unwrap(); + + match textable.as_ref() { + Some(current_textable) => { + if text.is_empty() { + current_textable.clear_callback(); + + if is_visible { + current_textable.delete()?; + } + + *textable = None; + } else { + current_textable.set_text(text)?; + } + } + None => { + if !text.is_empty() { + let new_textable = Textable::new( + self.framable.clone(), + text, + *self.ratio.lock().unwrap(), + *self.alignment.lock().unwrap(), + *self.color.lock().unwrap(), + )?; + + if self.framable.is_framed() { + new_textable.update_text()?; + } + + new_textable.set_ui_layer(self.framable.ui_layer()); + + if is_visible { + new_textable.add()?; + } + + *textable = Some(new_textable); + } + } + } + + Ok(()) + } + + pub(crate) fn text(&self) -> Result> { + Ok(self + .textable + .lock() + .unwrap() + .as_ref() + .map(|textable| textable.text())) + } + + pub(crate) fn set_height_ratio(&self, height_ratio: f32) -> Result<()> { + *self.ratio.lock().unwrap() = height_ratio; + + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.set_size(height_ratio)?; + } + + Ok(()) + } + + pub(crate) fn height_ratio(&self) -> f32 { + *self.ratio.lock().unwrap() + } + + pub(crate) fn set_alignment(&self, alignment: TextAlignment) -> Result<()> { + *self.alignment.lock().unwrap() = alignment; + + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.set_text_alignment(alignment)?; + } + + Ok(()) + } + + pub(crate) fn update(&self) -> Result<()> { + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.update_text()?; + } + + Ok(()) + } + + pub(crate) fn enable(&self) -> Result<()> { + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.add()?; + } + + Ok(()) + } + + pub(crate) fn disable(&self) -> Result<()> { + if let Some(textable) = self.textable.lock().unwrap().as_ref() { + textable.delete()?; + } + + Ok(()) + } +} + +impl Drop for TextableWrapper { + fn drop(&mut self) { + if let Some(current_textable) = self.textable.lock().unwrap().as_ref() { + current_textable.clear_callback(); + } + } +} + +pub(crate) struct IconizableWrapper { + framable: Arc, + + iconizable: Mutex>>, + positioning: Option, + margin: AtomicU32, +} + +impl IconizableWrapper { + pub(crate) fn new( + framable: Arc, + builder: Option, + positioning: Option, + margin: u32, + ) -> Result { + let iconizable: Option>> = builder.map(|content| { + let iconizable = Iconizable::new(framable.clone(), content, positioning.clone())?; + + iconizable.set_margin(margin)?; + + Ok(iconizable) + }); + + let iconizable = iconizable.transpose()?; + + Ok(Self { + framable, + + iconizable: Mutex::new(iconizable), + positioning, + margin: AtomicU32::new(margin), + }) + } + + pub(crate) fn set_ui_layer(&self, layer: i32) -> Result<()> { + self.framable.set_ui_layer(layer); + + if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { + iconizable.set_ui_layer(layer); + } + + Ok(()) + } + + pub(crate) fn clear_icon(&self, is_visible: bool) -> Result<()> { + let mut iconizable = self.iconizable.lock().unwrap(); + + if let Some(iconizable) = iconizable.as_ref() { + if is_visible { + iconizable.delete()?; + } + + iconizable.clear_callback(); + } + + *iconizable = None; + + Ok(()) + } + + pub(crate) fn set_icon( + &self, + icon_builder: impl Into, + is_visible: bool, + ) -> Result<()> { + let mut iconizable = self.iconizable.lock().unwrap(); + + match iconizable.as_ref() { + Some(iconizable) => iconizable.set_icon(icon_builder)?, + None => { + let new_iconizable = Iconizable::new( + self.framable.clone(), + icon_builder, + self.positioning.clone(), + )?; + + new_iconizable.set_margin(self.margin.load(SeqCst))?; + + if self.framable.is_framed() { + new_iconizable.update_frame()?; + } + + new_iconizable.set_ui_layer(self.framable.ui_layer()); + + if is_visible { + new_iconizable.add()?; + } + + *iconizable = Some(new_iconizable); + } + } + + Ok(()) + } + + pub(crate) fn set_margin(&self, margin: u32) -> Result<()> { + if self.framable.is_framed() { + if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { + iconizable.set_margin(margin)?; + iconizable.update_frame()?; + } + } + + self.margin.store(margin, SeqCst); + + Ok(()) + } + + pub(crate) fn icon(&self) -> Result>> { + match self.iconizable.lock().unwrap().as_ref() { + Some(iconizable) => Ok(Some(iconizable.icon())), + None => Ok(None), + } + } + + pub(crate) fn enable(&self) -> Result<()> { + if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { + iconizable.add()?; + } + + Ok(()) + } + + pub(crate) fn disable(&self) -> Result<()> { + if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { + iconizable.delete()?; + } + + Ok(()) + } + + pub(crate) fn update_frame(&self) -> Result<()> { + if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { + iconizable.update_frame()?; + } + + Ok(()) + } +} + +impl Drop for IconizableWrapper { + fn drop(&mut self) { + if let Some(iconizable) = self.iconizable.lock().unwrap().as_ref() { + iconizable.clear_callback(); + } + } +} diff --git a/src/guihandler/gui/iconizable.rs b/src/guihandler/gui/iconizable.rs index f8a099b..5a5779b 100644 --- a/src/guihandler/gui/iconizable.rs +++ b/src/guihandler/gui/iconizable.rs @@ -55,6 +55,14 @@ impl From<&Arc> for IconBuilderType { } } +#[derive(Debug, Clone)] +pub struct IconizablePositioning { + pub left: f32, + pub right: f32, + pub top: f32, + pub bottom: f32, +} + /// `Iconizable` gives the ability to display a icon as icon on an UI item pub struct Iconizable { framable: Arc, @@ -66,6 +74,7 @@ pub struct Iconizable { margin: AtomicU32, ui_layer: AtomicI32, + positioning: Option, } impl Iconizable { @@ -78,6 +87,7 @@ impl Iconizable { pub fn new( framable: Arc, icon_builder: impl Into, + positioning: impl Into>, ) -> Result> { let icon = framable.gui_handler().request_icon(icon_builder)?; @@ -107,6 +117,7 @@ impl Iconizable { margin: AtomicU32::new(0), ui_layer: AtomicI32::new(0), + positioning: positioning.into(), }); let iconizable_clone = iconizable.clone(); @@ -168,13 +179,22 @@ impl Iconizable { assert!(self.framable.is_framed(), "framable is not framed yet"); // frame parameter - let parent_left = self.framable.left(); + let mut parent_left = self.framable.left(); let parent_right = self.framable.right(); - let parent_top = self.framable.top(); + let mut parent_top = self.framable.top(); let parent_bottom = self.framable.bottom(); - let parent_width = parent_right as i32 - parent_left; - let parent_height = parent_bottom as i32 - parent_top; + let mut parent_width = parent_right as i32 - parent_left; + let mut parent_height = parent_bottom as i32 - parent_top; + + if let Some(positioning) = &self.positioning { + parent_left += ((parent_width as f32 / 2.0) * positioning.left) as i32; + parent_width = + (parent_width as f32 * ((positioning.left + positioning.right) / 2.0)) as i32; + parent_top += ((parent_height as f32 / 2.0) * positioning.top) as i32; + parent_height = + (parent_height as f32 * ((positioning.top + positioning.bottom) / 2.0)) as i32; + } // icon parameter let (icon_width, icon_height) = {