news 2026/9/5 20:43:59

Windows Terminal 设置 UI 设计解析:导航结构、外观预览窗口与级联继承在源码中的落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Windows Terminal 设置 UI 设计解析:导航结构、外观预览窗口与级联继承在源码中的落地

Windows Terminal 设置 UI 设计解析:导航结构、外观预览窗口与级联继承在源码中的落地

【免费下载链接】terminalThe new Windows Terminal and the original Windows console host, all in the same place!项目地址: https://gitcode.com/GitHub_Trending/term/terminal

本文围绕 设计文档(issue #1564 的 Settings UI Design)展开,讲清楚 Windows Terminal 设置界面的页面导航布局、各页面的完整设置项清单、带实时预览窗口的 Appearance 页设计以及键盘绑定编辑弹窗形态,并结合仓库中 TerminalSettingsEditor 与 TerminalSettingsModel 的实际源码,印证这些设计如何演化为今天可以运行的设置 UI——读完后你既能理解设计稿中每个页面与控件的意图,也能定位到实现它的 XAML、导航标签与继承机制代码。

![Settings UI 整体导航结构](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_source=gitcode_repo_files#1564 - Settings UI/navigation-2.png)

一、设计文档的定位:从 issue #1564 到三份配套规格

design.md 的文档头元数据表明,它由 Kayla Cinnamon 于 2020-07-13 创建、2020-08-11 最后更新,对应 issue #1564。文档摘要明确了两点:

  • 它描述设置 UI 每个页面的布局,并给出设计稿(mockup)展示 UI 的外观;
  • 设计稿只用于示意外观,其中的布局与命名可能与最终实现不同,该文档被视为最终裁决("This doc should be considered the final say")

同一目录下还有两份配套文档,与 design.md 互为补充:

  • spec.md:定义设置 UI 的基本功能——如何禁用 UI、导航项、启动方式与设置编辑保存机制;
  • cascading-settings.md:探讨级联设置(cascading settings)与profiles.defaults如何在设置 UI 中表示。

值得注意的是,当时 Windows Terminal 的默认设置体验是用文本编辑器打开settings.json,设置 UI 是全新引入的界面,因此设计文档同时给出了导航方案对比(更细粒度的分类导航 vs 与 JSON 结构对齐的导航),并在 spec.md 中记录了备选方案(新窗口启动、自动保存等)及各自的取舍。

二、顶层导航设计:General / Appearance / Profiles / Keyboard

design.md 给出的左侧导航栏顶层结构如下(带星号的页面在对应功能实现后才加入):

  • General
    • Startup
    • Interaction
    • Rendering
  • Appearance
    • Global
    • Color schemes
    • Themes*
  • Profiles
    • Defaults
    • Enumerate profiles
    • Add new
  • Keyboard
  • Mouse*
  • Command Palette*
  • Marketplace*

在 spec.md 中,还记录了另一套被否决的导航方案——"与 JSON 对齐":顶层只有 Globals、Profiles、Color schemes、Bindings 四项(Bindings 下挂 key bindings、mouse bindings 与 command palette)。最终产品选择了更细分、更易消化的分类导航,理由是"与其他终端更一致"。

对照源码:今天的导航项与导航标签

从 MainPage.xaml 的NavigationView.MenuItems可以看到,现行导航项已演进为平铺的页面列表:Launch(对应原 General-Startup)、Interaction、Appearance、Color Schemes、Rendering、Compatibility、Actions(带 New 徽标)、New Tab Menu、Extensions,加上 Profiles 分组头与 Base Layer(x:Uid="Nav_ProfileDefaults",即级联设置文档中把 "Global" 页改名后的 "Base layer")。导航标签常量集中定义在 NavConstants.h,其中til::static_map把每个NavigationTag映射到 Segoe MDL2 Assets 图标字形,例如launchTag → \xE7B5actionsTag → \xE765(Keyboard Classic)。

spec.md 中"导航菜单底部放一个 'Open the JSON file' 按钮"的设计也已落地:MainPage.xaml 的FooterMenuItems中有OpenJsonNavItemTag="OpenJson_Nav"),用户随时可以从 UI 回到原始 JSON 文件编辑。

三、Appearance 页设计:内嵌 TerminalControl 的实时预览窗口

design.md 指出 Profile appearance 页需要特殊设计,因为它内嵌了一个 TerminalControl 预览窗口,用于实时预览外观变更。该预览窗口出现在两个页面:

  • Appearance - Color Schemes
  • Profiles - Appearance

![Appearance 页内嵌预览窗口的设计稿](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_source=gitcode_repo_files#1564 - Settings UI/appearance.png)

源码印证:预览窗口不启动真实进程

PreviewConnection.cpp 实现了这个预览窗口背后的数据源:它实现了一个TerminalConnection,但WriteInput/Resize/Close全部为空操作,Start()只通过TerminalOutput.raise(...)向渲染层写出一段固定的示例文本——包括硬重置序列(RIS)、Windows Terminal标题、一段仿git diff -w的彩色输出(红- Windows Console、绿+ Windows Terminal!、灰Write-Host "🛃!")。它还根据字体是否支持 powerline 字形在PromptTextPlainC:\>)与PromptTextPowerline\x1b[49;34m\xe0b6…等 ANSI 序列拼出的C:\提示符)之间切换并重新发送。

从源码结构看,预览窗口与真实终端共用同一个 TerminalControl 渲染管线,只是数据源换成PreviewConnection:用户每改一项颜色、字体或 acrylic 参数,渲染层就会用新的设置重绘这段固定样例,从而在点击保存前看到外观效果——这正是 spec.md 中"在写回 settings.json 之前预览变更"这一决策的实现路径。

四、Keyboard 页设计:绑定列表与动态生长的编辑弹窗

design.md 对键盘页的描述包含三个要点:

  1. 页面列出所有已启用的按键绑定,并提供添加与删除入口;
  2. 悬停某一项时出现 Edit 与 Delete 按钮;
  3. 点击 Edit 弹出模态框:对于无参数/无 actions 的命令,模态框只显示命令与按键输入区;若命令带有额外参数或 actions,模态框会随参数/actions 的添加动态增高。设计稿同时注明,希望未来的输入框能"监听"按键组合,即界面上增加一个 "listen" 按钮。

![键盘绑定编辑弹窗(无参数命令)设计稿](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_source=gitcode_repo_files#1564 - Settings UI/keyboard-modal.png)

今天该页面已演进为Actions 页:Actions.xaml 与 EditAction 承担"绑定列表 + 编辑弹窗"的职责,而 "listen" 构想则由 KeyChordListener 组件落地——它暴露一个Keys依赖属性(DEPENDENCY_PROPERTY(Control::KeyChord, Keys))并在KeyChordTextBox_KeyDown中捕获按键事件把组合键写入KeyChord,即"点击输入框后直接按键即可录入组合"。

五、完整设置清单:八个页面的控件布局

design.md 的核心内容是一张覆盖全部设置项的布局表。标题行与 UI 左侧的导航视图对齐,列中加粗的标题(如GeneralAppearanceAdvanced)对应页面顶部的 pivot 导航。以下完整继承原文档表格:

General - StartupGeneral - InteractionGeneral - RenderingAppearance - GlobalAppearance - Color SchemesProfiles - GlobalProfiles - Enumerate profilesProfiles - Add new
Default profile (dropdown)Copy after selection is made (checkbox)Software rendering (checkbox)Theme (radio)Name (text box)GeneralGeneralGeneralGeneral
Launch on startup (checkbox)Copy formatting (checkbox)Screen redrawing (checkbox)Show/Hide the title bar (checkbox)Cursor color (color picker)Command line (text box)Scrollbar visibility (radio)Scrollbar visibility (radio)
Launch size (radio)Word delimiters (text box)Show terminal title in title bar (checkbox)Selection background (color picker)Starting directory (browse button)Command line (browse button)Command line (browse button)
Launch position (text box)Window resize behavior (checkbox)Always show tabs (checkbox)Background (color picker)Icon (browse button)Starting directory (browse button)Starting directory (browse button)
Columns on first launch (number picker)Tab width mode (radio)Foreground (color picker)Tab title (text box)Name (text box)Name (text box)
Rows on first launch (number picker)Hide close all tabs popup (checkbox)Black (color picker)Scrollbar visibility (radio)Icon (browse button)Icon (browse button)
Automatically create new profiles when new shells are installed (checkbox)Blue (color picker)AppearanceTab title (text box)Tab title (text box)
Cyan (color picker)Font face (text box)AppearanceAppearance
Green (color picker)Font size (number picker)Retro terminal effects (checkbox)Retro terminal effects (checkbox)
Purple (color picker)Font weight (dropdown)Font face (text box)Font face (text box)
Red (color picker)Padding (text box)Font size (number picker)Font size (number picker)
White (color picker)Cursor shape (radio)Font weight (dropdown)Font weight (dropdown)
Yellow (color picker)Cursor color (color picker)Padding (text box)Padding (text box)
Bright black (color picker)Cursor height (number picker)Cursor shape (radio)Cursor shape (radio)
Bright blue (color picker)Color scheme (dropdown)Cursor color (color picker)Cursor color (color picker)
Bright cyan (color picker)Foreground color (color picker)Cursor height (number picker)Cursor height (number picker)
Bright green (color picker)Background color (color picker)Color scheme (dropdown)Color scheme (dropdown)
Bright purple (color picker)Selection background color (color picker)Foreground color (color picker)Foreground color (color picker)
Bright red (color picker)Enable acrylic (checkbox)Background color (color picker)Background color (color picker)
Bright white (color picker)Acrylic opacity (number picker)Selection background color (color picker)Selection background color (color picker)
Bright yellow (color picker)Background image (browse button)Enable acrylic (checkbox)Enable acrylic (checkbox)
Background image stretch mode (radio)Acrylic opacity (number picker)Acrylic opacity (number picker)
Background image alignment (dropdown)Background image (browse button)Background image (browse button)
Background image opacity (number picker)Background image stretch mode (radio)Background image stretch mode (radio)
Retro terminal effects (checkbox)Background image alignment (dropdown)Background image alignment (dropdown)
AdvancedBackground image opacity (number picker)Background image opacity (number picker)
Hide profile from dropdown (checkbox)AdvancedAdvanced
Suppress title changes (checkbox)GUID (text box)GUID (text box)
Antialiasing text (radio)Hide profile from dropdown (checkbox)Hide profile from dropdown (checkbox)
AltGr aliasing (checkbox)Suppress title changes (checkbox)Suppress title changes (checkbox)
Scroll to input when typing (checkbox)Antialiasing text (radio)Antialiasing text (radio)
History size (number picker)AltGr aliasing (checkbox)AltGr aliasing (checkbox)
How the profile closes (radio)Scroll to input when typing (checkbox)Scroll to input when typing (checkbox)
History size (number picker)History size (number picker)
How the profile closes (radio)How the profile closes (radio)

表格与真实默认值 JSON 的对应关系

表中每一项都对应 defaults.json 中的一个 JSON 键。该文件是系统级默认值层(设计文档中"system set value"的来源),节选可验证上述表格的取值形态:

  • Startup 组:initialCols: 120initialRows: 30launchMode: "default"对应 "Columns/Rows on first launch" 与 "Launch size" 控件;
  • Interaction 组:copyOnSelect: falsecopyFormatting: truewordDelimiters: " /\\()\"'-.,:;<>~!@#$%^&*|+=[]{}~?\u2502"对应 "Copy after selection is made / Copy formatting / Word delimiters" 三个控件;
  • Appearance - Global:alwaysShowTabs: trueshowTerminalTitleInTitlebar: truetabWidthMode: "equal"theme: "dark"对应表中 "Always show tabs / Show terminal title in title bar / Tab width mode / Theme" 控件;
  • Profiles 层:historySize: 9001closeOnExit: "automatic"antialiasingMode: "grayscale"altGrAliasing: truesnapOnInput: true等对应 Advanced pivot 下的 History size、How the profile closes、Antialiasing text、AltGr aliasing、Scroll to input when typing 控件;useAcrylic: false对应 Enable acrylic。

这验证了 cascading-settings.md 中所述的三级取值链:用户 settings.json 值 → defaults.json 值 → 系统内建值

六、保存机制:Save 按钮、未保存提示与 Portable 模式

spec.md 对编辑保存的决策是"实现一个 Save 按钮":

  • 用户只有点击 Save 后,变更才写回settings.json——与今天用文本编辑器改 JSON 并保存的行为对齐;
  • 被否掉的备选方案是"边改边自动保存",实时生效但失去了与 JSON 工作流的对等性。

当前实现与该决策一致,且功能更多:MainPage.xaml 底部条包含SaveButton(AccentButtonStyle 强调按钮)与ResetButton,左侧有一个默认CollapsedSettings_UnsavedSettingsWarning文本(Goldenrod 颜色)用于提示存在未保存变更;当CascadiaSettings.IsPortableMode为真时还会显示 Portable 模式说明与链接。保存/重置的实际处理逻辑在 MainPage.cpp 的SaveButton_Click/ResetButton_Click中。

spec.md 同时要求整个 UI 通过完整的无障碍测试:所有条目必须可被屏幕阅读器和键盘访问,并全量本地化。从 TerminalSettingsEditor/Resources 下覆盖 de-DE、zh-CN、ja-JP 等十余种语言的Resources.resw目录结构看,本地化要求已被落实。

七、级联设置在 UI 中的表示:Base layer、重置与跨 Profile 复制

cascading-settings.md(Carlos Zamora 与 Kayla Cinnamon,2020-11-10)探讨的是:既然每个设置的值可能来自 profile 自身、profiles.defaults或 defaults.json 多层声明,设置 UI 应如何表达"覆盖/继承"关系。文档给出了一组将组合使用的 UI 提案:

  1. 控件下方文字标注:把 Profiles 下的 "Global" 页改名为 "Base layer";覆盖了 base layer 的设置,控件下方显示 "Overrides Base layer." 文字,标题旁提供一个带 "Reset" 提示的重置按钮;
  2. Add New → Duplicate Profile:新增 Profile 入口改为一个选择页,用户可以在"复制某个已有 profile"与"从默认设置新建"之间单选,随后进入的 Profile 页会按所选来源预填字段;
  3. Reset Profile 按钮:在 Profile 页的 Advanced pivot 底部提供 "Reset to default settings",清除该 profile 对象内的自定义设置,优先级回落到profile.defaults然后 defaults.json;
  4. "Apply to all profiles":每个 Profile 的 Advanced 页提供 "Copy settings to..." 按钮,弹出对话框以树视图列出全部 profile 设置项供勾选,底部以复选框列出所有 profile 作为复制目标。

文档还为每个提案对比了同类终端的做法(ConEmu/Cmder 的 Clone profile、iTerm2 的 Bulk Copy from Selected Profile 等),并记录了两个被否决的方案及其理由:

  • <inherit>下拉项:每个设置变成可编辑 ComboBox、附带 inherit 选项。优点是界面不杂乱,缺点是每个设置都是下拉框,且颜色选择器在该模型下无法自洽;
  • 锁按钮:锁住 = 继承自 Global 且控件禁用。缺点是语义易误解("锁住"直觉上表示"固定在本 profile",与当前设计恰好相反)。

源码印证:Has/Clear/OverrideSource 三件套

cascading-settings.md 指出 XAML 层会为每个设置引入一个ContentControl包装控件,并利用 TerminalSettingsModel 提供的四件套 API:

// Note: String and "Name" are replaced for each setting bool HasName(); void ClearName(); String Name(); void Name(String val);

这套接口在 IInheritable.h 中由宏体系完整实现:

  • INHERITABLE_SETTING宏为每个设置生成Has<NAME>()(判断用户是否显式设置过值)、<NAME>OverrideSource()(返回提供当前解析值的那一层对象)、Clear<NAME>()(清回继承态)与 getter/setter;
  • getter 的解析注释直接写着 fallback 顺序:user set value --> inherited value --> system set value——与文档摘要中"settings.json 值 → defaults.json 值 → 系统值"的级联链一一对应;
  • 每个设置存储为std::optionalnullopt表示"必须向父层继承";_parents是一个std::vector<com_ptr<T>>AddLeastImportantParent/AddMostImportantParent维护父子优先级,<NAME>OverrideSource()会沿父链回溯找到第一个显式设置该值的祖先;
  • 文档特别提到INHERITABLE_NULLABLE_SETTING用于Profile.Foreground这类"null 本身是合法值"的可空设置,用双层 optional(NullableSetting<T> = std::optional<std::optional<T>>)区分"未设置需继承"与"显式清空为 null"两种状态。

正是OverrideSource()让 UI 能精确回答"这个值到底来自哪一层",从而驱动 "Overrides Base layer." 标注与每行重置按钮——设计文档中抽象的 API 需求在这里有了逐行对应的实现。

八、能力与兼容性:文档中的边界声明

spec.md 的 Capabilities 一节明确了该功能的能力边界,写作与评审设置 UI 相关代码时值得参照:

  • 无障碍:全新 UI 元素,必须完成屏幕阅读器与键盘全路径测试,且全量本地化;
  • 安全 / 可靠性 / 性能功耗:均不受影响;
  • 兼容性:默认体验从"文本编辑器打开 JSON"变为"打开设置 UI",且该行为可通过修改openSettings键绑定加settingsUI选项回退——对应今天的 Actions 页中 openSettings 的settingsUI参数;
  • 未来考量hidden属性需要特殊处理(理想情况下所有 profile 无论hidden与否都应出现在设置中)、需要撤销功能、Marketplace 实现后加入顶层导航、导航结构随功能增长持续调整。

cascading-settings.md 另指出一个兼容性取舍:设置 UI 只提供 JSON 的"部分对等"(partial parity)是有意的——它是面向普通用户的简化工具,若为追求全量对等而堆满选项,会牺牲设置 UI 的简洁性这一核心价值。

九、延伸阅读路径

围绕本文主题,仓库内可按以下路径继续深入:

  • 设计稿三件套:design.md、spec.md、cascading-settings.md;
  • UI 实现:MainPage.xaml(导航、搜索框、Save/Reset 底栏)、NavConstants.h(导航标签与图标映射)、PreviewConnection.cpp(外观预览数据源)、KeyChordListener.h(组合键录入)、ActionEntry.cpp 所在的 Actions 模型;
  • 设置模型与继承机制:IInheritable.h(继承链与可清空设置宏)、Profile.h、defaults.json(系统默认值层,文件头注明为自动生成,修改会被忽略);
  • 更宏观的模型背景可参阅 Terminal Settings Model 规格 与 TerminalSettings-spec.md。

需要说明适用前提:design.md 成文于 2020 年,文中 "Launch on startup"、"Launch position" 等 Startup 组控件与现行 Launch.xaml 的项集合已有差异(现行版本新增了 startupActions、alwaysOnTop 等,defaults.json 中可见);但导航分层思路、Appearance 预览窗口、Save 保存模型与级联继承表达这四大设计决策,在今天的源码中仍然成立。

【免费下载链接】terminalThe new Windows Terminal and the original Windows console host, all in the same place!项目地址: https://gitcode.com/GitHub_Trending/term/terminal

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 20:39:24

基于MADDPG与Gymnasium的多无人机协同围捕仿真实战

简介&#xff1a;本资源是一个面向人工智能与机器人方向研究者、高校师生及强化学习实践者的多无人机协同控制仿真项目&#xff0c;聚焦于利用多智能体深度强化学习解决动态环境下的目标围捕与协同决策问题。项目基于MADDPG算法&#xff0c;在自定义Gymnasium仿真环境中训练3架…

作者头像 李华
网站建设 2026/9/5 20:36:19

本地部署大模型实战:Ollama、Transformers与llama.cpp量化指南

最早决定在自己电脑上折腾大模型本地部署&#xff0c;是因为炼丹房里排队排到怀疑人生&#xff0c;而且有些内部数据实在不方便往外丢。后来发现这事儿的门槛并没有想象中那么高&#xff0c;关键是找对工具链。目前主流的三条路线——Ollama、transformers、llama.cpp——我前前…

作者头像 李华
网站建设 2026/9/5 20:32:38

军事体能考核Python评定系统设计与实战落地

简介&#xff1a;这是一套面向军队院校、基层部队体能训练管理人员及Python数据分析初学者的军事体能考核成绩自动化评定工具&#xff0c;依据2021年1月最新通用训练课目标准开发&#xff0c;解决人工计算仰卧起坐、蛇形跑、单杠引体向上、3000米跑及身高体重体脂体型、高原海拔…

作者头像 李华