add option to delete solutions, with a confirmation dialog

This commit is contained in:
Crispy 2024-12-24 23:11:04 +01:00
parent 14e90a7849
commit 2c522c1fe0
2 changed files with 45 additions and 4 deletions

View file

@ -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<usize>,
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);
}
}

View file

@ -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)