feat(app-iced): M93 —— 外观接线:整窗 α / 面板 α / 背景图 / 配色来源
把 appearance.* 那批键接到窗口与像素上(M91 只落了键与判据,零调用方)。
整窗 α(D34/D36)
- `ensure_layered(hwnd)` 落在唯一 unsafe 文件 `platform/win32/transparency.rs`
(`WS_EX_LAYERED` 只有 Get/SetWindowLongPtrW 能加,且 CI 的 unsafe-scope 是集合相等);
`app/boot.rs` 只负责开窗,句柄到手后由 `Message::WindowHandle` → `window_alpha::dispatch`
先补样式再下发。本机实测 `layered=ok outcome=Applied { byte: 205 }`(α=0.8)。
- 三条入口都会重算并下发:启动(句柄到达)、设置页改动、配置文件热切。
- `layered` 日志有三态:`n/a`(α≥1,压根不需要)/ `ok` / `FAILED`,避免把「没用到」写成假红。
面板 α 与 CPU 档(D36)
- 面板 α 独立于整窗 α:只作用到外壳层(根容器 / 标题栏 / 导航轨)与外观卡片;
CPU 档强制 1.0、玻璃强制关(`pages/appearance/alpha.rs` 的真值表 + 单测)。
- 色卡档继续走令牌 baseline,只有取色档(①②级)才换 `Ui` 的 scheme(`Ui::from_scheme`)。
背景图(D38)
- 读盘解码(png)→ cover/contain/tile 三种填充几何 → `bg_dim` 向底色退 → 36dp 网格马赛克;
iced 的 `image` widget 需要 `iced/image` feature(Cargo.toml 不在 scope),故为已登记降级。
- 读盘失败静默回落 + 一条可读诊断(设置页错误行 + 日志),配色经 `Provenance` 回落色卡。
设置页「外观」分组
- 整窗透明度滑块(下限 0.08)/ 面板透明度(CPU 档禁用并写明 55%→100% 的降级)/
背景图开关与路径 / 填充三档 / 暗化 / 配色来源三档;改完即时生效并写回:
bridge 覆盖的 5 个键走 `SettingsBridge::persist`,`window_opacity` / `palette_source`
走 `AppCommand::SetSetting`(每个键只有一个写者)。
- `SettingsBridge::load_base()`(presenter)让 app-iced 不需要直接依赖 core 就能读回
`window_opacity` / `palette_source`。
取证
- `ULL_APPEARANCE_*` / `ULL_START_ROUTE` 只影响本次进程(语义同 ULL_TICK_TRACE),
截图通道不读用户配置(D30)。
This commit is contained in:
1 parent
eae7ae0ff4
commit
b8ab46662c
24 files changed
+3119
-48
No files matched your search
@@ -92,6 +92,7 @@
|
||||
//! 产品二进制的截图走 `--screenshot`(页面树由 app 层按路由装配),本 harness 只出**单页**图,
|
||||
//! 用于页面级回归与宽度对照。
|
||||
|
||||
pub mod appearance;
|
||||
pub mod frame;
|
||||
pub mod harness;
|
||||
pub mod layout;
|
||||
@@ -135,6 +136,11 @@ pub enum Message {
|
||||
Launch(String),
|
||||
/// 停止某实例(app 层翻成 `AppCommand::StopInstance`)。
|
||||
Stop(String),
|
||||
/// 外观项改动(设置页「外观」分组 → `App` 的状态与落盘)。
|
||||
///
|
||||
/// 载荷是**用户请求值**(未钳位):钳位与 CPU 档降级在 `appearance::alpha` 里做,
|
||||
/// 页面只表达意图(与组件库「不持有业务状态」同一条纪律)。
|
||||
Appearance(appearance::Change),
|
||||
}
|
||||
|
||||
/// 页面动作清单(骨架期够用就行;接线时按业务语义重命名/扩充)。
|
||||
@@ -278,19 +284,40 @@ const NAV: [(Option<NavSection>, IconKind, &str, Route); 5] = [
|
||||
|
||||
/// **单页内容**(不含外壳):交给 `shell::view_with_content` 塞进真标题栏与导航轨之间。
|
||||
///
|
||||
/// 产品路径(`app/view.rs`)走这个入口:外壳由 `shell` 画(拖动/缩放/三个 caption 键、rail 88),
|
||||
/// 这里只画「页头 + 内容列」。列宽仍按**整个窗口宽**算(`layout::frame_metrics` 内部会扣掉
|
||||
/// rail 88 与页边距),所以外壳换了不影响版面判据。
|
||||
/// 产品路径(`app/view.rs`)走 [`page_with_appearance`]:外壳由 `shell` 画(拖动/缩放/三个
|
||||
/// caption 键、rail 88),这里只画「页头 + 内容列」。列宽仍按**整个窗口宽**算
|
||||
/// (`layout::frame_metrics` 内部会扣掉 rail 88 与页边距),所以外壳换了不影响版面判据。
|
||||
///
|
||||
/// 视图模型由**调用方持有**(`App` 在状态变化时重建一次 `Model`),这里只借用:
|
||||
/// `view(&self)` 不能返回一棵借用局部变量的树。
|
||||
pub fn page<'a>(ui: &'a Ui, model: &'a Model) -> Element<'a, Message> {
|
||||
render(ui, model, None)
|
||||
}
|
||||
|
||||
/// 同 [`page`],但带上**外观状态**(设置页的「外观」分组要读当前值与诊断)。
|
||||
///
|
||||
/// 为什么另开一个入口而不是给 `Model` 加字段:`pages/model.rs` 是页面与 presenter 之间的展示
|
||||
/// 契约(`Model` 只装「要画什么」),外观是**运行时状态**(滑块请求值、已解码的背景图、诊断),
|
||||
/// 塞进去会让演示数据(`pages::demo`)也得伪造一份外观状态。
|
||||
pub fn page_with_appearance<'a>(
|
||||
ui: &'a Ui,
|
||||
model: &'a Model,
|
||||
appearance: &'a appearance::State,
|
||||
) -> Element<'a, Message> {
|
||||
render(ui, model, Some(appearance))
|
||||
}
|
||||
|
||||
fn render<'a>(
|
||||
ui: &'a Ui,
|
||||
model: &'a Model,
|
||||
appearance: Option<&'a appearance::State>,
|
||||
) -> Element<'a, Message> {
|
||||
let metrics = layout::frame_metrics(model.screen.kit(), model.window_width);
|
||||
|
||||
match model.screen {
|
||||
Screen::Instances => instances::view(ui, metrics, model),
|
||||
Screen::Download => download::view(ui, metrics),
|
||||
Screen::Settings => settings::view(ui, metrics),
|
||||
Screen::Settings => settings::view(ui, metrics, appearance),
|
||||
Screen::Logs => logs::view(ui, metrics),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user