From 6a1b87cdb1f016a79a99db74c8c49e6bb9a499a4 Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 18 Mar 2025 21:48:36 +0100 Subject: [PATCH 01/17] Update name of VRAM images to reflect data --- src/Tools/tim_tool/src/gui/main_tab/mod.rs | 82 +++++++++++++--------- src/Tools/tim_tool/ui/app-window.slint | 2 +- src/Tools/tim_tool/ui/tab/main-tab.slint | 56 ++++++++------- 3 files changed, 81 insertions(+), 59 deletions(-) diff --git a/src/Tools/tim_tool/src/gui/main_tab/mod.rs b/src/Tools/tim_tool/src/gui/main_tab/mod.rs index 00748d63..8b4c0870 100644 --- a/src/Tools/tim_tool/src/gui/main_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/main_tab/mod.rs @@ -1,28 +1,28 @@ mod callbacks; -use crate::{gui::{MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, VRAMImage}; +use crate::{gui::{MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, VRAMImgData, VRAMInfo, VRAMData}; use super::MainWindowRef; use slint::{Model, SharedString}; use std::{cell::RefCell, ops::RangeInclusive, rc::Rc, sync::{Arc, Mutex}}; use tim_tool::logic::tim::types::Encoding; struct VRAM { - count: usize, - file_list: Rc>, - image_list: Rc> + count: usize, + file_list: Rc>, + info: Rc> } impl VRAM { - pub fn push(&mut self, name: slint::StandardListViewItem, image: VRAMImage) { + pub fn push(&mut self, name: slint::StandardListViewItem, image: VRAMData) { self.file_list.push(name); - self.image_list.push(image); + self.info.push(image); self.count += 1; } pub fn remove(&mut self, idx: usize) { self.count -= 1; self.file_list.remove(idx); - self.image_list.remove(idx); + self.info.remove(idx); } pub fn pop(&mut self) { @@ -40,12 +40,12 @@ impl MainTab { pub fn new(main_window: MainWindowRef, tim_manager: MutexTIMManager) -> SharedMainTab { let vram_file_list:Vec = main_window.borrow().get_main_tab_vram_file_list().iter().collect(); let vram_file_list = Rc::new(slint::VecModel::from(vram_file_list)); - let vram_image_list = Rc::new(slint::VecModel::from(Vec::::new())); + let info = Rc::new(slint::VecModel::from(Vec::::new())); main_window.borrow().set_main_tab_vram_file_list(vram_file_list.clone().into()); - main_window.borrow().set_main_tab_vram_images(vram_image_list.clone().into()); + main_window.borrow().set_main_tab_vram_data(info.clone().into()); - let object = SharedMainTab::new(MainTab{vram: Arc::new(Mutex::new(VRAM{count: 0, file_list: vram_file_list, image_list: vram_image_list}))}.into()); + let object = SharedMainTab::new(MainTab{vram: Arc::new(Mutex::new(VRAM{count: 0, file_list: vram_file_list, info}))}.into()); let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_move_vram_image()); main_window.borrow().on_move_vram_image(move |idx, dx, dy| { @@ -63,14 +63,18 @@ impl MainTab { let mut vram_data = self.vram.lock().expect("VRAM already locked"); let mut add_new_image = |file_name: &String, full_image: slint::Image, image: slint::Image, encoding: Encoding, palette_count: i32, is_palette: bool| { let encoding_str = if is_palette {""} else {encoding.to_str()}; - let vram_image = VRAMImage{ - full_img: full_image, - img: image, - x: 0, - y: 0, - encoding_str: SharedString::from(encoding_str), - palette_count, - is_palette, + let vram_image = VRAMData { + images: VRAMImgData { + full_image, + image + }, + info: VRAMInfo { + x: 0, + y: 0, + encoding_str: SharedString::from(encoding_str), + palette_count, + is_palette, + } }; vram_data.push(slint::StandardListViewItem::from(file_name.as_str()), vram_image); @@ -91,13 +95,13 @@ impl MainTab { pub fn remove_vram_file(&mut self, idx: usize) -> Result, &'static str> { let mut vram_data = self.vram.lock().expect("VRAM already locked"); let extras = { - if let Some(element) = vram_data.image_list.iter().skip(idx).next() { - if element.is_palette { + if let Some(element) = vram_data.info.iter().skip(idx).next() { + if element.info.is_palette { return Err("Can not remove palette. Delete image instead"); } else { - element.palette_count as usize + element.info.palette_count as usize } } @@ -126,28 +130,38 @@ impl MainTab { pub fn move_vram_image(&mut self, idx: usize, dx: i32, dy: i32) { let vram_data = self.vram.lock().expect("VRAM already locked"); - if let Some(mut vram_info) = vram_data.image_list.row_data(idx) { - vram_info.x += dx; - vram_info.y += dy; + if let Some(mut vram_info) = vram_data.info.row_data(idx) { + vram_info.info.x += dx; + vram_info.info.y += dy; - if vram_info.x < 0 { - vram_info.x = 0; + if vram_info.info.x < 0 { + vram_info.info.x = 0; } - if vram_info.y < 0 { - vram_info.y = 0; + if vram_info.info.y < 0 { + vram_info.info.y = 0; } - let (vram_img_width, vram_img_height) = (vram_info.img.size().width as i32, vram_info.img.size().height as i32); - if (vram_info.x + vram_img_width) > VRAM_WIDTH as i32 { - vram_info.x = VRAM_WIDTH as i32 - vram_img_width; + let (vram_img_width, vram_img_height) = (vram_info.images.image.size().width as i32, vram_info.images.image.size().height as i32); + if (vram_info.info.x + vram_img_width) > VRAM_WIDTH as i32 { + vram_info.info.x = VRAM_WIDTH as i32 - vram_img_width; } - if (vram_info.y + vram_img_height) > VRAM_HEIGHT as i32 { - vram_info.y = VRAM_HEIGHT as i32 - vram_img_height; + if (vram_info.info.y + vram_img_height) > VRAM_HEIGHT as i32 { + vram_info.info.y = VRAM_HEIGHT as i32 - vram_img_height; } - vram_data.image_list.set_row_data(idx, vram_info); + vram_data.info.set_row_data(idx, vram_info); } } + + /*pub fn _clone_vram_images(&self) -> Vec { + let vram_data = self.vram.lock().expect("VRAM already locked"); + let mut images = Vec::new(); + + for image in vram_data.image_list.iter() { + images.push(image.clone()); + } + images + }*/ } \ No newline at end of file diff --git a/src/Tools/tim_tool/ui/app-window.slint b/src/Tools/tim_tool/ui/app-window.slint index 5d16b2c0..a6b27cd9 100644 --- a/src/Tools/tim_tool/ui/app-window.slint +++ b/src/Tools/tim_tool/ui/app-window.slint @@ -7,7 +7,7 @@ export component MainWindow inherits Window { // Main Tab values in-out property main_tab_vram_bg <=> main_tab.vram_bg; in-out property main_tab_vram_file_list <=> main_tab.vram_files; - in-out property main_tab_vram_images <=> main_tab.vram_images; + in-out property main_tab_vram_data <=> main_tab.vram_data; callback main_tab_remove_file_clicked <=> main_tab.remove_file_clicked; callback move_vram_image <=> main_tab.move_vram_image; diff --git a/src/Tools/tim_tool/ui/tab/main-tab.slint b/src/Tools/tim_tool/ui/tab/main-tab.slint index fdd28332..1c7ef2c1 100644 --- a/src/Tools/tim_tool/ui/tab/main-tab.slint +++ b/src/Tools/tim_tool/ui/tab/main-tab.slint @@ -1,9 +1,12 @@ import { VRAMArea } from "../vram-components.slint"; import { Button, ComboBox, GroupBox, StandardListView, LineEdit, ScrollView, Slider } from "std-widgets.slint"; -struct VRAMImage { - full_img: image, - img: image, +struct VRAMImgData { + full_image: image, + image: image, +} + +struct VRAMInfo { x: int, y: int, encoding_str: string, @@ -11,11 +14,16 @@ struct VRAMImage { is_palette: bool, } +struct VRAMData { + images: VRAMImgData, + info: VRAMInfo, +} + export component MainTab inherits Rectangle { - property scale: 1.0; + property scale: 1.0; in-out property vram_bg; - in-out property <[StandardListViewItem]> vram_files: []; - in-out property <[VRAMImage]> vram_images: []; + in-out property <[StandardListViewItem]> vram_files: []; + in-out property <[VRAMData]> vram_data: []; callback add_file_clicked(); callback remove_file_clicked(int); @@ -54,12 +62,12 @@ export component MainTab inherits Rectangle { scale: scale; } - for vram_image[i] in root.vram_images: VRAMArea { + for vram_data[i] in root.vram_data: VRAMArea { x: root.get_border_width()*1px; y: root.get_border_width()*1px; - img: vram_image.img; - img_x: vram_image.x; - img_y: vram_image.y; + img: vram_data.images.image; + img_x: vram_data.info.x; + img_y: vram_data.info.y; scale: scale; TouchArea { @@ -82,8 +90,8 @@ export component MainTab inherits Rectangle { if event.kind == PointerEventKind.down { cur_sel_x.text = parent.img_x; cur_sel_y.text = parent.img_y; - cur_sel_img.source = vram-image.full_img; - encoding_text.encoding_str = vram-image.encoding_str; + cur_sel_img.source = vram_data.images.full_image; + encoding_text.encoding_str = vram_data.info.encoding_str; cur_sel_img.visible = true; vram_files_list.current-item = i; @@ -154,10 +162,10 @@ export component MainTab inherits Rectangle { model: root.vram_files; current-item-changed(current-item) => { - cur_sel_x.text = root.vram_images[current-item].x; - cur_sel_y.text = root.vram_images[current-item].y; - cur_sel_img.source = root.vram_images[current-item].full_img; - encoding_text.encoding_str = root.vram_images[current-item].encoding_str; + cur_sel_x.text = root.vram_data[current-item].info.x; + cur_sel_y.text = root.vram_data[current-item].info.y; + cur_sel_img.source = root.vram_data[current-item].images.full_image; + encoding_text.encoding_str = root.vram_data[current-item].info.encoding_str; cur_sel_img.visible = true; } } @@ -210,8 +218,8 @@ export component MainTab inherits Rectangle { accepted(text) => { if(vram_files_list.current-item != -1) { - root.move_vram_image(vram_files_list.current-item, text.to-float() - vram_images[vram_files_list.current-item].x, 0); - self.text = vram_images[vram_files_list.current-item].x; + root.move_vram_image(vram_files_list.current-item, text.to-float() - vram_data[vram_files_list.current-item].info.x, 0); + self.text = vram_data[vram_files_list.current-item].info.x; } } } @@ -231,8 +239,8 @@ export component MainTab inherits Rectangle { accepted(text) => { if(vram_files_list.current-item != -1) { - root.move_vram_image(vram_files_list.current-item, 0, text.to-float() - vram_images[vram_files_list.current-item].y); - self.text = vram_images[vram_files_list.current-item].y; + root.move_vram_image(vram_files_list.current-item, 0, text.to-float() - vram_data[vram_files_list.current-item].info.y); + self.text = vram_data[vram_files_list.current-item].info.y; } } } @@ -252,22 +260,22 @@ export component MainTab inherits Rectangle { if(vram_files_list.current-item != -1) { if(event.text == Key.LeftArrow) { root.move_vram_image(vram_files_list.current-item, -1, 0); - cur_sel_x.text = vram_images[vram_files_list.current-item].x; + cur_sel_x.text = vram_data[vram_files_list.current-item].info.x; } if(event.text == Key.RightArrow) { root.move_vram_image(vram_files_list.current-item, 1, 0); - cur_sel_x.text = vram_images[vram_files_list.current-item].x; + cur_sel_x.text = vram_data[vram_files_list.current-item].info.x; } if(event.text == Key.UpArrow) { root.move_vram_image(vram_files_list.current-item, 0, -1); - cur_sel_y.text = vram_images[vram_files_list.current-item].y; + cur_sel_y.text = vram_data[vram_files_list.current-item].info.y; } if(event.text == Key.DownArrow) { root.move_vram_image(vram_files_list.current-item, 0, 1); - cur_sel_y.text = vram_images[vram_files_list.current-item].y; + cur_sel_y.text = vram_data[vram_files_list.current-item].info.y; } } accept -- 2.30.2 From 602fb3a5c2e2e9e30c103ca06a8d1909c3bf0639 Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 18 Mar 2025 21:54:25 +0100 Subject: [PATCH 02/17] Obtain all required vectors; Quick draft for project --- .../tim_tool/src/gui/file_tab/callbacks.rs | 8 +++++-- src/Tools/tim_tool/src/gui/file_tab/mod.rs | 8 +++---- src/Tools/tim_tool/src/gui/main_tab/mod.rs | 12 +++++----- src/Tools/tim_tool/src/logic/mod.rs | 1 + src/Tools/tim_tool/src/logic/project/mod.rs | 22 +++++++++++++++++++ src/Tools/tim_tool/src/logic/tim/mod.rs | 2 ++ src/Tools/tim_tool/src/logic/tim_mgr.rs | 4 ++++ 7 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 src/Tools/tim_tool/src/logic/project/mod.rs 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 f1d11052..16c2d63a 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -65,8 +65,12 @@ pub(super) fn on_load_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) } } -pub(super) fn on_save_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { - move |_file_tab, _main_window| { +pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainTab, &MainWindow) -> Result<(), Error> + 'static { + move |_file_tab, main_tab, _main_window| { + let _tim_info = tim_manager.lock().expect("VRAM already locked").clone_added_tims(); + let _vram_info = main_tab.clone_vram_info(); + + Err(Error::not_implemented("on_save_project_clicked")) } } diff --git a/src/Tools/tim_tool/src/gui/file_tab/mod.rs b/src/Tools/tim_tool/src/gui/file_tab/mod.rs index 21f3bb4e..1c06be47 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/mod.rs @@ -65,9 +65,9 @@ impl FileTab { } }); - let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_add_image(tim_manager.clone())); + let (cloned_object, cloned_main_tab, cloned_main_window, mut function) = (object.clone(), main_tab.clone(), main_window.clone(), callbacks::on_add_image(tim_manager.clone())); main_window.borrow().on_file_tab_add_convert_image(move || { - if let Err(error) = function(&mut cloned_object.borrow_mut(), &mut main_tab.borrow_mut(), &cloned_main_window.borrow()) { + if let Err(error) = function(&mut cloned_object.borrow_mut(), &mut cloned_main_tab.borrow_mut(), &cloned_main_window.borrow()) { display_error("Adding file failed", &error.to_string()); } }); @@ -80,9 +80,9 @@ impl FileTab { } }); - let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_save_project_clicked()); + let (cloned_object, cloned_main_tab, cloned_main_window, mut function) = (object.clone(), main_tab.clone(), main_window.clone(), callbacks::on_save_project_clicked(tim_manager.clone())); main_window.borrow().on_project_widget_save_project_clicked (move || { - if let Err(error) = function(&mut cloned_object.borrow_mut(), &cloned_main_window.borrow()) { + if let Err(error) = function(&mut cloned_object.borrow_mut(), &cloned_main_tab.borrow(), &cloned_main_window.borrow()) { display_error("Saving project failed", &error.to_string()); } }); diff --git a/src/Tools/tim_tool/src/gui/main_tab/mod.rs b/src/Tools/tim_tool/src/gui/main_tab/mod.rs index 8b4c0870..a980ff97 100644 --- a/src/Tools/tim_tool/src/gui/main_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/main_tab/mod.rs @@ -155,13 +155,13 @@ impl MainTab { } } - /*pub fn _clone_vram_images(&self) -> Vec { + pub fn clone_vram_info(&self) -> Vec { let vram_data = self.vram.lock().expect("VRAM already locked"); - let mut images = Vec::new(); + let mut infos = Vec::new(); - for image in vram_data.image_list.iter() { - images.push(image.clone()); + for vram_data in vram_data.info.iter() { + infos.push(vram_data.info.clone()); } - images - }*/ + infos + } } \ No newline at end of file diff --git a/src/Tools/tim_tool/src/logic/mod.rs b/src/Tools/tim_tool/src/logic/mod.rs index e5dc964f..bdb4faae 100644 --- a/src/Tools/tim_tool/src/logic/mod.rs +++ b/src/Tools/tim_tool/src/logic/mod.rs @@ -1,3 +1,4 @@ +pub mod project; pub mod tim; pub mod tim_mgr; diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs new file mode 100644 index 00000000..5797515e --- /dev/null +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -0,0 +1,22 @@ +use std::path::PathBuf; + +struct Job { + name: String, + file_path: PathBuf, +} + +impl Job { + pub fn new(name: String, file_path: PathBuf) -> Job { + Job{name, file_path} + } +} + +struct Project { + jobs: Vec +} + +impl Project { + pub fn new(jobs: Vec) -> Project { + Project{jobs} + } +} \ No newline at end of file diff --git a/src/Tools/tim_tool/src/logic/tim/mod.rs b/src/Tools/tim_tool/src/logic/tim/mod.rs index ab0f8c5b..96e4f54b 100644 --- a/src/Tools/tim_tool/src/logic/tim/mod.rs +++ b/src/Tools/tim_tool/src/logic/tim/mod.rs @@ -5,6 +5,7 @@ use slint::{Rgba8Pixel, SharedPixelBuffer}; use tool_helper::Error; use types::Encoding; +#[derive(Clone)] pub struct TIMInfo { _path: PathBuf, image_data: SharedPixelBuffer, @@ -119,6 +120,7 @@ impl TIMInfo { } } +#[derive(Clone)] struct PaletteInfo { data: Vec, width: u32, diff --git a/src/Tools/tim_tool/src/logic/tim_mgr.rs b/src/Tools/tim_tool/src/logic/tim_mgr.rs index 36d09310..63c6e994 100644 --- a/src/Tools/tim_tool/src/logic/tim_mgr.rs +++ b/src/Tools/tim_tool/src/logic/tim_mgr.rs @@ -69,4 +69,8 @@ impl TIMManager { Ok(None) } } + + pub fn clone_added_tims(&self) -> Vec> { + self.added_tims.clone() + } } \ No newline at end of file -- 2.30.2 From b394330405813f0ddbc2e98173509136c943cdc4 Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 18 Mar 2025 22:31:59 +0100 Subject: [PATCH 03/17] zip jobs --- .../tim_tool/src/gui/file_tab/callbacks.rs | 34 ++++++++++++++++--- src/Tools/tim_tool/src/logic/project/mod.rs | 12 +++++-- 2 files changed, 39 insertions(+), 7 deletions(-) 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 16c2d63a..ecefbad9 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -1,8 +1,10 @@ -use crate::{gui::{main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; +use std::fmt::format; + +use crate::{gui::{main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow, VRAMInfo}; use super::FileTab; use rfd::FileDialog; use slint::SharedString; -use tim_tool::logic::tim::types::Encoding; +use tim_tool::logic::{project::{Job, Project}, tim::{self, types::Encoding}}; use tool_helper::Error; pub(super) fn on_browse_file(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { @@ -67,11 +69,33 @@ pub(super) fn on_load_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainTab, &MainWindow) -> Result<(), Error> + 'static { move |_file_tab, main_tab, _main_window| { - 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(); + if tim_info.len() != vram_info.len() { + return Err(Error::from_str("TIM and VRAM info not in sync! Please close program")); + } - Err(Error::not_implemented("on_save_project_clicked")) + let mut cur_job = None; + let mut project = Project::new(tim_info.into_iter().zip(vram_info.into_iter()).filter_map(|(tim, vram)| { + if vram.is_palette { + // Add palette to cur_job + None + } + + else { + // We are done with the old job + let prev_job = std::mem::replace(&mut cur_job, None); + + cur_job = Some(Job::new("Planschi".to_owned(), std::path::PathBuf::from("value"))); + prev_job + } + }).collect()); + if let Some(cur_job) = cur_job { + project.push(cur_job); + } + + Err(Error::from_text(format!("Adding {} jobs", project.len()))) } } diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index 5797515e..b66ca164 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -struct Job { +pub struct Job { name: String, file_path: PathBuf, } @@ -11,7 +11,7 @@ impl Job { } } -struct Project { +pub struct Project { jobs: Vec } @@ -19,4 +19,12 @@ impl Project { pub fn new(jobs: Vec) -> Project { Project{jobs} } + + pub fn push(&mut self, job: Job) { + self.jobs.push(job); + } + + pub fn len(&self) -> usize { + self.jobs.len() + } } \ No newline at end of file -- 2.30.2 From 7a197d9b71053e19835b3c8cb1a6190a9191e9d5 Mon Sep 17 00:00:00 2001 From: Jaby Date: Wed, 19 Mar 2025 20:21:45 +0100 Subject: [PATCH 04/17] Create a simple Job --- src/Tools/tim_tool/src/gui/file_tab/callbacks.rs | 16 ++++++++-------- src/Tools/tim_tool/src/gui/main_tab/mod.rs | 12 +++++------- src/Tools/tim_tool/src/logic/project/mod.rs | 2 ++ src/Tools/tim_tool/src/logic/tim/mod.rs | 10 +++++++--- 4 files changed, 22 insertions(+), 18 deletions(-) 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 ecefbad9..79da4100 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -1,10 +1,8 @@ -use std::fmt::format; - -use crate::{gui::{main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow, VRAMInfo}; +use crate::{gui::{main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; use super::FileTab; use rfd::FileDialog; use slint::SharedString; -use tim_tool::logic::{project::{Job, Project}, tim::{self, types::Encoding}}; +use tim_tool::logic::{project::{Job, Project}, tim::types::Encoding}; use tool_helper::Error; pub(super) fn on_browse_file(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { @@ -77,7 +75,7 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu } let mut cur_job = None; - let mut project = Project::new(tim_info.into_iter().zip(vram_info.into_iter()).filter_map(|(tim, vram)| { + let mut project = Project::new(tim_info.into_iter().zip(vram_info.into_iter()).filter_map(|(tim, (file_name, vram))| { if vram.is_palette { // Add palette to cur_job None @@ -85,9 +83,11 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu else { // We are done with the old job - let prev_job = std::mem::replace(&mut cur_job, None); + let prev_job = std::mem::replace(&mut cur_job, None); - cur_job = Some(Job::new("Planschi".to_owned(), std::path::PathBuf::from("value"))); + if let Some(tim) = tim { + cur_job = Some(Job::new(file_name, tim.get_path())); + } prev_job } }).collect()); @@ -95,7 +95,7 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu project.push(cur_job); } - Err(Error::from_text(format!("Adding {} jobs", project.len()))) + Err(Error::from_text(format!("Adding {:?} jobs", project))) } } diff --git a/src/Tools/tim_tool/src/gui/main_tab/mod.rs b/src/Tools/tim_tool/src/gui/main_tab/mod.rs index a980ff97..e4963730 100644 --- a/src/Tools/tim_tool/src/gui/main_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/main_tab/mod.rs @@ -155,13 +155,11 @@ impl MainTab { } } - pub fn clone_vram_info(&self) -> Vec { - let vram_data = self.vram.lock().expect("VRAM already locked"); - let mut infos = Vec::new(); + pub fn clone_vram_info(&self) -> Vec<(String, VRAMInfo)> { + let vram_data = self.vram.lock().expect("VRAM already locked"); - for vram_data in vram_data.info.iter() { - infos.push(vram_data.info.clone()); - } - infos + vram_data.info.iter().zip(vram_data.file_list.iter()).map(|(vram_data, file_name)| { + (file_name.text.to_string(), vram_data.info.clone()) + }).collect() } } \ No newline at end of file diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index b66ca164..d96164e8 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +#[derive(Debug)] pub struct Job { name: String, file_path: PathBuf, @@ -11,6 +12,7 @@ impl Job { } } +#[derive(Debug)] pub struct Project { jobs: Vec } diff --git a/src/Tools/tim_tool/src/logic/tim/mod.rs b/src/Tools/tim_tool/src/logic/tim/mod.rs index 96e4f54b..1321bd33 100644 --- a/src/Tools/tim_tool/src/logic/tim/mod.rs +++ b/src/Tools/tim_tool/src/logic/tim/mod.rs @@ -7,7 +7,7 @@ use types::Encoding; #[derive(Clone)] pub struct TIMInfo { - _path: PathBuf, + path: PathBuf, image_data: SharedPixelBuffer, palette: Option, } @@ -53,7 +53,7 @@ impl TIMInfo { _ => {return Err(Error::from_str("Only 4 and 8bit color depth are supported for indexed color images"));} } } - Ok(TIMInfo{_path: path.clone(), image_data, palette: Some(PaletteInfo::new(palette_colors))}) + Ok(TIMInfo{path: path.clone(), image_data, palette: Some(PaletteInfo::new(palette_colors))}) } else { @@ -71,7 +71,7 @@ impl TIMInfo { _ => {return Err(Error::from_str("Only 8bit color depth are supported for direct color images"));} } } - Ok(TIMInfo{_path: path.clone(), image_data, palette: None}) + Ok(TIMInfo{path: path.clone(), image_data, palette: None}) } } @@ -118,6 +118,10 @@ impl TIMInfo { None }) } + + pub fn get_path(&self) -> std::path::PathBuf { + self.path.clone() + } } #[derive(Clone)] -- 2.30.2 From d42fe2776c397c4fd34f7b2740176829511033fb Mon Sep 17 00:00:00 2001 From: Jaby Date: Wed, 19 Mar 2025 20:47:21 +0100 Subject: [PATCH 05/17] Serialize project to json --- src/Tools/tim_tool/Cargo.lock | 6 ++++-- src/Tools/tim_tool/Cargo.toml | 2 ++ src/Tools/tim_tool/src/gui/file_tab/callbacks.rs | 9 ++++++++- src/Tools/tim_tool/src/logic/project/mod.rs | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Tools/tim_tool/Cargo.lock b/src/Tools/tim_tool/Cargo.lock index 24e46b9e..b265ea81 100644 --- a/src/Tools/tim_tool/Cargo.lock +++ b/src/Tools/tim_tool/Cargo.lock @@ -3677,9 +3677,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -4113,6 +4113,8 @@ version = "0.1.0" dependencies = [ "png", "rfd", + "serde", + "serde_json", "slint", "slint-build", "tiny-skia", diff --git a/src/Tools/tim_tool/Cargo.toml b/src/Tools/tim_tool/Cargo.toml index a5253132..a9b3f0d2 100644 --- a/src/Tools/tim_tool/Cargo.toml +++ b/src/Tools/tim_tool/Cargo.toml @@ -11,6 +11,8 @@ 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" 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 79da4100..27caacf9 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -95,7 +95,14 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu project.push(cur_job); } - Err(Error::from_text(format!("Adding {:?} jobs", project))) + let string = match serde_json::to_string(&project) { + Ok(string) => string, + Err(error) => { + return Err(Error::from_error(error)); + } + }; + + Err(Error::from_text(format!("Adding {} jobs", string))) } } diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index d96164e8..f7934a9a 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -1,6 +1,7 @@ +use serde::{Deserialize, Serialize}; use std::path::PathBuf; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Job { name: String, file_path: PathBuf, @@ -12,7 +13,7 @@ impl Job { } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Project { jobs: Vec } -- 2.30.2 From 18e6800e0fe2b852bbd4a067e6d34306e5396fbc Mon Sep 17 00:00:00 2001 From: Jaby Date: Wed, 19 Mar 2025 21:17:26 +0100 Subject: [PATCH 06/17] Implement browsing project save location --- src/Tools/tim_tool/src/gui/file_tab/callbacks.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 27caacf9..9d3c5934 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -113,7 +113,19 @@ pub(super) fn on_browse_open_project_clicked() -> impl FnMut(&mut FileTab, &Main } pub(super) fn on_browse_save_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { - move |_file_tab, _main_window| { - Err(Error::not_implemented("on_browse_save_project_clicked")) + move |_file_tab, main_window| { + let file_path = FileDialog::new() + .add_filter("TIM project file (.tim_project)", &["tim_project"]) + .add_filter("JSON file (.json; .jsn)", &["json", "jsn"]) + .add_filter("All", &["*"]) + .set_title("Save location for TIM project file") + .save_file(); + + if let Some(file_path) = file_path { + if let Some(file_path) = file_path.to_str() { + main_window.set_project_widget_save_project_path(SharedString::from(file_path)); + } + } + Ok(()) } } \ No newline at end of file -- 2.30.2 From d1d590d32a4cf2a21ae85ff5ff71326ccfab660f Mon Sep 17 00:00:00 2001 From: Jaby Date: Wed, 19 Mar 2025 21:32:18 +0100 Subject: [PATCH 07/17] Save tim_project files --- .../tim_tool/src/gui/file_tab/callbacks.rs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) 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 9d3c5934..2e60d382 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -1,4 +1,6 @@ -use crate::{gui::{main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; +use std::{fs::File, io::Write}; + +use crate::{gui::{self, main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; use super::FileTab; use rfd::FileDialog; use slint::SharedString; @@ -66,7 +68,12 @@ pub(super) fn on_load_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) } pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainTab, &MainWindow) -> Result<(), Error> + 'static { - move |_file_tab, main_tab, _main_window| { + move |_file_tab, main_tab, main_window| { + let save_location = main_window.get_project_widget_save_project_path(); + if save_location.is_empty() { + 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(); @@ -95,14 +102,18 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu project.push(cur_job); } - let string = match serde_json::to_string(&project) { - Ok(string) => string, - Err(error) => { + let json_content = match serde_json::to_string(&project) { + Ok(json_content) => json_content, + Err(error) => { return Err(Error::from_error(error)); } }; - Err(Error::from_text(format!("Adding {} jobs", string))) + let mut file = File::create(save_location)?; + file.write_all(json_content.as_bytes())?; + + gui::display_information("Saving project", "Project saved successfully"); + Ok(()) } } -- 2.30.2 From aae57e47e40a22e325ecbfc88744e2215b7403f1 Mon Sep 17 00:00:00 2001 From: Jaby Date: Wed, 19 Mar 2025 22:01:32 +0100 Subject: [PATCH 08/17] Implement writing image and half the platte information --- .../tim_tool/src/gui/file_tab/callbacks.rs | 11 +++- src/Tools/tim_tool/src/gui/file_tab/mod.rs | 2 +- src/Tools/tim_tool/src/logic/project/mod.rs | 65 ++++++++++++++++--- src/Tools/tim_tool/src/logic/tim/mod.rs | 18 +++-- src/Tools/tim_tool/src/logic/tim_mgr.rs | 2 +- src/Tools/tim_tool/ui/tab/main-tab.slint | 2 +- 6 files changed, 82 insertions(+), 18 deletions(-) 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 2e60d382..7f689469 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -4,7 +4,7 @@ use crate::{gui::{self, main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WI use super::FileTab; use rfd::FileDialog; use slint::SharedString; -use tim_tool::logic::{project::{Job, Project}, tim::types::Encoding}; +use tim_tool::logic::{project::{Job, PaletteRect, Project}, tim::types::Encoding}; use tool_helper::Error; pub(super) fn on_browse_file(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { @@ -34,7 +34,7 @@ pub(super) fn on_browse_file(tim_manager: MutexTIMManager) -> impl FnMut(&mut Fi }; } -pub(super) fn on_update_palette_size(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow, u32, u32) -> Result<(), Error> + 'static { +pub(super) fn on_update_palette_size(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow, u16, u16) -> Result<(), Error> + 'static { return move |file_tab, _main_window, width, height| -> Result<(), Error> { file_tab.update_palette(tim_manager.lock().expect("VRAM already locked").change_unadded_tim_palette_size(width, height)?); Ok(()) @@ -93,7 +93,12 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu let prev_job = std::mem::replace(&mut cur_job, None); if let Some(tim) = tim { - cur_job = Some(Job::new(file_name, tim.get_path())); + let mut job = Job::new(file_name, tim.get_path(), (vram.x as u16, vram.y as u16)); + + if let Some((width, height)) = tim.get_palette_size() { + job.add_palette(PaletteRect::new(0, 0, width, height)); + } + cur_job = Some(job); } prev_job } diff --git a/src/Tools/tim_tool/src/gui/file_tab/mod.rs b/src/Tools/tim_tool/src/gui/file_tab/mod.rs index 1c06be47..4d0b0232 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/mod.rs @@ -60,7 +60,7 @@ impl FileTab { let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_update_palette_size(tim_manager.clone())); main_window.borrow().on_file_tab_update_palette_size(move |width, height| { - if let Err(error) = function(&mut cloned_object.borrow_mut(), &cloned_main_window.borrow(), width as u32, height as u32) { + if let Err(error) = function(&mut cloned_object.borrow_mut(), &cloned_main_window.borrow(), width as u16, height as u16) { display_error("Updating palette failed", &error.to_string()); } }); diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index f7934a9a..240d080c 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -1,19 +1,68 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; -#[derive(Debug, Serialize, Deserialize)] -pub struct Job { - name: String, - file_path: PathBuf, +#[derive(Serialize, Deserialize)] +struct ImagePosition { + pub x: u16, + pub y: u16, } -impl Job { - pub fn new(name: String, file_path: PathBuf) -> Job { - Job{name, file_path} +impl std::default::Default for ImagePosition { + fn default() -> Self { + ImagePosition{x: 0, y: 0} } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] +struct ImageSize { + pub width: u16, + pub height: u16, +} + +impl std::default::Default for ImageSize { + fn default() -> Self { + ImageSize{width: 0, height: 0} + } +} + +#[derive(Serialize, Deserialize)] +pub struct PaletteRect { + pos: ImagePosition, + size: ImageSize, +} + +impl PaletteRect { + pub fn new(x: u16, y: u16, width: u16, height: u16) -> PaletteRect { + PaletteRect{pos: ImagePosition{x, y}, size: ImageSize{width, height}} + } +} + +impl std::default::Default for PaletteRect { + fn default() -> Self { + PaletteRect{pos: ImagePosition::default(), size: ImageSize::default()} + } +} + +#[derive(Serialize, Deserialize)] +pub struct Job { + name: String, + file_path: PathBuf, + image_pos: ImagePosition, + palette_rect: PaletteRect, +} + +impl Job { + pub fn new(name: String, file_path: PathBuf, image_pos: (u16, u16)) -> Job { + Job{name, file_path, image_pos: ImagePosition{x: image_pos.0, y: image_pos.1}, palette_rect: PaletteRect::default()} + } + + pub fn add_palette(&mut self, palette_rect: PaletteRect) -> &mut Self { + self.palette_rect = palette_rect; + self + } +} + +#[derive(Serialize, Deserialize)] pub struct Project { jobs: Vec } diff --git a/src/Tools/tim_tool/src/logic/tim/mod.rs b/src/Tools/tim_tool/src/logic/tim/mod.rs index 1321bd33..bb27bd7d 100644 --- a/src/Tools/tim_tool/src/logic/tim/mod.rs +++ b/src/Tools/tim_tool/src/logic/tim/mod.rs @@ -75,7 +75,7 @@ impl TIMInfo { } } - pub fn change_palette_size(&mut self, width: u32, height: u32) -> Result, Error> { + pub fn change_palette_size(&mut self, width: u16, height: u16) -> Result, Error> { if let Some(palette) = &mut self.palette { if width == 0 || height == 0 { return Err(Error::from_text(format!("{}px x {}px is not a valid size for palette", width, height))); @@ -119,6 +119,16 @@ impl TIMInfo { }) } + pub fn get_palette_size(&self) -> Option<(u16, u16)> { + if let Some(palette_info) = &self.palette { + Some((palette_info.width, palette_info.height)) + } + + else { + None + } + } + pub fn get_path(&self) -> std::path::PathBuf { self.path.clone() } @@ -127,8 +137,8 @@ impl TIMInfo { #[derive(Clone)] struct PaletteInfo { data: Vec, - width: u32, - height: u32, + width: u16, + height: u16, } impl PaletteInfo { @@ -138,7 +148,7 @@ impl PaletteInfo { } pub fn get_image(&self) -> slint::Image { - let mut image_data = SharedPixelBuffer::new(self.width, self.height); + let mut image_data = SharedPixelBuffer::new(self.width as u32, self.height as u32); let dst_pixels = image_data.make_mut_slice(); for (idx, byte) in dst_pixels.iter_mut().enumerate() { diff --git a/src/Tools/tim_tool/src/logic/tim_mgr.rs b/src/Tools/tim_tool/src/logic/tim_mgr.rs index 63c6e994..2476c173 100644 --- a/src/Tools/tim_tool/src/logic/tim_mgr.rs +++ b/src/Tools/tim_tool/src/logic/tim_mgr.rs @@ -60,7 +60,7 @@ impl TIMManager { } } - pub fn change_unadded_tim_palette_size(&mut self, width: u32, height: u32) -> Result, Error> { + pub fn change_unadded_tim_palette_size(&mut self, width: u16, height: u16) -> Result, Error> { if let Some(unadded_tim) = &mut self.unadded_tim { unadded_tim.change_palette_size(width, height) } diff --git a/src/Tools/tim_tool/ui/tab/main-tab.slint b/src/Tools/tim_tool/ui/tab/main-tab.slint index 1c7ef2c1..13a22654 100644 --- a/src/Tools/tim_tool/ui/tab/main-tab.slint +++ b/src/Tools/tim_tool/ui/tab/main-tab.slint @@ -11,7 +11,7 @@ struct VRAMInfo { y: int, encoding_str: string, palette_count: int, - is_palette: bool, + is_palette: bool, // < Can we combine the palette into this, instead of having it separate? } struct VRAMData { -- 2.30.2 From e0a266317e77ef9e19c391cf08ae416caeccc078 Mon Sep 17 00:00:00 2001 From: Jaby Date: Thu, 20 Mar 2025 20:57:10 +0100 Subject: [PATCH 09/17] Support saving palette information --- .../tim_tool/src/gui/file_tab/callbacks.rs | 21 +++++++++------- src/Tools/tim_tool/src/logic/project/mod.rs | 24 ++++++++++++++----- 2 files changed, 31 insertions(+), 14 deletions(-) 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 7f689469..2481c0ce 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -4,7 +4,7 @@ use crate::{gui::{self, main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WI use super::FileTab; use rfd::FileDialog; use slint::SharedString; -use tim_tool::logic::{project::{Job, PaletteRect, Project}, tim::types::Encoding}; +use tim_tool::logic::{project::{ImagePosition, Job, PaletteRect, Project}, tim::types::Encoding}; use tool_helper::Error; pub(super) fn on_browse_file(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { @@ -81,10 +81,17 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu return Err(Error::from_str("TIM and VRAM info not in sync! Please close program")); } - let mut cur_job = None; - let mut project = Project::new(tim_info.into_iter().zip(vram_info.into_iter()).filter_map(|(tim, (file_name, vram))| { + 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))| { if vram.is_palette { - // Add palette to cur_job + let cur_palette = std::mem::replace(&mut cur_palette, None); + if let Some(mut cur_palette) = cur_palette { + cur_palette.pos = ImagePosition::new(vram.x as u16, vram.y as u16); + if let Some(cur_job) = &mut cur_job { + cur_job.add_palette(cur_palette); + } + } None } @@ -93,12 +100,10 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu let prev_job = std::mem::replace(&mut cur_job, None); if let Some(tim) = tim { - let mut job = Job::new(file_name, tim.get_path(), (vram.x as u16, vram.y as u16)); - if let Some((width, height)) = tim.get_palette_size() { - job.add_palette(PaletteRect::new(0, 0, width, height)); + cur_palette = Some(PaletteRect::new(0, 0, width, height)); } - cur_job = Some(job); + cur_job = Some(Job::new(file_name, tim.get_path(), (vram.x as u16, vram.y as u16))); } prev_job } diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index 240d080c..2dca49be 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -2,33 +2,45 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; #[derive(Serialize, Deserialize)] -struct ImagePosition { +pub struct ImagePosition { pub x: u16, pub y: u16, } +impl ImagePosition { + pub fn new(x: u16, y: u16) -> ImagePosition { + ImagePosition{x, y} + } +} + impl std::default::Default for ImagePosition { fn default() -> Self { - ImagePosition{x: 0, y: 0} + ImagePosition::new(0, 0) } } #[derive(Serialize, Deserialize)] -struct ImageSize { +pub struct ImageSize { pub width: u16, pub height: u16, } +impl ImageSize { + pub fn new(width: u16, height: u16) -> ImageSize { + ImageSize{width, height} + } +} + impl std::default::Default for ImageSize { fn default() -> Self { - ImageSize{width: 0, height: 0} + ImageSize::new(0, 0) } } #[derive(Serialize, Deserialize)] pub struct PaletteRect { - pos: ImagePosition, - size: ImageSize, + pub pos: ImagePosition, + pub size: ImageSize, } impl PaletteRect { -- 2.30.2 From 2345b3da570070d443f7dca36048fcd9173a1d80 Mon Sep 17 00:00:00 2001 From: Jaby Date: Thu, 20 Mar 2025 21:16:41 +0100 Subject: [PATCH 10/17] Save encoding information --- src/Tools/tim_tool/src/gui/file_tab/callbacks.rs | 2 +- src/Tools/tim_tool/src/logic/project/mod.rs | 13 +++++++++---- src/Tools/tim_tool/src/logic/tim/types.rs | 13 ++++++++++++- 3 files changed, 22 insertions(+), 6 deletions(-) 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 2481c0ce..38e1f532 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -103,7 +103,7 @@ 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))); + 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()))); } prev_job } diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index 2dca49be..bfaeca04 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -1,3 +1,4 @@ +use super::tim::types::Encoding; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -61,16 +62,20 @@ pub struct Job { file_path: PathBuf, image_pos: ImagePosition, palette_rect: PaletteRect, + encoding: Encoding, } impl Job { - pub fn new(name: String, file_path: PathBuf, image_pos: (u16, u16)) -> Job { - Job{name, file_path, image_pos: ImagePosition{x: image_pos.0, y: image_pos.1}, palette_rect: PaletteRect::default()} + 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 add_palette(&mut self, palette_rect: PaletteRect) -> &mut Self { + pub fn add_encoding(&mut self, encoding: Encoding) { + self.encoding = encoding; + } + + pub fn add_palette(&mut self, palette_rect: PaletteRect) { self.palette_rect = palette_rect; - self } } diff --git a/src/Tools/tim_tool/src/logic/tim/types.rs b/src/Tools/tim_tool/src/logic/tim/types.rs index 01ef2f10..8b84f01d 100644 --- a/src/Tools/tim_tool/src/logic/tim/types.rs +++ b/src/Tools/tim_tool/src/logic/tim/types.rs @@ -1,4 +1,6 @@ -#[derive(Clone, Copy)] +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Deserialize, Serialize)] pub enum Encoding { FourBit, EightBit, @@ -17,4 +19,13 @@ impl Encoding { Encoding::FullColor => Self::FULL_COLOR_NAME, } } + + pub fn from_str(str: &str) -> Encoding { + match str { + Self::FOUR_BIT_NAME => Encoding::FourBit, + Self::EIGHT_BIT_NAME => Encoding::EightBit, + Self::FULL_COLOR_NAME => Encoding::FullColor, + _ => Encoding::FullColor, + } + } } \ No newline at end of file -- 2.30.2 From 5f4ade47bdf7f85f31142c0db9d505d2e5ad58bc Mon Sep 17 00:00:00 2001 From: Jaby Date: Thu, 20 Mar 2025 21:26:32 +0100 Subject: [PATCH 11/17] Support selecting project to open --- .../tim_tool/src/gui/file_tab/callbacks.rs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) 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 38e1f532..5c44bbd0 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -128,17 +128,23 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu } pub(super) fn on_browse_open_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { - move |_file_tab, _main_window| { - Err(Error::not_implemented("on_browse_open_project_clicked")) + move |_file_tab, main_window| { + let file_path = create_project_file_dialog() + .set_title("Save location for TIM project file") + .pick_file(); + + if let Some(file_path) = file_path { + if let Some(file_path) = file_path.to_str() { + main_window.set_project_widget_open_project_path(SharedString::from(file_path)); + } + } + Ok(()) } } pub(super) fn on_browse_save_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { move |_file_tab, main_window| { - let file_path = FileDialog::new() - .add_filter("TIM project file (.tim_project)", &["tim_project"]) - .add_filter("JSON file (.json; .jsn)", &["json", "jsn"]) - .add_filter("All", &["*"]) + let file_path = create_project_file_dialog() .set_title("Save location for TIM project file") .save_file(); @@ -149,4 +155,11 @@ pub(super) fn on_browse_save_project_clicked() -> impl FnMut(&mut FileTab, &Main } Ok(()) } +} + +fn create_project_file_dialog() -> FileDialog { + FileDialog::new() + .add_filter("TIM project file (.tim_project)", &["tim_project"]) + .add_filter("JSON file (.json; .jsn)", &["json", "jsn"]) + .add_filter("All", &["*"]) } \ No newline at end of file -- 2.30.2 From 5cc88e0b87f0c54e95fd7ec9e9f1f5103525e9a8 Mon Sep 17 00:00:00 2001 From: Jaby Date: Thu, 20 Mar 2025 21:37:19 +0100 Subject: [PATCH 12/17] Deserialize project --- .../tim_tool/src/gui/file_tab/callbacks.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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 5c44bbd0..2f3d1608 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -1,4 +1,4 @@ -use std::{fs::File, io::Write}; +use std::{fs::File, io::Write, path::PathBuf}; use crate::{gui::{self, main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; use super::FileTab; @@ -62,8 +62,21 @@ pub(super) fn on_add_image(tim_manager: MutexTIMManager) -> impl FnMut(&mut File } pub(super) fn on_load_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { - move |_file_tab, _main_window| { - Err(Error::not_implemented("on_load_project_clicked")) + move |_file_tab, main_window| { + let open_location = main_window.get_project_widget_open_project_path(); + if open_location.is_empty() { + return Err(Error::from_str("Please specify location for project file to open")); + } + + let file_content = tool_helper::read_file_to_string(&PathBuf::from(open_location.as_str()))?; + let _new_project = match serde_json::from_str::(&file_content) { + Ok(project) => project, + Err(error) => { + return Err(Error::from_error(error)); + } + }; + + Ok(()) } } -- 2.30.2 From a260c1ffb75fc9474c2a728a491641421283bd9c Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 1 Apr 2025 15:24:41 +0200 Subject: [PATCH 13/17] Allow position information for newly added VRAM items --- .../tim_tool/src/gui/file_tab/callbacks.rs | 39 ++++++++++++------- src/Tools/tim_tool/src/gui/file_tab/mod.rs | 2 +- src/Tools/tim_tool/src/gui/main_tab/mod.rs | 29 ++++++++++---- src/Tools/tim_tool/src/logic/project/mod.rs | 28 +++---------- 4 files changed, 54 insertions(+), 44 deletions(-) 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 2f3d1608..8567251d 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -1,6 +1,6 @@ use std::{fs::File, io::Write, path::PathBuf}; -use crate::{gui::{self, main_tab::MainTab, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; +use crate::{gui::{self, main_tab::{MainTab, NewVRAMImageInfo}, MutexTIMManager, VRAM_HEIGHT, VRAM_WIDTH}, MainWindow}; use super::FileTab; use rfd::FileDialog; use slint::SharedString; @@ -45,15 +45,8 @@ pub(super) fn on_add_image(tim_manager: MutexTIMManager) -> impl FnMut(&mut File return move |file_tab, main_tab, main_window| { let file_name = file_tab.get_file_name(); let encoding = file_tab.get_encoding()?; - let mut tim_mgr = tim_manager.lock().expect("VRAM already locked"); - let (image, palette_image) = tim_mgr.get_converted_unadded_tim_image(encoding)?; - let (full_image, _) = tim_mgr.get_converted_unadded_tim_image(Encoding::FullColor)?; - let images_created = main_tab.add_new_vram_file(&file_name, full_image, image, encoding, palette_image); - if let Err(error) = tim_mgr.add_unadded_tim(images_created) { - main_tab.pop_vram_files(images_created); - return Err(error); - } + add_unadded_tim(main_tab, tim_manager.clone(), &file_name, encoding)?; file_tab.clear_load(); main_window.invoke_change_to_main(); @@ -61,7 +54,7 @@ pub(super) fn on_add_image(tim_manager: MutexTIMManager) -> impl FnMut(&mut File }; } -pub(super) fn on_load_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { +pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { move |_file_tab, main_window| { let open_location = main_window.get_project_widget_open_project_path(); if open_location.is_empty() { @@ -69,13 +62,17 @@ pub(super) fn on_load_project_clicked() -> impl FnMut(&mut FileTab, &MainWindow) } let file_content = tool_helper::read_file_to_string(&PathBuf::from(open_location.as_str()))?; - let _new_project = match serde_json::from_str::(&file_content) { + let new_project = match serde_json::from_str::(&file_content) { Ok(project) => project, Err(error) => { return Err(Error::from_error(error)); } }; + for job in new_project.jobs { + let (_, _) = tim_manager.lock().expect("VRAM already locked").load_unadded_tim(&job.file_path)?; + } + Ok(()) } } @@ -102,7 +99,7 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu if let Some(mut cur_palette) = cur_palette { cur_palette.pos = ImagePosition::new(vram.x as u16, vram.y as u16); if let Some(cur_job) = &mut cur_job { - cur_job.add_palette(cur_palette); + cur_job.palette_rect = cur_palette; } } None @@ -122,7 +119,7 @@ pub(super) fn on_save_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu } }).collect()); if let Some(cur_job) = cur_job { - project.push(cur_job); + project.jobs.push(cur_job); } let json_content = match serde_json::to_string(&project) { @@ -170,6 +167,22 @@ pub(super) fn on_browse_save_project_clicked() -> impl FnMut(&mut FileTab, &Main } } +fn add_unadded_tim(main_tab: &mut MainTab, tim_manager: MutexTIMManager, file_name: &String, encoding: Encoding) -> Result<(), Error> { + let mut tim_mgr = tim_manager.lock().expect("VRAM already locked"); + let (image, palette_image) = tim_mgr.get_converted_unadded_tim_image(encoding)?; + let (full_image, _) = tim_mgr.get_converted_unadded_tim_image(Encoding::FullColor)?; + let image = NewVRAMImageInfo::new(image, 0, 0, encoding); + let palette_image = if let Some(palette_image) = palette_image { Some(NewVRAMImageInfo::new(palette_image, 0, 0, Encoding::FullColor)) } else { None }; + + let images_created = main_tab.add_new_vram_file(file_name, full_image, image, palette_image); + if let Err(error) = tim_mgr.add_unadded_tim(images_created) { + main_tab.pop_vram_files(images_created); + return Err(error); + } + + Ok(()) +} + fn create_project_file_dialog() -> FileDialog { FileDialog::new() .add_filter("TIM project file (.tim_project)", &["tim_project"]) diff --git a/src/Tools/tim_tool/src/gui/file_tab/mod.rs b/src/Tools/tim_tool/src/gui/file_tab/mod.rs index 4d0b0232..cbe7aad6 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/mod.rs @@ -73,7 +73,7 @@ impl FileTab { }); // Project functions - let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_load_project_clicked()); + let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_load_project_clicked(tim_manager.clone())); main_window.borrow().on_project_widget_load_project_clicked(move || { if let Err(error) = function(&mut cloned_object.borrow_mut(), &cloned_main_window.borrow()) { display_error("Loading project failed", &error.to_string()); diff --git a/src/Tools/tim_tool/src/gui/main_tab/mod.rs b/src/Tools/tim_tool/src/gui/main_tab/mod.rs index e4963730..4b9b3cc5 100644 --- a/src/Tools/tim_tool/src/gui/main_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/main_tab/mod.rs @@ -6,6 +6,19 @@ use slint::{Model, SharedString}; use std::{cell::RefCell, ops::RangeInclusive, rc::Rc, sync::{Arc, Mutex}}; use tim_tool::logic::tim::types::Encoding; +pub struct NewVRAMImageInfo { + pub image: slint::Image, + pub x: i32, + pub y: i32, + pub encoding: Encoding, +} + +impl NewVRAMImageInfo { + pub fn new(image: slint::Image, x: i32, y: i32, encoding: Encoding) -> NewVRAMImageInfo { + NewVRAMImageInfo{image, x, y, encoding} + } +} + struct VRAM { count: usize, file_list: Rc>, @@ -59,18 +72,18 @@ impl MainTab { object } - pub fn add_new_vram_file(&mut self, file_name: &String, full_image: slint::Image, image: slint::Image, encoding: Encoding, image_palette: Option) -> usize { + pub fn add_new_vram_file(&mut self, file_name: &String, full_image: slint::Image, texture: NewVRAMImageInfo, image_palette: Option) -> usize { let mut vram_data = self.vram.lock().expect("VRAM already locked"); - let mut add_new_image = |file_name: &String, full_image: slint::Image, image: slint::Image, encoding: Encoding, palette_count: i32, is_palette: bool| { - let encoding_str = if is_palette {""} else {encoding.to_str()}; + let mut add_new_image = |file_name: &String, full_image: slint::Image, vram_image: NewVRAMImageInfo, palette_count: i32, is_palette: bool| { + let encoding_str = if is_palette {""} else {vram_image.encoding.to_str()}; let vram_image = VRAMData { images: VRAMImgData { full_image, - image + image: vram_image.image, }, info: VRAMInfo { - x: 0, - y: 0, + x: vram_image.x, + y: vram_image.y, encoding_str: SharedString::from(encoding_str), palette_count, is_palette, @@ -81,12 +94,12 @@ impl MainTab { }; let mut images_added = 1; - add_new_image(file_name, full_image, image, encoding, if image_palette.is_some() {1} else {0}, false); + add_new_image(file_name, full_image, texture, if image_palette.is_some() {1} else {0}, false); if let Some(image_palette) = image_palette { let file_name = " => ".to_owned() + file_name.as_str() + " (Palette)"; images_added += 1; - add_new_image(&file_name, image_palette.clone(), image_palette, encoding, 0, true); + add_new_image(&file_name, image_palette.image.clone(), image_palette, 0, true); } images_added diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index bfaeca04..32a7d0a1 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -58,42 +58,26 @@ impl std::default::Default for PaletteRect { #[derive(Serialize, Deserialize)] pub struct Job { - name: String, - file_path: PathBuf, - image_pos: ImagePosition, - palette_rect: PaletteRect, - encoding: Encoding, + pub name: String, + pub file_path: PathBuf, + pub image_pos: ImagePosition, + pub palette_rect: PaletteRect, + pub encoding: Encoding, } 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 add_encoding(&mut self, encoding: Encoding) { - self.encoding = encoding; - } - - pub fn add_palette(&mut self, palette_rect: PaletteRect) { - self.palette_rect = palette_rect; - } } #[derive(Serialize, Deserialize)] pub struct Project { - jobs: Vec + pub jobs: Vec } impl Project { pub fn new(jobs: Vec) -> Project { Project{jobs} } - - pub fn push(&mut self, job: Job) { - self.jobs.push(job); - } - - pub fn len(&self) -> usize { - self.jobs.len() - } } \ No newline at end of file -- 2.30.2 From bab01bbd869a82a232bdaa03a35e521860c2d274 Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 1 Apr 2025 16:03:35 +0200 Subject: [PATCH 14/17] Load VRAM images from project file --- .../tim_tool/src/gui/file_tab/callbacks.rs | 51 ++++++++++++++----- src/Tools/tim_tool/src/gui/file_tab/mod.rs | 4 +- src/Tools/tim_tool/src/gui/main_tab/mod.rs | 10 ++-- src/Tools/tim_tool/src/logic/project/mod.rs | 8 ++- 4 files changed, 52 insertions(+), 21 deletions(-) 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 8567251d..fec59379 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -4,7 +4,7 @@ use crate::{gui::{self, main_tab::{MainTab, NewVRAMImageInfo}, MutexTIMManager, use super::FileTab; use rfd::FileDialog; use slint::SharedString; -use tim_tool::logic::{project::{ImagePosition, Job, PaletteRect, Project}, tim::types::Encoding}; +use tim_tool::logic::{project::{ImagePosition, Job, PaletteRect, Project}, tim::types::Encoding, TIMManager}; use tool_helper::Error; pub(super) fn on_browse_file(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { @@ -46,7 +46,7 @@ pub(super) fn on_add_image(tim_manager: MutexTIMManager) -> impl FnMut(&mut File let file_name = file_tab.get_file_name(); let encoding = file_tab.get_encoding()?; - add_unadded_tim(main_tab, tim_manager.clone(), &file_name, encoding)?; + add_unadded_tim(main_tab, &mut tim_manager.lock().expect("VRAM already locked"), UnaddedTIM::new(&file_name, encoding))?; file_tab.clear_load(); main_window.invoke_change_to_main(); @@ -54,8 +54,8 @@ pub(super) fn on_add_image(tim_manager: MutexTIMManager) -> impl FnMut(&mut File }; } -pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &MainWindow) -> Result<(), Error> + 'static { - move |_file_tab, main_window| { +pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMut(&mut FileTab, &mut MainTab, &MainWindow) -> Result<(), Error> + 'static { + move |_file_tab, main_tab, main_window| { let open_location = main_window.get_project_widget_open_project_path(); if open_location.is_empty() { return Err(Error::from_str("Please specify location for project file to open")); @@ -70,9 +70,16 @@ pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu }; for job in new_project.jobs { - let (_, _) = tim_manager.lock().expect("VRAM already locked").load_unadded_tim(&job.file_path)?; + let mut tim_manager = tim_manager.lock().expect("VRAM already locked"); + + let (_, _) = tim_manager.load_unadded_tim(&job.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))?; } + main_window.invoke_change_to_main(); Ok(()) } } @@ -167,15 +174,33 @@ pub(super) fn on_browse_save_project_clicked() -> impl FnMut(&mut FileTab, &Main } } -fn add_unadded_tim(main_tab: &mut MainTab, tim_manager: MutexTIMManager, file_name: &String, encoding: Encoding) -> Result<(), Error> { - let mut tim_mgr = tim_manager.lock().expect("VRAM already locked"); - let (image, palette_image) = tim_mgr.get_converted_unadded_tim_image(encoding)?; - let (full_image, _) = tim_mgr.get_converted_unadded_tim_image(Encoding::FullColor)?; - let image = NewVRAMImageInfo::new(image, 0, 0, encoding); - let palette_image = if let Some(palette_image) = palette_image { Some(NewVRAMImageInfo::new(palette_image, 0, 0, Encoding::FullColor)) } else { None }; +struct UnaddedTIM<'a> { + pub file_name: &'a String, + pub image_x: u16, + pub image_y: u16, + pub palette_x: u16, + pub palette_y: u16, + pub encoding: Encoding, +} + +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> { + let (image, palette_image) = tim_manager.get_converted_unadded_tim_image(unadded_tim.encoding)?; + let (full_image, _) = tim_manager.get_converted_unadded_tim_image(Encoding::FullColor)?; + let image = NewVRAMImageInfo::new(image, unadded_tim.image_x, unadded_tim.image_y, unadded_tim.encoding); + let palette_image = if let Some(palette_image) = palette_image { Some(NewVRAMImageInfo::new(palette_image, unadded_tim.palette_x, unadded_tim.palette_y, Encoding::FullColor)) } else { None }; - let images_created = main_tab.add_new_vram_file(file_name, full_image, image, palette_image); - if let Err(error) = tim_mgr.add_unadded_tim(images_created) { + let images_created = main_tab.add_new_vram_file(unadded_tim.file_name, full_image, image, palette_image); + if let Err(error) = tim_manager.add_unadded_tim(images_created) { main_tab.pop_vram_files(images_created); return Err(error); } diff --git a/src/Tools/tim_tool/src/gui/file_tab/mod.rs b/src/Tools/tim_tool/src/gui/file_tab/mod.rs index cbe7aad6..b5ad144c 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/mod.rs @@ -73,9 +73,9 @@ impl FileTab { }); // Project functions - let (cloned_object, cloned_main_window, mut function) = (object.clone(), main_window.clone(), callbacks::on_load_project_clicked(tim_manager.clone())); + let (cloned_object, cloned_main_tab, cloned_main_window, mut function) = (object.clone(), main_tab.clone(), main_window.clone(), callbacks::on_load_project_clicked(tim_manager.clone())); main_window.borrow().on_project_widget_load_project_clicked(move || { - if let Err(error) = function(&mut cloned_object.borrow_mut(), &cloned_main_window.borrow()) { + if let Err(error) = function(&mut cloned_object.borrow_mut(), &mut cloned_main_tab.borrow_mut(), &cloned_main_window.borrow()) { display_error("Loading project failed", &error.to_string()); } }); diff --git a/src/Tools/tim_tool/src/gui/main_tab/mod.rs b/src/Tools/tim_tool/src/gui/main_tab/mod.rs index 4b9b3cc5..71ed1135 100644 --- a/src/Tools/tim_tool/src/gui/main_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/main_tab/mod.rs @@ -8,13 +8,13 @@ use tim_tool::logic::tim::types::Encoding; pub struct NewVRAMImageInfo { pub image: slint::Image, - pub x: i32, - pub y: i32, + pub x: u16, + pub y: u16, pub encoding: Encoding, } impl NewVRAMImageInfo { - pub fn new(image: slint::Image, x: i32, y: i32, encoding: Encoding) -> NewVRAMImageInfo { + pub fn new(image: slint::Image, x: u16, y: u16, encoding: Encoding) -> NewVRAMImageInfo { NewVRAMImageInfo{image, x, y, encoding} } } @@ -82,8 +82,8 @@ impl MainTab { image: vram_image.image, }, info: VRAMInfo { - x: vram_image.x, - y: vram_image.y, + x: vram_image.x as i32, + y: vram_image.y as i32, encoding_str: SharedString::from(encoding_str), palette_count, is_palette, diff --git a/src/Tools/tim_tool/src/logic/project/mod.rs b/src/Tools/tim_tool/src/logic/project/mod.rs index 32a7d0a1..32f7b726 100644 --- a/src/Tools/tim_tool/src/logic/project/mod.rs +++ b/src/Tools/tim_tool/src/logic/project/mod.rs @@ -20,7 +20,7 @@ impl std::default::Default for ImagePosition { } } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Copy, Serialize, Deserialize)] pub struct ImageSize { pub width: u16, pub height: u16, @@ -32,6 +32,12 @@ impl ImageSize { } } +impl From for (u16, u16) { + fn from(value: ImageSize) -> Self { + (value.width, value.height) + } +} + impl std::default::Default for ImageSize { fn default() -> Self { ImageSize::new(0, 0) -- 2.30.2 From 47b5de2d6aee969409cf0cd4338ae30f512a9f7c Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 1 Apr 2025 16:28:27 +0200 Subject: [PATCH 15/17] Clear existing elements --- src/Tools/tim_tool/src/gui/file_tab/callbacks.rs | 13 ++++++++++--- src/Tools/tim_tool/src/gui/main_tab/mod.rs | 9 +++++++++ src/Tools/tim_tool/src/logic/tim_mgr.rs | 4 ++++ src/Tools/tim_tool/ui/app-window.slint | 4 ++++ src/Tools/tim_tool/ui/tab/main-tab.slint | 12 ++++++++---- 5 files changed, 35 insertions(+), 7 deletions(-) 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 fec59379..ba53b540 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -69,9 +69,11 @@ pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu } }; - for job in new_project.jobs { - let mut tim_manager = tim_manager.lock().expect("VRAM already locked"); - + let mut tim_manager = tim_manager.lock().expect("VRAM already locked"); + clear_all_vram_images(main_tab, &mut tim_manager); + main_window.invoke_clear_file_tab_current_selected_file(); + + for job in new_project.jobs { let (_, _) = tim_manager.load_unadded_tim(&job.file_path)?; let (pal_width, pal_height) = job.palette_rect.size.into(); @@ -208,6 +210,11 @@ fn add_unadded_tim(main_tab: &mut MainTab, tim_manager: &mut TIMManager, unadded Ok(()) } +fn clear_all_vram_images(main_tab: &mut MainTab, tim_manager: &mut TIMManager) { + tim_manager.clear(); + main_tab.clear(); +} + fn create_project_file_dialog() -> FileDialog { FileDialog::new() .add_filter("TIM project file (.tim_project)", &["tim_project"]) diff --git a/src/Tools/tim_tool/src/gui/main_tab/mod.rs b/src/Tools/tim_tool/src/gui/main_tab/mod.rs index 71ed1135..a4cf8087 100644 --- a/src/Tools/tim_tool/src/gui/main_tab/mod.rs +++ b/src/Tools/tim_tool/src/gui/main_tab/mod.rs @@ -72,6 +72,15 @@ impl MainTab { object } + pub fn clear(&mut self) { + let mut vram_data = self.vram.lock().expect("VRAM already locked"); + let count = vram_data.count; + + for _ in 0..count { + vram_data.pop(); + } + } + pub fn add_new_vram_file(&mut self, file_name: &String, full_image: slint::Image, texture: NewVRAMImageInfo, image_palette: Option) -> usize { let mut vram_data = self.vram.lock().expect("VRAM already locked"); let mut add_new_image = |file_name: &String, full_image: slint::Image, vram_image: NewVRAMImageInfo, palette_count: i32, is_palette: bool| { diff --git a/src/Tools/tim_tool/src/logic/tim_mgr.rs b/src/Tools/tim_tool/src/logic/tim_mgr.rs index 2476c173..930df311 100644 --- a/src/Tools/tim_tool/src/logic/tim_mgr.rs +++ b/src/Tools/tim_tool/src/logic/tim_mgr.rs @@ -13,6 +13,10 @@ impl TIMManager { TIMManager{added_tims: Default::default(), unadded_tim: None} } + pub fn clear(&mut self) { + self.added_tims.clear(); + } + pub fn remove_added_tim(&mut self, range: RangeInclusive) { let idx = *range.start(); for _ in range { diff --git a/src/Tools/tim_tool/ui/app-window.slint b/src/Tools/tim_tool/ui/app-window.slint index a6b27cd9..7ccd88ba 100644 --- a/src/Tools/tim_tool/ui/app-window.slint +++ b/src/Tools/tim_tool/ui/app-window.slint @@ -80,4 +80,8 @@ export component MainWindow inherits Window { public function change_to_main() { tab_widget.current-index = 1; } + + public function clear_file_tab-current_selected_file() { + main_tab.clear_current_selection(); + } } \ No newline at end of file diff --git a/src/Tools/tim_tool/ui/tab/main-tab.slint b/src/Tools/tim_tool/ui/tab/main-tab.slint index 13a22654..6bff7047 100644 --- a/src/Tools/tim_tool/ui/tab/main-tab.slint +++ b/src/Tools/tim_tool/ui/tab/main-tab.slint @@ -179,10 +179,7 @@ export component MainTab inherits Rectangle { text: "Remove file"; clicked => { root.remove_file_clicked(vram_files_list.current_item); - vram_files_list.current-item = -1; - cur_sel_x.text = 0; - cur_sel_y.text = 0; - cur_sel_img.visible = false; + root.clear_current_selection(); } } } @@ -285,4 +282,11 @@ export component MainTab inherits Rectangle { function get_border_width() -> int { return 4; } + + public function clear_current_selection() { + vram_files_list.current-item = -1; + cur_sel_x.text = 0; + cur_sel_y.text = 0; + cur_sel_img.visible = false; + } } \ No newline at end of file -- 2.30.2 From a9801e9fe2102bfab18e32461328af6cc6930a27 Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 1 Apr 2025 17:19:28 +0200 Subject: [PATCH 16/17] Support appending and overriding existing elements from project --- .../tim_tool/src/gui/file_tab/callbacks.rs | 7 +++-- src/Tools/tim_tool/ui/app-window.slint | 2 ++ src/Tools/tim_tool/ui/tab/file-tab.slint | 26 +++++++++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) 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 ba53b540..8c5bedd6 100644 --- a/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs +++ b/src/Tools/tim_tool/src/gui/file_tab/callbacks.rs @@ -70,8 +70,11 @@ pub(super) fn on_load_project_clicked(tim_manager: MutexTIMManager) -> impl FnMu }; let mut tim_manager = tim_manager.lock().expect("VRAM already locked"); - clear_all_vram_images(main_tab, &mut tim_manager); - main_window.invoke_clear_file_tab_current_selected_file(); + + if !main_window.get_project_widget_append_project_elements() { + clear_all_vram_images(main_tab, &mut tim_manager); + main_window.invoke_clear_file_tab_current_selected_file(); + } for job in new_project.jobs { let (_, _) = tim_manager.load_unadded_tim(&job.file_path)?; diff --git a/src/Tools/tim_tool/ui/app-window.slint b/src/Tools/tim_tool/ui/app-window.slint index 7ccd88ba..66615c4e 100644 --- a/src/Tools/tim_tool/ui/app-window.slint +++ b/src/Tools/tim_tool/ui/app-window.slint @@ -14,6 +14,8 @@ export component MainWindow inherits Window { // Project widget values in-out property project_widget-open_project_path <=> file_tab.project_widget-open_project_path; in-out property project_widget-save_project_path <=> file_tab.project_widget-save_project_path; + in-out property project_widget-append_project_elements <=> file_tab.project_widget-append_project_elements; + in-out property project_widget-use_rel_paths <=> file_tab.project_widget-use_rel_paths; callback project_widget-load_project_clicked <=> file_tab.project_widget-load_project_clicked; callback project_widget-save_project_clicked <=> file_tab.project_widget-save_project_clicked; callback project_widget-browse_open_project_clicked <=> file_tab.project_widget-browse_open_project_clicked; diff --git a/src/Tools/tim_tool/ui/tab/file-tab.slint b/src/Tools/tim_tool/ui/tab/file-tab.slint index 600f0d8f..f21b47a6 100644 --- a/src/Tools/tim_tool/ui/tab/file-tab.slint +++ b/src/Tools/tim_tool/ui/tab/file-tab.slint @@ -8,6 +8,8 @@ export enum State { component ProjectWidget inherits Rectangle { in-out property open_project_path; in-out property save_project_path; + in-out property append_project_elements; + in-out property use_rel_paths; callback load_project_clicked(); callback save_project_clicked(); @@ -24,7 +26,7 @@ component ProjectWidget inherits Rectangle { VerticalLayout { alignment: start; Text { - text: "Select a project to open. Any existing changes will be dropped"; + text: "Select a project to open."; } HorizontalLayout { alignment: start; @@ -39,6 +41,15 @@ component ProjectWidget inherits Rectangle { } } } + HorizontalLayout { + alignment: start; + CheckBox { + text: "Append elements from project"; + toggled() => { + root.append_project_elements = self.checked; + } + } + } HorizontalLayout { alignment: start; Button { @@ -72,7 +83,8 @@ component ProjectWidget inherits Rectangle { } } CheckBox { - text: "Use relative path for files"; + text: "Use relative path for files"; + checked: root.use_rel_paths; } HorizontalLayout { alignment: start; @@ -282,6 +294,8 @@ export component FileTab inherits Rectangle { // For project widget in-out property project_widget-open_project_path; in-out property project_widget-save_project_path; + in-out property project_widget-append_project_elements; + in-out property project_widget-use_rel_paths; callback project_widget-load_project_clicked(); callback project_widget-save_project_clicked(); callback project_widget-browse_open_project_clicked(); @@ -332,9 +346,11 @@ export component FileTab inherits Rectangle { padding: 4px; alignment: start; if root.state == State.Project : ProjectWidget { - open_project_path <=> root.project_widget-open_project_path; - save_project_path <=> root.project_widget-save_project_path; - + open_project_path <=> root.project_widget-open_project_path; + save_project_path <=> root.project_widget-save_project_path; + append_project_elements <=> root.project_widget-append_project_elements; + use_rel_paths <=> root.project_widget-use_rel_paths; + load_project_clicked() => { root.project_widget-load_project_clicked(); } -- 2.30.2 From 2e6aa8dbe96c6720b716a36774b2ac8d3839050c Mon Sep 17 00:00:00 2001 From: Jaby Date: Tue, 1 Apr 2025 17:20:05 +0200 Subject: [PATCH 17/17] Improve text message for appending elements --- src/Tools/tim_tool/ui/tab/file-tab.slint | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/tim_tool/ui/tab/file-tab.slint b/src/Tools/tim_tool/ui/tab/file-tab.slint index f21b47a6..c398e2d6 100644 --- a/src/Tools/tim_tool/ui/tab/file-tab.slint +++ b/src/Tools/tim_tool/ui/tab/file-tab.slint @@ -44,7 +44,7 @@ component ProjectWidget inherits Rectangle { HorizontalLayout { alignment: start; CheckBox { - text: "Append elements from project"; + text: "Append elements from project to existing elements"; toggled() => { root.append_project_elements = self.checked; } -- 2.30.2