//! 外观分组第 ④ ⑤ ⑥ ⑦ ⑧ 段:**背景图**——开关、路径、诊断、填充档、暗化强度。 //! //! 这五段挤在一起是因为它们读同一份 `bg_*` 状态,而且**诊断必须紧贴控件**(复审 r1 P2-3: //! 读盘失败 / CPU 降级 / 配色回落这些提示落在折叠线以下等于没提示)。 use iced::widget::column; use iced::{Element, Length}; use unlucky_design::color::Role; use unlucky_design::spacing::Space; use unlucky_presenter::prefs::BgFill; use crate::app::components::inputs::{slider, text_field, Field, Slider}; use crate::pages::Message; use crate::theme::Ui; use super::super::background::{self, BG_DIM_MAX}; use super::super::state::State; use super::super::Change; use super::{choice, choice_row, label, note_line, slider_row}; /// 把 ④ 开关、⑤ 路径、⑥ 诊断、⑦ 填充、⑧ 暗化按视觉顺序推进 `rows`。 pub(super) fn push<'a>(ui: &'a Ui, state: &'a State, rows: &mut Vec>) { // ④ 背景图开关 rows.push(choice_row( ui, "Background image", vec![ choice(ui, "Off", !state.bg_enabled, Change::BgEnabled(false)), choice(ui, "On", state.bg_enabled, Change::BgEnabled(true)), ], )); // ⑤ 路径(文本框:受控,输入即生效) let path_field: Element<'a, Message> = text_field( ui, Field::new(&state.bg_path) .label("Image path") .placeholder("D:/Pictures/background.png"), |value| Message::Appearance(Change::BgImage(value)), ); rows.push( column![label(ui, "Image path"), path_field] .spacing(ui.space(Space::X1)) .width(Length::Fill) .into(), ); // ⑥ 诊断(读盘失败 / CPU 降级 / 配色回落)——**不许静默**,且必须在**首屏可见处** // (复审 r1 P2-3:文案落在折叠线以下等于没提示)。位置就在背景图那两行的紧下方。 for note in state.diagnostics() { rows.push(note_line(ui, note, ui.color(Role::Error))); } if let Some(note) = state.backend_note() { rows.push(note_line(ui, note, ui.color(Role::OnSurfaceVariant))); } if let Some(note) = state .image() .and_then(|image| background::small_tile_note(image, state.bg_fill)) { rows.push(note_line(ui, ¬e, ui.color(Role::OnSurfaceVariant))); } if let Some(note) = state.palette_note() { rows.push(note_line(ui, note, ui.color(Role::OnSurfaceVariant))); } let resolved = format!("Colours: {}", state.palette_level()); rows.push(note_line(ui, &resolved, ui.color(Role::OnSurfaceVariant))); // ⑦ 填充 rows.push(choice_row( ui, "Fill", vec![ choice( ui, "Cover", state.bg_fill == BgFill::Cover, Change::BgFill(BgFill::Cover), ), choice( ui, "Contain", state.bg_fill == BgFill::Contain, Change::BgFill(BgFill::Contain), ), choice( ui, "Tile", state.bg_fill == BgFill::Tile, Change::BgFill(BgFill::Tile), ), ], )); // ⑧ 暗化 rows.push(slider_row( ui, "Dim", format!("{:.0}%", state.bg_dim * 100.0), format!( "Blends the image toward the panel colour so text stays readable. Max {BG_DIM_MAX:.2}." ), state.bg_dim > 0.0, slider( Slider::new(ui, state.bg_dim / BG_DIM_MAX) .on_change(|fraction| Message::Appearance(Change::BgDim(fraction * BG_DIM_MAX))), ), )); }