Moved PreviewPanel to it's own module.

This commit is contained in:
Filipe Rodrigues 2021-05-29 22:00:27 +01:00
parent e15afa6b6d
commit 9f7f9f6ab7
2 changed files with 180 additions and 158 deletions

View File

@ -12,24 +12,17 @@
)]
// Modules
pub mod preview_panel;
pub mod tree;
// Imports
use anyhow::Context;
use dcb_cdrom_xa::CdRomCursor;
use dcb_io::{game_file::Path, GameFile};
use dcb_tim::{Tim, Tis};
use eframe::{
egui::{self, Color32, TextureId},
epi, NativeOptions,
};
use eframe::{egui, epi, NativeOptions};
use native_dialog::{FileDialog, MessageDialog, MessageType};
use std::{
fs,
io::{BufReader, Write},
mem,
path::PathBuf,
};
use preview_panel::PreviewPanel;
use std::{fs, io::Write, mem, path::PathBuf};
use tree::FsTree;
fn main() {
@ -204,138 +197,25 @@ impl epi::App for FileEditor {
.show(ui, |ui| loaded_game.p_tree.display(ui, "P:\\", &mut display_ctx));
if let Some(path) = preview_path {
let panel: Result<_, anyhow::Error> = match path {
path if path.ends_with(".TIM") => {
try {
// Deserialize the tim
let path = Path::from_ascii(&path).context("Unable to create path")?;
let mut file =
loaded_game.game_file.open_file(path).context("Unable to open file")?;
let image: Tim = Tim::deserialize(&mut file).context("Unable to parse file")?;
// Then create a texture with it
let [width, height] = image.size();
let textures = (0..image.pallettes())
.map(|pallette| {
let colors: Box<[_]> = image
.colors(Some(pallette))
.context("Unable to get image colors")?
.to_vec()
.into_iter()
.map(|[r, g, b, a]| Color32::from_rgba_premultiplied(r, g, b, a))
.collect();
let texture_id = frame
.tex_allocator()
.alloc_srgba_premultiplied((width, height), &*colors);
Ok(texture_id)
})
.collect::<Result<_, anyhow::Error>>()?;
Some(PreviewPanel::Tim { image, textures })
}
},
path if path.ends_with(".TIS") => {
try {
// Deserialize the tis
let path = Path::from_ascii(&path).context("Unable to create path")?;
let file = loaded_game.game_file.open_file(path).context("Unable to open file")?;
let mut file = BufReader::new(file);
let images: Tis = Tis::deserialize(&mut file).context("Unable to parse file")?;
// Then create all textures
let images = images
.tims
.into_iter()
.map(|image| {
// Create a texture with it
let [width, height] = image.size();
let textures = (0..image.pallettes())
.map(|pallette| {
let colors: Box<[_]> = image
.colors(Some(pallette))
.context("Unable to get image colors")?
.to_vec()
.into_iter()
.map(|[r, g, b, a]| {
Color32::from_rgba_premultiplied(r, g, b, a)
})
.collect();
let texture_id = frame
.tex_allocator()
.alloc_srgba_premultiplied((width, height), &*colors);
Ok(texture_id)
})
.collect::<Result<_, anyhow::Error>>()?;
Ok((image, textures))
})
.collect::<Result<Vec<_>, anyhow::Error>>()?;
Some(PreviewPanel::Tis { images })
}
},
_ => Ok(None),
};
let panel = PreviewPanel::new(loaded_game, &path, frame.tex_allocator())
.context("Unable to preview file");
// Drop previous images, if they exist
#[allow(clippy::single_match)] // We'll have more in the future
match &*preview_panel {
Some(PreviewPanel::Tim { textures, .. }) => {
for &texture_id in textures {
frame.tex_allocator().free(texture_id);
}
},
Some(PreviewPanel::Tis { images }) => {
for (_, textures) in images {
for &texture_id in textures {
frame.tex_allocator().free(texture_id);
}
}
},
_ => (),
if let Some(preview_panel) = preview_panel {
preview_panel.drop_textures(frame.tex_allocator());
}
match panel {
Ok(panel) => *preview_panel = panel,
Err(err) => {
*preview_panel = Some(PreviewPanel::Error {
err: format!("{err:?}"),
})
},
}
*preview_panel = panel.unwrap_or_else(|err| {
let err = format!("{err:?}");
Some(PreviewPanel::Error { err })
});
}
});
}
});
if let Some(preview_panel) = preview_panel {
egui::CentralPanel::default().show(ctx, |ui| match &*preview_panel {
PreviewPanel::Tim { textures, image } => {
egui::ScrollArea::auto_sized().show(ui, |ui| {
for &texture_id in textures {
ui.image(texture_id, image.size().map(|dim| dim as f32));
ui.separator();
}
});
},
PreviewPanel::Tis { images } => {
egui::ScrollArea::auto_sized().show(ui, |ui| {
for (image, textures) in images {
for &texture_id in textures {
ui.image(texture_id, image.size().map(|dim| dim as f32));
ui.separator();
}
}
});
},
PreviewPanel::Error { err } => {
ui.group(|ui| {
ui.heading("Error");
ui.label(err);
});
},
});
preview_panel.display(ctx);
}
if let (Some(swap_window), Some(loaded_game)) = (swap_window, loaded_game) {
@ -424,31 +304,6 @@ pub struct SwapWindow {
second: SwapFileStatus,
}
/// Preview panel
#[derive(PartialEq, Clone)]
pub enum PreviewPanel {
/// Tim image
Tim {
/// Image
image: Tim,
/// All textures
textures: Vec<TextureId>,
},
/// Tim collection
Tis {
/// Images
images: Vec<(Tim, Vec<TextureId>)>,
},
/// Error
Error {
/// Error
err: String,
},
}
/// Status of a file being swapped
#[derive(PartialEq, Clone)]
pub enum SwapFileStatus {

View File

@ -0,0 +1,167 @@
//! Preview panel
// Imports
use crate::LoadedGame;
use anyhow::Context;
use dcb_io::game_file::Path;
use dcb_tim::{Tim, Tis};
use eframe::{
egui::{self, Color32, TextureId},
epi::TextureAllocator,
};
use std::io::BufReader;
/// Preview panel
#[derive(PartialEq, Clone)]
pub enum PreviewPanel {
/// Tim image
Tim {
/// Image
image: Tim,
/// All textures
pallettes: Vec<TextureId>,
},
/// Tim collection
Tis {
/// Images
images: Vec<(Tim, Vec<TextureId>)>,
},
/// Error
Error {
/// Error
err: String,
},
}
impl PreviewPanel {
/// Creates a preview panel
pub fn new(
loaded_game: &mut LoadedGame, path: &str, tex_allocator: &mut dyn TextureAllocator,
) -> Result<Option<Self>, anyhow::Error> {
let panel = match path {
path if path.ends_with(".TIM") => {
// Deserialize the tim
let path = Path::from_ascii(&path).context("Unable to create path")?;
let mut file = loaded_game.game_file.open_file(path).context("Unable to open file")?;
let image: Tim = Tim::deserialize(&mut file).context("Unable to parse file")?;
// Then create all pallettes
let pallettes = create_image_pallettes(&image, tex_allocator)?;
Self::Tim { image, pallettes }
},
path if path.ends_with(".TIS") => {
// Deserialize the tis
let path = Path::from_ascii(&path).context("Unable to create path")?;
let file = loaded_game.game_file.open_file(path).context("Unable to open file")?;
let mut file = BufReader::new(file);
let images: Tis = Tis::deserialize(&mut file).context("Unable to parse file")?;
// Then create all images
let images = images
.tims
.into_iter()
.map(|image| {
let pallettes = create_image_pallettes(&image, tex_allocator)
.context("Unable to create image pallettes")?;
Ok((image, pallettes))
})
.collect::<Result<Vec<_>, anyhow::Error>>()?;
Self::Tis { images }
},
_ => return Ok(None),
};
Ok(Some(panel))
}
/// Drops all textures in this panel
pub fn drop_textures(&mut self, tex_allocator: &mut dyn TextureAllocator) {
match self {
PreviewPanel::Tim { pallettes, .. } => {
for texture_id in pallettes.drain(..) {
tex_allocator.free(texture_id);
}
},
PreviewPanel::Tis { images } => {
for (_, textures) in images {
for texture_id in textures.drain(..) {
tex_allocator.free(texture_id);
}
}
},
_ => (),
}
}
/// Displays this panel
pub fn display(&self, ctx: &egui::CtxRef) {
egui::CentralPanel::default().show(ctx, |ui| match self {
Self::Tim { pallettes, image } => {
egui::ScrollArea::auto_sized().show(ui, |ui| {
for &texture_id in pallettes {
ui.image(texture_id, image.size().map(|dim| dim as f32));
ui.separator();
}
});
},
Self::Tis { images } => {
egui::ScrollArea::auto_sized().show(ui, |ui| {
for (image, pallettes) in images {
for &texture_id in pallettes {
ui.image(texture_id, image.size().map(|dim| dim as f32));
ui.separator();
}
}
});
},
Self::Error { err } => {
ui.group(|ui| {
ui.heading("Error");
ui.label(err);
});
},
});
}
}
impl Drop for PreviewPanel {
fn drop(&mut self) {
// Make sure we don't have any textures remaining
match self {
PreviewPanel::Tim { pallettes, .. } => assert_eq!(pallettes.len(), 0),
PreviewPanel::Tis { images } => {
for (_, pallettes) in images {
assert_eq!(pallettes.len(), 0)
}
},
PreviewPanel::Error { .. } => {},
};
}
}
/// Creates all pallettes for an image
fn create_image_pallettes(
image: &Tim, tex_allocator: &mut dyn TextureAllocator,
) -> Result<Vec<TextureId>, anyhow::Error> {
let [width, height] = image.size();
let textures = (0..image.pallettes())
.map(|pallette| {
let colors: Box<[_]> = image
.colors(Some(pallette))
.context("Unable to get image colors")?
.to_vec()
.into_iter()
.map(|[r, g, b, a]| Color32::from_rgba_premultiplied(r, g, b, a))
.collect();
let texture_id = tex_allocator.alloc_srgba_premultiplied((width, height), &*colors);
Ok(texture_id)
})
.collect::<Result<_, anyhow::Error>>()?;
Ok(textures)
}