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
@@ -110,6 +110,15 @@ pub struct App {
|
||||
pub(super) refreshes: u64,
|
||||
/// 首屏快照到位后是否已经自动选中过第一行(list-detail 的桌面惯例,见 `update::auto_select`)。
|
||||
pub(super) auto_selected: bool,
|
||||
/// 窗口高度(背景图马赛克的视口判据;宽度在 `width`)。
|
||||
pub(super) height: f32,
|
||||
/// 外观运行期状态(M93):面板 α / 背景图 / 配色来源 / 诊断。
|
||||
pub(super) appearance: pages::appearance::State,
|
||||
/// 设置文件里那 8 个「UI 写入」外观字段的最近快照(写回时只改我们真改了的字段,
|
||||
/// 强调色这类本 mission 不管的字段原样保留)。
|
||||
pub(super) appearance_prefs: unlucky_presenter::prefs::AppearancePrefs,
|
||||
/// 窗口句柄(`Message::WindowHandle` 之后才有;非 Windows 平台恒 `None`)。
|
||||
pub(super) hwnd: Option<isize>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -140,14 +149,34 @@ impl App {
|
||||
bridge: SettingsBridge,
|
||||
) -> Self {
|
||||
let width = WINDOW_SIZE.width;
|
||||
let height = WINDOW_SIZE.height;
|
||||
let theme_mode = bridge.load().1;
|
||||
// 外观两半分开读:`load()` 给 8 个 UI 写入字段,`load_base()` 给 3 个只读下层键
|
||||
// (整窗 α / 标题栏三态 / 配色来源)。M93 之前这两个键在 app 侧**根本读不到**。
|
||||
//
|
||||
// 截图通道**不读用户配置**(D30:同一份代码在两台机器上要出同一张图):外观一律取出厂值,
|
||||
// 矩阵需要的值由 `ULL_APPEARANCE_*` 显式灌进来。
|
||||
let (appearance_prefs, appearance_base) = if options.screenshot.is_some() {
|
||||
(
|
||||
unlucky_presenter::prefs::AppearancePrefs::factory(),
|
||||
unlucky_presenter::prefs::AppearanceBase::factory(),
|
||||
)
|
||||
} else {
|
||||
(bridge.load().0, bridge.load_base())
|
||||
};
|
||||
let appearance = pages::appearance::State::new(
|
||||
&appearance_prefs,
|
||||
&appearance_base,
|
||||
options.backend,
|
||||
flavor,
|
||||
);
|
||||
let view = pages::Model::new(
|
||||
pages::Screen::Instances,
|
||||
width,
|
||||
Some(pages::Screen::Instances.nav()),
|
||||
);
|
||||
|
||||
Self {
|
||||
let mut app = Self {
|
||||
ui: Ui::new(flavor, families),
|
||||
families,
|
||||
options,
|
||||
@@ -166,7 +195,14 @@ impl App {
|
||||
frames: 0,
|
||||
refreshes: 0,
|
||||
auto_selected: false,
|
||||
}
|
||||
height,
|
||||
appearance,
|
||||
appearance_prefs,
|
||||
hwnd: None,
|
||||
};
|
||||
// 配色来源档可能已经指向一张背景图:那时 `Ui` 必须由解析出的方案构造,而不是 baseline。
|
||||
app.rebuild_ui();
|
||||
app
|
||||
}
|
||||
|
||||
/// 本次进程是否走截图通道。
|
||||
@@ -174,19 +210,41 @@ impl App {
|
||||
self.options.screenshot.is_some()
|
||||
}
|
||||
|
||||
/// 切主题:只重建 [`Ui`](= 重建 Style),**不动任何 UI 状态**。
|
||||
/// 切主题:重建 [`Ui`](= 重建 Style),**不动任何 UI 状态**。
|
||||
///
|
||||
/// M93 起 `Ui` 有两个来源:配色来源取到了图(①②级)就用解析出的方案,否则用令牌 baseline。
|
||||
/// 所以这里改叫「重算 `Ui`」:先让外观状态记住新深浅(配色解析要它),再重建。
|
||||
pub(super) fn set_flavor(&mut self, flavor: SchemeFlavor) {
|
||||
if self.ui.flavor() == flavor {
|
||||
if self.ui.flavor() == flavor && self.appearance.flavor() == flavor {
|
||||
return;
|
||||
}
|
||||
|
||||
let next = Ui::new(flavor, self.families);
|
||||
self.appearance.set_flavor(flavor);
|
||||
let previous = self.ui.name();
|
||||
self.rebuild_ui();
|
||||
eprintln!(
|
||||
"[theme] {} -> {} (Theme::name 变化触发缓存重算)",
|
||||
self.ui.name(),
|
||||
next.name()
|
||||
previous,
|
||||
self.ui.name()
|
||||
);
|
||||
self.ui = next;
|
||||
}
|
||||
|
||||
/// 按「配色来源是否取色成功」重建 [`Ui`]。
|
||||
///
|
||||
/// 色卡档(③)刻意继续走 `Scheme::baseline`:`resolve_source` 的色卡档返回的是
|
||||
/// `DEFAULT_CARD`(天蓝卡)方案,与令牌 baseline 逐色不同,应用它会把**全部既有验收图的
|
||||
/// 像素**改掉。这条偏离登记在 `pages::appearance` 的偏离表 #4。
|
||||
pub(super) fn rebuild_ui(&mut self) {
|
||||
self.ui = match self.appearance.derived_scheme() {
|
||||
Some(scheme) => {
|
||||
eprintln!(
|
||||
"[appearance] palette={} → Ui::from_scheme(取色方案接管 49 个角色)",
|
||||
self.appearance.palette_level()
|
||||
);
|
||||
Ui::from_scheme(*scheme, self.families)
|
||||
}
|
||||
None => Ui::new(self.appearance.flavor(), self.families),
|
||||
};
|
||||
}
|
||||
|
||||
/// 把 presenter 的快照转换成页面视图模型(**展示转换在 UI 侧做**)。
|
||||
|
||||
Reference in new issue
Block a user