diff --git a/src/Tools/tim_tool/src/gui/file_tab.rs b/src/Tools/tim_tool/src/gui/file_tab.rs index d076e654..df361c1a 100644 --- a/src/Tools/tim_tool/src/gui/file_tab.rs +++ b/src/Tools/tim_tool/src/gui/file_tab.rs @@ -2,7 +2,7 @@ use crate::MainWindow; use super::{GUIElements, GUIElementsRef, MainWindowRef, display_error}; use slint::{Image, SharedString}; use std::rc::Rc; -use tim_tool::logic::tim::Encoding; +use tim_tool::logic::tim::types::Encoding; use tool_helper::Error; pub struct FileTab { diff --git a/src/Tools/tim_tool/src/gui/main_tab.rs b/src/Tools/tim_tool/src/gui/main_tab.rs index 4e2b5c32..4bb58145 100644 --- a/src/Tools/tim_tool/src/gui/main_tab.rs +++ b/src/Tools/tim_tool/src/gui/main_tab.rs @@ -2,12 +2,31 @@ use crate::{gui::{VRAM_HEIGHT, VRAM_WIDTH}, MainWindow, VRAMImage}; use super::{GUIElementsRef, MainWindowRef}; use slint::{Model, SharedString}; -use tim_tool::logic::tim::Encoding; -use std::{rc::Rc, sync::{Arc, Mutex}}; +use tim_tool::logic::tim::types::Encoding; +use std::{ops::RangeInclusive, rc::Rc, sync::{Arc, Mutex}}; struct VRAM { - pub file_list: Rc>, - pub image_list: Rc> + count: usize, + file_list: Rc>, + image_list: Rc> +} + +impl VRAM { + pub fn push(&mut self, name: slint::StandardListViewItem, image: VRAMImage) { + self.file_list.push(name); + self.image_list.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); + } + + pub fn pop(&mut self) { + self.remove(self.count - 1); + } } pub struct MainTab { @@ -24,14 +43,15 @@ impl MainTab { 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()); - MainTab{main_window, vram: Arc::new(Mutex::new(VRAM{file_list: vram_file_list, image_list: vram_image_list}))} + MainTab{main_window, vram: Arc::new(Mutex::new(VRAM{count: 0, file_list: vram_file_list, image_list: vram_image_list}))} } - pub fn add_new_vram_file(&mut self, file_name: &String, image: slint::Image, encoding: Encoding, image_palette: Option) { - let vram_data = self.vram.lock().expect("VRAM already locked"); - let add_new_image = |file_name: &String, image: slint::Image, encoding: Encoding, palette_count: i32, is_palette: bool| { + pub fn add_new_vram_file(&mut self, file_name: &String, full_image: slint::Image, image: slint::Image, encoding: Encoding, 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 vram_image = VRAMImage{ + full_img: full_image, img: image, x: 0, y: 0, @@ -40,28 +60,27 @@ impl MainTab { is_palette, }; - vram_data.file_list.push(slint::StandardListViewItem::from(file_name.as_str())); - vram_data.image_list.push(vram_image); + vram_data.push(slint::StandardListViewItem::from(file_name.as_str()), vram_image); }; - add_new_image(file_name, image, encoding, if image_palette.is_some() {1} else {0}, false); + let mut images_added = 1; + add_new_image(file_name, full_image, image, encoding, 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)"; - add_new_image(&file_name, image_palette, encoding, 0, true); + + images_added += 1; + add_new_image(&file_name, image_palette.clone(), image_palette, encoding, 0, true); } + + images_added } - pub fn remove_vram_file(&mut self, idx: usize) -> bool { - let vram_data = self.vram.lock().expect("VRAM already locked"); - let remove_image = |idx: usize| { - vram_data.file_list.remove(idx); - vram_data.image_list.remove(idx); - }; - - let extras = { + 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 { - return false; + return Err("Can not remove palette. Delete image instead"); } else { @@ -74,10 +93,22 @@ impl MainTab { } }; - for _ in idx..=idx+extras { + let range = idx..=idx+extras; + let mut remove_image = |idx: usize| { + vram_data.remove(idx); + }; + + for _ in range.clone() { remove_image(idx); } - return true; + return Ok(range); + } + + pub fn pop_vram_files(&mut self, count: usize) { + let mut vram_data = self.vram.lock().expect("VRAM already locked"); + for _ in 0..count { + vram_data.pop(); + } } pub fn move_vram_image(&mut self, idx: usize, dx: i32, dy: i32) { diff --git a/src/Tools/tim_tool/src/logic/mod.rs b/src/Tools/tim_tool/src/logic/mod.rs index 71fbe9fc..9c7791cf 100644 --- a/src/Tools/tim_tool/src/logic/mod.rs +++ b/src/Tools/tim_tool/src/logic/mod.rs @@ -1,20 +1,27 @@ pub mod tim; - -use std::path::PathBuf; +use std::{ops::RangeInclusive, path::PathBuf}; use slint::Image; -use tim::{Encoding, TIMInfo}; +use tim::{types::Encoding, TIMInfo}; use tool_helper::Error; pub struct Logic { + added_tims: Vec>, unadded_tim: Option, } impl Logic { pub fn new() -> Logic { - Logic{unadded_tim: None} + Logic{added_tims: Default::default(), unadded_tim: None} } - pub fn set_unadded_tim(&mut self, path: &PathBuf) -> Result<(Image, Option), Error> { + pub fn remove_added_tim(&mut self, range: RangeInclusive) { + let idx = *range.start(); + for _ in range { + self.added_tims.remove(idx); + } + } + + pub fn load_unadded_tim(&mut self, path: &PathBuf) -> Result<(Image, Option), Error> { let tim_info = TIMInfo::from_image(path)?; let image = tim_info.get_slint_images(Encoding::FullColor); @@ -22,14 +29,33 @@ impl Logic { Ok(image) } - pub fn add_unadded_tim_as(&mut self, _name: &String, encoding: Encoding) -> Result<(Image, Option), Error> { + pub fn get_converted_unadded_tim_image(&self, encoding: Encoding) -> Result<(Image, Option), Error> { if let Some(unadded_tim) = &self.unadded_tim { let (image, palette) = unadded_tim.get_slint_images(encoding); - - self.unadded_tim = None; Ok((image, palette)) } + else { + Err(Error::from_str("No data found for loaded image")) + } + } + + pub fn add_unadded_tim(&mut self, images_added: usize) -> Result<(), Error> { + if let Some(_) = &self.unadded_tim { + if images_added >= 1 { + self.added_tims.push(std::mem::replace(&mut self.unadded_tim, None)); + + for _ in 0..(images_added - 1) { + self.added_tims.push(None); + } + Ok(()) + } + + else { + Err(Error::from_str("Can not add 0 images")) + } + } + else { Err(Error::from_str("No data found for loaded image")) } diff --git a/src/Tools/tim_tool/src/logic/tim.rs b/src/Tools/tim_tool/src/logic/tim/mod.rs similarity index 89% rename from src/Tools/tim_tool/src/logic/tim.rs rename to src/Tools/tim_tool/src/logic/tim/mod.rs index 6f176afc..ab0f8c5b 100644 --- a/src/Tools/tim_tool/src/logic/tim.rs +++ b/src/Tools/tim_tool/src/logic/tim/mod.rs @@ -1,29 +1,12 @@ +pub mod types; + use std::{fs::File, path::PathBuf}; use slint::{Rgba8Pixel, SharedPixelBuffer}; use tool_helper::Error; - -#[derive(Clone, Copy)] -pub enum Encoding { - FourBit, - EightBit, - FullColor, -} - -impl Encoding { - const FOUR_BIT_NAME:&str = "4 bit"; - const EIGHT_BIT_NAME:&str = "8 bit"; - const FULL_COLOR_NAME:&str = "Full color"; - - pub const fn to_str(&self) -> &str { - match self { - Encoding::FourBit => Self::FOUR_BIT_NAME, - Encoding::EightBit => Self::EIGHT_BIT_NAME, - Encoding::FullColor => Self::FULL_COLOR_NAME, - } - } -} +use types::Encoding; pub struct TIMInfo { + _path: PathBuf, image_data: SharedPixelBuffer, palette: Option, } @@ -69,7 +52,7 @@ impl TIMInfo { _ => {return Err(Error::from_str("Only 4 and 8bit color depth are supported for indexed color images"));} } } - Ok(TIMInfo{image_data, palette: Some(PaletteInfo::new(palette_colors))}) + Ok(TIMInfo{_path: path.clone(), image_data, palette: Some(PaletteInfo::new(palette_colors))}) } else { @@ -87,7 +70,7 @@ impl TIMInfo { _ => {return Err(Error::from_str("Only 8bit color depth are supported for direct color images"));} } } - Ok(TIMInfo{image_data, palette: None}) + Ok(TIMInfo{_path: path.clone(), image_data, palette: None}) } } diff --git a/src/Tools/tim_tool/src/logic/tim/types.rs b/src/Tools/tim_tool/src/logic/tim/types.rs new file mode 100644 index 00000000..01ef2f10 --- /dev/null +++ b/src/Tools/tim_tool/src/logic/tim/types.rs @@ -0,0 +1,20 @@ +#[derive(Clone, Copy)] +pub enum Encoding { + FourBit, + EightBit, + FullColor, +} + +impl Encoding { + const FOUR_BIT_NAME:&str = "4 bit"; + const EIGHT_BIT_NAME:&str = "8 bit"; + const FULL_COLOR_NAME:&str = "Full color"; + + pub const fn to_str(&self) -> &str { + match self { + Encoding::FourBit => Self::FOUR_BIT_NAME, + Encoding::EightBit => Self::EIGHT_BIT_NAME, + Encoding::FullColor => Self::FULL_COLOR_NAME, + } + } +} \ No newline at end of file diff --git a/src/Tools/tim_tool/src/main.rs b/src/Tools/tim_tool/src/main.rs index 496e4767..44cf7809 100644 --- a/src/Tools/tim_tool/src/main.rs +++ b/src/Tools/tim_tool/src/main.rs @@ -6,7 +6,7 @@ use gui::{GUIElements, VRAM_WIDTH, VRAM_HEIGHT, display_information}; use rfd::FileDialog; use std::{cell::RefCell, rc::Rc}; use slint::SharedString; -use tim_tool::logic::Logic; +use tim_tool::logic::{tim::types::Encoding, Logic}; use tool_helper::Error; slint::include_modules!(); @@ -17,24 +17,27 @@ fn main() -> Result<(), slint::PlatformError> { let main_window_ref = Rc::new(RefCell::new(MainWindow::new()?)); let gui_elements_ref = Rc::new(RefCell::new(GUIElements::new(main_window_ref.clone())?)); - setup_main_tab(gui_elements_ref.clone()); - setup_file_tab(gui_elements_ref.clone(), logic_ref); + setup_main_tab(gui_elements_ref.clone(), logic_ref.clone()); + setup_file_tab(gui_elements_ref.clone(), logic_ref.clone()); + setup_about_tab(main_window_ref.clone()); let main_window = main_window_ref.borrow(); main_window.run() } -fn setup_main_tab(gui_elements_ref: Rc>) { +fn setup_main_tab(gui_elements_ref: Rc>, logic_ref: Rc>) { let gui_elements = gui_elements_ref.borrow(); gui_elements.main_tab.on_move_vram_image(gui_elements_ref.clone(), move |main_tab, _main_window, idx, dx, dy| { main_tab.move_vram_image(idx as usize, dx, dy); }); + let logic = logic_ref.clone(); gui_elements.main_tab.on_remove_file(gui_elements_ref.clone(), move |main_tab, _main_window, idx| { if idx >= 0 { - if !main_tab.remove_vram_file(idx as usize) { - display_information("Removing VRAM file", "Can not remove palette. Delete image instead"); + match main_tab.remove_vram_file(idx as usize) { + Ok(range) => logic.borrow_mut().remove_added_tim(range), + Err(error) => display_information("Removing VRAM file", error) } } }); @@ -66,7 +69,7 @@ fn setup_file_tab(gui_elements_ref: Rc>, logic_ref: Rc VRAM_WIDTH as u32 || img_size.height > VRAM_HEIGHT as u32 { @@ -85,11 +88,24 @@ fn setup_file_tab(gui_elements_ref: Rc>, logic_ref: Rc>) { + const VERSION: &str = env!("CARGO_PKG_VERSION"); + + let main_window = main_window_ref.borrow(); + main_window.invoke_set_version(SharedString::from(VERSION)); } \ 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 e933f4dd..6d58590e 100644 --- a/src/Tools/tim_tool/ui/app-window.slint +++ b/src/Tools/tim_tool/ui/app-window.slint @@ -57,10 +57,14 @@ export component MainWindow inherits Window { } Tab { title: "About"; - AboutTab {} + about_tab := AboutTab {} } } + public function set_version(version: string) { + about_tab.version = version; + } + public function change_to_load_file() { file_tab.state = State.ConvertImage; tab_widget.current-index = 0; diff --git a/src/Tools/tim_tool/ui/tab/about-tab.slint b/src/Tools/tim_tool/ui/tab/about-tab.slint index 6f470cf6..54e0770f 100644 --- a/src/Tools/tim_tool/ui/tab/about-tab.slint +++ b/src/Tools/tim_tool/ui/tab/about-tab.slint @@ -1,14 +1,19 @@ import { AboutSlint } from "std-widgets.slint"; export component AboutTab { + in property version; y: 0px; VerticalLayout { padding: 8px; alignment: start; Text { font-size: 24pt; - text: "TIM_Tool Version 0.1.0"; + text: "TIM_Tool Version " + root.version; horizontal-alignment: center; } + Image { + source: @image-url("../assets/TimTool64x64.png"); + image-rendering: pixelated; + } Text { font-size: 20pt; text: "Part of JabyEngine"; diff --git a/src/Tools/tim_tool/ui/tab/file-tab.slint b/src/Tools/tim_tool/ui/tab/file-tab.slint index a9a9e078..bb0a78ba 100644 --- a/src/Tools/tim_tool/ui/tab/file-tab.slint +++ b/src/Tools/tim_tool/ui/tab/file-tab.slint @@ -7,7 +7,10 @@ export enum State { component ProjectWidget inherits Rectangle { Text { - text: "!!Planschbecken!!"; + text: "Projects not supported yet"; + color: #FF0000; + font-size: 30pt; + font-weight: 800; } } diff --git a/src/Tools/tim_tool/ui/tab/main-tab.slint b/src/Tools/tim_tool/ui/tab/main-tab.slint index fbfcbe30..fdd28332 100644 --- a/src/Tools/tim_tool/ui/tab/main-tab.slint +++ b/src/Tools/tim_tool/ui/tab/main-tab.slint @@ -2,6 +2,7 @@ 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, x: int, y: int, @@ -81,7 +82,7 @@ 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 = parent.img; + cur_sel_img.source = vram-image.full_img; encoding_text.encoding_str = vram-image.encoding_str; cur_sel_img.visible = true; @@ -111,11 +112,11 @@ export component MainTab inherits Rectangle { function update_viewport() { if abs(self.viewport-x) + self.width > self.viewport-width { - self.viewport-x = 0; + self.viewport-x += (self.width + abs(self.viewport-x)) - self.viewport-width; } if abs(self.viewport-y) + self.height > self.viewport-height { - self.viewport-y = 0; + self.viewport-y += (self.height + abs(self.viewport-y)) - self.viewport-height; } } } @@ -155,7 +156,7 @@ export component MainTab inherits Rectangle { 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].img; + cur_sel_img.source = root.vram_images[current-item].full_img; encoding_text.encoding_str = root.vram_images[current-item].encoding_str; cur_sel_img.visible = true; }