161 lines
6.2 KiB
Rust
161 lines
6.2 KiB
Rust
// 澶栧3璁剧疆鎸佷箙鍖?(W-CFG-01~03): %APPDATA%\com.iboard.app\shell-config.json
|
|
// - 涓庡墠绔处鍙?鏈嶅姟绔棤鍏? 绂荤嚎鍙敤;
|
|
// - 瀛楁缂哄け/鎹熷潖鏃跺洖閫€榛樿鍊?(serde(default) + 瀹芥澗鍔犺浇);
|
|
// - 鍐欏叆閲囩敤 涓存椂鏂囦欢 + 鏇挎崲 鐨勫師瀛愯涔夈€?
|
|
use serde::{Deserialize, Serialize};
|
|
use std::path::Path;
|
|
|
|
pub const FILE_NAME: &str = "shell-config.json";
|
|
|
|
/// 璁捐鍩哄噯灏哄 (绉诲姩绔竷灞€鍙e緞): 绐楀彛姣斾緥閿佹涓?405:720
|
|
pub const DESIGN_WIDTH: f64 = 405.0;
|
|
pub const DESIGN_HEIGHT: f64 = 720.0;
|
|
/// 窗口宽度可配置范围 (逻辑像素); 高度由比例推导, 不接受单独配置
|
|
pub const WIDTH_MIN: f64 = 242.0;
|
|
pub const WIDTH_MAX: f64 = 620.0;
|
|
|
|
/// 鎸夐攣瀹氭瘮渚嬬敱瀹藉害鎺ㄥ楂樺害 (鍞竴灏哄鍏ュ彛)
|
|
pub fn height_for_width(width: f64) -> f64 {
|
|
let w = width.clamp(WIDTH_MIN, WIDTH_MAX);
|
|
(w * DESIGN_HEIGHT / DESIGN_WIDTH).round()
|
|
}
|
|
|
|
/// 鍚搁檮杈?(W-SNP-01: 鍥涜竟)
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum Edge {
|
|
#[default]
|
|
Left,
|
|
Right,
|
|
Top,
|
|
Bottom,
|
|
}
|
|
|
|
impl Edge {
|
|
pub fn css(&self) -> &'static str {
|
|
match self {
|
|
Edge::Left => "left",
|
|
Edge::Right => "right",
|
|
Edge::Top => "top",
|
|
Edge::Bottom => "bottom",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 涓荤獥鍙h蹇?(W-WIN-07): 灏哄涓洪€昏緫鍍忕礌 (DPI 绋冲畾), 浣嶇疆涓虹墿鐞嗗儚绱?(鍔犺浇鏃舵牎楠屽す鍙?
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(default)]
|
|
pub struct WindowCfg {
|
|
pub width: f64,
|
|
pub height: f64,
|
|
pub x: Option<i32>,
|
|
pub y: Option<i32>,
|
|
}
|
|
|
|
impl Default for WindowCfg {
|
|
fn default() -> Self {
|
|
// 323x574 = 405:720 姣斾緥 (0.797x of 405x720, 2026-10-26 鏀惧ぇ 12%)
|
|
Self { width: 323.0, height: height_for_width(323.0), x: None, y: None }
|
|
}
|
|
}
|
|
|
|
/// 鎮诞鐞冨仠闈?(W-SNP-02/12): 杈?+ 娌胯竟浣嶇疆 (鎮诞鐞冧腑蹇? 鐗╃悊鍍忕礌)
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(default)]
|
|
pub struct DockCfg {
|
|
pub edge: Edge,
|
|
pub offset: i32,
|
|
}
|
|
|
|
impl Default for DockCfg {
|
|
fn default() -> Self {
|
|
Self { edge: Edge::Left, offset: 360 }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(default)]
|
|
pub struct ShellConfig {
|
|
/// 鍚搁檮鎬诲紑鍏?(W-SNP-09, 榛樿寮€鍚?
|
|
pub snap_enabled: bool,
|
|
pub window: WindowCfg,
|
|
pub dock: DockCfg,
|
|
/// 绐楀彛瀹藉害 (閫昏緫鍍忕礌) 鈥斺€?**鍞竴灏哄閰嶇疆椤?*銆? /// 楂樺害鎸?405:720 閿佸畾姣斾緥鑷姩鎺ㄥ, 鏃犻渶涔熸棤娉曞崟鐙厤缃?
|
|
/// 鐣欑┖鏃跺洖钀藉埌 window.width銆? #[serde(default)]
|
|
pub window_width: Option<f64>,
|
|
/// 閰嶇疆缁撴瀯鐗堟湰: 0 = 鏃х増 (绐楀彛灏哄鎸?405x720 鍙e緞淇濆瓨),
|
|
/// 1 = 鏁翠綋缂╁皬 30% (288 鍙e緞), 2 = 鏀惧ぇ 12% (323 鍙e緞) + 鍗曞€煎搴﹂厤缃€? /// load 鏃跺仛涓€娆℃€ц縼绉汇€? /// 娉ㄦ剰蹇呴』鐢ㄥ瓧娈电骇 serde(default) (u8 鈫?0): 瀹瑰櫒绾?default 浼氬彇
|
|
/// ShellConfig::default() 鐨?2, 鏃ч厤缃枃浠跺氨姘歌繙涓嶈縼绉讳簡銆? #[serde(default)]
|
|
pub cfg_version: u8,
|
|
}
|
|
|
|
impl Default for ShellConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
snap_enabled: true,
|
|
window: WindowCfg::default(),
|
|
dock: DockCfg::default(),
|
|
window_width: Some(WindowCfg::default().width),
|
|
cfg_version: 2,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 杩佺Щ鍓嶇殑绐楀彛瀹藉害 (鏃у彛寰?, 渚?load 浣跨敤
|
|
impl WindowCfg {
|
|
/// 搴旂敤閿佸畾姣斾緥: 瀹藉害澶瑰彇鍒板悎娉曡寖鍥? 楂樺害鐢卞搴︽帹瀵?(蹇界暐瀛樼洏楂樺害)
|
|
pub(crate) fn normalize(&mut self) {
|
|
self.width = self.width.clamp(WIDTH_MIN, WIDTH_MAX);
|
|
self.height = height_for_width(self.width);
|
|
}
|
|
}
|
|
|
|
impl ShellConfig {
|
|
pub fn load(dir: &Path) -> ShellConfig {
|
|
let path = dir.join(FILE_NAME);
|
|
let mut cfg = match std::fs::read_to_string(&path) {
|
|
Ok(text) => match serde_json::from_str::<ShellConfig>(&text) {
|
|
Ok(cfg) => cfg,
|
|
Err(_) => ShellConfig::default(), // 鍐欏潖 JSON 鈫?榛樿鍊?(W-CFG-03)
|
|
},
|
|
Err(_) => ShellConfig::default(),
|
|
};
|
|
// 一次性迁移
|
|
if cfg.cfg_version < 1 {
|
|
// v0 (405 鍙e緞) 鈫?v1: 鏁翠綋缂╁皬 30%
|
|
cfg.window.width = (cfg.window.width * 0.7).max(216.0);
|
|
cfg.window.height = (cfg.window.height * 0.7).max(384.0);
|
|
cfg.cfg_version = 1;
|
|
}
|
|
if cfg.cfg_version < 2 {
|
|
// v1 (288 口径) -> v2: 放大 12% (323 口径), 引入单值宽度配置
|
|
cfg.window.width = (cfg.window.width * 1.12).max(WIDTH_MIN);
|
|
cfg.window.height = height_for_width(cfg.window.width);
|
|
cfg.cfg_version = 2;
|
|
}
|
|
// 鍗曞€煎搴︿紭鍏? 楂樺害涓€寰嬫寜閿佸畾姣斾緥鎺ㄥ (蹇界暐瀛樼洏楂樺害)
|
|
if let Some(w) = cfg.window_width {
|
|
cfg.window.width = w;
|
|
}
|
|
cfg.window.normalize();
|
|
cfg.window_width = Some(cfg.window.width);
|
|
cfg.save(dir);
|
|
cfg
|
|
}
|
|
|
|
pub fn save(&self, dir: &Path) {
|
|
let path = dir.join(FILE_NAME);
|
|
let tmp = dir.join(format!("{FILE_NAME}.tmp"));
|
|
let text = match serde_json::to_string_pretty(self) {
|
|
Ok(t) => t,
|
|
Err(_) => return,
|
|
};
|
|
if std::fs::write(&tmp, text).is_ok() {
|
|
// Windows 上 rename 不能覆盖已存在文件, 先移除
|
|
let _ = std::fs::remove_file(&path);
|
|
let _ = std::fs::rename(&tmp, &path);
|
|
}
|
|
// 鍐欏け璐ヤ繚鎸侀潤榛?(W-CFG-04): 杩愯涓殑澶栧3涓嶅彈褰卞搷
|
|
}
|
|
}
|