Implement controller icon for button
This commit is contained in:
parent
d1b59e008f
commit
17a12024bb
7 changed files with 382 additions and 317 deletions
|
@ -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 anyhow::Result;
|
||||||
use assetpath::AssetPath;
|
use assetpath::AssetPath;
|
||||||
|
@ -7,7 +10,8 @@ use vulkan_rs::prelude::*;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
fill_type::{FillType, InnerFillType},
|
fill_type::{FillType, InnerFillType},
|
||||||
IconBuilderType, IconizableWrapper, TextableWrapper,
|
wrapper::{IconizableWrapper, TextableWrapper},
|
||||||
|
IconBuilderType,
|
||||||
};
|
};
|
||||||
use cgmath::{vec2, vec4};
|
use cgmath::{vec2, vec4};
|
||||||
|
|
||||||
|
@ -177,6 +181,19 @@ impl ButtonBuilder {
|
||||||
let iconizable = IconizableWrapper::new(
|
let iconizable = IconizableWrapper::new(
|
||||||
framable.clone(),
|
framable.clone(),
|
||||||
self.icon.map(IconBuilderType::Image),
|
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,
|
self.margin,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -187,6 +204,7 @@ impl ButtonBuilder {
|
||||||
selectable,
|
selectable,
|
||||||
textable,
|
textable,
|
||||||
iconizable,
|
iconizable,
|
||||||
|
button_info,
|
||||||
|
|
||||||
#[cfg(feature = "audio")]
|
#[cfg(feature = "audio")]
|
||||||
_click_sound: click_sound,
|
_click_sound: click_sound,
|
||||||
|
@ -234,6 +252,7 @@ pub struct Button {
|
||||||
framable: Arc<Framable>,
|
framable: Arc<Framable>,
|
||||||
iconizable: IconizableWrapper,
|
iconizable: IconizableWrapper,
|
||||||
textable: TextableWrapper,
|
textable: TextableWrapper,
|
||||||
|
button_info: IconizableWrapper,
|
||||||
|
|
||||||
#[cfg(feature = "audio")]
|
#[cfg(feature = "audio")]
|
||||||
_click_sound: Option<Arc<Audible>>,
|
_click_sound: Option<Arc<Audible>>,
|
||||||
|
@ -321,6 +340,10 @@ impl Button {
|
||||||
self.iconizable.icon()
|
self.iconizable.icon()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_button_info(&self, button: &Arc<Image>) -> Result<()> {
|
||||||
|
self.button_info.set_icon(button, self.visible())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn text(&self) -> Result<Option<String>> {
|
pub fn text(&self) -> Result<Option<String>> {
|
||||||
self.textable.text()
|
self.textable.text()
|
||||||
}
|
}
|
||||||
|
@ -412,6 +435,7 @@ impl Visibility for Button {
|
||||||
|
|
||||||
self.textable.enable()?;
|
self.textable.enable()?;
|
||||||
self.iconizable.enable()?;
|
self.iconizable.enable()?;
|
||||||
|
self.button_info.enable()?;
|
||||||
|
|
||||||
match *self.button_state.lock().unwrap() {
|
match *self.button_state.lock().unwrap() {
|
||||||
ButtonState::Normal => self.normal.enable()?,
|
ButtonState::Normal => self.normal.enable()?,
|
||||||
|
@ -442,6 +466,7 @@ impl Gridable for Button {
|
||||||
self.selected.update_frame()?;
|
self.selected.update_frame()?;
|
||||||
self.textable.update()?;
|
self.textable.update()?;
|
||||||
self.iconizable.update_frame()?;
|
self.iconizable.update_frame()?;
|
||||||
|
self.button_info.update_frame()?;
|
||||||
|
|
||||||
if self.select_mode == ButtonSelectMode::Bigger {
|
if self.select_mode == ButtonSelectMode::Bigger {
|
||||||
self.modify_hovered_vbo()?;
|
self.modify_hovered_vbo()?;
|
||||||
|
@ -465,6 +490,7 @@ impl Gridable for Button {
|
||||||
self.framable.set_ui_layer(layer);
|
self.framable.set_ui_layer(layer);
|
||||||
self.iconizable.set_ui_layer(layer)?;
|
self.iconizable.set_ui_layer(layer)?;
|
||||||
self.textable.set_ui_layer(layer)?;
|
self.textable.set_ui_layer(layer)?;
|
||||||
|
self.button_info.set_ui_layer(layer)?;
|
||||||
|
|
||||||
self.normal.set_ui_layer(layer);
|
self.normal.set_ui_layer(layer);
|
||||||
self.selected.set_ui_layer(layer);
|
self.selected.set_ui_layer(layer);
|
||||||
|
@ -609,6 +635,7 @@ impl Button {
|
||||||
|
|
||||||
self.textable.disable()?;
|
self.textable.disable()?;
|
||||||
self.iconizable.disable()?;
|
self.iconizable.disable()?;
|
||||||
|
self.button_info.disable()?;
|
||||||
|
|
||||||
self.normal.disable()?;
|
self.normal.disable()?;
|
||||||
self.selected.disable()?;
|
self.selected.disable()?;
|
||||||
|
|
|
@ -8,7 +8,11 @@ use std::sync::{
|
||||||
Arc, RwLock,
|
Arc, RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{fill_type::FillType, IconBuilderType, IconizableWrapper, TextableWrapper};
|
use super::{
|
||||||
|
fill_type::FillType,
|
||||||
|
wrapper::{IconizableWrapper, TextableWrapper},
|
||||||
|
IconBuilderType,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct IconBuilder {
|
pub struct IconBuilder {
|
||||||
content: Option<IconBuilderType>,
|
content: Option<IconBuilderType>,
|
||||||
|
@ -61,7 +65,7 @@ impl IconBuilder {
|
||||||
let framable = Framable::new(gui_handler, false)?;
|
let framable = Framable::new(gui_handler, false)?;
|
||||||
|
|
||||||
let iconizable_wrapper =
|
let iconizable_wrapper =
|
||||||
IconizableWrapper::new(framable.clone(), self.content, self.margin)?;
|
IconizableWrapper::new(framable.clone(), self.content, None, self.margin)?;
|
||||||
|
|
||||||
let background = RwLock::new(
|
let background = RwLock::new(
|
||||||
self.background
|
self.background
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{builder::validator::labelinfo::LabelInfo, prelude::*};
|
use crate::{builder::validator::labelinfo::LabelInfo, prelude::*};
|
||||||
|
|
||||||
use super::{fill_type::FillType, TextableWrapper};
|
use super::{fill_type::FillType, wrapper::TextableWrapper};
|
||||||
|
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering::SeqCst},
|
atomic::{AtomicBool, Ordering::SeqCst},
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
use crate::{guihandler::gui::iconizable::IconBuilderType, prelude::*};
|
use crate::{guihandler::gui::iconizable::IconBuilderType, prelude::*};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::sync::{
|
use std::sync::{Arc, RwLock};
|
||||||
atomic::{AtomicU32, Ordering::SeqCst},
|
|
||||||
Arc, Mutex, RwLock,
|
|
||||||
};
|
|
||||||
use utilities::prelude::*;
|
|
||||||
use vulkan_rs::prelude::*;
|
|
||||||
|
|
||||||
use self::fill_type::FillType;
|
use self::fill_type::FillType;
|
||||||
|
|
||||||
|
@ -24,307 +19,7 @@ pub mod traits;
|
||||||
|
|
||||||
mod callback_builder;
|
mod callback_builder;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
mod wrapper;
|
||||||
pub(crate) struct TextableWrapper {
|
|
||||||
framable: Arc<Framable>,
|
|
||||||
|
|
||||||
textable: Mutex<Option<Arc<Textable>>>,
|
|
||||||
|
|
||||||
color: Mutex<Color>,
|
|
||||||
ratio: Mutex<f32>,
|
|
||||||
alignment: Mutex<TextAlignment>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextableWrapper {
|
|
||||||
pub(crate) fn new(
|
|
||||||
framable: Arc<Framable>,
|
|
||||||
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<Option<String>> {
|
|
||||||
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<Framable>,
|
|
||||||
|
|
||||||
iconizable: Mutex<Option<Arc<Iconizable>>>,
|
|
||||||
margin: AtomicU32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IconizableWrapper {
|
|
||||||
pub(crate) fn new(
|
|
||||||
framable: Arc<Framable>,
|
|
||||||
builder: Option<IconBuilderType>,
|
|
||||||
margin: u32,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let iconizable: Option<Result<Arc<Iconizable>>> = 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<IconBuilderType>,
|
|
||||||
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<Option<Arc<Image>>> {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_background(
|
pub(crate) fn set_background(
|
||||||
visible: bool,
|
visible: bool,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use utilities::prelude::*;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
fill_type::{FillType, InnerFillType},
|
fill_type::{FillType, InnerFillType},
|
||||||
TextableWrapper,
|
wrapper::TextableWrapper,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
319
src/elements/wrapper.rs
Normal file
319
src/elements/wrapper.rs
Normal file
|
@ -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<Framable>,
|
||||||
|
|
||||||
|
textable: Mutex<Option<Arc<Textable>>>,
|
||||||
|
|
||||||
|
color: Mutex<Color>,
|
||||||
|
ratio: Mutex<f32>,
|
||||||
|
alignment: Mutex<TextAlignment>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextableWrapper {
|
||||||
|
pub(crate) fn new(
|
||||||
|
framable: Arc<Framable>,
|
||||||
|
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<Option<String>> {
|
||||||
|
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<Framable>,
|
||||||
|
|
||||||
|
iconizable: Mutex<Option<Arc<Iconizable>>>,
|
||||||
|
positioning: Option<IconizablePositioning>,
|
||||||
|
margin: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IconizableWrapper {
|
||||||
|
pub(crate) fn new(
|
||||||
|
framable: Arc<Framable>,
|
||||||
|
builder: Option<IconBuilderType>,
|
||||||
|
positioning: Option<IconizablePositioning>,
|
||||||
|
margin: u32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let iconizable: Option<Result<Arc<Iconizable>>> = 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<IconBuilderType>,
|
||||||
|
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<Option<Arc<Image>>> {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,14 @@ impl From<&Arc<Image>> 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
|
/// `Iconizable` gives the ability to display a icon as icon on an UI item
|
||||||
pub struct Iconizable {
|
pub struct Iconizable {
|
||||||
framable: Arc<Framable>,
|
framable: Arc<Framable>,
|
||||||
|
@ -66,6 +74,7 @@ pub struct Iconizable {
|
||||||
|
|
||||||
margin: AtomicU32,
|
margin: AtomicU32,
|
||||||
ui_layer: AtomicI32,
|
ui_layer: AtomicI32,
|
||||||
|
positioning: Option<IconizablePositioning>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iconizable {
|
impl Iconizable {
|
||||||
|
@ -78,6 +87,7 @@ impl Iconizable {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
framable: Arc<Framable>,
|
framable: Arc<Framable>,
|
||||||
icon_builder: impl Into<IconBuilderType>,
|
icon_builder: impl Into<IconBuilderType>,
|
||||||
|
positioning: impl Into<Option<IconizablePositioning>>,
|
||||||
) -> Result<Arc<Self>> {
|
) -> Result<Arc<Self>> {
|
||||||
let icon = framable.gui_handler().request_icon(icon_builder)?;
|
let icon = framable.gui_handler().request_icon(icon_builder)?;
|
||||||
|
|
||||||
|
@ -107,6 +117,7 @@ impl Iconizable {
|
||||||
|
|
||||||
margin: AtomicU32::new(0),
|
margin: AtomicU32::new(0),
|
||||||
ui_layer: AtomicI32::new(0),
|
ui_layer: AtomicI32::new(0),
|
||||||
|
positioning: positioning.into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let iconizable_clone = iconizable.clone();
|
let iconizable_clone = iconizable.clone();
|
||||||
|
@ -168,13 +179,22 @@ impl Iconizable {
|
||||||
assert!(self.framable.is_framed(), "framable is not framed yet");
|
assert!(self.framable.is_framed(), "framable is not framed yet");
|
||||||
|
|
||||||
// frame parameter
|
// frame parameter
|
||||||
let parent_left = self.framable.left();
|
let mut parent_left = self.framable.left();
|
||||||
let parent_right = self.framable.right();
|
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_bottom = self.framable.bottom();
|
||||||
|
|
||||||
let parent_width = parent_right as i32 - parent_left;
|
let mut parent_width = parent_right as i32 - parent_left;
|
||||||
let parent_height = parent_bottom as i32 - parent_top;
|
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
|
// icon parameter
|
||||||
let (icon_width, icon_height) = {
|
let (icon_width, icon_height) = {
|
||||||
|
|
Loading…
Reference in a new issue