diff --git a/src/Tools/tim_tool/Cargo.lock b/src/Tools/tim_tool/Cargo.lock index b265ea81..ed25e7f2 100644 --- a/src/Tools/tim_tool/Cargo.lock +++ b/src/Tools/tim_tool/Cargo.lock @@ -3150,6 +3150,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -4111,6 +4117,7 @@ dependencies = [ name = "tim_tool" version = "0.1.0" dependencies = [ + "pathdiff", "png", "rfd", "serde", diff --git a/src/Tools/tim_tool/Cargo.toml b/src/Tools/tim_tool/Cargo.toml index a9b3f0d2..af703be9 100644 --- a/src/Tools/tim_tool/Cargo.toml +++ b/src/Tools/tim_tool/Cargo.toml @@ -7,12 +7,13 @@ edition = "2021" panic = "abort" [dependencies] +pathdiff = "0.2.3" png = "0.17.16" rfd = "0.15.2" slint = "1.9.2" -tiny-skia = "0.11.4" serde = {version = "1.0.140", features = ["derive"]} -serde_json = "1.0" +serde_json = "1.0" +tiny-skia = "0.11.4" tool_helper = {path = "../tool_helper"} [build-dependencies] diff --git a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs index 8c5bedd6..2cfdb929 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -76,12 +76,21 @@ pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu main_window.invoke_clear_file_tab_current_selected_file(); } - for job in new_project.jobs { - let (_, _) = tim_manager.load_unadded_tim(&job.file_path)?; + for job in new_project.jobs { + let file_path = Job::create_file_path(job.file_path, open_location.as_str()); + let (_, _) = tim_manager.load_unadded_tim(&file_path)?; let (pal_width, pal_height) = job.palette_rect.size.into(); tim_manager.change_unadded_tim_palette_size(pal_width, pal_height)?; - add_unadded_tim(main_tab, &mut tim_manager, UnaddedTIM::from_job(&job))?; + let unadded_tim = UnaddedTIM{ + file_name: &job.name, + image_x: job.image_pos.x, + image_y: job.image_pos.y, + palette_x: job.palette_rect.pos.x, + palette_y: job.palette_rect.pos.y, + encoding: job.encoding + }; + add_unadded_tim(main_tab, &mut tim_manager, unadded_tim)?; } main_window.invoke_change_to_main(); @@ -96,8 +105,9 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu return Err(Error::from_str("Please specify save location for project file")); } - let tim_info = tim_manager.lock().expect("VRAM already locked").clone_added_tims(); - let vram_info = main_tab.clone_vram_info(); + let tim_info = tim_manager.lock().expect("VRAM already locked").clone_added_tims(); + let vram_info = main_tab.clone_vram_info(); + let use_rel_path = main_window.get_project_widget_use_rel_paths(); if tim_info.len() != vram_info.len() { return Err(Error::from_str("TIM and VRAM info not in sync! Please close program")); @@ -105,7 +115,12 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu let mut cur_job:Option = None; let mut cur_palette:Option = None; - let mut project = Project::new(tim_info.into_iter().zip(vram_info.into_iter()).filter_map(|(tim, (file_name, vram))| { + let mut map_result = Ok(()); + let mut project = Project::new(tim_info.into_iter().zip(vram_info.into_iter()).filter_map(|(tim, (name, vram))| { + if map_result.is_err() { + return None; + } + if vram.is_palette { let cur_palette = std::mem::replace(&mut cur_palette, None); if let Some(mut cur_palette) = cur_palette { @@ -125,11 +140,22 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu if let Some((width, height)) = tim.get_palette_size() { cur_palette = Some(PaletteRect::new(0, 0, width, height)); } - cur_job = Some(Job::new(file_name, tim.get_path(), (vram.x as u16, vram.y as u16), Encoding::from_str(vram.encoding_str.as_str()))); + let file_path = if use_rel_path { + match tim.get_path_rel_to(PathBuf::from(save_location.as_str())) { + Ok(file_path) => file_path, + Err(error) => { + map_result = Err(error); + PathBuf::new() + } + } + } else {tim.get_path()}; + cur_job = Some(Job::new(name, file_path, (vram.x as u16, vram.y as u16), Encoding::from_str(vram.encoding_str.as_str()))); } prev_job } }).collect()); + map_result?; + if let Some(cur_job) = cur_job { project.jobs.push(cur_job); } @@ -192,10 +218,6 @@ impl<'a> UnaddedTIM<'a> { pub fn new(file_name: &String, encoding: Encoding,) -> UnaddedTIM { UnaddedTIM{file_name, image_x: 0, image_y: 0, palette_x: 0, palette_y: 0, encoding} } - - pub fn from_job(job: &Job) -> UnaddedTIM { - UnaddedTIM{file_name: &job.name, image_x: job.image_pos.x, image_y: job.image_pos.y, palette_x: job.palette_rect.pos.x, palette_y: job.palette_rect.pos.y, encoding: job.encoding } - } } fn add_unadded_tim(main_tab: &mut MainTab, tim_manager: &mut TIMManager, unadded_tim: UnaddedTIM) -> Result<(), Error> { diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index 32f7b726..ab120cc1 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -75,6 +75,20 @@ impl Job { pub fn new(name: String, file_path: PathBuf, image_pos: (u16, u16), encoding: Encoding) -> Job { Job{name, file_path, image_pos: ImagePosition{x: image_pos.0, y: image_pos.1}, palette_rect: PaletteRect::default(), encoding} } + + pub fn create_file_path>(file_path: PathBuf, location_path: &T) -> PathBuf { + if file_path.is_file() { + file_path + } + + else { + let mut new_file_path = PathBuf::from(location_path); + + new_file_path.pop(); + new_file_path.push(file_path); + new_file_path + } + } } #[derive(Serialize, Deserialize)] diff --git a/src/Tools/tim_tool/src/logic/tim/mod.rs b/src/Tools/tim_tool/src/logic/tim/mod.rs index bb27bd7d..51a0b241 100644 --- a/src/Tools/tim_tool/src/logic/tim/mod.rs +++ b/src/Tools/tim_tool/src/logic/tim/mod.rs @@ -1,5 +1,6 @@ pub mod types; +use pathdiff::diff_paths; use std::{fs::File, path::PathBuf}; use slint::{Rgba8Pixel, SharedPixelBuffer}; use tool_helper::Error; @@ -19,8 +20,8 @@ impl TIMInfo { *iter.next()?, *iter.next()?, *iter.next()?, if load_alpha {*iter.next()?} else {0xFF})) } - - let mut reader = png::Decoder::new(File::open(path)?).read_info().or_else(|error| {Err(Error::from_error(error))})?; + + let mut reader = png::Decoder::new(File::open(path).map_err(|error| Error::from_text(format!("Failed loading \"{}\" with {}", path.to_string_lossy().as_ref(), error)))?).read_info().or_else(|error| {Err(Error::from_error(error))})?; let info = reader.info().clone(); let mut buffer = vec![0; reader.output_buffer_size()]; @@ -132,6 +133,15 @@ impl TIMInfo { pub fn get_path(&self) -> std::path::PathBuf { self.path.clone() } + + pub fn get_path_rel_to(&self, mut reference_path: std::path::PathBuf) -> Result { + let file_path = self.path.clone(); + + reference_path.pop(); + diff_paths(&file_path, &reference_path).ok_or_else(|| { + Error::from_text(format!("Can not create relative path from {} to {}", file_path.to_string_lossy().as_ref(), reference_path.to_string_lossy().as_ref())) + }) + } } #[derive(Clone)] diff --git a/src/Tools/tim_tool/ui/tab/file-tab.slint b/src/Tools/tim_tool/ui/tab/file-tab.slint index c398e2d6..e5ad28eb 100644 --- a/src/Tools/tim_tool/ui/tab/file-tab.slint +++ b/src/Tools/tim_tool/ui/tab/file-tab.slint @@ -44,10 +44,8 @@ component ProjectWidget inherits Rectangle { HorizontalLayout { alignment: start; CheckBox { - text: "Append elements from project to existing elements"; - toggled() => { - root.append_project_elements = self.checked; - } + text: "Append elements from project to existing elements"; + checked <=> root.append_project_elements; } } HorizontalLayout { @@ -83,8 +81,8 @@ component ProjectWidget inherits Rectangle { } } CheckBox { - text: "Use relative path for files"; - checked: root.use_rel_paths; + text: "Use relative path for files"; + checked <=> root.use_rel_paths; } HorizontalLayout { alignment: start;