use crate::{error::GuiError, internal::UpdateMessage};
use parking_lot::RwLock;
use std::sync::{
atomic::{AtomicU64, Ordering},
mpsc::Sender,
Arc,
};
use vulkano::{
device::Queue,
format::R8G8B8A8Srgb,
image::{Dimensions, ImmutableImage},
sync::GpuFuture,
};
pub struct GuiElementRef {
pub data: Arc<RwLock<GuiElementData>>,
pub texture: Arc<ImmutableImage<R8G8B8A8Srgb>>,
pub texture_future: Option<Box<dyn GpuFuture>>,
}
impl GuiElementRef {
pub fn with_new_data(&self, new_data: Arc<RwLock<GuiElementData>>) -> GuiElementRef {
GuiElementRef {
data: new_data,
texture: self.texture.clone(),
texture_future: None,
}
}
}
pub struct GuiElementData {
pub dimensions: (i32, i32, u32, u32),
}
pub struct GuiElement {
id: u64,
data: Arc<RwLock<GuiElementData>>,
internal_update: Sender<UpdateMessage>,
}
static ID: AtomicU64 = AtomicU64::new(0);
impl Clone for GuiElement {
fn clone(&self) -> Self {
let old_id = self.id;
let new_id = ID.fetch_add(1, Ordering::Relaxed);
let data = self.data.read();
let data = Arc::new(RwLock::new(GuiElementData {
dimensions: data.dimensions,
}));
let _ = self.internal_update.send(UpdateMessage::NewGuiElement {
old_id,
new_id,
data: data.clone(),
});
Self {
id: new_id,
data,
internal_update: self.internal_update.clone(),
}
}
}
impl Drop for GuiElement {
fn drop(&mut self) {
let _ = self
.internal_update
.send(UpdateMessage::GuiElementDropped(self.id));
}
}
impl GuiElement {
pub(crate) fn new(
queue: Arc<Queue>,
dimensions: (i32, i32, u32, u32),
image_data: (u32, u32, Vec<u8>),
internal_update: Sender<UpdateMessage>,
) -> Result<(u64, GuiElementRef, GuiElement), GuiError> {
let id = ID.fetch_add(1, Ordering::Relaxed);
let (width, height, data) = image_data;
let (texture, texture_future) = ImmutableImage::from_iter(
data.into_iter(),
Dimensions::Dim2d { width, height },
R8G8B8A8Srgb,
queue,
)
.map_err(|inner| GuiError::CouldNotCreateTexture { inner })?;
let data = Arc::new(RwLock::new(GuiElementData { dimensions }));
Ok((
id,
GuiElementRef {
data: Arc::clone(&data),
texture,
texture_future: Some(texture_future.boxed()),
},
GuiElement {
id,
data,
internal_update,
},
))
}
pub fn modify(&self, cb: impl FnOnce(&mut GuiElementData)) {
let mut lock = self.data.write();
cb(&mut *lock);
}
}