feat(app-iced): M93 r2 —— 背景图真图直出 + 面板 α 收敛到 Ui::layer
复审前补齐两处(tower 扩 scope:Cargo.toml / pages/frame.* / theme.rs / presenter::prefs)。 1) 背景图**真图直出** - `iced` 开 `image-without-codecs`(刻意不用 `image`:后者会打开 `image/default` 全套编解码器); 编解码能力由本 crate 的 `image` features 决定,补了 `jpeg` / `bmp`(用户挑的背景图/壁纸多半是 jpg)。 - `pages/appearance/picture.rs`:`Cover`/`Contain` 走渲染器 `ContentFit`,`Tile` 按 `background::tiles` 算行列(上限 64 块)真的铺 N 个图块;暗化 = 一层「版面底色 @ α=dim」叠在图上。 - 36dp 马赛克那条路**已删除**(不再是主路径,也不留死代码)。 - 踩坑记录:`Handle::from_bytes` 的纹理分配赶不上截图第 3 帧(实测画面全空),改用 `Handle::from_path`(渲染器自己解码),已在 `picture::image_handle` 的文档里写明。 2) 面板 α **收敛到唯一来源** - `Ui::layer()` 直接乘上面板 α(新增 `Ui::panel_alpha` / `with_panel_alpha`,默认 1.0、 `scale_alpha(1.0)` 逐字节不变),`app::rebuild_ui` 注入生效值。 - 于是外壳(根容器/标题栏/导航轨)、`frame::card`(实例/下载/日志三页卡片)、 `frame::header_bar`(新增底色)、外观分组卡片、空态图标块**全部同源**, 调用点不再有任何 `panel_color(..)` 自乘(该 helper 已删)。 - 有背景图时根容器不再盖一层实色画布(否则 panel α=1 时背景图整块被挡)。 3) `presenter::prefs` 补重导出 `PANEL_ALPHA_MIN` / `BG_DIM_MAX`,app-iced 里两份 0.4 / 0.95 字面量改为转发常量。 验收:11+3 张图(`C:\Temp\ull-shots\wt-93\r2-*.png`)——三档填充肉眼可分、`.jpg` 能加载、 GPU 档 panel55 时卡片/分组卡/页头带都透出背景、CPU 档仍强制 1.0 且背景在面板空隙可见; 另附实例/下载/日志三页 panel55 各一张,证明三页都吃到同一个 α。
This commit is contained in:
1 parent
b8ab46662c
commit
22e4c423fa
18 files changed
+399
-535
No files matched your search
@@ -34,7 +34,6 @@ use unlucky_design::typography::TypeRole;
|
||||
use crate::app::Message;
|
||||
use crate::cli::ForcedState;
|
||||
use crate::icons;
|
||||
use crate::pages::appearance::panel_color;
|
||||
use crate::theme::Ui;
|
||||
|
||||
/// 整棵树(**内容槽位版**:外壳画标题栏 / 缩放热区 / 导航轨,中间那块交给调用方)。
|
||||
@@ -52,8 +51,8 @@ use crate::theme::Ui;
|
||||
/// 而页面自己的 `layout::frame_metrics` 仍以**窗口宽**为输入(它内部会再减 rail 与页边距),
|
||||
/// 两边的账不会算串。
|
||||
///
|
||||
/// M93 起面板 α 是**外壳层**的属性(根容器 / 标题栏 / 导航轨的底色按它乘 alpha):要背景层的
|
||||
/// 调用方走 [`view_with_background`]。
|
||||
/// 面板 α(D36 / M93)不从这里传:它是**表面色**的属性,唯一施加点是 `Ui::layer`
|
||||
/// (`crate::theme`)。外壳的根容器 / 标题栏 / 导航轨都走 `ui.layer(..)`,因此自动同源。
|
||||
pub fn view_with_content<'a>(
|
||||
ui: &'a Ui,
|
||||
selected: NavItem,
|
||||
@@ -61,7 +60,7 @@ pub fn view_with_content<'a>(
|
||||
content: Element<'a, Message>,
|
||||
forced: Option<ForcedState>,
|
||||
) -> Element<'a, Message> {
|
||||
view_with_background(ui, selected, app_title, None, 1.0, content, forced)
|
||||
view_with_background(ui, selected, app_title, None, content, forced)
|
||||
}
|
||||
|
||||
/// 同 [`view_with_content`],但可以在整棵树**最底下**垫一层背景(M93 的背景图马赛克)。
|
||||
@@ -73,20 +72,19 @@ pub fn view_with_background<'a>(
|
||||
selected: NavItem,
|
||||
app_title: &'a str,
|
||||
background: Option<Element<'a, Message>>,
|
||||
panel_alpha: f32,
|
||||
content: Element<'a, Message>,
|
||||
forced: Option<ForcedState>,
|
||||
) -> Element<'a, Message> {
|
||||
let work_area = column![
|
||||
titlebar(ui, app_title, forced, panel_alpha),
|
||||
row![nav::rail(ui, selected, forced, panel_alpha), content]
|
||||
titlebar(ui, app_title, forced),
|
||||
row![nav::rail(ui, selected, forced), content]
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill),
|
||||
]
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill);
|
||||
|
||||
window_frame(ui, background, panel_alpha, work_area.into())
|
||||
window_frame(ui, background, work_area.into())
|
||||
}
|
||||
|
||||
/// 整棵树(M68 骨架版:内容区是「页头 + 一张占位卡」)。
|
||||
@@ -112,12 +110,9 @@ pub fn view<'a>(
|
||||
|
||||
/// 无边框窗口的「外壳壳子」:背景层 + 工作区 + 两条缩放热区 + 根容器底色。
|
||||
///
|
||||
/// 面板 α 落在两处:根容器底色(= 整窗 Canvas 层)与标题栏 / 导航轨底色。`panel_alpha == 1.0`
|
||||
/// 时颜色逐字节不变,所以没开面板透明度时不动既有验收图。
|
||||
fn window_frame<'a>(
|
||||
ui: &'a Ui,
|
||||
background: Option<Element<'a, Message>>,
|
||||
panel_alpha: f32,
|
||||
work_area: Element<'a, Message>,
|
||||
) -> Element<'a, Message> {
|
||||
// 无边框窗口没有系统缩放边框 → 自己给两条热区(东/南)。
|
||||
@@ -150,7 +145,10 @@ fn window_frame<'a>(
|
||||
.height(Length::Fill)
|
||||
.align_y(Alignment::End);
|
||||
|
||||
// 背景在最底层:面板 α < 1 时从它的空隙里透出来(M93 / D34)。
|
||||
// 背景在最底层(M93 / D34)。有背景层时**根容器不再盖实色画布**:否则那张不透明的
|
||||
// `Canvas` 会把背景图整块挡住(r2 实测:panel α=1 时背景完全看不见)。
|
||||
// 各面板(标题栏 / 导航轨 / 卡片 / 页头带)自己画底色,空隙里露出的就是背景图。
|
||||
let has_background = background.is_some();
|
||||
let shell = match background {
|
||||
Some(layer) => stack![layer, work_area, east, south],
|
||||
None => stack![work_area, east, south],
|
||||
@@ -159,7 +157,13 @@ fn window_frame<'a>(
|
||||
container(shell)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.style(move |_theme| filled(panel_color(ui, MaterialLayer::Canvas, panel_alpha)))
|
||||
.style(move |_theme| {
|
||||
if has_background {
|
||||
container::Style::default()
|
||||
} else {
|
||||
filled(ui.layer(MaterialLayer::Canvas))
|
||||
}
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -182,12 +186,7 @@ fn resize_edge<'a>(
|
||||
|
||||
// ---------------------------------------------------------------- 标题栏
|
||||
|
||||
fn titlebar<'a>(
|
||||
ui: &'a Ui,
|
||||
title: &'a str,
|
||||
forced: Option<ForcedState>,
|
||||
panel_alpha: f32,
|
||||
) -> Element<'a, Message> {
|
||||
fn titlebar<'a>(ui: &'a Ui, title: &'a str, forced: Option<ForcedState>) -> Element<'a, Message> {
|
||||
let metrics = ui.metrics();
|
||||
|
||||
// 拖动热区:从窗口左缘到第一个按钮(按钮自己不能被拖区吞掉,所以只包左侧一段)
|
||||
@@ -219,7 +218,7 @@ fn titlebar<'a>(
|
||||
container(bar)
|
||||
.width(Length::Fill)
|
||||
.height(metrics.titlebar_height)
|
||||
.style(move |_theme| filled(panel_color(ui, MaterialLayer::Canvas, panel_alpha)))
|
||||
.style(move |_theme| filled(ui.layer(MaterialLayer::Canvas)))
|
||||
.into()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user