add option to delete solutions, with a confirmation dialog
This commit is contained in:
parent
14e90a7849
commit
2c522c1fe0
2 changed files with 45 additions and 4 deletions
34
src/main.rs
34
src/main.rs
|
@ -18,7 +18,7 @@ use editor::{Editor, ExitState};
|
||||||
use level::{Chapter, Level};
|
use level::{Chapter, Level};
|
||||||
use solution::Solution;
|
use solution::Solution;
|
||||||
use theme::*;
|
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::*;
|
use util::*;
|
||||||
|
|
||||||
const TITLE_TEXT: &str = concat!("Marble Machinations v", env!("CARGO_PKG_VERSION"));
|
const TITLE_TEXT: &str = concat!("Marble Machinations v", env!("CARGO_PKG_VERSION"));
|
||||||
|
@ -33,6 +33,7 @@ struct Game {
|
||||||
textures: Textures,
|
textures: Textures,
|
||||||
selected_level: usize,
|
selected_level: usize,
|
||||||
selected_solution: usize,
|
selected_solution: usize,
|
||||||
|
delete_solution: Option<usize>,
|
||||||
editing_solution_name: bool,
|
editing_solution_name: bool,
|
||||||
level_desc_text: ShapedText,
|
level_desc_text: ShapedText,
|
||||||
}
|
}
|
||||||
|
@ -74,6 +75,7 @@ impl Game {
|
||||||
textures,
|
textures,
|
||||||
selected_level: 0,
|
selected_level: 0,
|
||||||
selected_solution,
|
selected_solution,
|
||||||
|
delete_solution: None,
|
||||||
editing_solution_name: false,
|
editing_solution_name: false,
|
||||||
level_desc_text: ShapedText::new(20),
|
level_desc_text: ShapedText::new(20),
|
||||||
}
|
}
|
||||||
|
@ -112,6 +114,9 @@ impl Game {
|
||||||
fn draw(&mut self, d: &mut RaylibDrawHandle) {
|
fn draw(&mut self, d: &mut RaylibDrawHandle) {
|
||||||
d.clear_background(BG_DARK);
|
d.clear_background(BG_DARK);
|
||||||
|
|
||||||
|
let mut tooltip = Tooltip::default();
|
||||||
|
tooltip.init_frame(d);
|
||||||
|
|
||||||
d.draw_text(
|
d.draw_text(
|
||||||
TITLE_TEXT,
|
TITLE_TEXT,
|
||||||
d.get_screen_width() - 275,
|
d.get_screen_width() - 275,
|
||||||
|
@ -159,6 +164,7 @@ impl Game {
|
||||||
self.editing_solution_name = false;
|
self.editing_solution_name = false;
|
||||||
self.selected_level = level_index;
|
self.selected_level = level_index;
|
||||||
self.selected_solution = 0;
|
self.selected_solution = 0;
|
||||||
|
self.delete_solution = None;
|
||||||
// select the last solution of the level, if there is one
|
// select the last solution of the level, if there is one
|
||||||
if let Some(solutions) = self.solutions.get(level.id()) {
|
if let Some(solutions) = self.solutions.get(level.id()) {
|
||||||
self.selected_solution = solutions.len().saturating_sub(1);
|
self.selected_solution = solutions.len().saturating_sub(1);
|
||||||
|
@ -236,6 +242,14 @@ impl Game {
|
||||||
10,
|
10,
|
||||||
Color::WHITE,
|
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;
|
solution_y += solution_entry_height + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,8 +266,23 @@ impl Game {
|
||||||
solutions.push(Solution::new(level, next_id));
|
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) {
|
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.);
|
let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.);
|
||||||
if text_input(
|
if text_input(
|
||||||
d,
|
d,
|
||||||
|
@ -286,6 +315,7 @@ impl Game {
|
||||||
self.solutions.insert(level.id().to_owned(), Vec::new());
|
self.solutions.insert(level.id().to_owned(), Vec::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tooltip.draw(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::Write,
|
io::Write,
|
||||||
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -45,16 +46,26 @@ impl Solution {
|
||||||
self.solution_id
|
self.solution_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self) {
|
fn path(&self) -> PathBuf {
|
||||||
let dir = userdata_dir().join("solutions").join(&self.level_id);
|
let dir = userdata_dir().join("solutions").join(&self.level_id);
|
||||||
fs::create_dir_all(&dir).unwrap();
|
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 json = serde_json::to_string_pretty(self).unwrap();
|
||||||
let mut file = File::create(path).unwrap();
|
let mut file = File::create(path).unwrap();
|
||||||
file.write_all(json.as_bytes()).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 {
|
pub fn score_text(&self) -> String {
|
||||||
if let Some(score) = &self.score {
|
if let Some(score) = &self.score {
|
||||||
format!("C: {} T: {}", score.cycles, score.tiles)
|
format!("C: {} T: {}", score.cycles, score.tiles)
|
||||||
|
|
Loading…
Reference in a new issue