From 1bab1bff50aef2d39e56a0ef3c789e112166dc0f Mon Sep 17 00:00:00 2001 From: Xuz Date: Tue, 6 Oct 2026 22:34:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=EF=BC=9A=E5=88=87=E5=88=B0?= =?UTF-8?q?=E5=88=AB=E7=9A=84=E6=A0=87=E7=AD=BE=E5=86=8D=E5=9B=9E=E6=9D=A5?= =?UTF-8?q?=EF=BC=8C=E5=81=9C=E5=9C=A8=E5=8E=9F=E6=9D=A5=E7=9A=84=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 之前切回设置标签总是回到「外观」:gpui-kit 的 Settings 把选中的分类 放在元素状态里,标签不显示时就丢了。现在记下正在显示的分类,回来时 从它开始。页内的滚动位置和搜索框内容仍不保留。 Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 1 + src/settings/settings_panel.rs | 36 +++++++++++++++++++++++++++++++--- tests/ui/settings.rs | 2 ++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0529a01..2b2a6ee 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -168,6 +168,7 @@ cargo test -- --ignored # 会读写真实钥匙串的测试 - **滚动条挂在不滚动的外层上**,或直接用 `overflow_y_scrollbar()`:挂在滚动元素自己身上,滚动条会跟着内容一起移走。 - **按上一帧的尺寸重排**(路径标签、监控的竖条、图片预览的画框):render 时拿不到布局尺寸。放一个 `canvas`,在 prepaint 记下尺寸,变了就 `on_next_frame` 通知重画。绝对定位的 `canvas` 必须 `top_0().left_0()`。 - **`img` 会给自己的盒子加上图片的宽高比**,压过百分比高度。要控制尺寸就给宽和高都写绝对值。 +- **gpui-kit 的 `Settings` 把选中的分类放在元素状态里**,标签切走、不再绘制时就丢了,切回来回到第一类。设置页靠页头的 `title_suffix`(只给正在显示的页绘制)记下当前分类,再经 `default_selected_index` 恢复;页内滚动位置不保留。 - **`Select` 必须放进有尺寸的容器**,否则会盖住整行。`ListItem` 里会增长的文字要 `w_0().flex_grow(1.).overflow_x_hidden()`,否则会把 `suffix` 挤出去。 - **`ColorPicker` 要自己给常用色**(`featured_colors`):默认的第一行是主题色,它们也在下面的调色板里。gpui-kit 按十六进制给色块起 id,同一颜色出现两格就是重复的无障碍节点,调试版在辅助技术(或借助它的窗口管理工具)连着时直接 panic;测试平台不建无障碍树,测不出来。常用色不能取调色板(shadcn 的 stone、red … pink)里的颜色。 - **要彩色就不能用 `Icon`**:它把 SVG 当成单色遮罩画。系统徽章是「主题色圆底 + 单色 logo」。 diff --git a/src/settings/settings_panel.rs b/src/settings/settings_panel.rs index 93b5909..852f45b 100644 --- a/src/settings/settings_panel.rs +++ b/src/settings/settings_panel.rs @@ -1,3 +1,6 @@ +use std::cell::Cell; +use std::rc::Rc; + use gpui_kit::component::{ ActiveTheme as _, Disableable as _, Icon, IconName, Sizable as _, button::{Button, ButtonVariants as _}, @@ -7,7 +10,10 @@ use gpui_kit::component::{ label::Label, menu::PopupMenu, separator::Separator, - setting::{NumberFieldOptions, SettingField, SettingGroup, SettingItem, SettingPage, Settings}, + setting::{ + NumberFieldOptions, SelectIndex, SettingField, SettingGroup, SettingItem, SettingPage, + Settings, + }, tooltip::Tooltip, v_flex, }; @@ -56,6 +62,10 @@ pub struct SettingsPanel { /// The monospace families to choose the terminal font from; empty until /// the scan in the background comes back. font_families: &'static [SharedString], + /// The category last shown, for coming back to it. `Settings` keeps its + /// choice in element state, which goes while the tab is hidden; its + /// page header records the category it draws. + shown_category: Rc>, focus_handle: FocusHandle, tab_group: Option>, _subscriptions: [Subscription; 3], @@ -94,6 +104,7 @@ impl SettingsPanel { updater, highlight_rules, font_families: &[], + shown_category: Rc::default(), focus_handle: cx.focus_handle(), tab_group: None, _subscriptions: subscriptions, @@ -190,7 +201,18 @@ impl Render for SettingsPanel { // Split geometry is an API boundary that takes `Pixels`. .sidebar_width(px(200.)) .with_group_variant(GroupBoxVariant::Outline) - .pages(CATEGORIES.iter().map(|category| category.page(self, cx))), + // Used only when the tab comes back and `Settings` + // starts over. + .default_selected_index(SelectIndex { + page_ix: self.shown_category.get(), + group_ix: None, + }) + .pages( + CATEGORIES + .iter() + .enumerate() + .map(|(ix, category)| category.page(ix, self, cx)), + ), ) } } @@ -237,9 +259,17 @@ const CATEGORIES: [Category; 5] = [ ]; impl Category { - fn page(&self, panel: &SettingsPanel, cx: &App) -> SettingPage { + /// The page of the category at `ix` in `CATEGORIES`. + fn page(&self, ix: usize, panel: &SettingsPanel, cx: &App) -> SettingPage { + let shown = panel.shown_category.clone(); SettingPage::new(self.title) .icon(Icon::new(self.icon)) + // Drawn only for the page on display: nothing to see, it notes + // which one that is. + .title_suffix(move |_, _| { + shown.set(ix); + Empty + }) .groups((self.groups)(panel, cx)) } } diff --git a/tests/ui/settings.rs b/tests/ui/settings.rs index 3008c7d..dae05eb 100644 --- a/tests/ui/settings.rs +++ b/tests/ui/settings.rs @@ -79,6 +79,8 @@ fn settings_open_from_the_host_list_as_one_tab(cx: &mut TestAppContext) { window.render_frame(cx); assert!(window.find("settings").visible()); assert_eq!(window.find("settings").focused(), Some(true)); + // Back on the category it showed, 终端, not the first one. + assert!(window.find("terminal-font-preview").visible()); }) .unwrap(); cx.update(|cx| {