From 2c522c1fe0bb261dd9242bf77b29edf1d4ac5a8e Mon Sep 17 00:00:00 2001 From: CrispyPin Date: Tue, 24 Dec 2024 23:11:04 +0100 Subject: [PATCH] add option to delete solutions, with a confirmation dialog --- src/main.rs | 34 ++++++++++++++++++++++++++++++++-- src/solution.rs | 15 +++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6344959..77ff9f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use editor::{Editor, ExitState}; use level::{Chapter, Level}; use solution::Solution; use theme::*; -use ui::{simple_option_button, text_button, text_input, ShapedText}; +use ui::{simple_option_button, tex32_button, text_button, text_input, ShapedText, Tooltip}; use util::*; const TITLE_TEXT: &str = concat!("Marble Machinations v", env!("CARGO_PKG_VERSION")); @@ -33,6 +33,7 @@ struct Game { textures: Textures, selected_level: usize, selected_solution: usize, + delete_solution: Option, editing_solution_name: bool, level_desc_text: ShapedText, } @@ -74,6 +75,7 @@ impl Game { textures, selected_level: 0, selected_solution, + delete_solution: None, editing_solution_name: false, level_desc_text: ShapedText::new(20), } @@ -112,6 +114,9 @@ impl Game { fn draw(&mut self, d: &mut RaylibDrawHandle) { d.clear_background(BG_DARK); + let mut tooltip = Tooltip::default(); + tooltip.init_frame(d); + d.draw_text( TITLE_TEXT, d.get_screen_width() - 275, @@ -159,6 +164,7 @@ impl Game { self.editing_solution_name = false; self.selected_level = level_index; self.selected_solution = 0; + self.delete_solution = None; // select the last solution of the level, if there is one if let Some(solutions) = self.solutions.get(level.id()) { self.selected_solution = solutions.len().saturating_sub(1); @@ -236,6 +242,14 @@ impl Game { 10, Color::WHITE, ); + if tex32_button( + (d, &mouse), + (level_list_width + entry_width + 15, solution_y + 4), + self.textures.get("cancel"), + (&mut tooltip, "delete"), + ) { + self.delete_solution = Some(solution_index); + } solution_y += solution_entry_height + 10; } @@ -252,8 +266,23 @@ impl Game { solutions.push(Solution::new(level, next_id)); } + if let Some(i) = self.delete_solution { + let text = format!("really delete solution '{}'?", &solutions[i].name); + let y = (solution_y + 40).max(240); + let x = level_list_width + 10; + d.draw_text(&text, x, y, 20, Color::ORANGE); + if text_button(d, &mouse, x, y + 30, 100, "yes") { + solutions[i].remove_file(); + solutions.remove(i); + self.delete_solution = None; + } + if text_button(d, &mouse, x + 110, y + 30, 100, "no") { + self.delete_solution = None; + } + } + if let Some(solution) = solutions.get_mut(self.selected_solution) { - let column_x = level_list_width + entry_width + 20; + let column_x = level_list_width + entry_width + 56; let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.); if text_input( d, @@ -286,6 +315,7 @@ impl Game { self.solutions.insert(level.id().to_owned(), Vec::new()); } } + tooltip.draw(d); } } diff --git a/src/solution.rs b/src/solution.rs index 11fd23f..37d4c25 100644 --- a/src/solution.rs +++ b/src/solution.rs @@ -1,6 +1,7 @@ use std::{ fs::{self, File}, io::Write, + path::PathBuf, }; use serde::{Deserialize, Serialize}; @@ -45,16 +46,26 @@ impl Solution { self.solution_id } - pub fn save(&self) { + fn path(&self) -> PathBuf { let dir = userdata_dir().join("solutions").join(&self.level_id); fs::create_dir_all(&dir).unwrap(); - let path = dir.join(format!("solution_{}.json", &self.solution_id)); + dir.join(format!("solution_{}.json", &self.solution_id)) + } + pub fn save(&self) { + let path = self.path(); let json = serde_json::to_string_pretty(self).unwrap(); let mut file = File::create(path).unwrap(); file.write_all(json.as_bytes()).unwrap(); } + pub fn remove_file(&self) { + let path = self.path(); + if let Err(e) = fs::remove_file(path) { + eprint!("Error removing solution file: {e}"); + } + } + pub fn score_text(&self) -> String { if let Some(score) = &self.score { format!("C: {} T: {}", score.cycles, score.tiles)