设置:切到别的标签再回来,停在原来的分类上

- 之前切回设置标签总是回到「外观」:gpui-kit 的 Settings 把选中的分类
  放在元素状态里,标签不显示时就丢了。现在记下正在显示的分类,回来时
  从它开始。页内的滚动位置和搜索框内容仍不保留。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
XuzandClaude Opus 5.5 committed 2026-10-06 22:34:55 +08:00
1 parent 613287aedd
commit 1bab1bff50
3 files changed
+36 -3

No files matched your search

+1
View File
@@ -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」。
+33 -3
View File
@@ -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<Cell<usize>>,
focus_handle: FocusHandle,
tab_group: Option<WeakEntity<TabGroup>>,
_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))
}
}
+2
View File
@@ -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| {