use egui::ColorImage;
use egui::load::SizedTexture;
use fltk::{
enums,
image::SvgImage,
prelude::{FltkError, ImageExt},
};
use std::sync::Mutex;
pub struct RetainedEguiImage {
debug_name: String,
size: [usize; 2],
image: Mutex<egui::ColorImage>,
texture: Mutex<Option<egui::TextureHandle>>,
options: egui::TextureOptions,
}
impl RetainedEguiImage {
pub fn from_color_image(
debug_name: impl Into<String>,
image: ColorImage,
options: egui::TextureOptions,
) -> Self {
Self {
debug_name: debug_name.into(),
size: image.size,
image: Mutex::new(image),
texture: Default::default(),
options,
}
}
pub fn from_fltk_image<I: ImageExt>(
debug_name: impl Into<String>,
image: I,
options: egui::TextureOptions,
) -> Result<RetainedEguiImage, FltkError> {
let size = [image.data_w() as usize, image.data_h() as usize];
let color_image = egui::ColorImage::from_rgba_unmultiplied(
size,
&image
.to_rgb()?
.convert(enums::ColorDepth::Rgba8)?
.to_rgb_data(),
);
Ok(RetainedEguiImage::from_color_image(
debug_name,
color_image,
options,
))
}
pub fn from_fltk_image_as_ref<I: ImageExt>(
debug_name: impl Into<String>,
image: &I,
options: egui::TextureOptions,
) -> Result<RetainedEguiImage, FltkError> {
let size = [image.data_w() as usize, image.data_h() as usize];
let color_image = egui::ColorImage::from_rgba_unmultiplied(
size,
&image
.to_rgb()?
.convert(enums::ColorDepth::Rgba8)?
.to_rgb_data(),
);
Ok(RetainedEguiImage::from_color_image(
debug_name,
color_image,
options,
))
}
pub fn from_fltk_svg_image_as_ref(
debug_name: impl Into<String>,
svg_image: &mut SvgImage,
options: egui::TextureOptions,
) -> Result<RetainedEguiImage, FltkError> {
svg_image.normalize();
let size = [svg_image.data_w() as usize, svg_image.data_h() as usize];
let color_image = egui::ColorImage::from_rgba_unmultiplied(
size,
&svg_image
.to_rgb()?
.convert(enums::ColorDepth::Rgba8)?
.to_rgb_data(),
);
Ok(RetainedEguiImage::from_color_image(
debug_name,
color_image,
options,
))
}
pub fn from_fltk_svg_image(
debug_name: impl Into<String>,
mut svg_image: SvgImage,
options: egui::TextureOptions,
) -> Result<RetainedEguiImage, FltkError> {
svg_image.normalize();
let size = [svg_image.data_w() as usize, svg_image.data_h() as usize];
let color_image = egui::ColorImage::from_rgba_unmultiplied(
size,
&svg_image
.to_rgb()?
.convert(enums::ColorDepth::Rgba8)?
.to_rgb_data(),
);
Ok(RetainedEguiImage::from_color_image(
debug_name,
color_image,
options,
))
}
pub fn size(&self) -> [usize; 2] {
self.size
}
pub fn size_vec2(&self) -> egui::Vec2 {
let [w, h] = self.size();
egui::vec2(w as f32, h as f32)
}
pub fn debug_name(&self) -> &str {
&self.debug_name
}
pub fn texture_id(&self, ctx: &egui::Context) -> egui::TextureId {
self.texture
.lock()
.unwrap()
.get_or_insert_with(|| {
let image: &mut ColorImage = &mut self.image.lock().unwrap();
let image = std::mem::take(image);
ctx.load_texture(&self.debug_name, image, self.options)
})
.id()
}
pub fn show_max_size(&self, ui: &mut egui::Ui, max_size: egui::Vec2) -> egui::Response {
let mut desired_size = self.size_vec2();
desired_size *= (max_size.x / desired_size.x).min(1.0);
desired_size *= (max_size.y / desired_size.y).min(1.0);
self.show_size(ui, desired_size)
}
pub fn show(&self, ui: &mut egui::Ui) -> egui::Response {
self.show_size(ui, self.size_vec2())
}
pub fn show_scaled(&self, ui: &mut egui::Ui, scale: f32) -> egui::Response {
self.show_size(ui, self.size_vec2() * scale)
}
pub fn show_size(&self, ui: &mut egui::Ui, desired_size: egui::Vec2) -> egui::Response {
ui.image(SizedTexture { id: self.texture_id(ui.ctx()), size: desired_size })
}
}