use glib::prelude::Cast;
use gtk::{gdk, glib};
use png::ColorType;
use std::path::{Path, PathBuf};
use libmosh::{
MoshCore, MoshData, MoshOptions,
err::MoshError,
ops::{read_file, write_file},
};
pub struct Base {
pub core: MoshCore,
pub texture: gdk::Texture,
pub settings: Option<MoshOptions>,
}
impl Base {
fn new() -> Self {
Self {
core: MoshCore::new(),
texture: gdk::MemoryTexture::new(
1_i32,
1_i32,
gdk::MemoryFormat::R8g8b8,
&glib::Bytes::from_owned([1, 1, 1]),
3,
)
.upcast(),
settings: None,
}
}
pub fn generate_texture(data: &MoshData, options: &MoshOptions) -> gdk::MemoryTexture {
let mut palette = None;
let buf = &data.buf;
let width = data.width;
let height = data.height;
let color_type = if options.ansi {
ColorType::Indexed
} else {
data.color_type
};
if options.ansi {
palette = Some(libmosh::generate_palette());
} else if color_type == ColorType::Indexed {
palette.clone_from(&data.palette);
}
let (format, stride) = match color_type {
ColorType::Grayscale => (gdk::MemoryFormat::G8, (width)),
ColorType::GrayscaleAlpha => (gdk::MemoryFormat::G8a8, (width * 2)),
ColorType::Rgb => (gdk::MemoryFormat::R8g8b8, (width * 3)),
ColorType::Rgba => (gdk::MemoryFormat::R8g8b8a8, (width * 4)),
ColorType::Indexed => {
let p = palette.unwrap();
let mut rgb = Vec::with_capacity(buf.len());
for i in buf.iter().copied().map(usize::from) {
rgb.push(p[i * 3]);
rgb.push(p[i * 3 + 1]);
rgb.push(p[i * 3 + 2]);
}
return gdk::MemoryTexture::new(
width as i32,
height as i32,
gdk::MemoryFormat::R8g8b8,
&glib::Bytes::from_owned(rgb),
width as usize * 3,
)
.upcast();
}
};
gdk::MemoryTexture::new(
width as i32,
height as i32,
format,
&glib::Bytes::from(buf),
stride as usize,
)
}
pub fn open_file(&mut self, file: &PathBuf) -> Result<(), MoshError> {
let input = read_file(file)?;
self.core.read_image(&input)?;
Ok(())
}
pub fn save_file(&mut self, file: &Path) -> Result<(), MoshError> {
write_file(file.to_str().unwrap(), &self.core.data, &self.core.options)?;
Ok(())
}
pub fn mosh_file(&mut self) -> Result<(), MoshError> {
let min_rate = self.core.options.min_rate;
let max_rate = std::cmp::max(self.core.options.max_rate, min_rate);
if min_rate == max_rate {
self.core.options.max_rate = max_rate + 1;
}
self.core.mosh()?;
self.texture = Self::generate_texture(&self.core.data, &self.core.options).upcast();
Ok(())
}
pub fn get_texture(&mut self) -> gdk::Texture {
self.texture.clone()
}
pub fn new_seed(&mut self) {
self.core.options.new_seed();
}
pub fn get_seed(&self) -> u64 {
self.core.options.seed
}
pub fn set_ansi(&mut self, value: bool) {
self.core.options.ansi = value;
}
pub fn set_seed(&mut self, value: u64) {
self.core.options.seed = value;
}
pub fn set_min_rate(&mut self, value: u16) {
self.core.options.min_rate = value;
}
pub fn set_max_rate(&mut self, value: u16) {
self.core.options.max_rate = value;
}
pub fn set_pixelation(&mut self, value: u8) {
self.core.options.pixelation = value;
}
pub fn set_line_shift(&mut self, value: f64) {
self.core.options.line_shift = value;
}
pub fn set_reverse(&mut self, value: f64) {
self.core.options.reverse = value;
}
pub fn set_flip(&mut self, value: f64) {
self.core.options.flip = value;
}
pub fn set_channel_swap(&mut self, value: f64) {
self.core.options.channel_swap = value;
}
pub fn set_channel_shift(&mut self, value: f64) {
self.core.options.channel_shift = value;
}
pub fn save_settings(&mut self) {
self.settings = Some(self.core.options.clone());
}
pub fn load_settings(&mut self) {
if let Some(settings) = self.settings.clone() {
self.core.options = settings;
self.settings = None;
}
}
}
impl Default for Base {
fn default() -> Self {
Self::new()
}
}