1use crate::constants::DisplayMode;
2use ratatui::style::Color;
3use serde::{Deserialize, Serialize};
4use std::fs;
5use std::path::Path;
6
7fn default_piece_style_str() -> String {
8 DisplayMode::DEFAULT.to_string()
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub struct Skin {
13 pub name: String,
14 #[serde(default = "default_piece_style_str", alias = "display_mode")]
15 pub piece_style: String,
16 pub board_white_color: Color,
17 pub board_black_color: Color,
18 pub piece_white_color: Color,
19 pub piece_black_color: Color,
20 pub cursor_color: Color,
21 pub selection_color: Color,
22 pub last_move_color: Color,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
27pub struct PieceStyleSize {
28 pub bishop: String,
29 pub king: String,
30 pub knight: String,
31 pub pawn: String,
32 pub queen: String,
33 pub rook: String,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
38pub struct PieceStyle {
39 pub name: String,
40 pub small: PieceStyleSize,
41 pub compact: PieceStyleSize,
42 pub extended: PieceStyleSize,
43 pub large: PieceStyleSize,
44}
45
46impl Default for Skin {
47 fn default() -> Self {
48 Self {
49 name: "Default".to_string(),
50 piece_style: DisplayMode::DEFAULT.to_string(),
51 board_white_color: Color::Rgb(160, 160, 160),
52 board_black_color: Color::Rgb(128, 95, 69),
53 piece_white_color: Color::White,
54 piece_black_color: Color::Black,
55 cursor_color: Color::LightBlue,
56 selection_color: Color::LightGreen,
57 last_move_color: Color::LightGreen,
58 }
59 }
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct SkinCollection {
64 pub skins: Vec<Skin>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct PieceStyleCollection {
69 pub piece_styles: Vec<PieceStyle>,
70}
71
72impl Skin {
73 pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
79 let content = fs::read_to_string(path)?;
80 let skin: Skin = serde_json::from_str(&content)?;
81 Ok(skin)
82 }
83
84 pub fn load_all_skins<P: AsRef<Path>>(
90 path: P,
91 ) -> Result<Vec<Skin>, Box<dyn std::error::Error>> {
92 let content = fs::read_to_string(path)?;
93 let collection: SkinCollection = serde_json::from_str(&content)?;
94 Ok(collection.skins)
95 }
96
97 #[must_use]
98 pub fn get_skin_by_name(skins: &[Skin], name: &str) -> Option<Skin> {
99 skins.iter().find(|s| s.name == name).cloned()
100 }
101
102 pub fn load_all_piece_styles<P: AsRef<Path>>(
103 path: P,
104 ) -> Result<Vec<PieceStyle>, Box<dyn std::error::Error>> {
105 let content = fs::read_to_string(path)?;
106 let collection: PieceStyleCollection = serde_json::from_str(&content)?;
107 Ok(collection.piece_styles)
108 }
109
110 #[must_use]
112 pub fn default_display_mode() -> Self {
113 Self {
114 name: "Default".to_string(),
115 piece_style: DisplayMode::DEFAULT.to_string(),
116 board_white_color: Color::Rgb(160, 160, 160),
117 board_black_color: Color::Rgb(128, 95, 69),
118 piece_white_color: Color::White,
119 piece_black_color: Color::Black,
120 cursor_color: Color::LightBlue,
121 selection_color: Color::LightGreen,
122 last_move_color: Color::LightGreen,
123 }
124 }
125
126 #[must_use]
128 pub fn ascii_display_mode() -> Self {
129 Self {
130 name: "ASCII".to_string(),
131 piece_style: DisplayMode::ASCII.to_string(),
132 board_white_color: Color::Rgb(160, 160, 160),
133 board_black_color: Color::Rgb(128, 95, 69),
134 piece_white_color: Color::White,
135 piece_black_color: Color::Black,
136 cursor_color: Color::LightBlue,
137 selection_color: Color::LightGreen,
138 last_move_color: Color::LightGreen,
139 }
140 }
141}