ui/src/gui_handler/gui/writeable.rs
2025-03-04 11:37:45 +01:00

126 lines
3.8 KiB
Rust

//! `Writeable` is a property to change text of an item
use crate::prelude::*;
use anyhow::Result;
use std::sync::{
Arc, RwLock,
atomic::{AtomicI32, Ordering::SeqCst},
};
pub trait ModifyText: Send + Sync {
fn set_text(&self, gui_handler: &mut GuiHandler<'_>, text: String) -> Result<()>;
fn add_letter(&self, gui_handler: &mut GuiHandler<'_>, letter: char) -> Result<String>;
fn remove_last(&self, gui_handler: &mut GuiHandler<'_>) -> Result<Option<String>>;
}
/// `Writeable` gives the ability to modify the text inside an `Textable`
pub struct Writeable {
modifyable: Arc<dyn ModifyText>,
text_change_executable: Arc<Executable<Option<String>>>,
activation_changed_executable:
RwLock<Option<Box<dyn Fn(&mut GuiHandler<'_>, bool) -> Result<()> + Send + Sync>>>,
ui_layer: AtomicI32,
}
impl Writeable {
/// Factory method for `Writeable`, returns `Arc<Writeable>`.
pub fn new(
modifyable: Arc<dyn ModifyText>,
text_change_executable: Arc<Executable<Option<String>>>,
) -> Result<Arc<Self>> {
Ok(Arc::new(Writeable {
modifyable,
text_change_executable,
activation_changed_executable: RwLock::new(None),
ui_layer: AtomicI32::new(0),
}))
}
pub fn set_active(self: &Arc<Self>, gui_handler: &mut GuiHandler<'_>) -> Result<()> {
if gui_handler.set_active_writeable(self.clone())? {
if let Some(exec) = &*self.activation_changed_executable.read().unwrap() {
exec(true)?;
}
}
Ok(())
}
pub(crate) fn inactivation_event(&self) -> Result<()> {
if let Some(exec) = &*self.activation_changed_executable.read().unwrap() {
exec(false)?;
}
Ok(())
}
pub fn set_activation_changed<F>(&self, f: F)
where
F: Fn(&mut GuiHandler<'_>, bool) -> Result<()> + Send + Sync + 'static,
{
*self.activation_changed_executable.write().unwrap() = Some(Box::new(f));
}
/// Add method
///
/// # Arguments
///
/// * `writeable` is a `&Arc<Writeable>` instance that is going to be added
pub fn add(self: &Arc<Self>, gui_handler: &mut GuiHandler<'_>) -> Result<()> {
gui_handler.add_writeable(self.ui_layer.load(SeqCst), self.clone())
}
/// Delete method, has to be explicitly called, otherwise it will remain in memory.
///
/// # Arguments
///
/// * `writeable` is a `&Arc<Writeable>` instance that is going to be deleted
pub fn delete(self: &Arc<Self>, gui_handler: &mut GuiHandler<'_>) -> Result<()> {
gui_handler.delete_writeable(self.ui_layer.load(SeqCst), self)
}
pub fn set_ui_layer(&self, ui_layer: i32) {
self.ui_layer.store(ui_layer, SeqCst);
}
/// Replaces the text of `Textable`
///
/// # Arguments
///
/// * `text` that replaces the current text
pub fn set_text(&self, gui_handler: &mut GuiHandler<'_>, text: String) -> Result<()> {
self.modifyable.set_text(gui_handler, text.clone())?;
self.text_change_executable
.execute(gui_handler, if text.is_empty() { None } else { Some(text) })?;
Ok(())
}
/// Adds the letter to Text
///
/// # Arguments
///
/// * `letter` the letter thats going to be added
pub fn add_letter(&self, gui_handler: &mut GuiHandler<'_>, letter: char) -> Result<()> {
self.text_change_executable.execute(
gui_handler,
Some(self.modifyable.add_letter(gui_handler, letter)?),
)?;
Ok(())
}
/// Removes the last letter
pub fn remove_last(&self, gui_handler: &mut GuiHandler<'_>) -> Result<()> {
self.text_change_executable
.execute(gui_handler, self.modifyable.remove_last(gui_handler)?)?;
Ok(())
}
}