Compare commits

..

88 Commits

Author SHA1 Message Date
Carlos Zamora
f0c63b9281 PRE-MERGE #20014 Add settings for "notifying" on "activity" 2026-05-13 14:53:56 -07:00
Carlos Zamora
cfccd1f4be PRE-MERGE #20012 Add support for OSC777 (Send Notification) 2026-05-13 14:25:35 -07:00
Carlos Zamora
2ee29177ba PRE-MERGE #20059 Show terminal size overlay (COLSxROWS) during resize (#2833) 2026-05-13 14:24:50 -07:00
Carlos Zamora
edf18a2255 PRE-MERGE #20068 Add per-pane title header for split panes (#4717) 2026-05-13 14:23:17 -07:00
Carlos Zamora
f97cddcdd6 PRE-MERGE #20105 Clear scroll marks when clearing the buffer 2026-05-13 12:14:43 -07:00
Carlos Zamora
c84651b0f1 PRE-MERGE #20162 Add support for "workspaces" based on window names 2026-05-13 12:14:26 -07:00
Carlos Zamora
eb6deaf67c PRE-MERGE #20200 Add expander groups to settings UI 2026-05-13 12:10:20 -07:00
Carlos Zamora
6c1b73ef9c PRE-MERGE #20199 Introduce Profiles page to SUI 2026-05-13 11:30:10 -07:00
Carlos Zamora
b7701c909d PRE-MERGE #20203 Redesign new tab menu page -> dropdown 2026-05-13 11:29:46 -07:00
Carlos Zamora
0c621d11d8 PRE-MERGE #20215 Update styling of Actions page 2026-05-13 11:29:37 -07:00
Carlos Zamora
e42b3020b0 remove '-' & use 'threshold' term 2026-05-13 11:25:21 -07:00
Carlos Zamora
89b2295a8c code format 2026-05-12 18:34:10 -07:00
Carlos Zamora
56718992ac reuse existing resources for auto props 2026-05-12 18:21:09 -07:00
Carlos Zamora
5f38be735b add "notifyOnActivityThreshold" & "notifyOnNextPromptThreshold" 2026-05-12 18:02:48 -07:00
Carlos Zamora
054afcc59d const 2026-05-12 15:12:28 -07:00
Carlos Zamora
0fe41d7db8 const 2026-05-12 15:12:04 -07:00
Carlos Zamora
03dfed4d54 const 2026-05-12 15:10:39 -07:00
Carlos Zamora
84390c5b27 Fold new converter into existing code better 2026-05-12 15:08:00 -07:00
Carlos Zamora
b0c1611673 code format 2026-05-12 14:41:55 -07:00
Carlos Zamora
5a45c8d7e4 improve "view all" UI; consistently use "shortcut" 2026-05-12 14:37:26 -07:00
Carlos Zamora
fa0f2a7e16 Add SectionExpanderStyle to deduplicate code 2026-05-12 14:15:33 -07:00
Carlos Zamora
56aa5fc73f add "Profiles" to search results 2026-05-12 11:41:29 -07:00
Carlos Zamora
fa2d052ccd spell check + remove comment 2026-05-12 10:43:59 -07:00
Carlos Zamora
3ee13c679f spell check 2026-05-12 10:27:52 -07:00
Carlos Zamora
76f89bff04 polish 2026-05-11 21:08:30 -07:00
Carlos Zamora
a7aefad0ba Add containers to Actions page 2026-05-11 19:06:07 -07:00
Carlos Zamora
bf2cb051b4 Profiles: Add 'Window settings' group 2026-05-11 15:29:41 -07:00
Carlos Zamora
fbfc761450 Redesign new tab menu page -> dropdown 2026-05-08 13:21:22 -07:00
Mike Griese
74b740cf0c format, for real 2026-05-08 06:40:40 -05:00
Carlos Zamora
2fba2ee281 add polish 2026-05-07 19:14:28 -07:00
Carlos Zamora
87d9fdb1da add polish 2026-05-07 18:53:54 -07:00
Carlos Zamora
e8a5c32612 [SUI] Add expander groups to settings 2026-05-07 18:23:44 -07:00
Carlos Zamora
7cbfb5784a [SUI] Move profiles into a new Profiles page 2026-05-07 15:59:50 -07:00
Mike Griese
afe42d456f format 2026-05-07 13:43:50 -05:00
Mike Griese
12e2daaeb9 actions are good for our keyboard inclined 2026-05-07 13:41:46 -05:00
Mike Griese
b9896f51e4 delete workspaces ; better padding 2026-05-07 12:55:16 -05:00
Mike Griese
79d681e394 focus the window renamer better 2026-05-06 10:32:34 -05:00
Mike Griese
00aa707825 don't crash when closing the last pane in a workspace 2026-05-06 10:32:11 -05:00
Carlos Zamora
30020752ca NotificationEventArgs: OnlyWhenInactive --> AlwaysNotify (flip logic) 2026-05-05 18:29:10 -07:00
Carlos Zamora
dc27359f56 TerminalPaneContent: OutputIdle --> OutputBurstEnded 2026-05-05 18:08:48 -07:00
Carlos Zamora
8f4aa8e635 add indicator to cmd plt 2026-05-05 17:15:20 -07:00
Carlos Zamora
e82fe2e548 default allowOSC777=false 2026-05-05 16:23:09 -07:00
Carlos Zamora
f15a9305fe revert bad AUMID handling 2026-05-05 16:18:44 -07:00
Mike Griese
d5d4f99673 fix ci 2026-05-05 13:33:12 -05:00
Mike Griese
7dd7783aff wle 2026-05-05 11:33:39 -05:00
Mike Griese
ee1601e405 Merge remote-tracking branch 'origin/main' into dev/migrie/workspaces-for-pr 2026-05-05 11:32:01 -05:00
Carlos Zamora
071963420e {0} --> ::None; remove _restoring 2026-05-04 19:04:13 -07:00
Carlos Zamora
07a4f3acfc remove .leading from throttledTaskbarProgressChanged 2026-05-04 17:57:55 -07:00
Carlos Zamora
042eb5b1a9 autoDetectRunningCommand --> bool; _autoDetectEnabled --> _autoDetectCommandActivity 2026-05-04 17:55:03 -07:00
Carlos Zamora
611f5a31b4 remove redefinition 2026-05-04 16:57:32 -07:00
Carlos Zamora
cdb99bbe8b remove duplicate NotificationEventArgs 2026-05-04 15:52:34 -07:00
Carlos Zamora
fbec4ee41f Merge branch 'main' into dev/cazamor/toast/osc777 2026-05-04 14:52:27 -07:00
Carlos Zamora
cab78edde0 address feedback 2026-05-04 14:49:03 -07:00
Carlos Zamora
b044fd661d psychically debug failed formatter 2026-05-04 12:30:00 -07:00
Carlos Zamora
234838075f notifyOnInactiveOutput --> notifyOnActivity 2026-05-04 12:18:49 -07:00
Carlos Zamora
4e6209247f Merge branch 'main' into dev/cazamor/toast/activity 2026-05-04 11:27:58 -07:00
Carlos Zamora
a07dba52ef fix build 2026-04-29 19:07:09 -07:00
Carlos Zamora
fcaf3daa8d run code formatter 2026-04-29 18:24:59 -07:00
Carlos Zamora
68fccb5efb Merge branch 'main' into dev/cazamor/toast/activity 2026-04-29 18:22:19 -07:00
Carlos Zamora
6c2b796253 Address Leonard's feedback 2026-04-29 17:23:14 -07:00
Carlos Zamora
d4ff09f82e use split_iterator 2026-04-29 16:32:35 -07:00
Carlos Zamora
19286b7043 spell fight 2: electric boogaloo 2026-04-29 16:32:35 -07:00
Carlos Zamora
8868dfa6ee include everything after the semicolon for body 2026-04-29 16:32:35 -07:00
Carlos Zamora
04f6273e4b 🥊spell checker🥊 2026-04-29 16:32:35 -07:00
Carlos Zamora
f483eae7a9 spell 2026-04-29 16:32:35 -07:00
Carlos Zamora
0856bce421 DesktopNotification -> UrxvtAction; add _api.UnknownSequence() call 2026-04-29 16:32:35 -07:00
Carlos Zamora
582ffb615e Add support for OSC777 (Send Notification) 2026-04-29 16:32:34 -07:00
Carlos Zamora
da00f8863b Fix settings UI 2026-04-29 14:56:21 -07:00
Carlos Zamora
62727bf6d1 minor cleanup 2026-04-29 14:56:21 -07:00
Carlos Zamora
15ce2fd513 Add settings for "notifying" on "activity" 2026-04-29 14:56:20 -07:00
Carlos Zamora
6c88741e26 Merge branch 'main' into dev/cazamor/toast/base 2026-04-29 14:47:38 -07:00
Carlos Zamora
54009e1305 --from-toast & GetTickCount64() 2026-04-29 14:40:33 -07:00
Mike Griese
0c0a16e10a Add support for "workspaces" based on window names
This adds a new feature to the Windows Terminal: "Workspaces"

Workspaces are very shamelessly inspired by Edge workspaces of the same name.

{{video here}}

The core idea is that when users name a window and they close that window, we
will persist that Windows layout and buffers, seperately from the rest of window
restoration. So a user can open a named window, open some profiles, some panes,
do some stuff in it, then close it, and we will keep that state around for the
next time the user opens that window name.

Unnamed windows still behave the same. If you close an unnamed window, and it's
not the last window, then we won't persist the state of it.

To facilitate restoring named windows, we add a `openWorkspace` action. This
allows us to persist the open workspace action in the window layout restoration
path. So when we deserialize the list of tab layouts, and open workspace action
will tell us, hey, go retrieve this known workspace from the state.json, instead
of trying to serialize the window state in two places.

<details>
<summary>
state.json
</summary>

```jsonc

	"persistedWindowLayouts" :
	[
		{
			"initialPosition" : "910,462",
			"initialSize" :
			{
				"height" : 623.20001220703125,
				"width" : 934.4000244140625
			},
			"launchMode" : "default",
			"tabLayout" :
			[
				{
					"action" : "newTab",
					"commandline" : "\"C:\\Program Files\\PowerShell\\7\\pwsh.exe\"",
					"profile" : "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
					"sessionId" : "{09d3ef05-ba3d-44ed-a8f1-065d08a806a4}",
					"startingDirectory" : "C:\\Users\\zadji",
					"suppressApplicationTitle" : false,
					"tabTitle" : "PowerShell"
				},
			]
		},
		{
			"tabLayout" :
			[
				{
					"action" : "openWorkspace",
					"name" : "wsl"
				}
			]
		}
	],
	"persistedWorkspaces" :
	{
		"wsl" :
		{
			"initialPosition" : "109,502",
			"initialSize" :
			{
				"height" : 568,
				"width" : 1184.800048828125
			},
			"launchMode" : "default",
			"tabLayout" :
			[
				{
					"action" : "newTab",
					"commandline" : "ubuntu.exe",
					"profile" : "{51855cb2-8cce-5362-8f54-464b92b32386}",
					"sessionId" : "{a7f70c49-71ec-4ac4-9f3a-4884528a3fd6}",
					"startingDirectory" : null,
					"suppressApplicationTitle" : false,
					"tabTitle" : "Ubuntu"
				},
				{
					"action" : "renameWindow",
					"name" : "wsl"
				}
			]
		}
	},
```

</details>

As demoed in the video, we add a flyout to list the windows that the user has
open, and the named workspaces that they have saved. This allows users to
quickly reopen previously closed workspaces, as well as quickly rename a window,
thereby adding it to the list of saved workspaces. This button can also be
hidden using the theme settings.
2026-04-28 14:32:46 -05:00
sagarbhure-msft
fe650d0c27 Address review: fix timer lambda leak and stale font-size overlay
- Fix Tick handler lambda leak: initialize the timer and register the
  Tick handler only once on first use, then just restart the timer on
  subsequent calls (lhecker, DHowett)
- Use std::optional<SafeDispatcherTimer> to defer initialization until
  first use (lhecker)
- Remove _ShowResizeOverlay from _coreFontSizeChanged: the viewport
  dimensions are stale at that point because ControlCore still holds
  the write lock. The overlay will be shown by _SwapChainSizeChanged
  which fires after the resize completes with correct values (DHowett)
2026-04-19 13:28:32 +05:30
Carlos Zamora
b53ccb853e Suppress notification if focused; add pane data 2026-04-16 17:58:58 -07:00
SushaanthSrinivasan
ac400756e8 Add ClearMarksInRange to _EraseAll for clear/cls path 2026-04-14 19:30:01 -07:00
sagarbhure-msft
7378b8ac8c Show overlay on font-size zoom, skip in Settings preview
Show the resize overlay when Ctrl+Scroll changes font size and alters
the grid dimensions. Extract overlay logic into _ShowResizeOverlay()
helper called from both _SwapChainSizeChanged and _coreFontSizeChanged.

Skip the overlay when the control is disabled (IsEnabled() == false),
which is the case for the Settings page terminal preview.
2026-04-14 09:20:10 +05:30
sagarbhure-msft
9f2dcfd5ee Fix spell-check: replace COLSxROWS with plain text in comments 2026-04-13 23:03:26 +05:30
sagarbhure-msft
ab2514b9cc Fix code formatting in TermControl.xaml
Run Invoke-CodeFormat: reorder XAML attributes alphabetically
and normalize comment spacing per project style.
2026-04-13 22:33:04 +05:30
SushaanthSrinivasan
b21ba2b053 Clear scroll marks when clearing the buffer (#20086) 2026-04-11 13:44:19 -07:00
sagarbhure-msft
5279226646 Add showPaneHeaders global appearance setting
Adds a 'showPaneHeaders' boolean setting (default: true) to control
whether per-pane title headers are displayed when multiple panes are
open. The setting is available in Settings > Appearance as a toggle
and persists via settings.json.

Headers are refreshed live when the setting is changed — toggling off
hides headers on all existing panes immediately.
2026-04-07 22:12:09 +05:30
sagarbhure-msft
c7a51c978c Show terminal size overlay (COLSxROWS) during resize (#2833)
Display a centered overlay showing columns x rows when the terminal
control is resized. The overlay auto-hides after 750ms of inactivity.

- Add ResizeOverlay Border element to TermControl.xaml
- Add ViewWidth() to ControlCore (matches existing ViewHeight())
- Show overlay in _SwapChainSizeChanged using SafeDispatcherTimer
- Use fmt::format for string formatting

Closes #2833
2026-04-04 10:10:47 +05:30
sagarbhure-msft
44456be4eb Add per-pane title header for split panes (#4717)
Shows a thin title bar above each pane when multiple panes are open.
Headers display the pane title, update dynamically via Dispatcher when
the shell changes the title (e.g. via escape sequences), and use the
focus-state border color as background. Hidden when only one pane exists.

The header is placed directly in the pane root Grid (row 0, auto-sized)
with the content border in row 1 (star-sized), keeping the TermControl
as the direct child of the border so SwapChainPanel renders correctly.
2026-04-04 09:34:49 +05:30
Carlos Zamora
5f3db13e5f fix extra window and reorder/glom scenarios 2026-03-26 18:12:08 -07:00
Carlos Zamora
9df166efec Send notifications even when we're unpackaged (#20013)
## Summary of the Pull Request
Targets #20010 

Manually assign an AUMID to our process when we're running unpackaged.
Main difference from #19937 is what AUMID we use. Before, it was per
branding, but the `WindowEmperor` already appends an exe path hash for
unpackaged instances to prevent crosstalk. Here, we're just using the
same pattern: `Microsoft.WindowsTerminal.<hash>`.

Heavily based on #19937
Co-authored by @zadjii-msft
2026-03-25 13:27:12 -07:00
Carlos Zamora
aeb531f666 spell; prefer AppDisplayName; use C++20 designated init 2026-03-25 10:29:06 -07:00
Carlos Zamora
c23e507c20 spell 2026-03-25 10:29:06 -07:00
Carlos Zamora
c49bc1a789 Add toast notification infrastructure 2026-03-25 10:29:06 -07:00
155 changed files with 6319 additions and 3225 deletions

View File

@@ -17,6 +17,7 @@ ADDSTRING
ADDTOOL
adml
admx
Affordance
AFill
AFX
AHelper
@@ -1075,7 +1076,6 @@ NOCONTEXTHELP
NOCOPYBITS
nodiscard
NODUP
NODEFAULT
noexcepts
NOFONT
NOHIDDENTEXT
@@ -1106,7 +1106,6 @@ NOSIZE
NOSNAPSHOT
NOTHOUSANDS
NOTICKS
notif
NOTIMEOUTIFNOTHUNG
NOTIMPL
NOTOPMOST
@@ -1562,7 +1561,6 @@ SMARTQUOTE
SMTO
snapcx
snapcy
SND
snk
SOLIDBOX
Solutiondir
@@ -1757,6 +1755,7 @@ UPKEY
upss
uregex
URegular
urxvt
usebackq
USECALLBACK
USECOLOR

View File

@@ -479,6 +479,7 @@
"toggleReadOnlyMode",
"toggleShaderEffects",
"toggleSplitOrientation",
"workspaces",
"wt",
"unbound"
],
@@ -2040,6 +2041,11 @@
"unfocusedFrame": {
"description": "The color of the window frame when the window is inactive. This only works on Windows 11",
"$ref": "#/$defs/ThemeColor"
},
"showWindowsButton": {
"description": "When set to true, the workspace/windows button will be shown in the tab row.",
"type": "boolean",
"default": true
}
}
},
@@ -2794,6 +2800,11 @@
"description": "When set to true, VT applications will be allowed to set the contents of the local clipboard using OSC 52 (Manipulate Selection Data).",
"type": "boolean"
},
"compatibility.allowOSC777": {
"default": false,
"description": "When set to true, applications can send OSC 777 escape sequences to trigger desktop toast notifications with a custom title and body.",
"type": "boolean"
},
"unfocusedAppearance": {
"$ref": "#/$defs/AppearanceConfig",
"description": "Sets the appearance of the terminal when it is unfocused.",
@@ -2869,6 +2880,85 @@
"description": "Sets the sound played when the application emits a BEL. When set to an array, the terminal will pick one of those sounds at random.",
"$ref": "#/$defs/BellSound"
},
"notifyOnActivity": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string",
"enum": [
"taskbar",
"audible",
"tab",
"notification"
]
}
},
{
"type": "string",
"enum": [
"taskbar",
"audible",
"tab",
"notification",
"all",
"none"
]
}
],
"description": "Controls how you are notified when an inactive tab produces new output."
},
"notifyOnNextPrompt": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string",
"enum": [
"taskbar",
"audible",
"tab",
"notification"
]
}
},
{
"type": "string",
"enum": [
"taskbar",
"audible",
"tab",
"notification",
"all",
"none"
]
}
],
"description": "Controls how you are notified when a new shell prompt is detected. Requires shell integration."
},
"notifyOnActivityThreshold": {
"type": "integer",
"minimum": 0,
"default": 5,
"description": "Minimum number of seconds between consecutive activity notifications for this profile. Use this to suppress repeated notifications from chatty processes. The first notification after the pane has been silent always fires; subsequent notifications within this window are suppressed. Use 0 to always notify."
},
"notifyOnNextPromptThreshold": {
"type": "integer",
"minimum": 0,
"default": 5,
"description": "Suppress the next-prompt notification unless the just-finished command ran for at least this many seconds. Requires shell integration. Use 0 to always notify."
},
"autoDetectRunningCommand": {
"default": false,
"description": "Automatically detect when a command is running and show a progress indicator in the tab and taskbar.",
"type": "boolean"
},
"closeOnExit": {
"default": "automatic",
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"automatic\" (behave as \"graceful\" only for processes launched by terminal, behave as \"always\" otherwise)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",

View File

@@ -938,6 +938,27 @@ namespace winrt::TerminalApp::implementation
co_return;
}
// Launch `wt -w <name>` so the monarch can either summon an existing
// window with that name or restore a persisted workspace.
safe_void_coroutine TerminalPage::_OpenWorkspaceWindow(const winrt::hstring name)
{
co_await winrt::resume_background();
const auto exePath{ GetWtExePath() };
const auto cmdline = fmt::format(FMT_COMPILE(L"-w {}"), std::wstring_view{ name });
SHELLEXECUTEINFOW seInfo{ 0 };
seInfo.cbSize = sizeof(seInfo);
seInfo.fMask = SEE_MASK_NOASYNC;
seInfo.lpVerb = L"open";
seInfo.lpFile = exePath.c_str();
seInfo.lpParameters = cmdline.c_str();
seInfo.nShow = SW_SHOWNORMAL;
LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo));
co_return;
}
void TerminalPage::_HandleNewWindow(const IInspectable& /*sender*/,
const ActionEventArgs& actionArgs)
{
@@ -1058,6 +1079,7 @@ namespace winrt::TerminalApp::implementation
// Fun!
// WindowRenamerTextBox().Focus(FocusState::Programmatic);
_renamerLayoutUpdatedRevoker.revoke();
_renamerLayoutCount = 0;
_renamerLayoutUpdatedRevoker = WindowRenamerTextBox().LayoutUpdated(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (auto self{ weakThis.get() })
{
@@ -1633,4 +1655,35 @@ namespace winrt::TerminalApp::implementation
args.Handled(handled);
}
}
void TerminalPage::_HandleOpenWorkspace(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
// Open (or summon) a named window. We launch a new `wt -w <name>`
// process which the monarch will route to the correct live window or
// restore from a persisted workspace.
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<OpenWorkspaceArgs>())
{
const auto name = realArgs.Name();
if (!name.empty())
{
_OpenWorkspaceWindow(name);
}
args.Handled(true);
}
}
}
void TerminalPage::_HandleWorkspaces(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (_workspaceFlyout && _workspaceDropdown)
{
_workspaceFlyout.ShowAt(_workspaceDropdown);
}
args.Handled(true);
}
}

View File

@@ -231,6 +231,12 @@
Glyph="&#xEA8F;"
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).BellIndicator, Mode=OneWay}" />
<FontIcon Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="8"
Glyph="&#xF127;"
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).ActivityIndicator, Mode=OneWay}" />
<FontIcon Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="12"

View File

@@ -91,7 +91,7 @@ namespace winrt::TerminalApp::implementation
// When the user activates (clicks) the toast, fire the callback.
if (activatedFunc)
{
toast.Activated([activatedFunc](const auto& /*sender*/, const auto& /*eventArgs*/) {
toast.Activated([activatedFunc = std::move(activatedFunc)](const auto& /*sender*/, const auto& /*eventArgs*/) {
activatedFunc();
});
}

View File

@@ -21,6 +21,8 @@ namespace TerminalApp
{
String Title { get; };
String Body { get; };
Microsoft.Terminal.Control.OutputNotificationStyle Style { get; };
Boolean AlwaysNotify { get; };
};
interface IPaneContent
@@ -31,7 +33,7 @@ namespace TerminalApp
Windows.Foundation.Size MinimumSize { get; };
String Title { get; };
UInt64 TaskbarState { get; };
Microsoft.Terminal.Control.TaskbarState TaskbarState { get; };
UInt64 TaskbarProgress { get; };
Boolean ReadOnly { get; };
String Icon { get; };

View File

@@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
winrt::hstring Title() { return _filePath; }
uint64_t TaskbarState() { return 0; }
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;

View File

@@ -31,10 +31,14 @@ Pane::Pane(IPaneContent content, const bool lastFocused) :
_lastActive{ lastFocused }
{
_setPaneContent(std::move(content));
_root.Children().Append(_borderFirst);
_CreatePaneHeader();
const auto& control{ _content.GetRoot() };
_borderFirst.Child(control);
// Set up leaf layout: header in _root row 0, content in _borderFirst row 1.
// The TermControl stays as the direct child of _borderFirst (no Grid wrapper)
// so the SwapChainPanel renders correctly.
_SetupLeafLayout(control);
// Register an event with the control to have it inform us when it gains focus.
if (control)
@@ -92,6 +96,10 @@ INewContentArgs Pane::GetTerminalArgsForPane(BuildStartupKind kind) const
{
// Leaves are the only things that have controls
assert(_IsLeaf());
if (!_content)
{
return nullptr;
}
return _content.GetNewTerminalArgs(kind);
}
@@ -1228,6 +1236,12 @@ void Pane::UpdateVisuals()
const auto& brush{ _ComputeBorderColor() };
_borderFirst.BorderBrush(brush);
_borderSecond.BorderBrush(brush);
// Update pane header color to match focus state
if (_paneHeaderBorder && _paneHeaderBorder.Visibility() == winrt::Windows::UI::Xaml::Visibility::Visible)
{
_paneHeaderBorder.Background(brush);
}
}
// Method Description:
@@ -1450,9 +1464,9 @@ void Pane::_CloseChild(const bool closeFirst)
_root.RowDefinitions().Clear();
// Reattach the TermControl to our grid.
_root.Children().Append(_borderFirst);
_CreatePaneHeader();
const auto& control{ _content.GetRoot() };
_borderFirst.Child(control);
_SetupLeafLayout(control);
// Make sure to set our _splitState before focusing the control. If you
// fail to do this, when the tab handles the GotFocus event and asks us
@@ -1755,7 +1769,92 @@ void Pane::_setPaneContent(IPaneContent content)
}
// Method Description:
// - Sets up row/column definitions for this pane. There are three total
// - Creates the pane header UI elements (title bar shown above the content).
// The header is initially collapsed and only shown via ShowPaneHeaders().
void Pane::_CreatePaneHeader()
{
namespace WUX = winrt::Windows::UI::Xaml;
_paneHeaderText = Controls::TextBlock{};
_paneHeaderText.FontSize(12);
_paneHeaderText.Padding({ 8, 2, 8, 2 });
_paneHeaderText.IsTextSelectionEnabled(false);
_paneHeaderText.TextTrimming(WUX::TextTrimming::CharacterEllipsis);
if (_content)
{
_paneHeaderText.Text(_content.Title());
_titleChangedRevoker = _content.TitleChanged(winrt::auto_revoke, [this](auto&&, auto&&) {
_paneHeaderBorder.Dispatcher().RunAsync(
winrt::Windows::UI::Core::CoreDispatcherPriority::Normal,
[this]() {
if (_content && _paneHeaderText)
{
_paneHeaderText.Text(_content.Title());
}
});
});
}
_paneHeaderBorder = Controls::Border{};
_paneHeaderBorder.Padding({ 0, 0, 0, 0 });
_paneHeaderBorder.Child(_paneHeaderText);
_paneHeaderBorder.Visibility(WUX::Visibility::Collapsed);
}
// Method Description:
// - Sets up the leaf pane layout in _root: a header row (auto-sized) and a
// content row (star-sized). The TermControl stays as the direct child of
// _borderFirst so the SwapChainPanel renders correctly.
void Pane::_SetupLeafLayout(const winrt::Windows::UI::Xaml::UIElement& control)
{
auto headerRow = Controls::RowDefinition{};
headerRow.Height(GridLengthHelper::Auto());
auto contentRow = Controls::RowDefinition{};
contentRow.Height(GridLengthHelper::FromValueAndType(1, GridUnitType::Star));
_root.RowDefinitions().Append(headerRow);
_root.RowDefinitions().Append(contentRow);
Controls::Grid::SetRow(_paneHeaderBorder, 0);
Controls::Grid::SetRow(_borderFirst, 1);
_root.Children().Append(_paneHeaderBorder);
_root.Children().Append(_borderFirst);
if (control)
{
_borderFirst.Child(control);
}
}
// Method Description:
// - Show or hide the pane header title bar on all leaf panes in the tree.
// Called by Tab when the number of panes changes.
void Pane::ShowPaneHeaders(bool show)
{
if (_IsLeaf())
{
if (_paneHeaderBorder)
{
namespace WUX = winrt::Windows::UI::Xaml;
_paneHeaderBorder.Visibility(show ? WUX::Visibility::Visible : WUX::Visibility::Collapsed);
if (show)
{
const auto& brush = _ComputeBorderColor();
_paneHeaderBorder.Background(brush);
_paneHeaderText.Foreground(winrt::Windows::UI::Xaml::Media::SolidColorBrush(winrt::Windows::UI::Colors::White()));
}
}
}
else
{
_firstChild->ShowPaneHeaders(show);
_secondChild->ShowPaneHeaders(show);
}
}
// Method Description:
// - Sets up row/column definitions for this pane.There are three total
// row/cols. The middle one is for the separator. The first and third are for
// each of the child panes, and are given a size in pixels, based off the
// available space, and the percent of the space they respectively consume,
@@ -2321,6 +2420,10 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
_root.RowDefinitions().Clear();
_CreateRowColDefinitions();
// Reset Grid.Row on _borderFirst — it may have been set to row 1 in the
// leaf layout (header=row0, content=row1).
Controls::Grid::SetRow(_borderFirst, 0);
_borderFirst.Child(_firstChild->GetRootElement());
_borderSecond.Child(_secondChild->GetRootElement());

View File

@@ -150,6 +150,7 @@ public:
bool ContainsReadOnly() const;
void EnableBroadcast(bool enabled);
void ShowPaneHeaders(bool show);
void BroadcastKey(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const WORD vkey, const WORD scanCode, const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool keyDown);
void BroadcastChar(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const wchar_t vkey, const WORD scanCode, const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers);
void BroadcastString(const winrt::Microsoft::Terminal::Control::TermControl& sourceControl, const winrt::hstring& text);
@@ -235,6 +236,11 @@ private:
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
// Per-pane title header (visible when there are split panes)
winrt::Windows::UI::Xaml::Controls::Border _paneHeaderBorder{ nullptr };
winrt::Windows::UI::Xaml::Controls::TextBlock _paneHeaderText{ nullptr };
winrt::TerminalApp::IPaneContent::TitleChanged_revoker _titleChangedRevoker;
PaneResources _themeResources;
#pragma region Properties that need to be transferred between child / parent panes upon splitting / closing
@@ -266,6 +272,8 @@ private:
void _SetupChildCloseHandlers();
winrt::TerminalApp::IPaneContent _takePaneContent();
void _setPaneContent(winrt::TerminalApp::IPaneContent content);
void _CreatePaneHeader();
void _SetupLeafLayout(const winrt::Windows::UI::Xaml::UIElement& control);
bool _HasChild(const std::shared_ptr<Pane> child);
winrt::TerminalApp::TerminalPaneContent _getTerminalContent() const;

View File

@@ -85,6 +85,7 @@ namespace winrt::TerminalApp::implementation
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command, nullptr);
WINRT_PROPERTY(winrt::hstring, Content);
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::WindowLayout, PersistedLayout, nullptr);
};
}

View File

@@ -51,5 +51,6 @@ namespace TerminalApp
CommandlineArgs Command { get; };
String Content { get; };
Windows.Foundation.IReference<Windows.Foundation.Rect> InitialBounds { get; };
Microsoft.Terminal.Settings.Model.WindowLayout PersistedLayout;
};
}

View File

@@ -743,6 +743,38 @@
<value>unnamed window</value>
<comment>text used to identify when a window hasn't been assigned a name by the user</comment>
</data>
<data name="NameThisWindowMenuItem" xml:space="preserve">
<value>Name this window…</value>
<comment>Menu item text shown when the current window has no name assigned</comment>
</data>
<data name="RenameThisWindowMenuItem" xml:space="preserve">
<value>Rename this window…</value>
<comment>Menu item text shown when the current window already has a name</comment>
</data>
<data name="WindowListUnnamedEntry" xml:space="preserve">
<value>#{0} (unnamed)</value>
<comment>{0} is the window ID number. Shown in the workspace flyout for windows that have no name assigned.</comment>
</data>
<data name="DeleteWorkspaceMenuItem" xml:space="preserve">
<value>Delete workspace?</value>
<comment>Menu item text shown in the right-click context menu on a saved workspace</comment>
</data>
<data name="OpenWorkspaceMenuItem" xml:space="preserve">
<value>Open workspace</value>
<comment>Menu item text for opening a saved workspace</comment>
</data>
<data name="ConfirmDeleteWorkspaceTitle" xml:space="preserve">
<value>Are you sure you want to delete the workspace "{0}"?</value>
<comment>{0} is the workspace name. Shown in a confirmation dialog when the user tries to delete a saved workspace.</comment>
</data>
<data name="ConfirmDeleteWorkspaceDelete" xml:space="preserve">
<value>Delete</value>
<comment>Primary button text on the delete workspace confirmation dialog</comment>
</data>
<data name="ConfirmDeleteWorkspaceCancel" xml:space="preserve">
<value>Cancel</value>
<comment>Cancel button text on the delete workspace confirmation dialog</comment>
</data>
<data name="WindowRenamer.Subtitle" xml:space="preserve">
<value>Enter a new name:</value>
</data>

View File

@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
winrt::hstring Title() { return L"Scratchpad"; }
uint64_t TaskbarState() { return 0; }
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;

View File

@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(const BuildStartupKind kind) const;
winrt::hstring Title() { return RS_(L"SettingsTab"); }
uint64_t TaskbarState() { return 0; }
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;

View File

@@ -24,7 +24,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
winrt::hstring Title() { return RS_(L"SnippetPaneTitle/Text"); }
uint64_t TaskbarState() { return 0; }
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;

View File

@@ -123,6 +123,12 @@ namespace winrt::TerminalApp::implementation
_bellIndicatorTimer.Stop();
}
void Tab::_ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& /*sender*/, const Windows::Foundation::IInspectable& /*e*/)
{
ShowActivityIndicator(false);
_activityIndicatorTimer.Stop();
}
// Method Description:
// - Initializes a TabViewItem for this Tab instance.
// Arguments:
@@ -329,6 +335,10 @@ namespace winrt::TerminalApp::implementation
{
ShowBellIndicator(false);
}
if (_tabStatus.ActivityIndicator())
{
ShowActivityIndicator(false);
}
}
}
@@ -361,6 +371,10 @@ namespace winrt::TerminalApp::implementation
// The tabWidthMode may have changed, update the header control accordingly
_UpdateHeaderControlMaxWidth();
// Refresh pane header visibility based on the current setting
const auto showHeaders = settings.GlobalSettings().ShowPaneHeaders() && _rootPane->GetLeafPaneCount() > 1;
_rootPane->ShowPaneHeaders(showHeaders);
// Update the settings on all our panes.
_rootPane->WalkTree([&](const auto& pane) {
pane->UpdateSettings(settings);
@@ -459,6 +473,26 @@ namespace winrt::TerminalApp::implementation
_bellIndicatorTimer.Start();
}
void Tab::ShowActivityIndicator(const bool show)
{
ASSERT_UI_THREAD();
_tabStatus.ActivityIndicator(show);
}
void Tab::ActivateActivityIndicatorTimer()
{
ASSERT_UI_THREAD();
if (!_activityIndicatorTimer)
{
_activityIndicatorTimer.Interval(std::chrono::milliseconds(2000));
_activityIndicatorTimer.Tick({ get_weak(), &Tab::_ActivityIndicatorTimerTick });
}
_activityIndicatorTimer.Start();
}
// Method Description:
// - Gets the title string of the last focused terminal control in our tree.
// Returns the empty string if there is no such control.
@@ -646,6 +680,14 @@ namespace winrt::TerminalApp::implementation
// After split, Close Pane Menu Item should be visible
_closePaneMenuItem.Visibility(WUX::Visibility::Visible);
// Show pane headers now that we have multiple panes (if the setting is enabled)
try
{
const auto settings{ winrt::TerminalApp::implementation::AppLogic::CurrentAppSettings() };
_rootPane->ShowPaneHeaders(settings.GlobalSettings().ShowPaneHeaders());
}
CATCH_LOG();
// The active pane has an id if it is a leaf
if (activePaneId)
{
@@ -1181,8 +1223,45 @@ namespace winrt::TerminalApp::implementation
co_await wil::resume_foreground(dispatcher);
if (const auto tab{ weakThisCopy.get() })
{
const auto title = notifArgs.Title().empty() ? tab->Title() : notifArgs.Title();
tab->TabToastNotificationRequested.raise(title, notifArgs.Body(), sender);
const auto activeContent = tab->GetActiveContent();
const auto isActivePaneContent = activeContent && activeContent == sender;
if (!notifArgs.AlwaysNotify() && isActivePaneContent &&
tab->_focusState != WUX::FocusState::Unfocused)
{
co_return;
}
const auto style = notifArgs.Style();
if (WI_IsFlagSet(style, OutputNotificationStyle::Taskbar))
{
tab->TabRaiseVisualBell.raise();
}
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Audible))
{
if (const auto termContent{ sender.try_as<TerminalApp::TerminalPaneContent>() })
{
termContent.PlayNotificationSound();
}
}
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Tab))
{
tab->ShowActivityIndicator(true);
if (tab->_focusState != WUX::FocusState::Unfocused)
{
tab->ActivateActivityIndicatorTimer();
}
}
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Notification))
{
const auto title = notifArgs.Title().empty() ? tab->Title() : notifArgs.Title();
tab->TabToastNotificationRequested.raise(title, notifArgs.Body(), sender);
}
}
});
@@ -1242,11 +1321,10 @@ namespace winrt::TerminalApp::implementation
const auto taskbarState = state.State();
// The progress of the control changed, but not necessarily the progress of the tab.
// Set the tab's progress ring to the active pane's progress
if (taskbarState > 0)
if (taskbarState != winrt::Microsoft::Terminal::Control::TaskbarState::Clear)
{
if (taskbarState == 3)
if (taskbarState == winrt::Microsoft::Terminal::Control::TaskbarState::Indeterminate)
{
// 3 is the indeterminate state, set the progress ring as such
_tabStatus.IsProgressRingIndeterminate(true);
}
else
@@ -1337,6 +1415,7 @@ namespace winrt::TerminalApp::implementation
if (_rootPane->GetLeafPaneCount() == 1)
{
_closePaneMenuItem.Visibility(WUX::Visibility::Collapsed);
_rootPane->ShowPaneHeaders(false);
}
_RecalculateAndApplyReadOnly();
@@ -1422,6 +1501,10 @@ namespace winrt::TerminalApp::implementation
{
tab->ShowBellIndicator(false);
}
if (tab->_tabStatus.ActivityIndicator())
{
tab->ShowActivityIndicator(false);
}
}
});

View File

@@ -48,6 +48,9 @@ namespace winrt::TerminalApp::implementation
void ShowBellIndicator(const bool show);
void ActivateBellIndicatorTimer();
void ShowActivityIndicator(const bool show);
void ActivateActivityIndicatorTimer();
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
@@ -215,6 +218,9 @@ namespace winrt::TerminalApp::implementation
SafeDispatcherTimer _bellIndicatorTimer;
void _BellIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
SafeDispatcherTimer _activityIndicatorTimer;
void _ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
void _UpdateHeaderControlMaxWidth();
void _CreateContextMenu();

View File

@@ -32,6 +32,12 @@
FontSize="12"
Glyph="&#xEA8F;"
Visibility="{x:Bind TabStatus.BellIndicator, Mode=OneWay}" />
<FontIcon x:Name="HeaderActivityIndicator"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="8"
Glyph="&#xF127;"
Visibility="{x:Bind TabStatus.ActivityIndicator, Mode=OneWay}" />
<FontIcon x:Name="HeaderZoomIcon"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"

View File

@@ -450,6 +450,21 @@ namespace winrt::TerminalApp::implementation
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));
// If this is the last tab in a named window, persist the workspace
// layout now while tab content is still alive. After tab.Close()
// the pane content will be torn down by the time _RemoveTab runs.
if (_tabs.Size() == 1)
{
const auto& windowName = _WindowProperties.WindowName();
if (!windowName.empty())
{
if (const auto layout = GetWindowLayout())
{
ApplicationState::SharedInstance().SaveWorkspace(windowName, layout);
}
}
}
tab.Close();
}
@@ -471,6 +486,13 @@ namespace winrt::TerminalApp::implementation
const auto focusedTabIndex{ _GetFocusedTabIndex() };
// NOTE: Workspace persistence for named windows used to live here,
// but by the time _RemoveTab runs the pane content may already be
// torn down (e.g. from the close-pane path). Instead, workspace
// saves are handled earlier:
// - Close-pane (last pane): in _HandleClosePaneRequested
// - Close-tab: in _HandleCloseTabRequested
// Removing the tab from the collection should destroy its control and disconnect its connection,
// but it doesn't always do so. The UI tree may still be holding the control and preventing its destruction.
tab.Shutdown();
@@ -798,6 +820,28 @@ namespace winrt::TerminalApp::implementation
}
_AddPreviouslyClosedPaneOrTab(std::move(state.args));
// If this is the last pane on the last tab of a named window, persist
// the workspace layout now while the pane content is still alive.
// We can't wait until _RemoveTab, because pane->Close() below will
// destroy the content before _RemoveTab is reached.
if (_tabs.Size() == 1)
{
if (const auto activeTab{ _GetFocusedTabImpl() })
{
if (activeTab->GetLeafPaneCount() == 1)
{
const auto& windowName = _WindowProperties.WindowName();
if (!windowName.empty())
{
if (const auto layout = GetWindowLayout())
{
ApplicationState::SharedInstance().SaveWorkspace(windowName, layout);
}
}
}
}
}
// If specified, detach before closing to directly update the pane structure
pane->Close();
}
@@ -1353,7 +1397,11 @@ namespace winrt::TerminalApp::implementation
// Use the Tab object's identity hash as a stable toast tag.
// This survives tab reordering and cross-window moves.
const auto tabHash = std::hash<winrt::Windows::Foundation::IUnknown>{}(*tab);
#ifdef _WIN64
const hstring tabTag{ fmt::format(FMT_COMPILE(L"wt-tab-{:016x}"), tabHash) };
#else
const hstring tabTag{ fmt::format(FMT_COMPILE(L"wt-tab-{:08x}"), tabHash) };
#endif
const implementation::DesktopNotificationArgs args{
.Title = notificationTitle,
@@ -1366,8 +1414,8 @@ namespace winrt::TerminalApp::implementation
{
// The toast Activated callback runs on a background thread.
// Marshal to the UI thread for tab focus and window summon.
page->Dispatcher().RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakPage{ page->get_weak() }, weakTab, weakContent]() {
if (const auto p{ weakPage.get() })
page->Dispatcher().RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis, weakTab, weakContent]() {
if (const auto p{ weakThis.get() })
{
if (const auto t{ weakTab.get() })
{

View File

@@ -25,6 +25,15 @@ namespace winrt::TerminalApp::implementation
InitializeComponent();
}
void TabRowControl::WorkspaceName(const winrt::hstring& value)
{
if (_WorkspaceName != value)
{
_WorkspaceName = value;
PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"WorkspaceName" });
}
}
// Method Description:
// - Bound in the Xaml editor to the [+] button.
// Arguments:

View File

@@ -19,6 +19,14 @@ namespace winrt::TerminalApp::implementation
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(bool, ShowElevationShield, PropertyChanged.raise, false);
WINRT_OBSERVABLE_PROPERTY(bool, ShowWindowsButton, PropertyChanged.raise, true);
public:
winrt::hstring WorkspaceName() const noexcept { return _WorkspaceName; }
void WorkspaceName(const winrt::hstring& value);
private:
winrt::hstring _WorkspaceName{};
};
}

View File

@@ -9,5 +9,7 @@ namespace TerminalApp
TabRowControl();
Microsoft.UI.Xaml.Controls.TabView TabView { get; };
Boolean ShowElevationShield;
Boolean ShowWindowsButton;
String WorkspaceName;
}
}

View File

@@ -8,6 +8,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mtu="using:Microsoft.Terminal.UI"
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
Background="{ThemeResource TabViewBackground}"
mc:Ignorable="d">
@@ -35,14 +36,44 @@
TabWidthMode="Equal">
<mux:TabView.TabStripHeader>
<!-- EA18 is the "Shield" glyph -->
<FontIcon x:Uid="ElevationShield"
Margin="9,4,0,4"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="16"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
Glyph="&#xEA18;"
Visibility="{x:Bind ShowElevationShield, Mode=OneWay}" />
<StackPanel Orientation="Horizontal">
<!-- EA18 is the "Shield" glyph -->
<FontIcon x:Uid="ElevationShield"
Margin="9,4,0,4"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="16"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
Glyph="&#xEA18;"
Visibility="{x:Bind ShowElevationShield, Mode=OneWay}" />
<!-- Workspace/windows button -->
<Button x:Name="WorkspaceDropdown"
Margin="4,0,0,4"
Padding="8,0,0,0"
VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="0"
Visibility="{x:Bind ShowWindowsButton, Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal"
Spacing="8">
<!-- EE40 is the "TaskViewSettings" glyph -->
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="12"
Glyph="&#xEE40;" />
<TextBlock x:Name="WorkspaceNameText"
Padding="0,0,8,0"
VerticalAlignment="Center"
FontSize="12"
Text="{x:Bind WorkspaceName, Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(WorkspaceName), Mode=OneWay}" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<MenuFlyout x:Name="WorkspaceFlyout" />
</Button.Flyout>
</Button>
</StackPanel>
</mux:TabView.TabStripHeader>
<mux:TabView.TabStripFooter>

View File

@@ -9,27 +9,28 @@ namespace winrt::TerminalApp::implementation
{
// Default to unset, 0%.
TaskbarState::TaskbarState() :
TaskbarState(0, 0) {};
TaskbarState(winrt::Microsoft::Terminal::Control::TaskbarState::Clear, 0) {};
TaskbarState::TaskbarState(const uint64_t dispatchTypesState, const uint64_t progressParam) :
_State{ dispatchTypesState },
TaskbarState::TaskbarState(const winrt::Microsoft::Terminal::Control::TaskbarState state, const uint64_t progressParam) :
_State{ state },
_Progress{ progressParam } {}
uint64_t TaskbarState::Priority() const
{
// This seemingly nonsensical ordering is from
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group
using TbState = winrt::Microsoft::Terminal::Control::TaskbarState;
switch (_State)
{
case 0: // Clear = 0,
case TbState::Clear:
return 5;
case 1: // Set = 1,
case TbState::Set:
return 3;
case 2: // Error = 2,
case TbState::Error:
return 1;
case 3: // Indeterminate = 3,
case TbState::Indeterminate:
return 4;
case 4: // Paused = 4
case TbState::Paused:
return 2;
}
// Here, return 6, to definitely be greater than all the other valid values.

View File

@@ -16,13 +16,13 @@ namespace winrt::TerminalApp::implementation
{
public:
TaskbarState();
TaskbarState(const uint64_t dispatchTypesState, const uint64_t progress);
TaskbarState(const winrt::Microsoft::Terminal::Control::TaskbarState state, const uint64_t progress);
static int ComparePriority(const winrt::TerminalApp::TaskbarState& lhs, const winrt::TerminalApp::TaskbarState& rhs);
uint64_t Priority() const;
WINRT_PROPERTY(uint64_t, State, 0);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::TaskbarState, State, winrt::Microsoft::Terminal::Control::TaskbarState::Clear);
WINRT_PROPERTY(uint64_t, Progress, 0);
};
}

View File

@@ -6,9 +6,9 @@ namespace TerminalApp
[default_interface] runtimeclass TaskbarState
{
TaskbarState();
TaskbarState(UInt64 dispatchTypesState, UInt64 progress);
TaskbarState(Microsoft.Terminal.Control.TaskbarState state, UInt64 progress);
UInt64 State{ get; };
Microsoft.Terminal.Control.TaskbarState State{ get; };
UInt64 Progress{ get; };
UInt64 Priority { get; };
}

View File

@@ -25,6 +25,8 @@
#include "TerminalSettingsCache.h"
#include "LaunchPositionRequest.g.cpp"
#include "WindowListEntry.g.cpp"
#include "WindowListRequest.g.cpp"
#include "RenameWindowRequestedArgs.g.cpp"
#include "RequestMoveContentArgs.g.cpp"
#include "TerminalPage.g.cpp"
@@ -334,6 +336,21 @@ namespace winrt::TerminalApp::implementation
auto tabRowImpl = winrt::get_self<implementation::TabRowControl>(_tabRow);
_newTabButton = tabRowImpl->NewTabButton();
_workspaceFlyout = tabRowImpl->WorkspaceFlyout();
_workspaceDropdown = tabRowImpl->WorkspaceDropdown();
// Set the initial workspace name from the window name.
// Use raw WindowName() so unnamed windows show no text.
_tabRow.WorkspaceName(_WindowProperties.WindowName());
// Rebuild the workspace flyout each time it opens so it always
// reflects the latest set of persisted workspaces.
_workspaceFlyout.Opening([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
page->_PopulateWorkspaceFlyout();
}
});
if (_settings.GlobalSettings().ShowTabsInTitlebar())
{
@@ -443,6 +460,12 @@ namespace winrt::TerminalApp::implementation
_tabRow.ShowElevationShield(IsRunningElevated() && _settings.GlobalSettings().ShowAdminShield());
// Apply the ShowWindowsButton theme setting.
if (const auto theme = _settings.GlobalSettings().CurrentTheme())
{
_tabRow.ShowWindowsButton(theme.Window() ? theme.Window().ShowWindowsButton() : true);
}
_adjustProcessPriorityThrottled = std::make_shared<ThrottledFunc<>>(
DispatcherQueue::GetForCurrentThread(),
til::throttled_func_options{
@@ -2285,14 +2308,14 @@ namespace winrt::TerminalApp::implementation
QuitRequested.raise(nullptr, nullptr);
}
void TerminalPage::PersistState()
WindowLayout TerminalPage::GetWindowLayout()
{
// This method may be called for a window even if it hasn't had a tab yet or lost all of them.
// We shouldn't persist such windows.
const auto tabCount = _tabs.Size();
if (_startupState != StartupState::Initialized || tabCount == 0)
{
return;
return nullptr;
}
std::vector<ActionAndArgs> actions;
@@ -2307,7 +2330,7 @@ namespace winrt::TerminalApp::implementation
// Avoid persisting a window with zero tabs, because `BuildStartupActions` happened to return an empty vector.
if (actions.empty())
{
return;
return nullptr;
}
// if the focused tab was not the last tab, restore that
@@ -2356,7 +2379,49 @@ namespace winrt::TerminalApp::implementation
RequestLaunchPosition.raise(*this, launchPosRequest);
layout.InitialPosition(launchPosRequest.Position());
ApplicationState::SharedInstance().AppendPersistedWindowLayout(layout);
return layout;
}
void TerminalPage::PersistState()
{
// There are two persistence mechanisms in play here:
// * PersistedWindowLayouts (vector) — consumed on next startup to
// re-open a matching set of windows. Cleared after restore.
// * PersistedWorkspaces (name-keyed map) — the full tab/buffer
// state of a named window, claimed by name on demand via
// ApplicationState::TakeWorkspace.
//
// For named windows we save the full layout into the workspace map
// and drop a lightweight `openWorkspace` stub into the generic vector,
// so the generic restore path re-opens the named window which in
// turn claims its own workspace. Unnamed windows don't have a stable
// key, so their full layout is stored directly in the vector.
if (const auto layout = GetWindowLayout())
{
const auto& windowName = _WindowProperties.WindowName();
if (!windowName.empty())
{
// Persist the full layout into the workspace collection.
ApplicationState::SharedInstance().SaveWorkspace(windowName, layout);
// Build a minimal layout with just an openWorkspace action
// so the generic restore path re-opens this workspace by name.
std::vector<ActionAndArgs> actions;
ActionAndArgs action;
action.Action(ShortcutAction::OpenWorkspace);
OpenWorkspaceArgs args{ windowName };
action.Args(args);
actions.emplace_back(std::move(action));
WindowLayout stub;
stub.TabLayout(winrt::single_threaded_vector<ActionAndArgs>(std::move(actions)));
ApplicationState::SharedInstance().AppendPersistedWindowLayout(stub);
}
else
{
ApplicationState::SharedInstance().AppendPersistedWindowLayout(layout);
}
}
}
// Method Description:
@@ -4057,6 +4122,12 @@ namespace winrt::TerminalApp::implementation
_tabRow.ShowElevationShield(IsRunningElevated() && _settings.GlobalSettings().ShowAdminShield());
// Apply the ShowWindowsButton theme setting.
if (const auto theme = _settings.GlobalSettings().CurrentTheme())
{
_tabRow.ShowWindowsButton(theme.Window() ? theme.Window().ShowWindowsButton() : true);
}
Media::SolidColorBrush transparent{ Windows::UI::Colors::Transparent() };
_tabView.Background(transparent);
@@ -5697,6 +5768,199 @@ namespace winrt::TerminalApp::implementation
}
}
// Rebuild the workspace flyout contents. Called every time the flyout opens
// Rebuild the workspace flyout contents. Called every time the flyout opens
// so it reflects the current set of persisted workspaces.
void TerminalPage::_PopulateWorkspaceFlyout()
{
if (!_workspaceFlyout)
{
return;
}
_workspaceFlyout.Items().Clear();
// --- "Name / Rename this window" ---
{
MenuFlyoutItem item{};
item.Text(_WindowProperties.WindowName().empty() ? RS_(L"NameThisWindowMenuItem") : RS_(L"RenameThisWindowMenuItem"));
auto iconElement = UI::IconPathConverter::IconWUX(L"\uE8AC"); // Rename glyph
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
item.Icon(iconElement);
item.Click([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
page->_actionDispatch->DoAction(ActionAndArgs{ ShortcutAction::OpenWindowRenamer, nullptr });
}
});
_workspaceFlyout.Items().Append(item);
}
// --- Gather open window info first so we can filter workspaces ---
const auto windowListReq{ winrt::make<WindowListRequest>() };
RequestWindowList.raise(*this, windowListReq);
const auto windowEntries = windowListReq.Entries();
std::set<winrt::hstring> openWindowNames;
if (windowEntries)
{
for (const auto& entry : windowEntries)
{
const auto& name = entry.Name();
if (!name.empty())
{
openWindowNames.emplace(name);
}
}
}
// --- Saved workspaces section (only those not currently open) ---
// Collect workspace names that aren't currently open so we can show
// them both as top-level "open" items and inside the delete sub-menu.
const auto workspaces = ApplicationState::SharedInstance().AllPersistedWorkspaces();
if (workspaces && workspaces.Size() > 0)
{
bool addedSeparator = false;
for (const auto& pair : workspaces)
{
const auto name = pair.Key();
// Skip workspaces that correspond to a currently-open window.
if (openWindowNames.count(name))
{
continue;
}
if (!addedSeparator)
{
_workspaceFlyout.Items().Append(MenuFlyoutSeparator{});
addedSeparator = true;
}
MenuFlyoutItem item{};
item.Text(name);
auto iconElement = UI::IconPathConverter::IconWUX(L"\uE8F1"); // SwitchApps glyph
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
item.Icon(iconElement);
item.Click([weakThis{ get_weak() }, name](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
page->_OpenWorkspaceWindow(name);
}
});
// Right-click to delete: attach a context flyout with a
// "Delete workspace?" item that opens a confirmation dialog.
{
WUX::Controls::MenuFlyout deleteFlyout{};
deleteFlyout.Placement(WUX::Controls::Primitives::FlyoutPlacementMode::BottomEdgeAlignedRight);
WUX::Controls::MenuFlyoutItem deleteItem{};
deleteItem.Text(RS_(L"DeleteWorkspaceMenuItem"));
WUX::Controls::FontIcon trashIcon{};
trashIcon.Glyph(L"\xE74D"); // Delete glyph
trashIcon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
deleteItem.Icon(trashIcon);
deleteItem.Click([weakThis{ get_weak() }, name](auto&&, auto&&) -> safe_void_coroutine {
auto page{ weakThis.get() };
if (!page)
{
co_return;
}
// Build and show a confirmation ContentDialog.
ContentDialog dialog{};
dialog.Title(winrt::box_value(winrt::hstring{ RS_fmt(L"ConfirmDeleteWorkspaceTitle", name) }));
dialog.PrimaryButtonText(RS_(L"ConfirmDeleteWorkspaceDelete"));
dialog.CloseButtonText(RS_(L"ConfirmDeleteWorkspaceCancel"));
dialog.DefaultButton(ContentDialogButton::Close);
if (auto presenter{ page->_dialogPresenter.get() })
{
const auto result = co_await presenter.ShowDialog(dialog);
// Re-check after co_await
page = weakThis.get();
if (!page)
{
co_return;
}
if (result == ContentDialogResult::Primary)
{
ApplicationState::SharedInstance().RemoveWorkspace(name);
page->_PopulateWorkspaceFlyout();
}
}
});
deleteFlyout.Items().Append(deleteItem);
WUX::Controls::Primitives::FlyoutBase::SetAttachedFlyout(item, deleteFlyout);
item.ContextRequested([item](auto&&, auto&&) {
WUX::Controls::Primitives::FlyoutBase::ShowAttachedFlyout(item);
});
}
_workspaceFlyout.Items().Append(item);
}
}
// --- Open windows section ---
if (windowEntries && windowEntries.Size() > 0)
{
_workspaceFlyout.Items().Append(MenuFlyoutSeparator{});
const auto thisWindowId = _WindowProperties.WindowId();
for (const auto& entry : windowEntries)
{
const auto id = entry.Id();
const auto& name = entry.Name();
winrt::hstring displayText;
if (name.empty())
{
displayText = winrt::hstring{ RS_fmt(L"WindowListUnnamedEntry", id) };
}
else
{
displayText = winrt::hstring{ fmt::format(FMT_COMPILE(L"#{}: {}"), id, name) };
}
MenuFlyoutItem item{};
item.Text(displayText);
if (id == thisWindowId)
{
auto iconElement = UI::IconPathConverter::IconWUX(L"\uE73E"); // CheckMark glyph
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
item.Icon(iconElement);
item.IsEnabled(false);
}
else
{
auto iconElement = UI::IconPathConverter::IconWUX(L"\uE737"); // ChromeRestore glyph
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
item.Icon(iconElement);
item.Click([weakThis{ get_weak() }, id](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
page->SummonWindowByIdRequested.raise(*page, winrt::make<SummonWindowByIdRequestedArgs>(id));
}
});
}
_workspaceFlyout.Items().Append(item);
}
}
}
// Handler for our WindowProperties's PropertyChanged event. We'll use this
// to pop the "Identify Window" toast when the user renames our window.
void TerminalPage::_windowPropertyChanged(const IInspectable& /*sender*/, const WUX::Data::PropertyChangedEventArgs& args)
@@ -5706,6 +5970,10 @@ namespace winrt::TerminalApp::implementation
return;
}
// Keep the workspace dropdown label in sync with the window name.
// Use raw WindowName() so clearing the name hides the text.
_tabRow.WorkspaceName(_WindowProperties.WindowName());
// DON'T display the confirmation if this is the name we were
// given on startup!
if (_startupState == StartupState::Initialized)

View File

@@ -10,8 +10,11 @@
#include "AppKeyBindings.h"
#include "AppCommandlineArgs.h"
#include "RenameWindowRequestedArgs.g.h"
#include "SummonWindowByIdRequestedArgs.g.h"
#include "RequestMoveContentArgs.g.h"
#include "LaunchPositionRequest.g.h"
#include "WindowListEntry.g.h"
#include "WindowListRequest.g.h"
#include "Toast.h"
#include "WindowsPackageManagerFactory.h"
@@ -73,6 +76,15 @@ namespace winrt::TerminalApp::implementation
_ProposedName{ name } {};
};
struct SummonWindowByIdRequestedArgs : SummonWindowByIdRequestedArgsT<SummonWindowByIdRequestedArgs>
{
WINRT_PROPERTY(uint64_t, WindowId);
public:
SummonWindowByIdRequestedArgs(uint64_t id) :
_WindowId{ id } {};
};
struct RequestMoveContentArgs : RequestMoveContentArgsT<RequestMoveContentArgs>
{
WINRT_PROPERTY(winrt::hstring, Window);
@@ -94,6 +106,25 @@ namespace winrt::TerminalApp::implementation
til::property<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> Position;
};
struct WindowListEntry : WindowListEntryT<WindowListEntry>
{
WindowListEntry() = default;
til::property<uint64_t> Id;
til::property<winrt::hstring> Name;
};
struct WindowListRequest : WindowListRequestT<WindowListRequest>
{
WindowListRequest() :
_Entries{ winrt::single_threaded_vector<winrt::TerminalApp::WindowListEntry>() } {}
winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::WindowListEntry> Entries() const { return _Entries; }
private:
winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::WindowListEntry> _Entries;
};
struct WinGetSearchParams
{
winrt::Microsoft::Management::Deployment::PackageMatchField Field;
@@ -132,6 +163,7 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine RequestQuit();
safe_void_coroutine CloseWindow();
winrt::Microsoft::Terminal::Settings::Model::WindowLayout GetWindowLayout();
void PersistState();
std::vector<IPaneContent> Panes() const;
@@ -203,6 +235,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<IInspectable, IInspectable> IdentifyWindowsRequested;
til::typed_event<IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs> RenameWindowRequested;
til::typed_event<IInspectable, IInspectable> SummonWindowRequested;
til::typed_event<IInspectable, winrt::TerminalApp::SummonWindowByIdRequestedArgs> SummonWindowByIdRequested;
til::typed_event<IInspectable, winrt::TerminalApp::Tab> FocusTabRequested;
til::typed_event<IInspectable, winrt::Microsoft::Terminal::Control::WindowSizeChangedEventArgs> WindowSizeChanged;
@@ -215,6 +248,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs> RequestReceiveContent;
til::typed_event<IInspectable, winrt::TerminalApp::LaunchPositionRequest> RequestLaunchPosition;
til::typed_event<IInspectable, winrt::TerminalApp::WindowListRequest> RequestWindowList;
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, PropertyChanged.raise, nullptr);
@@ -237,6 +271,8 @@ namespace winrt::TerminalApp::implementation
TerminalApp::TabRowControl _tabRow{ nullptr };
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
Microsoft::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr };
Windows::UI::Xaml::Controls::MenuFlyout _workspaceFlyout{ nullptr };
Windows::UI::Xaml::Controls::Button _workspaceDropdown{ nullptr };
winrt::TerminalApp::ColorPickupFlyout _tabColorPicker{ nullptr };
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
@@ -335,6 +371,7 @@ namespace winrt::TerminalApp::implementation
void _restartPaneConnection(const TerminalApp::TerminalPaneContent&, const winrt::Windows::Foundation::IInspectable&);
safe_void_coroutine _OpenNewWindow(const Microsoft::Terminal::Settings::Model::INewContentArgs newContentArgs);
safe_void_coroutine _OpenWorkspaceWindow(const winrt::hstring name);
void _OpenNewTerminalViaDropdown(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
@@ -577,6 +614,7 @@ namespace winrt::TerminalApp::implementation
void _PopulateContextMenu(const Microsoft::Terminal::Control::TermControl& control, const Microsoft::UI::Xaml::Controls::CommandBarFlyout& sender, const bool withSelection);
void _PopulateQuickFixMenu(const Microsoft::Terminal::Control::TermControl& control, const Windows::UI::Xaml::Controls::MenuFlyout& sender);
void _PopulateWorkspaceFlyout();
winrt::Windows::UI::Xaml::Controls::MenuFlyout _CreateRunAsAdminFlyout(int profileIndex);
winrt::Microsoft::Terminal::Control::TermControl _senderOrActiveControl(const winrt::Windows::Foundation::IInspectable& sender);
@@ -603,4 +641,5 @@ namespace winrt::TerminalApp::implementation
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TerminalPage);
BASIC_FACTORY(WindowListEntry);
}

View File

@@ -19,6 +19,10 @@ namespace TerminalApp
{
String ProposedName { get; };
};
[default_interface] runtimeclass SummonWindowByIdRequestedArgs
{
UInt64 WindowId { get; };
};
[default_interface] runtimeclass RequestMoveContentArgs
{
String Window { get; };
@@ -50,6 +54,20 @@ namespace TerminalApp
Microsoft.Terminal.Settings.Model.LaunchPosition Position;
}
[default_interface] runtimeclass WindowListEntry
{
WindowListEntry();
UInt64 Id;
String Name;
}
// Raised by TerminalPage when it needs the list of open windows.
// The handler (AppHost) fills Entries synchronously.
[default_interface] runtimeclass WindowListRequest
{
Windows.Foundation.Collections.IVector<WindowListEntry> Entries { get; };
}
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged, Microsoft.Terminal.UI.IDirectKeyListener
{
TerminalPage(WindowProperties properties, ContentManager manager);
@@ -93,6 +111,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, SummonWindowByIdRequestedArgs> SummonWindowByIdRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.WindowSizeChangedEventArgs> WindowSizeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
@@ -103,5 +122,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
event Windows.Foundation.TypedEventHandler<Object, LaunchPositionRequest> RequestLaunchPosition;
event Windows.Foundation.TypedEventHandler<Object, WindowListRequest> RequestWindowList;
}
}

View File

@@ -10,6 +10,7 @@
#include "../../types/inc/utils.hpp"
#include "BellEventArgs.g.cpp"
#include "NotificationEventArgs.g.cpp"
#include "TerminalPaneContent.g.cpp"
using namespace winrt::Windows::Foundation;
@@ -34,6 +35,7 @@ namespace winrt::TerminalApp::implementation
{
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_controlConnectionStateChangedHandler });
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlWarningBellHandler });
_controlEvents._PromptStarted = _control.PromptStarted(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlPromptStartedHandler });
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_closeTerminalRequestedHandler });
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_restartTerminalRequestedHandler });
@@ -42,6 +44,9 @@ namespace winrt::TerminalApp::implementation
_controlEvents._SetTaskbarProgress = _control.SetTaskbarProgress(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlSetTaskbarProgress });
_controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlReadOnlyChanged });
_controlEvents._FocusFollowMouseRequested = _control.FocusFollowMouseRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlFocusFollowMouseRequested });
_controlEvents._ShowNotification = _control.ShowNotification(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlShowNotification });
_controlEvents._OutputStarted = _control.OutputStarted(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlOutputStartedHandler });
_controlEvents._OutputBurstEnded = _control.OutputIdle(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlOutputBurstEndedHandler });
}
void TerminalPaneContent::_removeControlEvents()
{
@@ -71,6 +76,18 @@ namespace winrt::TerminalApp::implementation
_removeControlEvents();
_control.Close();
// Clear out our media player callbacks, and stop any playing media. This
// will prevent the callback from being triggered after we've closed, and
// also make sure that our sound stops when we're closed.
if (_bellPlayer)
{
_bellPlayer.Pause();
_bellPlayer.Source(nullptr);
_bellPlayer.Close();
_bellPlayer = nullptr;
_bellPlayerCreated = false;
}
}
winrt::hstring TerminalPaneContent::Icon() const
@@ -161,6 +178,16 @@ namespace winrt::TerminalApp::implementation
{
TaskbarProgressChanged.raise(*this, nullptr);
}
winrt::Microsoft::Terminal::Control::TaskbarState TerminalPaneContent::TaskbarState()
{
return _control.TaskbarState();
}
uint64_t TerminalPaneContent::TaskbarProgress()
{
return _control.TaskbarProgress();
}
void TerminalPaneContent::_controlReadOnlyChanged(const IInspectable&, const IInspectable&)
{
ReadOnlyChanged.raise(*this, nullptr);
@@ -170,6 +197,11 @@ namespace winrt::TerminalApp::implementation
FocusRequested.raise(*this, nullptr);
}
void TerminalPaneContent::_controlShowNotification(const IInspectable& /*sender*/, const ShowNotificationEventArgs& args)
{
NotificationRequested.raise(*this, winrt::make<implementation::NotificationEventArgs>(OutputNotificationStyle::Notification, true, args.Title(), args.Body()));
}
// Method Description:
// - Called when our attached control is closed. Triggers listeners to our close
// event, if we're a leaf pane.
@@ -249,6 +281,25 @@ namespace winrt::TerminalApp::implementation
// has the 'visual' flag set
// Arguments:
// - <unused>
void TerminalPaneContent::PlayNotificationSound()
{
if (_profile)
{
auto sounds{ _profile.BellSound() };
if (sounds && sounds.Size() > 0)
{
winrt::hstring soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
winrt::Windows::Foundation::Uri uri{ soundPath };
_playBellSound(uri);
}
else
{
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
}
}
void TerminalPaneContent::_controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
@@ -260,19 +311,7 @@ namespace winrt::TerminalApp::implementation
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
{
// Audible is set, play the sound
auto sounds{ _profile.BellSound() };
if (sounds && sounds.Size() > 0)
{
// Sound paths are resolved and validated by CascadiaSettings
// before we reach this point.
auto soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
PlaySoundW(soundPath.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_SENTRY | SND_NODEFAULT);
}
else
{
const auto soundAlias = reinterpret_cast<LPCWSTR>(SND_ALIAS_SYSTEMHAND);
PlaySoundW(soundAlias, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
PlayNotificationSound();
}
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
@@ -289,6 +328,95 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPaneContent::_controlPromptStartedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (_profile)
{
const auto notifyStyle = _profile.NotifyOnNextPrompt();
if (notifyStyle != OutputNotificationStyle::None)
{
if (const auto thresholdInSeconds = _profile.NotifyOnNextPromptThreshold(); thresholdInSeconds > 0)
{
if (_lastOutputStartedAt == 0)
{
return;
}
if (const auto elapsedMs = GetTickCount64() - _lastOutputStartedAt; elapsedMs < (static_cast<uint64_t>(thresholdInSeconds) * 1000))
{
_lastOutputStartedAt = 0;
return;
}
}
_lastOutputStartedAt = 0;
NotificationRequested.raise(*this,
*winrt::make_self<TerminalApp::implementation::NotificationEventArgs>(notifyStyle, false));
}
}
}
void TerminalPaneContent::_controlOutputStartedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
_lastOutputStartedAt = GetTickCount64();
}
// The underlying TermControl::OutputIdle event is fired on the trailing
// edge of a 100ms-debounced output burst (see ControlCore::Initialize).
// When "notifyOnActivity" is enabled, we get one event per burst of
// output, which naturally coalesces a stream of output into a single notification.
void TerminalPaneContent::_controlOutputBurstEndedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (_profile)
{
const auto notifyStyle = _profile.NotifyOnActivity();
if (notifyStyle != OutputNotificationStyle::None)
{
const auto now = GetTickCount64();
const auto thresholdSeconds = _profile.NotifyOnActivityThreshold();
if (thresholdSeconds > 0 &&
_lastActivityNotificationAt != 0 &&
(now - _lastActivityNotificationAt) < (static_cast<uint64_t>(thresholdSeconds) * 1000))
{
return;
}
_lastActivityNotificationAt = now;
NotificationRequested.raise(*this,
*winrt::make_self<TerminalApp::implementation::NotificationEventArgs>(notifyStyle, false));
}
}
}
safe_void_coroutine TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri)
{
auto weakThis{ get_weak() };
co_await wil::resume_foreground(_control.Dispatcher());
if (auto pane{ weakThis.get() })
{
if (!_bellPlayerCreated)
{
// The MediaPlayer might not exist on Windows N SKU.
try
{
_bellPlayerCreated = true;
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
_bellPlayer.CommandManager().IsEnabled(false);
}
CATCH_LOG();
}
if (_bellPlayer)
{
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
_bellPlayer.Source(item);
_bellPlayer.Play();
}
}
}
void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{

View File

@@ -24,9 +24,11 @@ namespace winrt::TerminalApp::implementation
struct NotificationEventArgs : public NotificationEventArgsT<NotificationEventArgs>
{
public:
NotificationEventArgs(const winrt::hstring& title = {}, const winrt::hstring& body = {}) :
Title(title), Body(body) {}
NotificationEventArgs(winrt::Microsoft::Terminal::Control::OutputNotificationStyle style, bool alwaysNotify = true, const winrt::hstring& title = {}, const winrt::hstring& body = {}) :
Style(style), AlwaysNotify(alwaysNotify), Title(title), Body(body) {}
til::property<winrt::Microsoft::Terminal::Control::OutputNotificationStyle> Style;
til::property<bool> AlwaysNotify;
til::property<winrt::hstring> Title;
til::property<winrt::hstring> Body;
};
@@ -48,6 +50,7 @@ namespace winrt::TerminalApp::implementation
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
void MarkAsDefterm();
void PlayNotificationSound();
winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const
{
@@ -55,8 +58,8 @@ namespace winrt::TerminalApp::implementation
}
winrt::hstring Title() { return _control.Title(); }
uint64_t TaskbarState() { return _control.TaskbarState(); }
uint64_t TaskbarProgress() { return _control.TaskbarProgress(); }
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState();
uint64_t TaskbarProgress();
bool ReadOnly() { return _control.ReadOnly(); }
winrt::hstring Icon() const;
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept;
@@ -76,10 +79,21 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<TerminalSettingsCache> _cache{};
bool _isDefTermSession{ false };
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
bool _bellPlayerCreated{ false };
// Tracks the GetTickCount64() for NotifyOnActivityThreshold
// and NotifyOnNextPromptThreshold respectively.
uint64_t _lastActivityNotificationAt{ 0 };
uint64_t _lastOutputStartedAt{ 0 };
struct ControlEventTokens
{
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
winrt::Microsoft::Terminal::Control::TermControl::PromptStarted_revoker _PromptStarted;
winrt::Microsoft::Terminal::Control::TermControl::OutputStarted_revoker _OutputStarted;
winrt::Microsoft::Terminal::Control::TermControl::OutputIdle_revoker _OutputBurstEnded;
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
@@ -88,14 +102,20 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Control::TermControl::SetTaskbarProgress_revoker _SetTaskbarProgress;
winrt::Microsoft::Terminal::Control::TermControl::ReadOnlyChanged_revoker _ReadOnlyChanged;
winrt::Microsoft::Terminal::Control::TermControl::FocusFollowMouseRequested_revoker _FocusFollowMouseRequested;
winrt::Microsoft::Terminal::Control::TermControl::ShowNotification_revoker _ShowNotification;
} _controlEvents;
void _setupControlEvents();
void _removeControlEvents();
safe_void_coroutine _playBellSound(winrt::Windows::Foundation::Uri uri);
safe_void_coroutine _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _controlPromptStartedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& eventArgs);
void _controlOutputStartedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& eventArgs);
void _controlOutputBurstEndedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& eventArgs);
void _controlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);
void _controlTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
@@ -103,6 +123,7 @@ namespace winrt::TerminalApp::implementation
void _controlSetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlReadOnlyChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlFocusFollowMouseRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlShowNotification(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Microsoft::Terminal::Control::ShowNotificationEventArgs& args);
void _closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _restartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);

View File

@@ -11,6 +11,7 @@ namespace TerminalApp
Microsoft.Terminal.Control.TermControl GetTermControl();
void MarkAsDefterm();
void PlayNotificationSound();
Microsoft.Terminal.Settings.Model.Profile GetProfile();

View File

@@ -17,6 +17,7 @@ namespace winrt::TerminalApp::implementation
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, BellIndicator, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, ActivityIndicator, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsReadOnlyActive, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(uint32_t, ProgressValue, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsInputBroadcastActive, PropertyChanged.raise);

View File

@@ -12,6 +12,7 @@ namespace TerminalApp
Boolean IsProgressRingActive { get; set; };
Boolean IsProgressRingIndeterminate { get; set; };
Boolean BellIndicator { get; set; };
Boolean ActivityIndicator { get; set; };
UInt32 ProgressValue { get; set; };
Boolean IsReadOnlyActive { get; set; };
Boolean IsInputBroadcastActive { get; set; };

View File

@@ -258,6 +258,15 @@ namespace winrt::TerminalApp::implementation
AppLogic::Current()->NotifyRootInitialized();
}
WindowLayout TerminalWindow::GetWindowLayout()
{
if (_root)
{
return _root->GetWindowLayout();
}
return nullptr;
}
void TerminalWindow::PersistState()
{
if (_root)
@@ -1103,6 +1112,11 @@ namespace winrt::TerminalApp::implementation
_initialContentArgs = wil::to_vector(args);
}
void TerminalWindow::SetPersistedLayout(const winrt::Microsoft::Terminal::Settings::Model::WindowLayout& layout)
{
_cachedLayout = layout;
}
// Method Description:
// - Parse the provided commandline arguments into actions, and try to
// perform them immediately.
@@ -1223,7 +1237,14 @@ namespace winrt::TerminalApp::implementation
void TerminalWindow::WindowName(const winrt::hstring& name)
{
const auto oldIsQuakeMode = _WindowProperties->IsQuakeWindow();
const auto oldName = _WindowProperties->WindowName();
_WindowProperties->WindowName(name);
// If this window had a persisted workspace under the old name, rename
// that entry too so we don't leave a stale copy behind.
if (!oldName.empty() && !name.empty() && oldName != name)
{
ApplicationState::SharedInstance().RenameWorkspace(oldName, name);
}
if (!_root)
{
return;

View File

@@ -71,6 +71,7 @@ namespace winrt::TerminalApp::implementation
void Create();
winrt::Microsoft::Terminal::Settings::Model::WindowLayout GetWindowLayout();
void PersistState();
void UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args);
@@ -79,6 +80,7 @@ namespace winrt::TerminalApp::implementation
int32_t SetStartupCommandline(TerminalApp::CommandlineArgs args);
void SetStartupContent(const winrt::hstring& content, const Windows::Foundation::IReference<Windows::Foundation::Rect>& contentBounds);
void SetPersistedLayout(const winrt::Microsoft::Terminal::Settings::Model::WindowLayout& layout);
int32_t ExecuteCommandline(TerminalApp::CommandlineArgs args);
void SetSettingsStartupArgs(const std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
@@ -222,6 +224,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
FORWARDED_TYPED_EVENT(SummonWindowByIdRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::SummonWindowByIdRequestedArgs, _root, SummonWindowByIdRequested);
FORWARDED_TYPED_EVENT(FocusTabRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::Tab, _root, FocusTabRequested);
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
@@ -231,6 +234,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs, _root, RequestReceiveContent);
FORWARDED_TYPED_EVENT(RequestLaunchPosition, Windows::Foundation::IInspectable, winrt::TerminalApp::LaunchPositionRequest, _root, RequestLaunchPosition);
FORWARDED_TYPED_EVENT(RequestWindowList, Windows::Foundation::IInspectable, winrt::TerminalApp::WindowListRequest, _root, RequestWindowList);
#ifdef UNIT_TESTING
friend class TerminalAppLocalTests::CommandlineTest;

View File

@@ -56,11 +56,13 @@ namespace TerminalApp
Int32 SetStartupCommandline(CommandlineArgs args);
void SetStartupContent(String json, Windows.Foundation.IReference<Windows.Foundation.Rect> bounds);
void SetPersistedLayout(Microsoft.Terminal.Settings.Model.WindowLayout layout);
Int32 ExecuteCommandline(CommandlineArgs args);
Boolean ShouldImmediatelyHandoffToElevated();
void HandoffToElevated();
Microsoft.Terminal.Settings.Model.WindowLayout GetWindowLayout();
void PersistState();
Windows.UI.Xaml.UIElement GetRoot();
@@ -128,6 +130,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, SummonWindowByIdRequestedArgs> SummonWindowByIdRequested;
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.Tab> FocusTabRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
@@ -140,6 +143,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
event Windows.Foundation.TypedEventHandler<Object, LaunchPositionRequest> RequestLaunchPosition;
event Windows.Foundation.TypedEventHandler<Object, WindowListRequest> RequestWindowList;
void AttachContent(String content, UInt32 tabIndex);
void SendContentToOther(RequestReceiveContentArgs args);

View File

@@ -139,6 +139,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnSearchMissingCommand = [this](auto&& PH1, auto&& PH2) { _terminalSearchMissingCommand(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
_terminal->SetSearchMissingCommandCallback(pfnSearchMissingCommand);
auto pfnShowNotification = [this](auto&& PH1, auto&& PH2) { _terminalShowNotification(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
_terminal->SetShowNotificationCallback(pfnShowNotification);
auto pfnPromptStarted = [this] { _terminalPromptStarted(); };
_terminal->SetPromptStartedCallback(pfnPromptStarted);
auto pfnOutputStarted = [this] { _terminalOutputStarted(); };
_terminal->SetOutputStartedCallback(pfnOutputStarted);
auto pfnClearQuickFix = [this] { ClearQuickFix(); };
_terminal->SetClearQuickFixCallback(pfnClearQuickFix);
@@ -913,6 +922,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_hasUnfocusedAppearance = static_cast<bool>(newAppearance);
_unfocusedAppearance = _hasUnfocusedAppearance ? newAppearance : settings;
// Cache the auto-detect setting in an atomic so the off-thread output/prompt
// callbacks can read it without synchronizing with _settings. If the effective
// taskbar state changes (because a command is currently active and the setting
// toggled), notify listeners.
const auto nowEnabled = _settings.AutoDetectRunningCommand();
const auto wasEnabled = _autoDetectCommandActivity.exchange(nowEnabled, std::memory_order_relaxed);
if (wasEnabled != nowEnabled && _commandActive.load(std::memory_order_relaxed))
{
TaskbarProgressChanged.raise(*this, nullptr);
}
const auto lock = _terminal->LockForWriting();
_builtinGlyphs = _settings.EnableBuiltinGlyphs();
@@ -925,7 +945,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Manually turn off acrylic if they turn off transparency.
_runtimeUseAcrylic = _settings.Opacity() < 1.0 && _settings.UseAcrylic();
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta);
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize());
// Update the terminal core with its new Core settings
_terminal->UpdateSettings(_settings);
@@ -1163,10 +1183,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - none
void ControlCore::ResetFontSize()
{
if (std::exchange(_accumulatedFontSizeDelta, 0.f) != 0.f)
const auto lock = _terminal->LockForWriting();
if (_setFontSizeUnderLock(_settings.FontSize()))
{
// No point in doing this if there was no delta.
AdjustFontSize(0);
_refreshSizeUnderLock();
}
}
@@ -1176,11 +1197,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - fontSizeDelta: The amount to increase or decrease the font size by.
void ControlCore::AdjustFontSize(float fontSizeDelta)
{
_accumulatedFontSizeDelta += fontSizeDelta;
const auto lock = _terminal->LockForWriting();
if (_setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta))
if (_setFontSizeUnderLock(_desiredFont.GetFontSize() + fontSizeDelta))
{
_refreshSizeUnderLock();
}
@@ -1548,10 +1567,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - Gets the internal taskbar state value
// Return Value:
// - The taskbar state of this control
const size_t ControlCore::TaskbarState() const noexcept
const Control::TaskbarState ControlCore::TaskbarState() const noexcept
{
const auto lock = _terminal->LockForReading();
return _terminal->GetTaskbarState();
const auto vtState = static_cast<Control::TaskbarState>(_terminal->GetTaskbarState());
if (vtState == Control::TaskbarState::Clear &&
_autoDetectCommandActivity.load(std::memory_order_relaxed) &&
_commandActive.load(std::memory_order_relaxed))
{
return Control::TaskbarState::Indeterminate;
}
return vtState;
}
// Method Description:
@@ -1581,6 +1607,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _terminal->GetViewport().Height();
}
// Function Description:
// - Gets the width of the terminal in columns. This is just the
// width of the viewport.
// Return Value:
// - The width of the terminal in columns
int ControlCore::ViewWidth() const
{
const auto lock = _terminal->LockForReading();
return _terminal->GetViewport().Width();
}
// Function Description:
// - Gets the height of the terminal in lines of text. This includes the
// history AND the viewport.
@@ -1600,6 +1637,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WarningBell.raise(*this, nullptr);
}
void ControlCore::_terminalPromptStarted()
{
if (_commandActive.exchange(false, std::memory_order_relaxed) &&
_autoDetectCommandActivity.load(std::memory_order_relaxed))
{
TaskbarProgressChanged.raise(*this, nullptr);
}
PromptStarted.raise(*this, nullptr);
}
void ControlCore::_terminalOutputStarted()
{
if (!_commandActive.exchange(true, std::memory_order_relaxed) &&
_autoDetectCommandActivity.load(std::memory_order_relaxed))
{
TaskbarProgressChanged.raise(*this, nullptr);
}
OutputStarted.raise(*this, nullptr);
}
// Method Description:
// - Called for the Terminal's TitleChanged callback. This will re-raise
// a new winrt TypedEvent that can be listened to.
@@ -1692,6 +1749,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
SearchMissingCommand.raise(*this, make<implementation::SearchMissingCommandEventArgs>(hstring{ missingCommand }, bufferRow));
}
void ControlCore::_terminalShowNotification(std::wstring_view title, std::wstring_view body)
{
ShowNotification.raise(*this, make<implementation::ShowNotificationEventArgs>(hstring{ title }, hstring{ body }));
}
void ControlCore::OpenCWD()
{
const auto workingDirectory = WorkingDirectory();
@@ -2339,6 +2401,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
_terminal->Write(sequence);
// Clear scroll marks so they don't remain stale in the scrollbar.
// The Scrollback case is already handled by the \x1b[3J path (TextBuffer::ClearScrollback).
if (clearType != ClearBufferType::Scrollback)
{
_terminal->ClearAllMarks();
}
}
if (clearType == Control::ClearBufferType::Screen || clearType == Control::ClearBufferType::All)

View File

@@ -161,7 +161,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void OpenCWD();
#pragma region ICoreState
const size_t TaskbarState() const noexcept;
const Control::TaskbarState TaskbarState() const noexcept;
const size_t TaskbarProgress() const noexcept;
hstring Title();
@@ -172,6 +172,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
int ScrollOffset();
int ViewHeight() const;
int ViewWidth() const;
int BufferHeight() const;
bool HasSelection() const;
@@ -275,6 +276,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
til::typed_event<IInspectable, Control::WriteToClipboardEventArgs> WriteToClipboard;
til::typed_event<> WarningBell;
til::typed_event<> PromptStarted;
til::typed_event<> OutputStarted;
til::typed_event<> TabColorChanged;
til::typed_event<> BackgroundColorChanged;
til::typed_event<IInspectable, Control::ScrollPositionChangedArgs> ScrollPositionChanged;
@@ -292,6 +295,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<IInspectable, Control::OpenHyperlinkEventArgs> OpenHyperlink;
til::typed_event<IInspectable, Control::CompletionsChangedEventArgs> CompletionsChanged;
til::typed_event<IInspectable, Control::SearchMissingCommandEventArgs> SearchMissingCommand;
til::typed_event<IInspectable, Control::ShowNotificationEventArgs> ShowNotification;
til::typed_event<> RefreshQuickFixUI;
til::typed_event<IInspectable, Control::WindowSizeChangedEventArgs> WindowSizeChanged;
@@ -323,6 +327,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region TerminalCoreCallbacks
void _terminalWarningBell();
void _terminalPromptStarted();
void _terminalOutputStarted();
void _terminalTitleChanged(std::wstring_view wstr);
void _terminalScrollPositionChanged(const int viewTop,
const int viewHeight,
@@ -333,6 +339,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const int velocity,
const std::chrono::microseconds duration);
void _terminalSearchMissingCommand(std::wstring_view missingCommand, const til::CoordType& bufferRow);
void _terminalShowNotification(std::wstring_view title, std::wstring_view body);
void _terminalWindowSizeChanged(int32_t width, int32_t height);
void _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
@@ -391,7 +398,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _colorGlyphs = true;
CSSLengthPercentage _cellWidth;
CSSLengthPercentage _cellHeight;
float _accumulatedFontSizeDelta = 0.f; // Preserved across reloads to prevent user zoom from being overwritten.
// Rendering stuff.
winrt::handle _lastSwapChainHandle{ nullptr };
@@ -420,6 +426,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::optional<til::point> _lastHoveredCell;
uint16_t _lastHoveredId{ 0 };
std::atomic<bool> _initializedTerminal{ false };
std::atomic<bool> _autoDetectCommandActivity{ false };
std::atomic<bool> _commandActive{ false };
bool _isReadOnly{ false };
bool _closing{ false };

View File

@@ -192,12 +192,15 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, WriteToClipboardEventArgs> WriteToClipboard;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
event Windows.Foundation.TypedEventHandler<Object, Object> PromptStarted;
event Windows.Foundation.TypedEventHandler<Object, Object> OutputStarted;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
event Windows.Foundation.TypedEventHandler<Object, ShowNotificationEventArgs> ShowNotification;
event Windows.Foundation.TypedEventHandler<Object, Object> RefreshQuickFixUI;
event Windows.Foundation.TypedEventHandler<Object, WindowSizeChangedEventArgs> WindowSizeChanged;

View File

@@ -20,6 +20,7 @@
#include "CharSentEventArgs.g.h"
#include "StringSentEventArgs.g.h"
#include "SearchMissingCommandEventArgs.g.h"
#include "ShowNotificationEventArgs.g.h"
#include "WindowSizeChangedEventArgs.g.h"
namespace winrt::Microsoft::Terminal::Control::implementation
@@ -252,6 +253,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::property<til::CoordType> BufferRow;
};
struct ShowNotificationEventArgs : public ShowNotificationEventArgsT<ShowNotificationEventArgs>
{
public:
ShowNotificationEventArgs(const winrt::hstring& title, const winrt::hstring& body) :
Title(title),
Body(body) {}
til::property<winrt::hstring> Title;
til::property<winrt::hstring> Body;
};
struct WindowSizeChangedEventArgs : public WindowSizeChangedEventArgsT<WindowSizeChangedEventArgs>
{
public:

View File

@@ -160,6 +160,12 @@ namespace Microsoft.Terminal.Control
Int32 BufferRow { get; };
}
runtimeclass ShowNotificationEventArgs
{
String Title { get; };
String Body { get; };
}
runtimeclass WindowSizeChangedEventArgs
{
Int32 Width;

View File

@@ -29,6 +29,30 @@ namespace Microsoft.Terminal.Control
MinGW,
};
[flags]
enum OutputNotificationStyle
{
None = 0,
Taskbar = 0x1,
Audible = 0x2,
Tab = 0x4,
Notification = 0x8,
All = 0xffffffff
};
// Mirrors Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState
// (which is shared with conhost and lives outside the WinRT projection).
// Values must remain numerically identical so the conversion at the
// ControlCore boundary is a 1:1 cast.
enum TaskbarState
{
Clear = 0,
Set = 1,
Error = 2,
Indeterminate = 3,
Paused = 4,
};
// Class Description:
// TerminalSettings encapsulates all settings that control the
// TermControl's behavior. In these settings there is both the entirety
@@ -78,6 +102,12 @@ namespace Microsoft.Terminal.Control
PathTranslationStyle PathTranslationStyle { get; };
String DragDropDelimiter { get; };
OutputNotificationStyle NotifyOnActivity { get; };
OutputNotificationStyle NotifyOnNextPrompt { get; };
Int32 NotifyOnActivityThreshold { get; };
Int32 NotifyOnNextPromptThreshold { get; };
Boolean AutoDetectRunningCommand { get; };
// NOTE! When adding something here, make sure to update ControlProperties.h too!
};
}

View File

@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "IControlSettings.idl";
namespace Microsoft.Terminal.Control
{
enum MarkCategory
@@ -31,7 +33,7 @@ namespace Microsoft.Terminal.Control
interface ICoreState
{
String Title { get; };
UInt64 TaskbarState { get; };
Microsoft.Terminal.Control.TaskbarState TaskbarState { get; };
UInt64 TaskbarProgress { get; };
String WorkingDirectory { get; };

View File

@@ -328,6 +328,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_revokers.CompletionsChanged = _core.CompletionsChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCompletionsChanged });
_revokers.RestartTerminalRequested = _core.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleRestartTerminalRequested });
_revokers.SearchMissingCommand = _core.SearchMissingCommand(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSearchMissingCommand });
_revokers.ShowNotification = _core.ShowNotification(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleShowNotification });
_revokers.WindowSizeChanged = _core.WindowSizeChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWindowSizeChanged });
_revokers.WriteToClipboard = _core.WriteToClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleWriteToClipboard });
@@ -393,6 +394,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// attached content before we set up the throttled func, and that'll A/V
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
_revokers.PromptStarted = _core.PromptStarted(winrt::auto_revoke, { get_weak(), &TermControl::_corePromptStarted });
_revokers.OutputStarted = _core.OutputStarted(winrt::auto_revoke, { get_weak(), &TermControl::_coreOutputStarted });
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
@@ -2456,6 +2459,46 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_automationPeer.UpdateControlBounds();
}
// Show resize overlay with columns x rows
_ShowResizeOverlay();
}
// Method Description:
// - Shows a centered overlay with the current terminal dimensions (columns x rows).
// Used during window resize and font size changes. Skipped for disabled controls
// (e.g. the Settings preview terminal) to avoid visual noise.
void TermControl::_ShowResizeOverlay()
{
// Don't show the overlay in the Settings preview control
if (!IsEnabled())
{
return;
}
const auto coreImpl = winrt::get_self<ControlCore>(_core);
const auto cols = coreImpl->ViewWidth();
const auto rows = coreImpl->ViewHeight();
if (cols > 0 && rows > 0)
{
ResizeOverlayText().Text(fmt::format(FMT_COMPILE(L"{} \u00D7 {}"), cols, rows));
ResizeOverlay().Visibility(Visibility::Visible);
if (!_resizeOverlayTimer)
{
_resizeOverlayTimer.emplace();
_resizeOverlayTimer->Interval(std::chrono::milliseconds(750));
_resizeOverlayTimer->Tick([weakThis = get_weak()](auto&&, auto&&) {
if (auto self = weakThis.get())
{
self->ResizeOverlay().Visibility(Visibility::Collapsed);
self->_resizeOverlayTimer->Stop();
}
});
}
_resizeOverlayTimer->Start();
}
}
// Method Description:
@@ -3356,7 +3399,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - Gets the internal taskbar state value
// Return Value:
// - The taskbar state of this control
const uint64_t TermControl::TaskbarState() const noexcept
const Control::TaskbarState TermControl::TaskbarState() const noexcept
{
return _core.TaskbarState();
}
@@ -3726,6 +3769,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_playWarningBell->Run();
}
void TermControl::_corePromptStarted(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
PromptStarted.raise(*this, nullptr);
}
void TermControl::_coreOutputStarted(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
OutputStarted.raise(*this, nullptr);
}
hstring TermControl::ReadEntireBuffer() const
{
return _core.ReadEntireBuffer();
@@ -3843,6 +3896,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TermControl::_coreOutputIdle(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
_refreshSearch();
OutputIdle.raise(*this, nullptr);
}
void TermControl::OwningHwnd(uint64_t owner)

View File

@@ -86,7 +86,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ColorSelection(Control::SelectionColor fg, Control::SelectionColor bg, Core::MatchMode matchMode);
#pragma region ICoreState
const uint64_t TaskbarState() const noexcept;
const Control::TaskbarState TaskbarState() const noexcept;
const uint64_t TaskbarProgress() const noexcept;
hstring Title();
@@ -211,6 +211,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<IInspectable, IInspectable> FocusFollowMouseRequested;
til::typed_event<Control::TermControl, Windows::UI::Xaml::RoutedEventArgs> Initialized;
til::typed_event<> WarningBell;
til::typed_event<> PromptStarted;
til::typed_event<> OutputStarted;
til::typed_event<> OutputIdle;
til::typed_event<IInspectable, Control::KeySentEventArgs> KeySent;
til::typed_event<IInspectable, Control::CharSentEventArgs> CharSent;
til::typed_event<IInspectable, Control::StringSentEventArgs> StringSent;
@@ -230,6 +233,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
BUBBLED_FORWARDED_TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);
BUBBLED_FORWARDED_TYPED_EVENT(WriteToClipboard, IInspectable, Control::WriteToClipboardEventArgs);
BUBBLED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
BUBBLED_FORWARDED_TYPED_EVENT(ShowNotification, IInspectable, Control::ShowNotificationEventArgs);
// clang-format on
@@ -316,6 +320,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::hstring _restorePath;
bool _showMarksInScrollbar{ false };
std::optional<SafeDispatcherTimer> _resizeOverlayTimer;
void _ShowResizeOverlay();
bool _isBackgroundLight{ false };
bool _detached{ false };
til::CoordType _searchScrollOffset = 0;
@@ -424,6 +431,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
void _corePromptStarted(const IInspectable& sender, const IInspectable& args);
void _coreOutputStarted(const IInspectable& sender, const IInspectable& args);
void _coreOutputIdle(const IInspectable& sender, const IInspectable& args);
winrt::Windows::Foundation::Point _toPosInDips(const Core::Point terminalCellPos);
@@ -449,6 +458,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
Control::ControlCore::ScrollPositionChanged_revoker coreScrollPositionChanged;
Control::ControlCore::WarningBell_revoker WarningBell;
Control::ControlCore::PromptStarted_revoker PromptStarted;
Control::ControlCore::OutputStarted_revoker OutputStarted;
Control::ControlCore::RendererEnteredErrorState_revoker RendererEnteredErrorState;
Control::ControlCore::BackgroundColorChanged_revoker BackgroundColorChanged;
Control::ControlCore::FontSizeChanged_revoker FontSizeChanged;
@@ -468,6 +479,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::ControlCore::CompletionsChanged_revoker CompletionsChanged;
Control::ControlCore::RestartTerminalRequested_revoker RestartTerminalRequested;
Control::ControlCore::SearchMissingCommand_revoker SearchMissingCommand;
Control::ControlCore::ShowNotification_revoker ShowNotification;
Control::ControlCore::RefreshQuickFixUI_revoker RefreshQuickFixUI;
Control::ControlCore::WindowSizeChanged_revoker WindowSizeChanged;

View File

@@ -69,6 +69,9 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
event Windows.Foundation.TypedEventHandler<Object, Object> PromptStarted;
event Windows.Foundation.TypedEventHandler<Object, Object> OutputStarted;
event Windows.Foundation.TypedEventHandler<Object, Object> OutputIdle;
event Windows.Foundation.TypedEventHandler<Object, Object> HidePointerCursor;
event Windows.Foundation.TypedEventHandler<Object, Object> RestorePointerCursor;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
@@ -82,6 +85,7 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, CharSentEventArgs> CharSent;
event Windows.Foundation.TypedEventHandler<Object, StringSentEventArgs> StringSent;
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
event Windows.Foundation.TypedEventHandler<Object, ShowNotificationEventArgs> ShowNotification;
Microsoft.UI.Xaml.Controls.CommandBarFlyout ContextMenu { get; };

View File

@@ -1365,6 +1365,24 @@
</Grid>
<!-- Resize overlay: shows columns x rows when terminal is resized -->
<Border x:Name="ResizeOverlay"
Padding="16,8,16,8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
BorderBrush="{ThemeResource SystemAccentColor}"
BorderThickness="1"
CornerRadius="{ThemeResource OverlayCornerRadius}"
IsHitTestVisible="False"
Visibility="Collapsed">
<TextBlock x:Name="ResizeOverlayText"
FontSize="18"
FontWeight="SemiBold"
Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}"
TextAlignment="Center" />
</Border>
<Grid x:Name="RendererFailedNotice"
HorizontalAlignment="Center"
VerticalAlignment="Center"

View File

@@ -124,6 +124,7 @@ namespace Microsoft.Terminal.Core
Boolean AllowKittyKeyboardMode { get; };
Boolean AllowVtChecksumReport { get; };
Boolean AllowVtClipboardWrite { get; };
Boolean AllowOscNotifications { get; };
Boolean TrimBlockSelection { get; };
Boolean DetectURLs { get; };

View File

@@ -267,6 +267,7 @@ void Terminal::SetOptionalFeatures(winrt::Microsoft::Terminal::Core::ICoreSettin
auto features = til::enumset<ITermDispatch::OptionalFeature>{};
features.set(ITermDispatch::OptionalFeature::ChecksumReport, settings.AllowVtChecksumReport());
features.set(ITermDispatch::OptionalFeature::ClipboardWrite, settings.AllowVtClipboardWrite());
features.set(ITermDispatch::OptionalFeature::DesktopNotification, settings.AllowOscNotifications());
engine.Dispatch().SetOptionalFeatures(features);
}
@@ -767,6 +768,11 @@ TerminalInput::OutputType Terminal::SendCharEvent(const wchar_t ch, const WORD s
// This changed the scrollbar marks - raise a notification to update them
_NotifyScrollEvent();
}
// regardless, notify that we started command output
if (_pfnOutputStarted)
{
_pfnOutputStarted();
}
}
}
@@ -1252,7 +1258,7 @@ const std::optional<til::color> Terminal::GetTabColor() const
// - Gets the internal taskbar state value
// Return Value:
// - The taskbar state
const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarState() const noexcept
const Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState Microsoft::Terminal::Core::Terminal::GetTaskbarState() const noexcept
{
return _taskbarState;
}
@@ -1276,11 +1282,26 @@ void Microsoft::Terminal::Core::Terminal::SetSearchMissingCommandCallback(std::f
_pfnSearchMissingCommand.swap(pfn);
}
void Microsoft::Terminal::Core::Terminal::SetShowNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept
{
_pfnShowNotification.swap(pfn);
}
void Microsoft::Terminal::Core::Terminal::SetClearQuickFixCallback(std::function<void()> pfn) noexcept
{
_pfnClearQuickFix.swap(pfn);
}
void Terminal::SetPromptStartedCallback(std::function<void()> pfn) noexcept
{
_pfnPromptStarted.swap(pfn);
}
void Terminal::SetOutputStartedCallback(std::function<void()> pfn) noexcept
{
_pfnOutputStarted.swap(pfn);
}
// Method Description:
// - Stores the search highlighted regions in the terminal
void Terminal::SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept

View File

@@ -159,12 +159,14 @@ public:
bool IsVtInputEnabled() const noexcept override;
void NotifyBufferRotation(const int delta) override;
void NotifyShellIntegrationMark() override;
void NotifyShellIntegrationMark(ShellIntegrationMark mark) override;
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
void SearchMissingCommand(const std::wstring_view command) override;
void ShowNotification(const std::wstring_view title, const std::wstring_view body) override;
#pragma endregion
void ClearMark();
@@ -233,8 +235,11 @@ public:
void SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept;
void CompletionsChangedCallback(std::function<void(std::wstring_view, unsigned int)> pfn) noexcept;
void SetSearchMissingCommandCallback(std::function<void(std::wstring_view, const til::CoordType)> pfn) noexcept;
void SetShowNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept;
void SetClearQuickFixCallback(std::function<void()> pfn) noexcept;
void SetWindowSizeChangedCallback(std::function<void(int32_t, int32_t)> pfn) noexcept;
void SetPromptStartedCallback(std::function<void()> pfn) noexcept;
void SetOutputStartedCallback(std::function<void()> pfn) noexcept;
void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept;
void SetSearchHighlightFocused(size_t focusedIdx) noexcept;
void ScrollToSearchHighlight(til::CoordType searchScrollOffset);
@@ -243,7 +248,7 @@ public:
const std::optional<til::color> GetTabColor() const;
const size_t GetTaskbarState() const noexcept;
const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState GetTaskbarState() const noexcept;
const size_t GetTaskbarProgress() const noexcept;
void ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode);
@@ -341,8 +346,11 @@ private:
std::function<void(const int, const int, const std::chrono::microseconds)> _pfnPlayMidiNote;
std::function<void(std::wstring_view, unsigned int)> _pfnCompletionsChanged;
std::function<void(std::wstring_view, const til::CoordType)> _pfnSearchMissingCommand;
std::function<void(std::wstring_view, std::wstring_view)> _pfnShowNotification;
std::function<void()> _pfnClearQuickFix;
std::function<void(int32_t, int32_t)> _pfnWindowSizeChanged;
std::function<void()> _pfnPromptStarted;
std::function<void()> _pfnOutputStarted;
RenderSettings _renderSettings;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
@@ -363,6 +371,9 @@ private:
til::enumset<Mode> _systemMode{ Mode::AutoWrap };
::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState _taskbarState{ ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState::Clear };
size_t _taskbarProgress = 0;
bool _focused = false;
bool _snapOnInput = true;
bool _altGrAliasing = true;
@@ -371,9 +382,6 @@ private:
bool _autoMarkPrompts = false;
bool _rainbowSuggestions = false;
size_t _taskbarState = 0;
size_t _taskbarProgress = 0;
size_t _hyperlinkPatternId = 0;
std::wstring _answerbackMessage;

View File

@@ -173,7 +173,7 @@ void Terminal::SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::D
{
_assertLocked();
_taskbarState = static_cast<size_t>(state);
_taskbarState = state;
switch (state)
{
@@ -380,6 +380,14 @@ void Terminal::SearchMissingCommand(const std::wstring_view command)
}
}
void Terminal::ShowNotification(const std::wstring_view title, const std::wstring_view body)
{
if (_pfnShowNotification)
{
_pfnShowNotification(title, body);
}
}
void Terminal::NotifyBufferRotation(const int delta)
{
// Update our selection, so it doesn't move as the buffer is cycled
@@ -416,8 +424,26 @@ void Terminal::NotifyBufferRotation(const int delta)
}
}
void Terminal::NotifyShellIntegrationMark()
void Terminal::NotifyShellIntegrationMark(ShellIntegrationMark mark)
{
// Notify the scrollbar that marks have been added so it can refresh the mark indicators
_NotifyScrollEvent();
switch (mark)
{
case ShellIntegrationMark::Prompt:
if (_pfnPromptStarted)
{
_pfnPromptStarted();
}
break;
case ShellIntegrationMark::Output:
if (_pfnOutputStarted)
{
_pfnOutputStarted();
}
break;
default:
break;
}
}

View File

@@ -352,8 +352,14 @@ namespace winrt::Microsoft::Terminal::Settings
_AllowKittyKeyboardMode = profile.AllowKittyKeyboardMode();
_AllowVtChecksumReport = profile.AllowVtChecksumReport();
_AllowVtClipboardWrite = profile.AllowVtClipboardWrite();
_AllowOscNotifications = profile.AllowOscNotifications();
_PathTranslationStyle = profile.PathTranslationStyle();
_DragDropDelimiter = profile.DragDropDelimiter();
_NotifyOnActivity = profile.NotifyOnActivity();
_NotifyOnNextPrompt = profile.NotifyOnNextPrompt();
_NotifyOnActivityThreshold = profile.NotifyOnActivityThreshold();
_NotifyOnNextPromptThreshold = profile.NotifyOnNextPromptThreshold();
_AutoDetectRunningCommand = profile.AutoDetectRunningCommand();
}
// Method Description:

View File

@@ -7,7 +7,9 @@
#include "LibraryResources.h"
#include "../TerminalSettingsModel/AllShortcutActions.h"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
@@ -42,4 +44,65 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
// Builds the "view all" flyout lazily on the first click of a
// row's "..." button, then caches it on the button so subsequent clicks
// just re-show it.
void Actions::ViewAllKeyChordsButton_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
{
const auto button = sender.try_as<Button>();
if (!button)
{
return;
}
// Retrieve cached flyout, if possible
if (const auto existing = button.Flyout())
{
existing.ShowAt(button);
return;
}
const auto cmdVM = button.DataContext().try_as<Editor::CommandViewModel>();
if (!cmdVM)
{
return;
}
Flyout flyout;
flyout.Placement(Primitives::FlyoutPlacementMode::Bottom);
flyout.FlyoutPresenterStyle(Resources().Lookup(box_value(L"EdgeToEdgeFlyoutPresenterStyle")).as<winrt::Windows::UI::Xaml::Style>());
StackPanel content;
content.Orientation(Orientation::Vertical);
content.MinWidth(120.0);
if (cmdVM.HasNoKeyChords())
{
const auto emptyTemplate = Resources().Lookup(box_value(L"ViewAllKeyChordsFlyoutEmptyStateTemplate")).as<DataTemplate>();
content.Children().Append(emptyTemplate.LoadContent().as<UIElement>());
}
else
{
const auto separatorTemplate = Resources().Lookup(box_value(L"ViewAllKeyChordsFlyoutSeparatorTemplate")).as<DataTemplate>();
const auto itemTemplate = Resources().Lookup(box_value(L"ViewAllKeyChordsFlyoutItemTemplate")).as<DataTemplate>();
const auto chords = cmdVM.KeyChordList();
const auto count = chords.Size();
for (uint32_t i = 0; i < count; ++i)
{
if (i > 0)
{
content.Children().Append(separatorTemplate.LoadContent().as<UIElement>());
}
auto chordVisual = itemTemplate.LoadContent().as<Editor::KeyChordVisual>();
chordVisual.KeyChord(chords.GetAt(i).CurrentKeys());
content.Children().Append(chordVisual);
}
}
flyout.Content(content);
button.Flyout(flyout);
flyout.ShowAt(button);
}
}

View File

@@ -17,6 +17,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void ViewAllKeyChordsButton_Click(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Editor::ActionsViewModel, ViewModel, PropertyChanged.raise, nullptr);

View File

@@ -8,7 +8,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mtu="using:Microsoft.Terminal.UI"
mc:Ignorable="d">
<Page.Resources>
@@ -17,182 +16,116 @@
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Theme Dictionary -->
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<!-- TextBox colors ! -->
<SolidColorBrush x:Key="TextControlBackground"
Color="#333333" />
<SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush"
Color="#B5B5B5" />
<SolidColorBrush x:Key="TextControlForeground"
Color="#B5B5B5" />
<SolidColorBrush x:Key="TextControlBorderBrush"
Color="#404040" />
<SolidColorBrush x:Key="TextControlButtonForeground"
Color="#B5B5B5" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver"
Color="#404040" />
<SolidColorBrush x:Key="TextControlForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver"
Color="#404040" />
<SolidColorBrush x:Key="TextControlButtonForegroundPointerOver"
Color="#FF4343" />
<SolidColorBrush x:Key="TextControlBackgroundFocused"
Color="#333333" />
<SolidColorBrush x:Key="TextControlForegroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused"
Color="#404040" />
<SolidColorBrush x:Key="TextControlButtonForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlButtonBackgroundPressed"
Color="#FF4343" />
<!-- KeyChordText styles -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
<Style x:Key="KeyChordTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<!-- TextBox colors ! -->
<SolidColorBrush x:Key="TextControlBackground"
Color="#CCCCCC" />
<SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush"
Color="#636363" />
<SolidColorBrush x:Key="TextControlBorderBrush"
Color="#636363" />
<SolidColorBrush x:Key="TextControlButtonForeground"
Color="#636363" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver"
Color="#DADADA" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver"
Color="#636363" />
<SolidColorBrush x:Key="TextControlButtonForegroundPointerOver"
Color="#FF4343" />
<SolidColorBrush x:Key="TextControlBackgroundFocused"
Color="#CCCCCC" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused"
Color="#636363" />
<SolidColorBrush x:Key="TextControlButtonForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlButtonBackgroundPressed"
Color="#FF4343" />
<!-- KeyChordText styles -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
<Style x:Key="KeyChordTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<!-- KeyChordText styles (use XAML defaults for High Contrast theme) -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Border" />
<Style x:Key="KeyChordTextBlockStyle"
TargetType="TextBlock" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<!-- Styles -->
<Style x:Key="KeyBindingContainerStyle"
<Style x:Key="ActionRowItemContainerStyle"
BasedOn="{StaticResource DefaultListViewItemStyle}"
TargetType="ListViewItem">
<Setter Property="Padding" Value="12,4,4,4" />
<Setter Property="Padding" Value="{StaticResource SettingsCardPadding}" />
<Setter Property="MinHeight" Value="{StaticResource SettingsCardMinHeight}" />
<Setter Property="Margin" Value="{StaticResource SettingsCardItemMargin}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="XYFocusKeyboardNavigation" Value="Enabled" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
</Style>
<Style x:Key="KeyBindingNameTextBlockStyle"
<Style x:Key="ActionRowNameTextStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="TextWrapping" Value="WrapWholeWords" />
</Style>
<Style x:Key="KeyChordEditorStyle"
TargetType="local:KeyChordListener">
<Setter Property="HorizontalAlignment" Value="Right" />
<Style x:Key="ActionRowSubtleButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
<Setter Property="MinWidth" Value="32" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Padding" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
<!-- Converters & Misc. -->
<SolidColorBrush x:Key="ActionContainerBackgroundEditing"
Color="{ThemeResource SystemListMediumColor}" />
<SolidColorBrush x:Key="ActionContainerBackground"
Color="Transparent" />
<!--
FlyoutPresenter style with no internal padding so a full-width Border
separator inside the flyout can reach the flyout's left/right edges.
-->
<Style x:Key="EdgeToEdgeFlyoutPresenterStyle"
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="0" />
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
<!-- Templates -->
<DataTemplate x:Key="ViewAllKeyChordsFlyoutSeparatorTemplate">
<Border Height="1"
Margin="0,4,0,4"
Background="{ThemeResource DividerStrokeColorDefaultBrush}" />
</DataTemplate>
<DataTemplate x:Key="ViewAllKeyChordsFlyoutEmptyStateTemplate">
<TextBlock x:Uid="Actions_NoKeyBindings"
Margin="12,8,12,8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource SecondaryTextBlockStyle}" />
</DataTemplate>
<DataTemplate x:Key="ViewAllKeyChordsFlyoutItemTemplate">
<local:KeyChordVisual Margin="{ThemeResource MenuFlyoutItemThemePaddingNarrow}"
HorizontalAlignment="Right" />
</DataTemplate>
<DataTemplate x:Key="CommandTemplate"
x:DataType="local:CommandViewModel">
<ListViewItem AutomationProperties.Name="{x:Bind DisplayNameAndKeyChordAutomationPropName, Mode=OneWay}"
Style="{StaticResource KeyBindingContainerStyle}">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- command name -->
<ColumnDefinition Width="*" />
<!-- key chord -->
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid AutomationProperties.Name="{x:Bind DisplayNameAndKeyChordAutomationPropName, Mode=OneWay}"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- command name -->
<ColumnDefinition Width="*" />
<!-- key chord -->
<ColumnDefinition Width="Auto" />
<!-- edit button -->
<ColumnDefinition Width="Auto" />
<!-- "..." button -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Command Name -->
<TextBlock Grid.Column="0"
FontWeight="Normal"
Style="{StaticResource KeyBindingNameTextBlockStyle}"
Text="{x:Bind DisplayName, Mode=OneWay}" />
<!-- Key Chord Text -->
<Grid Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
Padding="8,4,8,4"
Style="{ThemeResource KeyChordBorderStyle}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(FirstKeyChordText)}">
<TextBlock FontSize="14"
Style="{ThemeResource KeyChordTextBlockStyle}"
Text="{x:Bind FirstKeyChordText, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
</Border>
<Border Grid.Column="1"
Padding="8,4,8,4"
Style="{ThemeResource KeyChordBorderStyle}"
ToolTipService.ToolTip="{x:Bind AdditionalKeyChordTooltipText, Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(AdditionalKeyChordCountText)}">
<TextBlock FontSize="14"
Style="{ThemeResource KeyChordTextBlockStyle}"
Text="{x:Bind AdditionalKeyChordCountText, Mode=OneWay}" />
</Border>
</Grid>
</Grid>
</ListViewItem>
<!-- Command Name -->
<TextBlock Grid.Column="0"
Style="{StaticResource ActionRowNameTextStyle}"
Text="{x:Bind DisplayName, Mode=OneWay}" />
<!-- Key Chord -->
<local:KeyChordVisual Grid.Column="1"
HorizontalAlignment="Right"
KeyChord="{x:Bind FirstKeyChord, Mode=OneWay}" />
<!-- Edit button -->
<Button x:Uid="Actions_EditButton"
Grid.Column="2"
AutomationProperties.Name="{x:Bind DisplayName, Mode=OneWay}"
Click="{x:Bind Edit_Click}"
Style="{StaticResource ActionRowSubtleButtonStyle}">
<FontIcon FontSize="14"
Glyph="&#xE70F;" />
</Button>
<!-- "..." button + flyout -->
<Button x:Uid="Actions_ViewAllKeyChordsButton"
Grid.Column="3"
Click="ViewAllKeyChordsButton_Click"
Style="{StaticResource ActionRowSubtleButtonStyle}">
<FontIcon FontSize="14"
Glyph="&#xE712;" />
</Button>
</Grid>
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
@@ -208,7 +141,8 @@
<!-- Add New Button -->
<Button x:Name="AddNewButton"
Margin="0,12,0,0"
Click="{x:Bind ViewModel.AddNewCommand}">
Click="{x:Bind ViewModel.AddNewCommand}"
Style="{StaticResource AccentButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
@@ -221,11 +155,42 @@
<!-- Commands -->
<ListView x:Name="CommandsListView"
Margin="-8,0,0,0"
IsItemClickEnabled="True"
ItemClick="{x:Bind ViewModel.CmdListItemClicked}"
ItemContainerStyle="{StaticResource ActionRowItemContainerStyle}"
ItemTemplate="{StaticResource CommandTemplate}"
ItemsSource="{x:Bind ViewModel.CommandList, Mode=OneWay}" />
ItemsSource="{x:Bind ViewModel.CommandList, Mode=OneWay}"
SelectionMode="None">
<!--
The framework ListViewItemPresenter reads its per-state backgrounds
from these theme resources (not from ListViewItem.Background), so we
override them here to match the card chrome on ActionRowItemContainerStyle.
-->
<ListView.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="ListViewItemBackground"
ResourceKey="ExpanderHeaderBackground" />
<StaticResource x:Key="ListViewItemBackgroundPointerOver"
ResourceKey="ControlFillColorSecondaryBrush" />
<StaticResource x:Key="ListViewItemBackgroundPressed"
ResourceKey="ControlFillColorTertiaryBrush" />
<StaticResource x:Key="ListViewItemBackgroundSelected"
ResourceKey="ExpanderHeaderBackground" />
<StaticResource x:Key="ListViewItemBackgroundSelectedPointerOver"
ResourceKey="ControlFillColorSecondaryBrush" />
<StaticResource x:Key="ListViewItemBackgroundSelectedPressed"
ResourceKey="ControlFillColorTertiaryBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="ListViewItemBackground"
ResourceKey="SystemColorButtonFaceColorBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</ListView.Resources>
</ListView>
</StackPanel>
</Border>
</Page>

View File

@@ -57,13 +57,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return;
}
std::vector<Editor::KeyChordViewModel> keyChordVMs;
int32_t idx = 1;
for (const auto keys : _keyChordList)
{
auto kcVM{ make<KeyChordViewModel>(keys) };
_RegisterKeyChordVMEvents(kcVM);
keyChordVMs.push_back(kcVM);
auto kcVM{ make_self<KeyChordViewModel>(keys) };
kcVM->Index(idx++);
_RegisterKeyChordVMEvents(*kcVM);
keyChordVMs.push_back(*kcVM);
}
_KeyChordList = single_threaded_observable_vector(std::move(keyChordVMs));
_KeyChordList.VectorChanged([weakThis{ get_weak() }](const auto& /*sender*/, const auto& /*args*/) {
if (auto self{ weakThis.get() })
{
self->_ReindexKeyChordList();
self->_NotifyChanges(L"FirstKeyChord", L"FirstKeyChordText", L"AdditionalKeyChordCountText", L"AdditionalKeyChordTooltipText", L"DisplayNameAndKeyChordAutomationPropName");
}
});
std::vector<hstring> shortcutActions;
for (const auto [action, name] : _availableActionsAndNamesMap)
@@ -119,7 +128,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _cachedDisplayName;
}
winrt::hstring CommandViewModel::Name()
winrt::hstring CommandViewModel::Name() const noexcept
{
return _command.HasName() ? _command.Name() : L"";
}
@@ -145,7 +154,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return result;
}
winrt::hstring CommandViewModel::FirstKeyChordText()
winrt::hstring CommandViewModel::FirstKeyChordText() const
{
if (_KeyChordList.Size() != 0)
{
@@ -154,7 +163,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return L"";
}
winrt::hstring CommandViewModel::AdditionalKeyChordCountText()
Control::KeyChord CommandViewModel::FirstKeyChord() const noexcept
{
if (_KeyChordList.Size() != 0)
{
return _KeyChordList.GetAt(0).CurrentKeys();
}
return nullptr;
}
bool CommandViewModel::HasNoKeyChords() const noexcept
{
return _KeyChordList.Size() == 0;
}
winrt::hstring CommandViewModel::AdditionalKeyChordCountText() const
{
const auto size = _KeyChordList.Size();
if (size > 1)
@@ -164,7 +187,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return L"";
}
winrt::hstring CommandViewModel::AdditionalKeyChordTooltipText()
winrt::hstring CommandViewModel::AdditionalKeyChordTooltipText() const
{
const auto size = _KeyChordList.Size();
if (size <= 1)
@@ -183,12 +206,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return winrt::hstring{ result };
}
winrt::hstring CommandViewModel::ID()
winrt::hstring CommandViewModel::ID() const noexcept
{
return _command.ID();
}
bool CommandViewModel::IsUserAction()
bool CommandViewModel::IsUserAction() const noexcept
{
return _command.Origin() == OriginTag::User;
}
@@ -206,23 +229,40 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void CommandViewModel::AddKeybinding_Click()
{
auto kbdVM{ make_self<KeyChordViewModel>(nullptr) };
kbdVM->Index(gsl::narrow_cast<int32_t>(_KeyChordList.Size()) + 1);
kbdVM->IsInEditMode(true);
_RegisterKeyChordVMEvents(*kbdVM);
KeyChordList().Append(*kbdVM);
FocusContainer.raise(*this, *kbdVM);
}
winrt::hstring CommandViewModel::ActionNameTextBoxAutomationPropName()
// Reassigns 1-based Index values for every KeyChordViewModel in the list. Called
// whenever the list changes shape so the per-row "Key Binding #N" label stays in sync.
void CommandViewModel::_ReindexKeyChordList()
{
const auto size = _KeyChordList.Size();
for (uint32_t i = 0; i < size; ++i)
{
auto kcVM{ _KeyChordList.GetAt(i) };
const auto newIdx = gsl::narrow_cast<int32_t>(i) + 1;
if (kcVM.Index() != newIdx)
{
kcVM.Index(newIdx);
}
}
}
winrt::hstring CommandViewModel::ActionNameTextBoxAutomationPropName() const
{
return RS_(L"Actions_Name/Text");
}
winrt::hstring CommandViewModel::ShortcutActionComboBoxAutomationPropName()
winrt::hstring CommandViewModel::ShortcutActionComboBoxAutomationPropName() const
{
return RS_(L"Actions_ShortcutAction/Text");
}
winrt::hstring CommandViewModel::AdditionalArgumentsControlAutomationPropName()
winrt::hstring CommandViewModel::AdditionalArgumentsControlAutomationPropName() const
{
return RS_(L"Actions_Arguments/Text");
}
@@ -273,6 +313,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
self->FocusContainer.raise(*self, senderVM);
}
}
else if (propertyName == L"KeyChordText")
{
// The first chord of the list is what the row visual on the Actions page binds to,
// so propagate the change up so the row updates.
if (self->_KeyChordList.Size() > 0 && self->_KeyChordList.GetAt(0) == senderVM)
{
self->_NotifyChanges(L"FirstKeyChord", L"FirstKeyChordText", L"DisplayNameAndKeyChordAutomationPropName");
}
else
{
self->_NotifyChanges(L"AdditionalKeyChordTooltipText");
}
}
}
});
}
@@ -1065,12 +1118,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
KeyChordViewModel::KeyChordViewModel(Control::KeyChord currentKeys)
{
CurrentKeys(currentKeys);
// DisplayLabel is derived from Index, so re-fire the change for it whenever Index changes.
PropertyChanged([this](const auto& /*sender*/, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args) {
if (args.PropertyName() == L"Index")
{
_NotifyChanges(L"DisplayLabel");
}
});
}
void KeyChordViewModel::CurrentKeys(const Control::KeyChord& newKeys)
{
_currentKeys = newKeys;
KeyChordText(Model::KeyChordSerialization::ToString(_currentKeys));
_NotifyChanges(L"CurrentKeys");
}
Control::KeyChord KeyChordViewModel::CurrentKeys() const noexcept
@@ -1126,6 +1188,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
hstring KeyChordViewModel::CancelButtonName() const noexcept { return RS_(L"Actions_CancelButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
hstring KeyChordViewModel::AcceptButtonName() const noexcept { return RS_(L"Actions_AcceptButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
hstring KeyChordViewModel::DeleteButtonName() const noexcept { return RS_(L"Actions_DeleteButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
hstring KeyChordViewModel::EditButtonName() const noexcept { return RS_(L"Actions_EditButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
winrt::hstring KeyChordViewModel::DisplayLabel() const
{
return hstring{ RS_fmt(L"EditAction_KeyBindingNumberFormat", _Index) };
}
ActionsViewModel::ActionsViewModel(Model::CascadiaSettings settings) :
_Settings{ settings }

View File

@@ -69,16 +69,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void Initialize();
winrt::hstring DisplayName();
winrt::hstring Name();
winrt::hstring Name() const noexcept;
void Name(const winrt::hstring& newName);
winrt::hstring DisplayNameAndKeyChordAutomationPropName();
winrt::hstring FirstKeyChordText();
winrt::hstring AdditionalKeyChordCountText();
winrt::hstring AdditionalKeyChordTooltipText();
winrt::hstring FirstKeyChordText() const;
Control::KeyChord FirstKeyChord() const noexcept;
bool HasNoKeyChords() const noexcept;
winrt::hstring AdditionalKeyChordCountText() const;
winrt::hstring AdditionalKeyChordTooltipText() const;
winrt::hstring ID();
bool IsUserAction();
winrt::hstring ID() const noexcept;
bool IsUserAction() const noexcept;
void Edit_Click();
til::typed_event<Editor::CommandViewModel, IInspectable> EditRequested;
@@ -89,9 +91,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void AddKeybinding_Click();
// UIA text
winrt::hstring ActionNameTextBoxAutomationPropName();
winrt::hstring ShortcutActionComboBoxAutomationPropName();
winrt::hstring AdditionalArgumentsControlAutomationPropName();
winrt::hstring ActionNameTextBoxAutomationPropName() const;
winrt::hstring ShortcutActionComboBoxAutomationPropName() const;
winrt::hstring AdditionalArgumentsControlAutomationPropName() const;
til::typed_event<IInspectable, Editor::ArgWrapper> PropagateColorSchemeRequested;
til::typed_event<IInspectable, Editor::ArgWrapper> PropagateColorSchemeNamesRequested;
@@ -115,6 +117,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void _RegisterActionArgsVMEvents(Editor::ActionArgsViewModel actionArgsVM);
void _ReplaceCommandWithUserCopy(bool reinitialize);
void _CreateAndInitializeActionArgsVMHelper();
void _ReindexKeyChordList();
};
struct ArgWrapper : ArgWrapperT<ArgWrapper>, ViewModelHelper<ArgWrapper>
@@ -230,15 +233,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void CancelChanges();
void DeleteKeyChord();
winrt::hstring DisplayLabel() const;
// UIA Text
hstring CancelButtonName() const noexcept;
hstring AcceptButtonName() const noexcept;
hstring DeleteButtonName() const noexcept;
hstring EditButtonName() const noexcept;
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, IsInEditMode, false);
VIEW_MODEL_OBSERVABLE_PROPERTY(Control::KeyChord, ProposedKeys);
VIEW_MODEL_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText);
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Controls::Flyout, AcceptChangesFlyout, nullptr);
VIEW_MODEL_OBSERVABLE_PROPERTY(int32_t, Index, 0);
public:
til::typed_event<Editor::KeyChordViewModel, Terminal::Control::KeyChord> AddKeyChordRequested;

View File

@@ -55,6 +55,8 @@ namespace Microsoft.Terminal.Settings.Editor
// View-model specific
String DisplayName { get; };
String FirstKeyChordText { get; };
Microsoft.Terminal.Control.KeyChord FirstKeyChord { get; };
Boolean HasNoKeyChords { get; };
String AdditionalKeyChordCountText { get; };
String AdditionalKeyChordTooltipText { get; };
String DisplayNameAndKeyChordAutomationPropName { get; };
@@ -138,9 +140,12 @@ namespace Microsoft.Terminal.Settings.Editor
String KeyChordText { get; };
// UI side
Microsoft.Terminal.Control.KeyChord CurrentKeys { get; };
Microsoft.Terminal.Control.KeyChord ProposedKeys;
Windows.UI.Xaml.Controls.Flyout AcceptChangesFlyout;
Boolean IsInEditMode { get; };
Int32 Index;
String DisplayLabel { get; };
void ToggleEditMode();
void AcceptChanges();
void CancelChanges();
@@ -148,6 +153,7 @@ namespace Microsoft.Terminal.Settings.Editor
String CancelButtonName { get; };
String AcceptButtonName { get; };
String DeleteButtonName { get; };
String EditButtonName { get; };
event Windows.Foundation.TypedEventHandler<KeyChordViewModel, Microsoft.Terminal.Control.KeyChord> AddKeyChordRequested;
event Windows.Foundation.TypedEventHandler<KeyChordViewModel, ModifyKeyChordEventArgs> ModifyKeyChordRequested;

File diff suppressed because it is too large Load Diff

View File

@@ -64,6 +64,7 @@
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<local:ColorToStringConverter x:Key="ColorToStringConverter" />
<mtu:StringNotEmptyToVisibilityConverter x:Key="StringNotEmptyToVisibilityConverter" />
<Color x:Key="DeleteButtonColor">Firebrick</Color>
@@ -1228,13 +1229,19 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="ContentPresenter"
Grid.Column="0"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<StackPanel Grid.Column="0"
Padding="0,12,0,12"
VerticalAlignment="Center">
<ContentPresenter x:Name="ContentPresenter"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<TextBlock Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{Binding Tag, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Visibility="{Binding Tag, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource StringNotEmptyToVisibilityConverter}}" />
</StackPanel>
<FontIcon Grid.Column="1"
Margin="20,0,8,0"
HorizontalAlignment="Right"

View File

@@ -17,6 +17,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
INITIALIZE_BINDABLE_ENUM_SETTING(TextMeasurement, TextMeasurement, winrt::Microsoft::Terminal::Control::TextMeasurement, L"Globals_TextMeasurement_", L"Text");
INITIALIZE_BINDABLE_ENUM_SETTING(AmbiguousWidth, AmbiguousWidth, winrt::Microsoft::Terminal::Control::AmbiguousWidth, L"Globals_AmbiguousWidth_", L"Text");
INITIALIZE_BINDABLE_ENUM_SETTING(GraphicsAPI, GraphicsAPI, winrt::Microsoft::Terminal::Control::GraphicsAPI, L"Globals_GraphicsAPI_", L"Text");
}
bool CompatibilityViewModel::DebugFeaturesAvailable() const noexcept

View File

@@ -28,6 +28,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
GETSET_BINDABLE_ENUM_SETTING(TextMeasurement, winrt::Microsoft::Terminal::Control::TextMeasurement, _settings.GlobalSettings().TextMeasurement);
GETSET_BINDABLE_ENUM_SETTING(AmbiguousWidth, winrt::Microsoft::Terminal::Control::AmbiguousWidth, _settings.GlobalSettings().AmbiguousWidth);
GETSET_BINDABLE_ENUM_SETTING(GraphicsAPI, winrt::Microsoft::Terminal::Control::GraphicsAPI, _settings.GlobalSettings().GraphicsAPI);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_settings.GlobalSettings(), DisablePartialInvalidation);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_settings.GlobalSettings(), SoftwareRendering);
private:
Model::CascadiaSettings _settings;
};

View File

@@ -23,6 +23,11 @@ namespace Microsoft.Terminal.Settings.Editor
IInspectable CurrentAmbiguousWidth;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> AmbiguousWidthList { get; };
IInspectable CurrentGraphicsAPI;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> GraphicsAPIList { get; };
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, DisablePartialInvalidation);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, SoftwareRendering);
}
[default_interface] runtimeclass Compatibility : Windows.UI.Xaml.Controls.Page

View File

@@ -25,83 +25,119 @@
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Allow Headless -->
<local:SettingContainer x:Name="AllowHeadless"
x:Uid="Globals_AllowHeadless">
<ToggleSwitch IsOn="{x:Bind ViewModel.AllowHeadless, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Section: Compatibility -->
<local:SettingContainer x:Uid="Compatibility_Section_Compatibility"
StartExpanded="True"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Allow Headless -->
<local:SettingContainer x:Name="AllowHeadless"
x:Uid="Globals_AllowHeadless">
<ToggleSwitch IsOn="{x:Bind ViewModel.AllowHeadless, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Text Measurement -->
<local:SettingContainer x:Name="TextMeasurement"
x:Uid="Globals_TextMeasurement">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TextMeasurementList}"
SelectedItem="{x:Bind ViewModel.CurrentTextMeasurement, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Ambiguous Width -->
<local:SettingContainer x:Name="AmbiguousWidth"
x:Uid="Globals_AmbiguousWidth">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.AmbiguousWidthList}"
SelectedItem="{x:Bind ViewModel.CurrentAmbiguousWidth, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Debug Features -->
<local:SettingContainer x:Name="DebugFeaturesEnabled"
x:Uid="Globals_DebugFeaturesEnabled"
Visibility="{x:Bind ViewModel.DebugFeaturesAvailable}">
<ToggleSwitch IsOn="{x:Bind ViewModel.DebugFeaturesEnabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Reset Application State -->
<local:SettingContainer x:Name="ResetApplicationState"
x:Uid="Settings_ResetApplicationState">
<Button x:Uid="Settings_ResetApplicationStateButton"
Style="{StaticResource DeleteButtonStyle}">
<Button.Flyout>
<Flyout x:Name="ResetCacheFlyout"
FlyoutPresenterStyle="{StaticResource CustomFlyoutPresenterStyle}">
<StackPanel>
<TextBlock x:Uid="Settings_ResetApplicationStateConfirmationMessageHeader"
Style="{StaticResource CustomFlyoutTextStyle}" />
<TextBlock x:Uid="Settings_ResetApplicationStateConfirmationMessageBody"
FontWeight="Normal"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Settings_ResetApplicationStateConfirmationButton"
Click="ResetApplicationStateButton_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</local:SettingContainer>
<!-- Reset to Default Settings -->
<local:SettingContainer x:Name="ResetToDefaultSettings"
x:Uid="Settings_ResetToDefaultSettings">
<Button x:Uid="Settings_ResetToDefaultSettingsButton"
Style="{StaticResource DeleteButtonStyle}">
<Button.Flyout>
<Flyout FlyoutPresenterStyle="{StaticResource CustomFlyoutPresenterStyle}">
<StackPanel>
<TextBlock x:Uid="Settings_ResetToDefaultSettingsConfirmationMessageHeader"
Style="{StaticResource CustomFlyoutTextStyle}" />
<TextBlock x:Uid="Settings_ResetToDefaultSettingsConfirmationMessageBody"
FontWeight="Normal"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Settings_ResetToDefaultSettingsConfirmationButton"
Click="{x:Bind ViewModel.ResetToDefaultSettings}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Text Measurement -->
<local:SettingContainer x:Name="TextMeasurement"
x:Uid="Globals_TextMeasurement">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TextMeasurementList}"
SelectedItem="{x:Bind ViewModel.CurrentTextMeasurement, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Section: Rendering -->
<local:SettingContainer x:Uid="Compatibility_Section_Rendering"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Graphics API -->
<local:SettingContainer x:Name="GraphicsAPI"
x:Uid="Globals_GraphicsAPI">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.GraphicsAPIList}"
SelectedItem="{x:Bind ViewModel.CurrentGraphicsAPI, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Ambiguous Width -->
<local:SettingContainer x:Name="AmbiguousWidth"
x:Uid="Globals_AmbiguousWidth">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.AmbiguousWidthList}"
SelectedItem="{x:Bind ViewModel.CurrentAmbiguousWidth, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Disable Partial Invalidation -->
<local:SettingContainer x:Name="DisablePartialInvalidation"
x:Uid="Globals_DisablePartialInvalidation">
<ToggleSwitch IsOn="{x:Bind ViewModel.DisablePartialInvalidation, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Debug Features -->
<local:SettingContainer x:Name="DebugFeaturesEnabled"
x:Uid="Globals_DebugFeaturesEnabled"
Visibility="{x:Bind ViewModel.DebugFeaturesAvailable}">
<ToggleSwitch IsOn="{x:Bind ViewModel.DebugFeaturesEnabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Software Rendering -->
<local:SettingContainer x:Name="SoftwareRendering"
x:Uid="Globals_SoftwareRendering">
<ToggleSwitch IsOn="{x:Bind ViewModel.SoftwareRendering, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Reset Application State -->
<local:SettingContainer x:Name="ResetApplicationState"
x:Uid="Settings_ResetApplicationState">
<Button x:Uid="Settings_ResetApplicationStateButton"
Style="{StaticResource DeleteButtonStyle}">
<Button.Flyout>
<Flyout x:Name="ResetCacheFlyout"
FlyoutPresenterStyle="{StaticResource CustomFlyoutPresenterStyle}">
<StackPanel>
<TextBlock x:Uid="Settings_ResetApplicationStateConfirmationMessageHeader"
Style="{StaticResource CustomFlyoutTextStyle}" />
<TextBlock x:Uid="Settings_ResetApplicationStateConfirmationMessageBody"
FontWeight="Normal"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Settings_ResetApplicationStateConfirmationButton"
Click="ResetApplicationStateButton_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</local:SettingContainer>
<!-- Reset to Default Settings -->
<local:SettingContainer x:Name="ResetToDefaultSettings"
x:Uid="Settings_ResetToDefaultSettings">
<Button x:Uid="Settings_ResetToDefaultSettingsButton"
Style="{StaticResource DeleteButtonStyle}">
<Button.Flyout>
<Flyout FlyoutPresenterStyle="{StaticResource CustomFlyoutPresenterStyle}">
<StackPanel>
<TextBlock x:Uid="Settings_ResetToDefaultSettingsConfirmationMessageHeader"
Style="{StaticResource CustomFlyoutTextStyle}" />
<TextBlock x:Uid="Settings_ResetToDefaultSettingsConfirmationMessageBody"
FontWeight="Normal"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Settings_ResetToDefaultSettingsConfirmationButton"
Click="{x:Bind ViewModel.ResetToDefaultSettings}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</local:SettingContainer>
</StackPanel>
</Page>

View File

@@ -17,130 +17,11 @@
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Theme Dictionary -->
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<!-- KeyChordText styles -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="1" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
<!-- Override visual states -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<!-- Define the appearance of the button -->
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="border"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightAccentRevealBackgroundBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="KeyChordTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<!-- KeyChordText styles -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="1" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
<!-- Override visual states -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<!-- Define the appearance of the button -->
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="border"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightAccentRevealBackgroundBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="KeyChordTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<!-- KeyChordText styles (use XAML defaults for High Contrast theme) -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Button" />
<Style x:Key="KeyChordTextBlockStyle"
TargetType="TextBlock" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<GridLength x:Key="ArgumentNameWidth">148</GridLength>
<!-- Styles -->
<Style x:Key="KeyBindingContainerStyle"
BasedOn="{StaticResource DefaultListViewItemStyle}"
TargetType="ListViewItem">
<Setter Property="Padding" Value="4" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="XYFocusKeyboardNavigation" Value="Enabled" />
</Style>
<Style x:Key="KeyChordEditorStyle"
TargetType="local:KeyChordListener">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<x:Int32 x:Key="EditButtonSize">32</x:Int32>
<x:Double x:Key="EditButtonIconSize">14</x:Double>
<Style x:Key="EditButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
@@ -149,6 +30,7 @@
<Setter Property="Height" Value="{StaticResource EditButtonSize}" />
<Setter Property="Width" Value="{StaticResource EditButtonSize}" />
</Style>
<Style x:Key="AccentEditButtonStyle"
BasedOn="{StaticResource AccentButtonStyle}"
TargetType="Button">
@@ -157,42 +39,63 @@
<Setter Property="Height" Value="{StaticResource EditButtonSize}" />
<Setter Property="Width" Value="{StaticResource EditButtonSize}" />
</Style>
<Style x:Key="TextBlockGroupingStyle"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
<Setter Property="Margin" Value="0,0,0,4" />
<Setter Property="FontSize" Value="16" />
<Style x:Key="KeyChordEditorStyle"
TargetType="local:KeyChordListener">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="MinWidth" Value="160" />
</Style>
<!-- Templates -->
<!--
Item container for the per-chord ListView. We're hosting a SettingContainer
inside each item, so strip the default ListViewItem visuals (padding, border,
hover/selection background) so they don't double up.
-->
<Style x:Key="KeyChordListViewItemStyle"
BasedOn="{StaticResource DefaultListViewItemStyle}"
TargetType="ListViewItem">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<!-- "Key Binding #N" template -->
<DataTemplate x:Key="KeyChordTemplate"
x:DataType="local:KeyChordViewModel">
<ListViewItem IsTabStop="False"
Style="{StaticResource KeyBindingContainerStyle}">
<Grid Padding="-4,0,0,0"
VerticalAlignment="Center">
<local:SettingContainer Header="{x:Bind DisplayLabel, Mode=OneWay}">
<Grid VerticalAlignment="Center"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<!-- Key visual / key chord listener -->
<ColumnDefinition Width="Auto" />
<!-- Cancel button (visible only in edit mode) -->
<ColumnDefinition Width="Auto" />
<!-- Accept button (visible only in edit mode) -->
<ColumnDefinition Width="Auto" />
<!-- Edit (pencil) button (visible only NOT in edit mode) -->
<ColumnDefinition Width="Auto" />
<!-- Delete button -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Background="{ThemeResource AppBarItemBackgroundThemeBrush}"
Click="{x:Bind ToggleEditMode}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}">
<TextBlock FontSize="14"
Text="{x:Bind KeyChordText, Mode=OneWay}"
TextWrapping="WrapWholeWords" />
</Button>
<!-- Read-only key chord visual -->
<local:KeyChordVisual Grid.Column="0"
KeyChord="{x:Bind CurrentKeys, Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}" />
<!-- Editable key chord listener -->
<local:KeyChordListener Grid.Column="0"
Keys="{x:Bind ProposedKeys, Mode=TwoWay}"
Style="{StaticResource KeyChordEditorStyle}"
Visibility="{x:Bind IsInEditMode, Mode=OneWay}" />
<!-- Cancel changes (edit mode only) -->
<Button x:Uid="Actions_CancelButton"
Grid.Column="1"
Margin="8,0,0,0"
AutomationProperties.Name="{x:Bind CancelButtonName}"
Click="{x:Bind CancelChanges}"
Style="{StaticResource EditButtonStyle}"
@@ -201,9 +104,9 @@
Glyph="&#xE711;" />
</Button>
<!-- Accept changes (edit mode only) -->
<Button x:Uid="Actions_AcceptButton"
Grid.Column="2"
Margin="8,0,8,0"
AutomationProperties.Name="{x:Bind AcceptButtonName}"
Click="{x:Bind AcceptChanges}"
Flyout="{x:Bind AcceptChangesFlyout, Mode=OneWay}"
@@ -213,8 +116,19 @@
Glyph="&#xE8FB;" />
</Button>
<Button Grid.Column="3"
HorizontalAlignment="Left"
<!-- Edit button -->
<Button x:Uid="Actions_EditButton"
Grid.Column="3"
AutomationProperties.Name="{x:Bind EditButtonName}"
Click="{x:Bind ToggleEditMode}"
Style="{StaticResource EditButtonStyle}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}">
<FontIcon FontSize="{StaticResource EditButtonIconSize}"
Glyph="&#xE70F;" />
</Button>
<!-- Delete button -->
<Button Grid.Column="4"
AutomationProperties.Name="{x:Bind DeleteButtonName}"
Style="{StaticResource DeleteSmallButtonStyle}">
<Button.Content>
@@ -233,25 +147,23 @@
</Button.Flyout>
</Button>
</Grid>
</ListViewItem>
</local:SettingContainer>
</DataTemplate>
<!--
BODGY: Each ArgWrapper DataTemplate below wraps its editor control
in a <local:SettingContainer Header="{x:Bind Name}"> rather than sharing a
single outer template. This is because a bug in WinUI 2 prevents a
ContentPresenter + ContentTemplateSelector pattern from working correctly,
resulting in "Microsoft.Terminal.Settings.Editor.ArgWrapper" being shown.
-->
<!-- Example shortcut action to test this template: Adjust Opacity -->
<!-- Currently that is the only Int32 arg, so just clamp the min/max values according to that -->
<DataTemplate x:Key="Int32Template"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<muxc:NumberBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<muxc:NumberBox MinWidth="160"
AutomationProperties.Name="{x:Bind Name}"
LargeChange="1"
Maximum="100"
@@ -259,24 +171,14 @@
SmallChange="10"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind UnboxInt32(Value), Mode=TwoWay, BindBack=Int32BindBack}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Switch To Tab -->
<DataTemplate x:Key="UInt32Template"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<muxc:NumberBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<muxc:NumberBox MinWidth="160"
AutomationProperties.Name="{x:Bind Name}"
LargeChange="1"
Maximum="999"
@@ -284,24 +186,14 @@
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind UnboxUInt32(Value), Mode=TwoWay, BindBack=UInt32BindBack}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Close Other Tabs -->
<DataTemplate x:Key="UInt32OptionalTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<muxc:NumberBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<muxc:NumberBox MinWidth="160"
AutomationProperties.Name="{x:Bind Name}"
LargeChange="1"
Maximum="999"
@@ -309,24 +201,14 @@
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind UnboxUInt32Optional(Value), Mode=TwoWay, BindBack=UInt32OptionalBindBack}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Split Pane -->
<DataTemplate x:Key="Int32OptionalTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<muxc:NumberBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<muxc:NumberBox MinWidth="160"
AutomationProperties.Name="{x:Bind Name}"
LargeChange="1"
Maximum="999"
@@ -334,24 +216,14 @@
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind UnboxInt32Optional(Value), Mode=TwoWay, BindBack=Int32OptionalBindBack}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Adjust Font Size -->
<DataTemplate x:Key="FloatTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<muxc:NumberBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<muxc:NumberBox MinWidth="160"
AutomationProperties.Name="{x:Bind Name}"
LargeChange="1"
Maximum="999"
@@ -359,24 +231,14 @@
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind UnboxFloat(Value), Mode=TwoWay, BindBack=FloatBindBack}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Split Pane -->
<DataTemplate x:Key="SplitSizeTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<muxc:NumberBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<muxc:NumberBox MinWidth="160"
AutomationProperties.Name="{x:Bind Name}"
LargeChange="0.2"
Maximum="1"
@@ -384,144 +246,95 @@
SmallChange="0.1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind UnboxFloat(Value), Mode=TwoWay, BindBack=FloatBindBack}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Send Input -->
<DataTemplate x:Key="StringTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*"
MinWidth="196" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<TextBox Grid.Column="1"
<local:SettingContainer Header="{x:Bind Name}">
<TextBox MinWidth="248"
AutomationProperties.Name="{x:Bind Name}"
Text="{x:Bind UnboxString(Value), Mode=TwoWay, BindBack=StringBindBack}"
TextWrapping="Wrap" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Set Color Scheme -->
<DataTemplate x:Key="ColorSchemeTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<ComboBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<ComboBox MinWidth="248"
AutomationProperties.Name="{x:Bind Name}"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind EnumList, Mode=OneWay}"
SelectedItem="{x:Bind EnumValue, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Export Buffer -->
<DataTemplate x:Key="FilePickerTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*"
MinWidth="196" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<TextBox Grid.Column="1"
AutomationProperties.Name="{x:Bind Name}"
Text="{x:Bind UnboxString(Value), Mode=TwoWay, BindBack=StringBindBack}"
TextWrapping="Wrap" />
<Button x:Uid="Actions_Browse"
Grid.Column="2"
Click="{x:Bind BrowseForFile_Click}"
Style="{StaticResource BrowseButtonStyle}" />
</Grid>
<local:SettingContainer Header="{x:Bind Name}">
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"
MinWidth="196" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
AutomationProperties.Name="{x:Bind Name}"
Text="{x:Bind UnboxString(Value), Mode=TwoWay, BindBack=StringBindBack}"
TextWrapping="Wrap" />
<Button x:Uid="Actions_Browse"
Grid.Column="1"
Click="{x:Bind BrowseForFile_Click}"
Style="{StaticResource BrowseButtonStyle}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: New Tab -->
<DataTemplate x:Key="FolderPickerTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*"
MinWidth="196" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<TextBox Grid.Column="1"
AutomationProperties.Name="{x:Bind Name}"
Text="{x:Bind UnboxString(Value), Mode=TwoWay, BindBack=StringBindBack}"
TextWrapping="Wrap" />
<Button x:Uid="Actions_Browse"
Grid.Column="2"
Click="{x:Bind BrowseForFolder_Click}"
Style="{StaticResource BrowseButtonStyle}" />
</Grid>
<local:SettingContainer Header="{x:Bind Name}">
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"
MinWidth="196" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
AutomationProperties.Name="{x:Bind Name}"
Text="{x:Bind UnboxString(Value), Mode=TwoWay, BindBack=StringBindBack}"
TextWrapping="Wrap" />
<Button x:Uid="Actions_Browse"
Grid.Column="1"
Click="{x:Bind BrowseForFolder_Click}"
Style="{StaticResource BrowseButtonStyle}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Set Focus Mode -->
<DataTemplate x:Key="BoolTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<ToggleSwitch Grid.Column="1"
HorizontalAlignment="Left"
AutomationProperties.Name="{x:Bind Name}"
IsOn="{x:Bind UnboxBool(Value), Mode=TwoWay, BindBack=BoolOptionalBindBack}" />
</Grid>
<local:SettingContainer Header="{x:Bind Name}">
<ToggleSwitch AutomationProperties.Name="{x:Bind Name}"
IsOn="{x:Bind UnboxBool(Value), Mode=TwoWay, BindBack=BoolOptionalBindBack}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Split Pane -->
<DataTemplate x:Key="BoolOptionalTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<CheckBox Grid.Column="1"
HorizontalAlignment="Left"
AutomationProperties.Name="{x:Bind Name}"
<local:SettingContainer Header="{x:Bind Name}">
<CheckBox AutomationProperties.Name="{x:Bind Name}"
IsChecked="{x:Bind UnboxBoolOptional(Value), Mode=TwoWay, BindBack=BoolOptionalBindBack}"
IsThreeState="True" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Resize Pane -->
@@ -532,24 +345,14 @@
<DataTemplate x:Key="EnumTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<ComboBox Grid.Column="1"
HorizontalAlignment="Stretch"
<local:SettingContainer Header="{x:Bind Name}">
<ComboBox MinWidth="248"
AutomationProperties.Name="{x:Bind Name}"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind EnumList, Mode=OneWay}"
SelectedItem="{x:Bind EnumValue, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Copy Text -->
@@ -572,66 +375,35 @@
<DataTemplate x:Key="FlagTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<ItemsControl Grid.Column="1"
Margin="0"
HorizontalAlignment="Left"
AutomationProperties.Name="{x:Bind Name}"
<local:SettingContainer Header="{x:Bind Name}">
<ItemsControl AutomationProperties.Name="{x:Bind Name}"
ItemTemplate="{StaticResource FlagItemTemplate}"
ItemsSource="{x:Bind FlagList, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Add Mark -->
<DataTemplate x:Key="TerminalCoreColorOptionalTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<local:SettingContainer Header="{x:Bind Name}">
<local:NullableColorPicker x:Uid="Actions_NullableColorPicker"
Grid.Column="1"
AutomationProperties.Name="{x:Bind Name}"
ColorSchemeVM="{x:Bind DefaultColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind UnboxTerminalCoreColorOptional(Value), Mode=TwoWay, BindBack=TerminalCoreColorBindBack}"
NullColorPreview="{x:Bind DefaultColorScheme.ForegroundColor.Color, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<!-- Example shortcut action to test this template: Set Tab Color -->
<DataTemplate x:Key="WindowsUIColorOptionalTemplate"
x:DataType="local:ArgWrapper">
<Grid Margin="0,4,0,4"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Name}"
TextWrapping="WrapWholeWords" />
<local:SettingContainer Header="{x:Bind Name}">
<local:NullableColorPicker x:Uid="Actions_NullableColorPicker"
Grid.Column="1"
AutomationProperties.Name="{x:Bind Name}"
ColorSchemeVM="{x:Bind DefaultColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind UnboxWindowsUIColorOptional(Value), Mode=TwoWay, BindBack=WindowsUIColorBindBack}"
NullColorPreview="{x:Bind DefaultColorScheme.ForegroundColor.Color, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
</DataTemplate>
<local:ArgsTemplateSelectors x:Key="ArgsTemplateSelector"
@@ -655,122 +427,106 @@
</ResourceDictionary>
</Page.Resources>
<Border MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="{StaticResource SettingStackMargin}">
<Grid Margin="{StaticResource SettingStackMargin}"
HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Actions_CommandDetails"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,0,0,12"
VerticalAlignment="Center"
Style="{StaticResource TextBlockGroupingStyle}" />
<TextBlock x:Uid="Actions_Name"
Grid.Row="1"
Grid.Column="0"
Margin="0,0,0,8"
VerticalAlignment="Center" />
<TextBox x:Name="CommandNameTextBox"
Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,8"
HorizontalAlignment="Stretch"
AutomationProperties.Name="{x:Bind ViewModel.ActionNameTextBoxAutomationPropName}"
PlaceholderText="{x:Bind ViewModel.DisplayName, Mode=OneWay}"
Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />
<TextBlock x:Uid="Actions_ShortcutAction"
Grid.Row="2"
Grid.Column="0"
Margin="0,0,0,12"
VerticalAlignment="Center" />
<AutoSuggestBox x:Name="ShortcutActionBox"
Grid.Row="2"
Grid.Column="1"
Margin="0,0,0,12"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind ViewModel.ShortcutActionComboBoxAutomationPropName}"
GotFocus="ShortcutActionBox_GotFocus"
LostFocus="ShortcutActionBox_LostFocus"
QuerySubmitted="ShortcutActionBox_QuerySubmitted"
TextChanged="ShortcutActionBox_TextChanged" />
<TextBlock x:Uid="Actions_Keybindings"
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,0,0,12"
VerticalAlignment="Center"
Style="{StaticResource TextBlockGroupingStyle}" />
<ListView x:Name="KeyChordListView"
x:Uid="Actions_KeyBindingsListView"
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,0,0,12"
ItemTemplate="{StaticResource KeyChordTemplate}"
ItemsSource="{x:Bind ViewModel.KeyChordList, Mode=OneWay}"
SelectionMode="None">
<ListView.Footer>
<Button Margin="0,4,0,0"
Click="{x:Bind ViewModel.AddKeybinding_Click}">
<TextBlock x:Uid="Actions_AddKeyChord" />
</Button>
</ListView.Footer>
</ListView>
<TextBlock x:Uid="Actions_Arguments"
Grid.Row="5"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,0,0,12"
VerticalAlignment="Center"
Style="{StaticResource TextBlockGroupingStyle}"
Visibility="{x:Bind ViewModel.ActionArgsVM.HasArgs, Mode=OneWay}" />
<ItemsControl Grid.Row="6"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,0,0,12"
HorizontalAlignment="Stretch"
AutomationProperties.Name="{x:Bind ViewModel.AdditionalArgumentsControlAutomationPropName}"
IsTabStop="False"
ItemTemplateSelector="{StaticResource ArgsTemplateSelector}"
ItemsSource="{x:Bind ViewModel.ActionArgsVM.ArgValues, Mode=OneWay}" />
<Button Grid.Row="7"
Grid.Column="0"
IsEnabled="{x:Bind ViewModel.IsUserAction, Mode=OneWay}"
Style="{StaticResource DeleteButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Actions_DeleteButton2"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Actions_CommandDeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Actions_CommandDeleteConfirmationButton"
Click="{x:Bind ViewModel.Delete_Click}" />
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<StackPanel HorizontalAlignment="Stretch"
Style="{StaticResource SettingsStackStyle}">
<!-- Action type (top-most setting on the page) -->
<local:SettingContainer x:Name="ActionType"
x:Uid="EditAction_ActionType">
<AutoSuggestBox x:Name="ShortcutActionBox"
MinWidth="248"
AutomationProperties.Name="{x:Bind ViewModel.ShortcutActionComboBoxAutomationPropName}"
GotFocus="ShortcutActionBox_GotFocus"
LostFocus="ShortcutActionBox_LostFocus"
QuerySubmitted="ShortcutActionBox_QuerySubmitted"
TextChanged="ShortcutActionBox_TextChanged" />
</local:SettingContainer>
<!-- Key bindings expander -->
<local:SettingContainer x:Name="KeyBindingsContainer"
x:Uid="EditAction_KeyBindings"
StartExpanded="{x:Bind mtu:Converters.InvertBoolean(ViewModel.HasNoKeyChords), Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<!-- "New key binding" button -->
<local:SettingContainer x:Name="NewKeyBinding"
x:Uid="EditAction_NewKeyBinding">
<Button x:Uid="EditAction_AddKeyBinding"
Click="{x:Bind ViewModel.AddKeybinding_Click}"
Style="{StaticResource AccentButtonStyle}" />
</local:SettingContainer>
<!-- Existing key bindings, one container per chord -->
<ListView x:Name="KeyChordListView"
x:Uid="Actions_KeyBindingsListView"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsItemClickEnabled="False"
ItemContainerStyle="{StaticResource KeyChordListViewItemStyle}"
ItemTemplate="{StaticResource KeyChordTemplate}"
ItemsSource="{x:Bind ViewModel.KeyChordList, Mode=OneWay}"
SelectionMode="None" />
</StackPanel>
</local:SettingContainer>
<!-- Additional customizations expander -->
<local:SettingContainer x:Name="AdditionalCustomizations"
x:Uid="EditAction_AdditionalCustomizations"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<!-- Action name -->
<local:SettingContainer x:Name="ActionName"
x:Uid="EditAction_ActionName">
<TextBox x:Name="CommandNameTextBox"
MinWidth="248"
AutomationProperties.Name="{x:Bind ViewModel.ActionNameTextBoxAutomationPropName}"
PlaceholderText="{x:Bind ViewModel.DisplayName, Mode=OneWay}"
Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Action argument controls -->
<ItemsControl HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
AutomationProperties.Name="{x:Bind ViewModel.AdditionalArgumentsControlAutomationPropName}"
IsTabStop="False"
ItemTemplateSelector="{StaticResource ArgsTemplateSelector}"
ItemsSource="{x:Bind ViewModel.ActionArgsVM.ArgValues, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Stretch" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</local:SettingContainer>
<!-- Delete command button -->
<local:SettingContainer x:Name="DeleteCommand"
x:Uid="EditAction_DeleteCommand">
<Button IsEnabled="{x:Bind ViewModel.IsUserAction, Mode=OneWay}"
Style="{StaticResource DeleteButtonStyle}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Actions_DeleteButton2"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Actions_CommandDeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Actions_CommandDeleteConfirmationButton"
Click="{x:Bind ViewModel.Delete_Click}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</local:SettingContainer>
</StackPanel>
</Border>
</Page>

View File

@@ -27,126 +27,164 @@
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Theme -->
<local:SettingContainer x:Name="Theme"
x:Uid="Globals_Theme">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind ViewModel.ThemeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Theme">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.ThemeNameConverter((model:Theme)), Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Section: Visual style -->
<local:SettingContainer x:Uid="Globals_Section_VisualStyle"
StartExpanded="True"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Theme -->
<local:SettingContainer x:Name="Theme"
x:Uid="Globals_Theme">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemsSource="{x:Bind ViewModel.ThemeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Theme">
<TextBlock Text="{x:Bind local:GlobalAppearanceViewModel.ThemeNameConverter((model:Theme)), Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Show Acrylic in Tab Row -->
<local:SettingContainer x:Name="AcrylicTabRow"
x:Uid="Globals_AcrylicTabRow">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAcrylicInTabRow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Enable Unfocused Acrylic -->
<local:SettingContainer x:Name="EnableUnfocusedAcrylic"
x:Uid="Globals_EnableUnfocusedAcrylic">
<ToggleSwitch IsOn="{x:Bind ViewModel.EnableUnfocusedAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Disable Animations -->
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
<local:SettingContainer x:Name="DisableAnimations"
x:Uid="Globals_DisableAnimationsReversed">
<ToggleSwitch IsOn="{x:Bind ViewModel.InvertedDisableAnimations, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show pane headers -->
<local:SettingContainer x:Name="ShowPaneHeaders"
x:Uid="Globals_ShowPaneHeaders">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowPaneHeaders, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Position of new tab -->
<local:SettingContainer x:Name="NewTabPosition"
x:Uid="Globals_NewTabPosition">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.NewTabPositionList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentNewTabPosition, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<!-- Section: Tabs and layout -->
<local:SettingContainer x:Uid="Globals_Section_TabsLayout"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Position of new tab -->
<local:SettingContainer x:Name="NewTabPosition"
x:Uid="Globals_NewTabPosition">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.NewTabPositionList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentNewTabPosition, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Always show tabs -->
<local:SettingContainer x:Name="AlwaysShowTabs"
x:Uid="Globals_AlwaysShowTabs">
<ToggleSwitch IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.ShowTabsInTitlebar), Mode=OneWay}"
IsOn="{x:Bind ViewModel.AlwaysShowTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show tabs in full screen -->
<local:SettingContainer x:Name="ShowTabsFullscreen"
x:Uid="Globals_ShowTabsFullscreen">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsFullscreen, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Tab Width Mode -->
<local:SettingContainer x:Name="TabWidthMode"
x:Uid="Globals_TabWidthMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabWidthModeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTabWidthMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Show Titlebar -->
<local:SettingContainer x:Name="ShowTitlebar"
x:Uid="Globals_ShowTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}"
Toggled="{x:Bind ViewModel.ShowTitlebarToggled}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Show Titlebar -->
<local:SettingContainer x:Name="ShowTitlebar"
x:Uid="Globals_ShowTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}"
Toggled="{x:Bind ViewModel.ShowTitlebarToggled}" />
<!-- Section: Window behavior -->
<local:SettingContainer x:Uid="Globals_Section_WindowBehavior"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Always on Top -->
<local:SettingContainer x:Name="AlwaysOnTop"
x:Uid="Globals_AlwaysOnTop">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysOnTop, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Automatically hide window -->
<local:SettingContainer x:Name="AutoHideWindow"
x:Uid="Globals_AutoHideWindow">
<ToggleSwitch IsOn="{x:Bind ViewModel.AutoHideWindow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Always show tabs -->
<local:SettingContainer x:Name="AlwaysShowTabs"
x:Uid="Globals_AlwaysShowTabs">
<ToggleSwitch IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.ShowTabsInTitlebar), Mode=OneWay}"
IsOn="{x:Bind ViewModel.AlwaysShowTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Section: Title bar & identity -->
<local:SettingContainer x:Uid="Globals_Section_TitleBarIdentity"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Show Title in Titlebar (use active terminal title as application title) -->
<local:SettingContainer x:Name="ShowTitleInTitlebar"
x:Uid="Globals_ShowTitleInTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTitleInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Admin Shield -->
<local:SettingContainer x:Name="ShowAdminShield"
x:Uid="Globals_ShowAdminShield">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowAdminShield, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Show tabs in full screen -->
<local:SettingContainer x:Name="ShowTabsFullscreen"
x:Uid="Globals_ShowTabsFullscreen">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsFullscreen, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Section: System integration & notifications -->
<local:SettingContainer x:Uid="Globals_Section_SystemIntegration"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Always Show Notification Icon -->
<local:SettingContainer x:Name="AlwaysShowNotificationIcon"
x:Uid="Globals_AlwaysShowNotificationIcon">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowNotificationIcon, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Acrylic in Tab Row -->
<local:SettingContainer x:Name="AcrylicTabRow"
x:Uid="Globals_AcrylicTabRow">
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAcrylicInTabRow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Title in Titlebar -->
<local:SettingContainer x:Name="ShowTitleInTitlebar"
x:Uid="Globals_ShowTitleInTitlebar">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTitleInTitlebar, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always on Top -->
<local:SettingContainer x:Name="AlwaysOnTop"
x:Uid="Globals_AlwaysOnTop">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysOnTop, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Tab Width Mode -->
<local:SettingContainer x:Name="TabWidthMode"
x:Uid="Globals_TabWidthMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabWidthModeList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentTabWidthMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Disable Animations -->
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
<local:SettingContainer x:Name="DisableAnimations"
x:Uid="Globals_DisableAnimationsReversed">
<ToggleSwitch IsOn="{x:Bind ViewModel.InvertedDisableAnimations, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Always Show Notification Icon -->
<local:SettingContainer x:Name="AlwaysShowNotificationIcon"
x:Uid="Globals_AlwaysShowNotificationIcon">
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowNotificationIcon, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Minimize To Notification Area -->
<local:SettingContainer x:Name="MinimizeToNotificationArea"
x:Uid="Globals_MinimizeToNotificationArea">
<ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Automatically hide window -->
<local:SettingContainer x:Name="AutoHideWindow"
x:Uid="Globals_AutoHideWindow">
<ToggleSwitch IsOn="{x:Bind ViewModel.AutoHideWindow, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Show Admin Shield -->
<local:SettingContainer x:Name="ShowAdminShield"
x:Uid="Globals_ShowAdminShield">
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowAdminShield, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Enable Unfocused Acrylic -->
<local:SettingContainer x:Name="EnableUnfocusedAcrylic"
x:Uid="Globals_EnableUnfocusedAcrylic">
<ToggleSwitch IsOn="{x:Bind ViewModel.EnableUnfocusedAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Minimize To Notification Area -->
<local:SettingContainer x:Name="MinimizeToNotificationArea"
x:Uid="Globals_MinimizeToNotificationArea">
<ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
</StackPanel>
</Page>

View File

@@ -33,6 +33,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AlwaysShowTabs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTabsFullscreen);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowPaneHeaders);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTabsInTitlebar);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, UseAcrylicInTabRow);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTitleInTitlebar);

View File

@@ -27,6 +27,7 @@ namespace Microsoft.Terminal.Settings.Editor
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AlwaysShowTabs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowTabsFullscreen);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowPaneHeaders);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowTabsInTitlebar);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, UseAcrylicInTabRow);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowTitleInTitlebar);

View File

@@ -26,149 +26,179 @@
<StackPanel>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Copy On Select -->
<local:SettingContainer x:Name="CopyOnSelect"
x:Uid="Globals_CopyOnSelect">
<ToggleSwitch IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Section: Clipboard and paste behavior -->
<local:SettingContainer x:Uid="Interaction_Section_Clipboard"
StartExpanded="True"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Copy On Select -->
<local:SettingContainer x:Name="CopyOnSelect"
x:Uid="Globals_CopyOnSelect">
<ToggleSwitch IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Trim Paste -->
<local:SettingContainer x:Name="TrimPaste"
x:Uid="Globals_TrimPaste">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimPaste, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Trim Block Selection -->
<local:SettingContainer x:Name="TrimBlockSelection"
x:Uid="Globals_TrimBlockSelection">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimBlockSelection, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Copy Format -->
<local:SettingContainer x:Name="CopyFormat"
x:Uid="Globals_CopyFormat">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.CopyFormatList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentCopyFormat, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Copy Format -->
<local:SettingContainer x:Name="CopyFormat"
x:Uid="Globals_CopyFormat">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.CopyFormatList, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.CurrentCopyFormat, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<!-- Section: Text selection & editing -->
<local:SettingContainer x:Uid="Interaction_Section_TextSelection"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Word Delimiters -->
<local:SettingContainer x:Name="WordDelimiters"
x:Uid="Globals_WordDelimiters"
CurrentValue="{x:Bind ViewModel.WordDelimiters, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.WordDelimiters, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Enable Color Selection -->
<local:SettingContainer x:Name="EnableColorSelection"
x:Uid="Globals_EnableColorSelection">
<ToggleSwitch IsOn="{x:Bind ViewModel.EnableColorSelection, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Trim Block Selection -->
<local:SettingContainer x:Name="TrimBlockSelection"
x:Uid="Globals_TrimBlockSelection">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimBlockSelection, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Section: Window and layout behavior -->
<local:SettingContainer x:Uid="Interaction_Section_WindowLayout"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Snap On Resize -->
<local:SettingContainer x:Name="SnapToGridOnResize"
x:Uid="Globals_SnapToGridOnResize">
<ToggleSwitch IsOn="{x:Bind ViewModel.SnapToGridOnResize, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Focus Follow Mouse Mode -->
<local:SettingContainer x:Name="FocusFollowMouse"
x:Uid="Globals_FocusFollowMouse">
<ToggleSwitch IsOn="{x:Bind ViewModel.FocusFollowMouse, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Tab Switcher Mode -->
<local:SettingContainer x:Name="TabSwitcherMode"
x:Uid="Globals_TabSwitcherMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabSwitcherModeList}"
SelectedItem="{x:Bind ViewModel.CurrentTabSwitcherMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Trim Paste -->
<local:SettingContainer x:Name="TrimPaste"
x:Uid="Globals_TrimPaste">
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimPaste, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Section: Mouse & scrolling -->
<local:SettingContainer x:Uid="Interaction_Section_MouseScrolling"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Enable Font Size Changes with Scrolling -->
<local:SettingContainer x:Name="ScrollToZoom"
x:Uid="Globals_ScrollToZoom">
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToZoom, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Enable Window Opacity Changes with Scrolling -->
<local:SettingContainer x:Name="ScrollToChangeOpacity"
x:Uid="Globals_ScrollToChangeOpacity">
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToChangeOpacity, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Word Delimiters -->
<local:SettingContainer x:Name="WordDelimiters"
x:Uid="Globals_WordDelimiters"
CurrentValue="{x:Bind ViewModel.WordDelimiters, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.WordDelimiters, Mode=TwoWay}" />
<!-- Section: URLs & external actions -->
<local:SettingContainer x:Uid="Interaction_Section_UrlsExternal"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Detect URLs -->
<local:SettingContainer x:Name="DetectURLs"
x:Uid="Globals_DetectURLs">
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Search Web Default Query URL -->
<local:SettingContainer x:Name="SearchWebDefaultQueryUrl"
x:Uid="Globals_SearchWebDefaultQueryUrl"
CurrentValue="{x:Bind ViewModel.SearchWebDefaultQueryUrl, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.SearchWebDefaultQueryUrl, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Snap On Resize -->
<local:SettingContainer x:Name="SnapToGridOnResize"
x:Uid="Globals_SnapToGridOnResize">
<ToggleSwitch IsOn="{x:Bind ViewModel.SnapToGridOnResize, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Section: Warnings -->
<local:SettingContainer x:Uid="Interaction_Section_Warnings"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Confirm Close On -->
<local:SettingContainer x:Name="ConfirmOnClose"
x:Uid="Globals_ConfirmOnClose">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.ConfirmOnCloseList}"
SelectedItem="{x:Bind ViewModel.CurrentConfirmOnClose, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Input Service Warning -->
<local:SettingContainer x:Name="InputServiceWarning"
x:Uid="Globals_InputServiceWarning">
<ToggleSwitch IsOn="{x:Bind ViewModel.InputServiceWarning, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Large Paste Warning -->
<local:SettingContainer x:Name="WarnAboutLargePaste"
x:Uid="Globals_WarnAboutLargePaste">
<ToggleSwitch IsOn="{x:Bind ViewModel.WarnAboutLargePaste, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Multi Line Paste Warning -->
<local:SettingContainer x:Name="WarnAboutMultiLinePaste"
x:Uid="Globals_WarnAboutMultiLinePaste">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind WarnAboutMultiLinePasteList}"
SelectedItem="{x:Bind CurrentWarnAboutMultiLinePaste, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Tab Switcher Mode -->
<local:SettingContainer x:Name="TabSwitcherMode"
x:Uid="Globals_TabSwitcherMode">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.TabSwitcherModeList}"
SelectedItem="{x:Bind ViewModel.CurrentTabSwitcherMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Focus Follow Mouse Mode -->
<local:SettingContainer x:Name="FocusFollowMouse"
x:Uid="Globals_FocusFollowMouse">
<ToggleSwitch IsOn="{x:Bind ViewModel.FocusFollowMouse, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Enable Font Size Changes with Scrolling -->
<local:SettingContainer x:Name="ScrollToZoom"
x:Uid="Globals_ScrollToZoom">
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToZoom, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Enable Window Opacity Changes with Scrolling -->
<local:SettingContainer x:Name="ScrollToChangeOpacity"
x:Uid="Globals_ScrollToChangeOpacity">
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToChangeOpacity, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Detect URLs -->
<local:SettingContainer x:Name="DetectURLs"
x:Uid="Globals_DetectURLs">
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Search Web Default Query URL -->
<local:SettingContainer x:Name="SearchWebDefaultQueryUrl"
x:Uid="Globals_SearchWebDefaultQueryUrl"
CurrentValue="{x:Bind ViewModel.SearchWebDefaultQueryUrl, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.SearchWebDefaultQueryUrl, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Enable Color Selection -->
<local:SettingContainer x:Name="EnableColorSelection"
x:Uid="Globals_EnableColorSelection">
<ToggleSwitch IsOn="{x:Bind ViewModel.EnableColorSelection, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Grouping: Warnings -->
<TextBlock x:Uid="Globals_WarningsHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Confirm Close On -->
<local:SettingContainer x:Name="ConfirmOnClose"
x:Uid="Globals_ConfirmOnClose">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.ConfirmOnCloseList}"
SelectedItem="{x:Bind ViewModel.CurrentConfirmOnClose, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Input Service Warning -->
<local:SettingContainer x:Name="InputServiceWarning"
x:Uid="Globals_InputServiceWarning">
<ToggleSwitch IsOn="{x:Bind ViewModel.InputServiceWarning, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Large Paste Warning -->
<local:SettingContainer x:Name="WarnAboutLargePaste"
x:Uid="Globals_WarnAboutLargePaste">
<ToggleSwitch IsOn="{x:Bind ViewModel.WarnAboutLargePaste, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Multi Line Paste Warning -->
<local:SettingContainer x:Name="WarnAboutMultiLinePaste"
x:Uid="Globals_WarnAboutMultiLinePaste">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind WarnAboutMultiLinePasteList}"
SelectedItem="{x:Bind CurrentWarnAboutMultiLinePaste, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
</StackPanel>
</Page>

View File

@@ -0,0 +1,131 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "KeyChordVisual.h"
#include "KeyChordVisual.g.cpp"
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::Foundation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DependencyProperty KeyChordVisual::_KeyChordProperty{ nullptr };
KeyChordVisual::KeyChordVisual()
{
InitializeComponent();
_InitializeProperties();
}
void KeyChordVisual::_InitializeProperties()
{
if (!_KeyChordProperty)
{
_KeyChordProperty =
DependencyProperty::Register(
L"KeyChord",
xaml_typename<Control::KeyChord>(),
xaml_typename<Editor::KeyChordVisual>(),
PropertyMetadata{ nullptr, PropertyChangedCallback{ &KeyChordVisual::_OnKeyChordChanged } });
}
}
void KeyChordVisual::_OnKeyChordChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
if (const auto control{ d.try_as<Editor::KeyChordVisual>() })
{
const auto controlImpl{ get_self<KeyChordVisual>(control) };
controlImpl->_UpdateKeyVisuals();
}
}
// Capitalizes the first character of the provided string.
// Examples: "enter" -> "Enter", "f1" -> "F1", "v" -> "V"
static winrt::hstring _formatMainKeyName(std::wstring_view part)
{
if (part.empty())
{
return {};
}
std::wstring buffer{ part };
buffer[0] = til::toupper_ascii(buffer[0]);
return winrt::hstring{ buffer };
}
void KeyChordVisual::_UpdateKeyVisuals()
{
auto panel{ KeysPanel() };
if (!panel)
{
return;
}
panel.Children().Clear();
const auto kc{ KeyChord() };
if (!kc)
{
return;
}
// Reuse the canonical serialization so the key naming stays in sync with the
// rest of the app. Then split on '+' (no key name in the table contains a literal
// '+'; VK_OEM_PLUS serializes as "plus") and render each part as its own visual.
const auto serialized{ Model::KeyChordSerialization::ToString(kc) };
if (serialized.empty())
{
return;
}
const std::wstring_view full{ serialized };
for (const auto part : til::split_iterator{ full, L'+' })
{
if (til::equals_insensitive_ascii(part, L"win"))
{
_AddGlyphKey();
}
else if (til::equals_insensitive_ascii(part, L"ctrl"))
{
_AddTextKey(L"Ctrl");
}
else if (til::equals_insensitive_ascii(part, L"alt"))
{
_AddTextKey(L"Alt");
}
else if (til::equals_insensitive_ascii(part, L"shift"))
{
_AddTextKey(L"Shift");
}
else
{
_AddTextKey(_formatMainKeyName(part));
}
}
}
void KeyChordVisual::_AddTextKey(const winrt::hstring& text)
{
const auto tmpl{ Resources().Lookup(box_value(L"KeyChordVisualTextKeyTemplate")).as<DataTemplate>() };
const auto border{ tmpl.LoadContent().as<Border>() };
if (const auto tb{ border.Child().try_as<TextBlock>() })
{
tb.Text(text);
}
KeysPanel().Children().Append(border);
}
void KeyChordVisual::_AddGlyphKey()
{
const auto tmpl{ Resources().Lookup(box_value(L"KeyChordVisualWindowsKeyTemplate")).as<DataTemplate>() };
const auto border{ tmpl.LoadContent().as<Border>() };
// Provide an accessible name for the glyph since it has no text fallback.
if (const auto path{ border.Child() })
{
Automation::AutomationProperties::SetName(path, L"Win");
}
KeysPanel().Children().Append(border);
}
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "KeyChordVisual.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct KeyChordVisual : KeyChordVisualT<KeyChordVisual>
{
public:
KeyChordVisual();
DEPENDENCY_PROPERTY(Control::KeyChord, KeyChord);
private:
static void _InitializeProperties();
static void _OnKeyChordChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
void _UpdateKeyVisuals();
void _AddTextKey(const winrt::hstring& text);
void _AddGlyphKey();
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(KeyChordVisual);
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass KeyChordVisual : Windows.UI.Xaml.Controls.UserControl
{
KeyChordVisual();
Microsoft.Terminal.Control.KeyChord KeyChord;
static Windows.UI.Xaml.DependencyProperty KeyChordProperty { get; };
}
}

View File

@@ -0,0 +1,82 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<UserControl x:Class="Microsoft.Terminal.Settings.Editor.KeyChordVisual"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsTabStop="False"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="KeyChordVisualKeyBackground"
ResourceKey="AccentFillColorDefaultBrush" />
<StaticResource x:Key="KeyChordVisualKeyForeground"
ResourceKey="TextOnAccentFillColorPrimaryBrush" />
<StaticResource x:Key="KeyChordVisualKeyBorderBrush"
ResourceKey="AccentControlElevationBorderBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="KeyChordVisualKeyBackground"
ResourceKey="SystemColorButtonFaceColorBrush" />
<StaticResource x:Key="KeyChordVisualKeyForeground"
ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="KeyChordVisualKeyBorderBrush"
ResourceKey="SystemColorButtonTextColorBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style x:Key="KeyChordVisualKeyBorderStyle"
TargetType="Border">
<Setter Property="MinWidth" Value="32" />
<Setter Property="MinHeight" Value="28" />
<Setter Property="Padding" Value="8,2,8,2" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Background" Value="{ThemeResource KeyChordVisualKeyBackground}" />
<Setter Property="BorderBrush" Value="{ThemeResource KeyChordVisualKeyBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
</Style>
<Style x:Key="KeyChordVisualKeyTextStyle"
TargetType="TextBlock">
<Setter Property="FontSize" Value="13" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="TextAlignment" Value="Center" />
<Setter Property="Foreground" Value="{ThemeResource KeyChordVisualKeyForeground}" />
</Style>
<DataTemplate x:Key="KeyChordVisualTextKeyTemplate">
<Border Style="{StaticResource KeyChordVisualKeyBorderStyle}">
<TextBlock Style="{StaticResource KeyChordVisualKeyTextStyle}" />
</Border>
</DataTemplate>
<DataTemplate x:Key="KeyChordVisualWindowsKeyTemplate">
<Border Style="{StaticResource KeyChordVisualKeyBorderStyle}">
<Path Width="11"
Height="11"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M9 20H0V11H9V20ZM20 20H11V11H20V20ZM9 9H0V0H9V9ZM20 9H11V0H20V9Z"
Fill="{ThemeResource KeyChordVisualKeyForeground}"
Stretch="Uniform" />
</Border>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel x:Name="KeysPanel"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="2" />
</UserControl>

View File

@@ -43,278 +43,291 @@
<StackPanel>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Default Profile -->
<local:SettingContainer x:Name="DefaultProfile"
x:Uid="Globals_DefaultProfile">
<ComboBox ItemsSource="{x:Bind ViewModel.DefaultProfiles}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultProfile, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<!-- Section: Launch behavior -->
<local:SettingContainer x:Uid="Launch_Section_LaunchBehavior"
StartExpanded="True"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Default Profile -->
<local:SettingContainer x:Name="DefaultProfile"
x:Uid="Globals_DefaultProfile">
<ComboBox ItemsSource="{x:Bind ViewModel.DefaultProfiles}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultProfile, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon.Resolved), Mode=OneTime}" />
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon.Resolved), Mode=OneTime}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Default Terminal -->
<local:SettingContainer x:Name="DefaultTerminalDropdown"
x:Uid="Globals_DefaultTerminal"
x:Load="false">
<ComboBox x:Name="DefaultTerminal"
ItemsSource="{x:Bind ViewModel.DefaultTerminals}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultTerminal, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:DefaultTerminal">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ColumnSpacing="8">
<!-- First Window Behavior -->
<local:SettingContainer x:Name="FirstWindowPreference"
x:Uid="Globals_FirstWindowPreference">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.FirstWindowPreferenceList}"
SelectedItem="{x:Bind ViewModel.CurrentFirstWindowPreference, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="auto" />
<!-- terminal name and author -->
<ColumnDefinition Width="auto" />
<!-- version -->
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!-- Windowing Behavior -->
<local:SettingContainer x:Name="WindowingBehavior"
x:Uid="Globals_WindowingBehavior">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.WindowingBehaviorList}"
SelectedItem="{x:Bind ViewModel.CurrentWindowingBehavior, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<Grid.RowDefinitions>
<!-- terminal name -->
<RowDefinition Height="auto" />
<!-- author and version -->
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<!-- Start on User Login -->
<local:SettingContainer x:Name="StartOnUserLogin"
x:Uid="Globals_StartOnUserLogin"
HelpText="{x:Bind ViewModel.StartOnUserLoginStatefulHelpText, Mode=OneWay}"
Visibility="{x:Bind ViewModel.StartOnUserLoginAvailable, Mode=OneTime}">
<ToggleSwitch IsEnabled="{x:Bind ViewModel.StartOnUserLoginConfigurable, Mode=OneWay}"
IsOn="{x:Bind ViewModel.StartOnUserLogin, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<IconSourceElement Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Width="24"
Height="24"
VerticalAlignment="Center"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon), Mode=OneTime}" />
<TextBlock Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Text="{x:Bind Name}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Author}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Author)}" />
<TextBlock Grid.Row="1"
Grid.Column="2"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Version}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Version)}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Language -->
<local:SettingContainer x:Name="Language"
x:Uid="Globals_Language">
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind local:LaunchViewModel.LanguageDisplayConverter((x:String))}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Language -->
<local:SettingContainer x:Name="DefaultInputScope"
x:Uid="Globals_DefaultInputScope">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.DefaultInputScopeList}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultInputScope, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Start on User Login -->
<local:SettingContainer x:Name="StartOnUserLogin"
x:Uid="Globals_StartOnUserLogin"
HelpText="{x:Bind ViewModel.StartOnUserLoginStatefulHelpText, Mode=OneWay}"
Visibility="{x:Bind ViewModel.StartOnUserLoginAvailable, Mode=OneTime}">
<ToggleSwitch IsEnabled="{x:Bind ViewModel.StartOnUserLoginConfigurable, Mode=OneWay}"
IsOn="{x:Bind ViewModel.StartOnUserLogin, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- First Window Behavior -->
<local:SettingContainer x:Name="FirstWindowPreference"
x:Uid="Globals_FirstWindowPreference">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.FirstWindowPreferenceList}"
SelectedItem="{x:Bind ViewModel.CurrentFirstWindowPreference, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Windowing Behavior -->
<local:SettingContainer x:Name="WindowingBehavior"
x:Uid="Globals_WindowingBehavior">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.WindowingBehaviorList}"
SelectedItem="{x:Bind ViewModel.CurrentWindowingBehavior, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Launch Size -->
<local:SettingContainer x:Name="LaunchSize"
x:Uid="Globals_LaunchSize"
CurrentValue="{x:Bind ViewModel.LaunchSizeCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid ColumnSpacing="12"
RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_InitialCols"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialColsBox"
Grid.Row="0"
Grid.Column="1"
VerticalAlignment="Center"
Maximum="999"
Minimum="1"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialCols, Mode=TwoWay}" />
<TextBlock x:Uid="Globals_InitialRows"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialRowsBox"
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Maximum="999"
Minimum="1"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialRows, Mode=TwoWay}" />
</Grid>
</local:SettingContainer>
<!-- Launch Parameters -->
<local:SettingContainer x:Name="LaunchParameters"
x:Uid="Globals_LaunchParameters"
CurrentValue="{x:Bind ViewModel.LaunchParametersCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_LaunchModeSetting"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center" />
<ComboBox x:Name="LaunchModeComboBox"
Grid.Row="0"
Grid.Column="1"
MinWidth="240"
AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.LaunchModeList}"
SelectedItem="{x:Bind ViewModel.CurrentLaunchMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<TextBlock x:Uid="Globals_LaunchPosition"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center" />
<Grid Grid.Row="1"
Grid.Column="1"
ColumnSpacing="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Match the width of these NumberBoxes to the Width of the LaunchModeComboBox above minus the Grid's ColumnSpacing -->
<muxc:NumberBox x:Name="PosXBox"
x:Uid="Globals_InitialPosXBox"
Grid.Row="0"
Grid.Column="0"
Width="118"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosX, Mode=TwoWay}" />
<muxc:NumberBox x:Name="PosYBox"
x:Uid="Globals_InitialPosYBox"
Grid.Row="0"
Grid.Column="1"
Width="118"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosY, Mode=TwoWay}" />
<CheckBox x:Name="UseDefaultLaunchPositionCheckbox"
x:Uid="Globals_DefaultLaunchPositionCheckbox"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
IsChecked="{x:Bind ViewModel.UseDefaultLaunchPosition, Mode=TwoWay}" />
</Grid>
<TextBlock x:Uid="Globals_CenterOnLaunch"
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center" />
<ToggleSwitch x:Name="CenterOnLaunchToggle"
Grid.Row="2"
<!-- Launch Parameters -->
<local:SettingContainer x:Name="LaunchParameters"
x:Uid="Globals_LaunchParameters"
CurrentValue="{x:Bind ViewModel.LaunchParametersCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_LaunchModeSetting"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center" />
<ComboBox x:Name="LaunchModeComboBox"
Grid.Row="0"
Grid.Column="1"
MinWidth="240"
AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.LaunchModeList}"
SelectedItem="{x:Bind ViewModel.CurrentLaunchMode, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<TextBlock x:Uid="Globals_LaunchPosition"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center" />
<Grid Grid.Row="1"
Grid.Column="1"
IsOn="{x:Bind ViewModel.CenterOnLaunch, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
ColumnSpacing="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Match the width of these NumberBoxes to the Width of the LaunchModeComboBox above minus the Grid's ColumnSpacing -->
<muxc:NumberBox x:Name="PosXBox"
x:Uid="Globals_InitialPosXBox"
Grid.Row="0"
Grid.Column="0"
Width="118"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosX, Mode=TwoWay}" />
<muxc:NumberBox x:Name="PosYBox"
x:Uid="Globals_InitialPosYBox"
Grid.Row="0"
Grid.Column="1"
Width="118"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.UseDefaultLaunchPosition), Mode=OneWay}"
Style="{StaticResource LaunchPositionNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialPosY, Mode=TwoWay}" />
<CheckBox x:Name="UseDefaultLaunchPositionCheckbox"
x:Uid="Globals_DefaultLaunchPositionCheckbox"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
IsChecked="{x:Bind ViewModel.UseDefaultLaunchPosition, Mode=TwoWay}" />
</Grid>
<TextBlock x:Uid="Globals_CenterOnLaunch"
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center" />
<ToggleSwitch x:Name="CenterOnLaunchToggle"
Grid.Row="2"
Grid.Column="1"
IsOn="{x:Bind ViewModel.CenterOnLaunch, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
</local:SettingContainer>
<!-- Launch Size -->
<local:SettingContainer x:Name="LaunchSize"
x:Uid="Globals_LaunchSize"
CurrentValue="{x:Bind ViewModel.LaunchSizeCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid ColumnSpacing="12"
RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Globals_InitialCols"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialColsBox"
Grid.Row="0"
Grid.Column="1"
VerticalAlignment="Center"
Maximum="999"
Minimum="1"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialCols, Mode=TwoWay}" />
<TextBlock x:Uid="Globals_InitialRows"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource SettingsPageItemHeaderStyle}" />
<muxc:NumberBox x:Uid="Globals_InitialRowsBox"
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Maximum="999"
Minimum="1"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind ViewModel.InitialRows, Mode=TwoWay}" />
</Grid>
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Section: System & input defaults -->
<local:SettingContainer x:Uid="Launch_Section_SystemInputDefaults"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Default Terminal -->
<local:SettingContainer x:Name="DefaultTerminalDropdown"
x:Uid="Globals_DefaultTerminal"
x:Load="false">
<ComboBox x:Name="DefaultTerminal"
ItemsSource="{x:Bind ViewModel.DefaultTerminals}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultTerminal, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="SettingsModel:DefaultTerminal">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="auto" />
<!-- terminal name and author -->
<ColumnDefinition Width="auto" />
<!-- version -->
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<!-- terminal name -->
<RowDefinition Height="auto" />
<!-- author and version -->
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<IconSourceElement Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Width="24"
Height="24"
VerticalAlignment="Center"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon), Mode=OneTime}" />
<TextBlock Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Text="{x:Bind Name}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Author}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Author)}" />
<TextBlock Grid.Row="1"
Grid.Column="2"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Version}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Version)}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Language -->
<local:SettingContainer x:Name="Language"
x:Uid="Globals_Language">
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind local:LaunchViewModel.LanguageDisplayConverter((x:String))}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Default IME Input Mode -->
<local:SettingContainer x:Name="DefaultInputScope"
x:Uid="Globals_DefaultInputScope">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.DefaultInputScopeList}"
SelectedItem="{x:Bind ViewModel.CurrentDefaultInputScope, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
</StackPanel>
</StackPanel>

View File

@@ -7,8 +7,6 @@
#include "Launch.h"
#include "Interaction.h"
#include "Compatibility.h"
#include "Rendering.h"
#include "RenderingViewModel.h"
#include "Extensions.h"
#include "Actions.h"
#include "ProfileViewModel.h"
@@ -17,6 +15,7 @@
#include "ColorSchemes.h"
#include "EditColorScheme.h"
#include "AddProfile.h"
#include "Profiles.h"
#include "InteractionViewModel.h"
#include "LaunchViewModel.h"
#include "NewTabMenuViewModel.h"
@@ -102,7 +101,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
MainPage::MainPage(const CascadiaSettings& settings) :
_settingsSource{ settings },
_settingsClone{ settings.Copy() },
_profileVMs{ single_threaded_observable_vector<Editor::ProfileViewModel>() }
_profilesPageVM{ winrt::make<ProfilesPageViewModel>() }
{
InitializeComponent();
_UpdateBackgroundForMica();
@@ -156,8 +155,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
});
_SetupProfilesPageEventHandling();
// Make sure to initialize the profiles _after_ we have initialized the color schemes page VM, because we pass
// that VM into the appearance VMs within the profiles
// that VM into the appearance VMs within the profiles. The Profiles VM owns the per-profile list itself.
_InitializeProfilesList();
// Apply icons and tooltips (GH#19688, long names may be truncated) to static nav items
@@ -205,28 +206,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_UpdateBackgroundForMica();
// Deduce information about the currently selected item
IInspectable lastBreadcrumb;
const auto size = _breadcrumbs.Size();
if (size > 0)
// Capture data about where we are right now, so we can re-navigate to the same
// place after we rebuild all the settings.
IInspectable destination{ nullptr };
auto subPage = BreadcrumbSubPage::None;
hstring parentNavTag{};
if (const auto size = _breadcrumbs.Size(); size > 0)
{
lastBreadcrumb = _breadcrumbs.GetAt(size - 1);
const auto& crumb = _breadcrumbs.GetAt(size - 1).as<Breadcrumb>();
destination = crumb->Tag();
subPage = crumb->SubPage();
// If we were inside the Profiles section, remember that so we can restore
// the "Profiles " prefix on the rebuilt navigation.
if (_RootCrumbIsProfilesBreadcrumb())
{
parentNavTag = hstring{ profilesTag };
}
}
// Collect only the first items out of the menu item source, the static
// ones that we don't want to regenerate.
//
// By manipulating a MenuItemsSource this way, rather than manipulating the
// MenuItems directly, we avoid a crash in WinUI.
//
// By making the vector only _originalNumItems big to start, GetMany
// will only fill that number of elements out of the current source.
std::vector<IInspectable> menuItemsSTL(_originalNumItems, nullptr);
_menuItemSource.GetMany(0, menuItemsSTL);
// now, just stick them back in.
_menuItemSource.ReplaceAll(menuItemsSTL);
// Repopulate profile-related menu items
_InitializeProfilesList();
// Update the Nav State with the new version of the settings
@@ -236,64 +233,43 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_extensionsVM.UpdateSettings(_settingsClone, _colorSchemesPageVM);
_profileDefaultsVM = nullptr; // Lazy-loaded upon navigation
// Now that the menuItems are repopulated,
// refresh the current page using the breadcrumb data we collected before the refresh
if (const auto& crumb{ lastBreadcrumb.try_as<Breadcrumb>() }; crumb && crumb->Tag())
if (const auto& profileTag{ destination.try_as<Editor::ProfileViewModel>() })
{
bool foundNavigationParams = false;
auto destination = crumb->Tag();
auto subPage = crumb->SubPage();
for (const auto& item : _menuItemSource)
// Find the new profile VM by guid
if (const auto newProfileVM = _FindProfileViewModelByGuid(profileTag.OriginalProfileGuid()))
{
const auto menuItem = item.try_as<MUX::Controls::NavigationViewItem>();
if (!menuItem)
{
continue;
}
const auto& tag = menuItem.Tag();
if (const auto& stringTag{ tag.try_as<hstring>() })
{
if (const auto& destString{ destination.try_as<hstring>() })
{
foundNavigationParams = (*stringTag == *destString);
}
else if (destination.try_as<Editor::FolderEntryViewModel>() && *stringTag == newTabMenuTag)
{
foundNavigationParams = true;
subPage = BreadcrumbSubPage::NewTabMenu_Folder;
}
else if (destination.try_as<Editor::ExtensionPackageViewModel>() && *stringTag == extensionsTag)
{
foundNavigationParams = true;
subPage = BreadcrumbSubPage::Extensions_Extension;
}
}
else if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
{
const auto destProfile = destination.try_as<ProfileViewModel>();
if (destProfile && profileTag->OriginalProfileGuid() == destProfile->OriginalProfileGuid())
{
// Use the new profile VM from the refreshed menu items
destination = tag;
foundNavigationParams = true;
}
}
if (foundNavigationParams)
{
// found the one that was selected before the refresh
_Navigate(destination, subPage);
return;
}
destination = newProfileVM;
}
else
{
// Fall back to the Profiles landing page
destination = box_value(profilesTag);
subPage = BreadcrumbSubPage::None;
parentNavTag = {};
}
}
else if (destination.try_as<Editor::FolderEntryViewModel>())
{
destination = box_value(newTabMenuTag);
subPage = BreadcrumbSubPage::NewTabMenu_Folder;
}
else if (destination.try_as<Editor::ExtensionPackageViewModel>())
{
destination = box_value(extensionsTag);
subPage = BreadcrumbSubPage::Extensions_Extension;
}
else if (!destination.try_as<hstring>())
{
// Couldn't find a meaningful previous page. Fall back to the first menu item.
if (_menuItemSource && _menuItemSource.Size() > 0)
{
destination = _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>().Tag();
subPage = BreadcrumbSubPage::None;
parentNavTag = {};
}
}
// Couldn't find the selected item, fall back to first menu item
// This happens when the selected item was a profile which doesn't exist in the new configuration
// We can use menuItemsSTL here because the only things they miss are profile entries.
const auto& firstItem{ _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>() };
_Navigate(firstItem.Tag(), BreadcrumbSubPage::None);
_Navigate(destination, subPage, {}, parentNavTag);
_UpdateSearchIndex();
}
@@ -325,12 +301,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// can be empty to indicate that we should create a fresh profile
void MainPage::_AddProfileHandler(winrt::guid profileGuid)
{
uint32_t insertIndex;
auto selectedItem{ SettingsNav().SelectedItem() };
if (_menuItemSource)
{
_menuItemSource.IndexOf(selectedItem, insertIndex);
}
if (profileGuid != winrt::guid{})
{
// if we were given a non-empty guid, we want to duplicate the corresponding profile
@@ -338,13 +308,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (profile)
{
const auto duplicated = _settingsClone.DuplicateProfile(profile);
_CreateAndNavigateToNewProfile(insertIndex, duplicated);
_CreateAndNavigateToNewProfile(duplicated);
}
}
else
{
// we were given an empty guid, create a new profile
_CreateAndNavigateToNewProfile(insertIndex, nullptr);
_CreateAndNavigateToNewProfile(nullptr);
}
}
@@ -451,7 +421,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
else if (_colorSchemesPageVM.CurrentPage() == ColorSchemesSubPage::Base)
{
_Navigate(boxedTag, BreadcrumbSubPage::None);
// Preserve the current root context so that "Profiles > Color schemes" still shows the Profiles prefix.
const hstring inheritedParentNavTag = _RootCrumbIsProfilesBreadcrumb() ? hstring{ profilesTag } : hstring{};
_Navigate(boxedTag, BreadcrumbSubPage::None, {}, inheritedParentNavTag);
}
}
else if (settingName == L"CurrentSchemeName")
@@ -521,6 +493,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (currentPage == ProfileSubPage::Base)
{
_breadcrumbs.Clear();
_AppendProfilesRootCrumb();
_breadcrumbs.Append(winrt::make<Breadcrumb>(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None));
}
_NavigateToProfileSubPage(profile, currentPage, breadcrumbTag, {});
@@ -535,7 +508,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// a view model object (i.e. ProfileViewModel, ColorSchemeViewModel, etc.) for dynamic pages
// - subPage: the sub page to navigate to, used for pages that have multiple sub pages (i.e. Profile > Appearance/Terminal/Advanced)
// - elementToFocus: the name of the element to focus on the target page
void MainPage::_Navigate(const IInspectable& vm, BreadcrumbSubPage subPage, hstring elementToFocus)
// - parentNavTag: optional nav tag of the parent page when this navigation is invoked from inside another
// landing page. Used by the Profiles landing page to keep itself selected and to prepend a
// "Profiles" breadcrumb when entering Color schemes / a profile / Defaults / Add Profile from there.
void MainPage::_Navigate(const IInspectable& vm, BreadcrumbSubPage subPage, hstring elementToFocus, const hstring& parentNavTag)
{
_PreNavigateHelper();
@@ -554,11 +530,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
contentFrame().Navigate(xaml_typename<Editor::Interaction>(), winrt::make<NavigateToPageArgs>(winrt::make<InteractionViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus));
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Interaction/Content"), BreadcrumbSubPage::None));
}
else if (*clickedItemTag == renderingTag)
{
contentFrame().Navigate(xaml_typename<Editor::Rendering>(), winrt::make<NavigateToPageArgs>(winrt::make<RenderingViewModel>(_settingsClone), *this, elementToFocus));
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Rendering/Content"), BreadcrumbSubPage::None));
}
else if (*clickedItemTag == compatibilityTag)
{
contentFrame().Navigate(xaml_typename<Editor::Compatibility>(), winrt::make<NavigateToPageArgs>(winrt::make<CompatibilityViewModel>(_settingsClone), *this, elementToFocus));
@@ -616,8 +587,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None));
}
}
else if (*clickedItemTag == profilesTag)
{
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), winrt::make<NavigateToPageArgs>(_profilesPageVM, *this, elementToFocus));
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Profiles/Content"), BreadcrumbSubPage::None));
}
else if (*clickedItemTag == globalProfileTag)
{
_AppendProfilesRootCrumb();
// lazy load profile defaults VM
if (!_profileDefaultsVM)
{
@@ -636,9 +614,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Register handler for future user-driven sub-page changes
_SetupProfileEventHandling(_profileDefaultsVM);
// Keep the Profiles nav item selected.
selectedNavTag = profilesTag;
}
else if (*clickedItemTag == colorSchemesTag)
{
// Color Schemes page is accessible from root level and within Profiles,
// so we need to prepend the root crumb in the second case.
if (parentNavTag == profilesTag)
{
_AppendProfilesRootCrumb();
selectedNavTag = profilesTag;
}
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None));
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus));
@@ -654,47 +643,62 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
else if (*clickedItemTag == addProfileTag)
{
_AppendProfilesRootCrumb();
auto addProfileState{ winrt::make<AddProfilePageNavigationState>(_settingsClone) };
addProfileState.AddNew({ get_weak(), &MainPage::_AddProfileHandler });
contentFrame().Navigate(xaml_typename<Editor::AddProfile>(), winrt::make<NavigateToPageArgs>(addProfileState, *this, elementToFocus));
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_AddNewProfile/Content"), BreadcrumbSubPage::None));
// Keep the Profiles nav item selected.
selectedNavTag = profilesTag;
}
}
else if (const auto& profile = vm.try_as<Editor::ProfileViewModel>())
{
_AppendProfilesRootCrumb();
selectedNavTag = profilesTag;
if (profile.Orphaned())
{
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base_Orphaned>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
profile.CurrentPage(ProfileSubPage::Base);
_SetupProfileEventHandling(profile);
return;
}
// Set CurrentPage before registering the handler to avoid double-navigation
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
profile.CurrentPage(profileSubPage);
// Navigate directly to the correct sub-page
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
_NavigateToProfileSubPage(profile, profileSubPage, vm, elementToFocus);
if (const auto profileNavItem = _FindProfileNavItem(profile.OriginalProfileGuid()))
else
{
SettingsNav().SelectedItem(profileNavItem);
}
// Set CurrentPage before registering the handler to avoid double-navigation
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
profile.CurrentPage(profileSubPage);
// Register handler for future user-driven sub-page changes
_SetupProfileEventHandling(profile);
// Navigate directly to the correct sub-page
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
_NavigateToProfileSubPage(profile, profileSubPage, vm, elementToFocus);
// Register handler for future user-driven sub-page changes
_SetupProfileEventHandling(profile);
}
}
else if (const auto& colorSchemeVM = vm.try_as<Editor::ColorSchemeViewModel>())
{
selectedNavTag = colorSchemesTag;
const auto boxedColorSchemesTag = box_value(colorSchemesTag);
// Suppress the handler to avoid double-navigation
_colorSchemesPageViewModelChangedRevoker.revoke();
// Color Schemes page is accessible from within Profiles and root level,
// so we need to prepend the root crumb in the first case.
if (parentNavTag == profilesTag)
{
_AppendProfilesRootCrumb();
selectedNavTag = profilesTag;
}
else
{
selectedNavTag = colorSchemesTag;
}
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedColorSchemesTag, RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None));
if (subPage == BreadcrumbSubPage::None)
@@ -813,26 +817,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
// Select the appropriate nav item
// NOTE: profiles are special in that they have their own nav item, so those are handled in the profile branch above
if (!selectedNavTag.empty())
{
for (auto&& menuItem : _menuItemSource)
{
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
{
if (const auto& tag{ navViewItem.Tag() })
{
if (const auto& stringTag{ tag.try_as<hstring>() })
{
if (*stringTag == selectedNavTag)
{
SettingsNav().SelectedItem(navViewItem);
break;
}
}
}
}
}
_SelectNavItemByTag(selectedNavTag);
}
}
@@ -855,7 +842,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (gsl::narrow_cast<uint32_t>(args.Index()) < (_breadcrumbs.Size() - 1))
{
const auto crumb = args.Item().as<Breadcrumb>();
_Navigate(crumb->Tag(), crumb->SubPage());
// If the breadcrumb chain is rooted at the Profiles landing page, preserve
// that context so navigating to sub pages (i.e. Color schemes) via a back-breadcrumb
// keeps the "Profiles " prefix.
const hstring parentNavTag = _RootCrumbIsProfilesBreadcrumb() ? hstring{ profilesTag } : hstring{};
_Navigate(crumb->Tag(), crumb->SubPage(), {}, parentNavTag);
}
}
@@ -872,35 +863,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_MoveXamlParsedNavItemsIntoItemSource();
}
// Manually create a NavigationViewItem and view model for each profile
// and keep a reference to them in a map so that we
// can easily modify the correct one when the associated
// profile changes.
_profileVMs.Clear();
// Populate the per-profile view models on the Profiles VM. The Profiles landing
// page (and the search index) read this same list back through the VM.
const auto& profileVMs = _profilesPageVM.Profiles();
profileVMs.Clear();
for (const auto& profile : _settingsClone.AllProfiles())
{
if (!profile.Deleted())
{
auto profileVM = _viewModelForProfile(profile, _settingsClone, Dispatcher());
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
auto navItem = _CreateProfileNavViewItem(profileVM);
_menuItemSource.Append(navItem);
profileVM.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
profileVMs.Append(profileVM);
}
}
// Top off (the end of the nav view) with the Add Profile item
MUX::Controls::NavigationViewItem addProfileItem;
const auto addProfileText = RS_(L"Nav_AddNewProfile/Content");
addProfileItem.Content(box_value(addProfileText));
addProfileItem.Tag(box_value(addProfileTag));
WUX::Controls::ToolTipService::SetToolTip(addProfileItem, box_value(addProfileText));
FontIcon icon;
// This is the "Add" symbol
icon.Glyph(NavTagIconMap[addProfileTag]);
addProfileItem.Icon(icon);
_menuItemSource.Append(addProfileItem);
}
// BODGY
@@ -936,79 +912,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
SettingsNav().MenuItemsSource(_menuItemSource);
}
void MainPage::_CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile)
void MainPage::_CreateAndNavigateToNewProfile(const Model::Profile& profile)
{
const auto newProfile{ profile ? profile : _settingsClone.CreateNewProfile() };
const auto profileViewModel{ _viewModelForProfile(newProfile, _settingsClone, Dispatcher()) };
profileViewModel.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
const auto navItem{ _CreateProfileNavViewItem(profileViewModel) };
profileViewModel.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
if (_menuItemSource)
{
_menuItemSource.InsertAt(index, navItem);
}
_profilesPageVM.Profiles().Append(profileViewModel);
// Select and navigate to the new profile
_Navigate(profileViewModel, BreadcrumbSubPage::None);
}
static MUX::Controls::InfoBadge _createGlyphIconBadge(wil::zwstring_view glyph)
{
MUX::Controls::InfoBadge badge;
MUX::Controls::FontIconSource icon;
icon.FontFamily(winrt::Windows::UI::Xaml::Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
icon.FontSize(12);
icon.Glyph(glyph);
badge.IconSource(icon);
return badge;
}
MUX::Controls::NavigationViewItem MainPage::_CreateProfileNavViewItem(const Editor::ProfileViewModel& profile)
{
MUX::Controls::NavigationViewItem profileNavItem;
profileNavItem.Content(box_value(profile.Name()));
profileNavItem.Tag(box_value<Editor::ProfileViewModel>(profile));
profileNavItem.Icon(UI::IconPathConverter::IconWUX(profile.EvaluatedIcon()));
WUX::Controls::ToolTipService::SetToolTip(profileNavItem, box_value(profile.Name()));
if (profile.Orphaned())
{
profileNavItem.InfoBadge(_createGlyphIconBadge(L"\xE7BA") /* Warning Triangle */);
}
else if (profile.Hidden())
{
profileNavItem.InfoBadge(_createGlyphIconBadge(L"\xED1A") /* Hide */);
}
// Update the menu item when the icon/name changes
auto weakMenuItem{ make_weak(profileNavItem) };
profile.PropertyChanged([weakMenuItem](const auto&, const WUX::Data::PropertyChangedEventArgs& args) {
if (auto menuItem{ weakMenuItem.get() })
{
const auto& tag{ menuItem.Tag().as<Editor::ProfileViewModel>() };
if (args.PropertyName() == L"Icon")
{
menuItem.Icon(UI::IconPathConverter::IconWUX(tag.EvaluatedIcon()));
}
else if (args.PropertyName() == L"Name")
{
menuItem.Content(box_value(tag.Name()));
WUX::Controls::ToolTipService::SetToolTip(menuItem, box_value(tag.Name()));
}
else if (args.PropertyName() == L"Hidden")
{
menuItem.InfoBadge(tag.Hidden() ? _createGlyphIconBadge(L"\xED1A") /* Hide */ : nullptr);
}
}
});
// Add an event handler for when the user wants to delete a profile.
profile.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
// Register the VM so that it appears in the search index
_profileVMs.Append(profile);
return profileNavItem;
_Navigate(profileViewModel);
}
void MainPage::_DeleteProfile(const IInspectable /*sender*/, const Editor::DeleteProfileEventArgs& args)
@@ -1025,33 +939,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
// remove selected item
uint32_t index;
auto selectedItem{ SettingsNav().SelectedItem() };
if (_menuItemSource)
// Remove the profile VM
const auto& profileVMs = _profilesPageVM.Profiles();
for (uint32_t i = 0; i < profileVMs.Size(); ++i)
{
_menuItemSource.IndexOf(selectedItem, index);
_menuItemSource.RemoveAt(index);
// Remove it from the list of VMs
auto profileVM = selectedItem.as<MUX::Controls::NavigationViewItem>().Tag().as<Editor::ProfileViewModel>();
uint32_t vmIndex;
if (_menuItemSource.IndexOf(profileVM, vmIndex))
if (profileVMs.GetAt(i).OriginalProfileGuid() == guid)
{
_profileVMs.RemoveAt(vmIndex);
profileVMs.RemoveAt(i);
break;
}
// navigate to the profile next to this one
const auto newSelectedItem{ _menuItemSource.GetAt(index < _menuItemSource.Size() - 1 ? index : index - 1) };
const auto newTag = newSelectedItem.as<MUX::Controls::NavigationViewItem>().Tag();
if (const auto profileViewModel = newTag.try_as<ProfileViewModel>())
{
profileViewModel->FocusDeleteButton(true);
}
_Navigate(newTag, BreadcrumbSubPage::None);
// Since we are navigating to a new profile after deletion, scroll up to the top
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
}
// Go back to the Profiles landing page
_Navigate(box_value(profilesTag));
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
}
IObservableVector<IInspectable> MainPage::Breadcrumbs() noexcept
@@ -1061,29 +962,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void MainPage::_NavigateToProfileHandler(const IInspectable& /*sender*/, winrt::guid profileGuid)
{
if (const auto profileNavItem = _FindProfileNavItem(profileGuid))
if (const auto profileVM = _FindProfileViewModelByGuid(profileGuid))
{
_Navigate(profileNavItem.Tag(), BreadcrumbSubPage::None);
_Navigate(profileVM);
}
// Silently fail if the profile wasn't found
}
MUX::Controls::NavigationViewItem MainPage::_FindProfileNavItem(winrt::guid profileGuid) const
Editor::ProfileViewModel MainPage::_FindProfileViewModelByGuid(winrt::guid profileGuid) const
{
for (auto&& menuItem : _menuItemSource)
for (const auto& profileVM : _profilesPageVM.Profiles())
{
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
if (profileVM.OriginalProfileGuid() == profileGuid)
{
if (const auto& tag{ navViewItem.Tag() })
{
if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
{
if (profileTag->OriginalProfileGuid() == profileGuid)
{
return navViewItem;
}
}
}
return profileVM;
}
}
return nullptr;
@@ -1094,6 +986,62 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_Navigate(box_value(hstring{ colorSchemesTag }), BreadcrumbSubPage::ColorSchemes_Edit);
}
void MainPage::_AppendProfilesRootCrumb()
{
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(profilesTag), RS_(L"Nav_Profiles/Content"), BreadcrumbSubPage::None));
}
bool MainPage::_RootCrumbIsProfilesBreadcrumb() const
{
if (_breadcrumbs.Size() == 0)
{
return false;
}
const auto rootTag = _breadcrumbs.GetAt(0).as<Breadcrumb>()->Tag().try_as<hstring>();
return rootTag && *rootTag == profilesTag;
}
void MainPage::_SelectNavItemByTag(std::wstring_view tag)
{
if (!_menuItemSource)
{
return;
}
for (auto&& menuItem : _menuItemSource)
{
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
{
if (const auto& itemTag{ navViewItem.Tag() })
{
if (const auto& stringTag{ itemTag.try_as<hstring>() })
{
if (*stringTag == tag)
{
SettingsNav().SelectedItem(navViewItem);
return;
}
}
}
}
}
}
void MainPage::_SetupProfilesPageEventHandling()
{
_profilesPageVM.OpenDefaultsRequested([this](const auto&, const auto&) {
_Navigate(box_value(globalProfileTag));
});
_profilesPageVM.OpenColorSchemesRequested([this](const auto&, const auto&) {
_Navigate(box_value(colorSchemesTag), {}, {}, hstring{ profilesTag });
});
_profilesPageVM.AddProfileRequested([this](const auto&, const auto&) {
_Navigate(box_value(addProfileTag));
});
_profilesPageVM.OpenProfileRequested([this](const auto&, const Editor::ProfileViewModel& profile) {
_Navigate(profile);
});
}
winrt::Windows::UI::Xaml::Media::Brush MainPage::BackgroundBrush()
{
return SettingsNav().Background();
@@ -1196,7 +1144,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
co_return;
}
_currentSearch = SearchIndex::Instance().SearchAsync(sanitizedQuery,
_profileVMs.GetView(),
_profilesPageVM.Profiles().GetView(),
get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList().GetView(),
_colorSchemesPageVM.AllColorSchemes().GetView(),
_extensionsVM.ExtensionPackages().GetView(),

View File

@@ -84,21 +84,25 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
std::optional<HWND> _hostingHwnd;
void _InitializeProfilesList();
void _CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile);
winrt::Microsoft::UI::Xaml::Controls::NavigationViewItem _CreateProfileNavViewItem(const Editor::ProfileViewModel& profile);
void _CreateAndNavigateToNewProfile(const Model::Profile& profile);
void _DeleteProfile(const Windows::Foundation::IInspectable sender, const Editor::DeleteProfileEventArgs& args);
void _AddProfileHandler(const winrt::guid profileGuid);
void _SetupProfileEventHandling(const winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel profile);
void _SetupColorSchemesEventHandling();
void _SetupActionsEventHandling();
void _SetupProfilesPageEventHandling();
void _NavigateToProfileSubPage(const Editor::ProfileViewModel& profile, ProfileSubPage page, const IInspectable& breadcrumbTag, const hstring& elementToFocus);
void _PreNavigateHelper();
void _Navigate(const IInspectable& vm, BreadcrumbSubPage subPage, hstring elementToFocus = {});
void _Navigate(const IInspectable& vm, BreadcrumbSubPage subPage = BreadcrumbSubPage::None, hstring elementToFocus = {}, const hstring& parentNavTag = {});
void _NavigateToProfileHandler(const IInspectable& sender, winrt::guid profileGuid);
void _NavigateToColorSchemeHandler(const IInspectable& sender, const IInspectable& args);
Microsoft::UI::Xaml::Controls::NavigationViewItem _FindProfileNavItem(winrt::guid profileGuid) const;
Editor::ProfileViewModel _FindProfileViewModelByGuid(winrt::guid profileGuid) const;
void _AppendProfilesRootCrumb();
bool _RootCrumbIsProfilesBreadcrumb() const;
void _SelectNavItemByTag(std::wstring_view tag);
void _UpdateBackgroundForMica();
void _MoveXamlParsedNavItemsIntoItemSource();
@@ -106,11 +110,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
safe_void_coroutine _UpdateSearchIndex();
winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel _profileDefaultsVM{ nullptr };
Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel> _profileVMs{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::ActionsViewModel _actionsVM{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::NewTabMenuViewModel _newTabMenuPageVM{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::ExtensionsViewModel _extensionsVM{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::ProfilesPageViewModel _profilesPageVM{ nullptr };
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable>> _currentSearch{ nullptr };

View File

@@ -167,10 +167,6 @@
Tag="ColorSchemes_Nav" />
<muxc:NavigationViewItem x:Name="RenderingNavItem"
x:Uid="Nav_Rendering"
Tag="Rendering_Nav" />
<muxc:NavigationViewItem x:Name="CompatibilityNavItem"
x:Uid="Nav_Compatibility"
Tag="Compatibility_Nav" />
@@ -192,11 +188,9 @@
x:Uid="Nav_Extensions"
Tag="Extensions_Nav" />
<muxc:NavigationViewItemHeader x:Uid="Nav_Profiles" />
<muxc:NavigationViewItem x:Name="BaseLayerMenuItem"
x:Uid="Nav_ProfileDefaults"
Tag="GlobalProfile_Nav" />
<muxc:NavigationViewItem x:Name="ProfilesNavItem"
x:Uid="Nav_Profiles"
Tag="Profiles_Nav" />
</muxc:NavigationView.MenuItems>
<muxc:NavigationView.FooterMenuItems>

View File

@@ -86,6 +86,9 @@
<ClInclude Include="KeyChordListener.h">
<DependentUpon>KeyChordListener.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="KeyChordVisual.h">
<DependentUpon>KeyChordVisual.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Launch.h">
<DependentUpon>Launch.xaml</DependentUpon>
</ClInclude>
@@ -119,8 +122,8 @@
<DependentUpon>ColorSchemesPageViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="RenderingViewModel.h">
<DependentUpon>RenderingViewModel.idl</DependentUpon>
<ClInclude Include="Profiles.h">
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="InteractionViewModel.h">
@@ -167,9 +170,6 @@
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Rendering.h">
<DependentUpon>Rendering.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="SettingContainer.h">
<DependentUpon>SettingContainer.idl</DependentUpon>
</ClInclude>
@@ -216,6 +216,9 @@
<Page Include="KeyChordListener.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="KeyChordVisual.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Launch.xaml">
<SubType>Designer</SubType>
</Page>
@@ -231,6 +234,9 @@
<Page Include="Profiles_Base.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles_Base_Orphaned.xaml">
<SubType>Designer</SubType>
</Page>
@@ -246,9 +252,6 @@
<Page Include="Appearances.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Rendering.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="SettingContainerStyle.xaml">
<Type>DefaultStyle</Type>
</Page>
@@ -297,6 +300,9 @@
<ClCompile Include="KeyChordListener.cpp">
<DependentUpon>KeyChordListener.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="KeyChordVisual.cpp">
<DependentUpon>KeyChordVisual.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Launch.cpp">
<DependentUpon>Launch.xaml</DependentUpon>
</ClCompile>
@@ -331,8 +337,8 @@
<DependentUpon>ColorSchemesPageViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="RenderingViewModel.cpp">
<DependentUpon>RenderingViewModel.idl</DependentUpon>
<ClCompile Include="Profiles.cpp">
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="InteractionViewModel.cpp">
@@ -379,9 +385,6 @@
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Rendering.cpp">
<DependentUpon>Rendering.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="SettingContainer.cpp">
<DependentUpon>SettingContainer.idl</DependentUpon>
</ClCompile>
@@ -427,6 +430,10 @@
<DependentUpon>KeyChordListener.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="KeyChordVisual.idl">
<DependentUpon>KeyChordVisual.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Launch.idl">
<DependentUpon>Launch.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -443,10 +450,6 @@
<DependentUpon>Compatibility.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Rendering.idl">
<DependentUpon>Rendering.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="SearchIndex.idl" />
<Midl Include="MainPage.idl">
<DependentUpon>MainPage.xaml</DependentUpon>
@@ -456,7 +459,10 @@
<Midl Include="TerminalColorConverters.idl" />
<Midl Include="ColorSchemeViewModel.idl" />
<Midl Include="ColorSchemesPageViewModel.idl" />
<Midl Include="RenderingViewModel.idl" />
<Midl Include="Profiles.idl">
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="InteractionViewModel.idl" />
<Midl Include="GlobalAppearanceViewModel.idl" />
<Midl Include="LaunchViewModel.idl" />

View File

@@ -24,7 +24,6 @@
<Midl Include="ActionsViewModel.idl" />
<Midl Include="ColorSchemeViewModel.idl" />
<Midl Include="ColorSchemesPageViewModel.idl" />
<Midl Include="RenderingViewModel.idl" />
<Midl Include="InteractionViewModel.idl" />
<Midl Include="GlobalAppearanceViewModel.idl" />
<Midl Include="LaunchViewModel.idl" />
@@ -48,14 +47,15 @@
<Page Include="Profiles_Advanced.xaml" />
<Page Include="Profiles_Appearance.xaml" />
<Page Include="Appearances.xaml" />
<Page Include="Rendering.xaml" />
<Page Include="Actions.xaml" />
<Page Include="EditAction.xaml" />
<Page Include="SettingContainerStyle.xaml" />
<Page Include="AddProfile.xaml" />
<Page Include="KeyChordListener.xaml" />
<Page Include="KeyChordVisual.xaml" />
<Page Include="NullableColorPicker.xaml" />
<Page Include="IconPicker.xaml" />
<Page Include="NewTabMenu.xaml" />
<Page Include="Profiles.xaml" />
</ItemGroup>
</Project>

View File

@@ -12,11 +12,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
inline constexpr std::wstring_view openJsonTag{ L"OpenJson_Nav" };
inline constexpr std::wstring_view launchTag{ L"Launch_Nav" };
inline constexpr std::wstring_view interactionTag{ L"Interaction_Nav" };
inline constexpr std::wstring_view renderingTag{ L"Rendering_Nav" };
inline constexpr std::wstring_view compatibilityTag{ L"Compatibility_Nav" };
inline constexpr std::wstring_view actionsTag{ L"Actions_Nav" };
inline constexpr std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
inline constexpr std::wstring_view extensionsTag{ L"Extensions_Nav" };
inline constexpr std::wstring_view profilesTag{ L"Profiles_Nav" };
inline constexpr std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
inline constexpr std::wstring_view addProfileTag{ L"AddProfile" };
inline constexpr std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
@@ -28,11 +28,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
std::pair{ interactionTag, L"\xE7C9" }, /* Touch Pointer */
std::pair{ globalAppearanceTag, L"\xE771" }, /* Personalize */
std::pair{ colorSchemesTag, L"\xE790" }, /* Color */
std::pair{ renderingTag, L"\xE7F8" }, /* Device Laptop No Pic */
std::pair{ compatibilityTag, L"\xEC7A" }, /* Developer Tools */
std::pair{ actionsTag, L"\xE765" }, /* Keyboard Classic */
std::pair{ newTabMenuTag, L"\xE71D" }, /* All Apps */
std::pair{ extensionsTag, L"\xEA86" }, /* Puzzle */
std::pair{ profilesTag, L"\xE7EE" }, /* Other User */
std::pair{ globalProfileTag, L"\xE81E" }, /* Map Layers */
std::pair{ addProfileTag, L"\xE710" }, /* Add */
std::pair{ openJsonTag, L"\xE713" }, /* Settings */

View File

@@ -227,11 +227,27 @@
</ResourceDictionary>
</Page.Resources>
<Grid RowSpacing="12">
<Grid x:Name="RootGrid"
MaxWidth="{StaticResource StandardControlMaxWidth}"
ColumnSpacing="16"
RowSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ControlsColumn"
Width="*" />
<ColumnDefinition x:Name="PreviewColumn"
Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<!--
In the wide/medium (2-column) states, both PreviewArea and ControlsArea span
both rows so the row sizing here doesn't matter.
In the narrow (stacked) state, PreviewArea moves to row 0 and ControlsArea
moves to row 1, and the rows are resized via the visual state setters.
-->
<RowDefinition x:Name="PreviewRow"
Height="0" />
<RowDefinition x:Name="ControlsRow"
Height="*" />
</Grid.RowDefinitions>
<!-- Folder Picker Dialog: used to select a folder to move entries to -->
@@ -267,253 +283,390 @@
</muxc:TreeView>
</ContentDialog>
<!-- New Tab Menu Content -->
<StackPanel Grid.Row="0"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Spacing="8">
<Border Height="300"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="0,12,0,0"
<Grid x:Name="PreviewArea"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Grid.ColumnSpan="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--
Invisible header placeholder so the preview's top edge aligns with the first
SettingContainer in the controls column
-->
<TextBlock x:Name="PreviewHeaderPlaceholder"
Grid.Row="0"
Margin="0,4,0,4"
AutomationProperties.AccessibilityView="Raw"
IsHitTestVisible="False"
Opacity="0"
Style="{StaticResource TextBlockSubHeaderStyle}"
Text="Preview" />
<!-- Preview Border: contains the ListView and the multi-select footer. -->
<Border Grid.Row="1"
MinHeight="300"
Margin="0,4,0,0"
VerticalAlignment="Stretch"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1"
CornerRadius="{ThemeResource ControlCornerRadius}">
<ListView x:Name="NewTabMenuListView"
AllowDrop="True"
CanDragItems="True"
CanReorderItems="True"
ItemTemplateSelector="{StaticResource NewTabMenuEntryTemplateSelector}"
ItemsSource="{x:Bind ViewModel.CurrentView, Mode=OneWay}"
SelectionMode="Multiple" />
</Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- General Controls -->
<StackPanel Orientation="Horizontal"
Spacing="10">
<Button x:Name="MoveToFolderButton"
Click="MoveMultiple_Click"
IsEnabled="False">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8DE;" />
<TextBlock x:Uid="NewTabMenu_MoveToFolderTextBlock"
Margin="8,0,0,0" />
</StackPanel>
</Button>
<Button x:Name="DeleteMultipleButton"
Click="DeleteMultiple_Click"
IsEnabled="False"
Style="{StaticResource DeleteButtonStyle}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="NewTabMenu_DeleteMultipleTextBlock"
Margin="8,0,0,0" />
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
<!-- Folder View Controls -->
<StackPanel Grid.Row="1"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Visibility="{x:Bind ViewModel.IsFolderView, Mode=OneWay}">
<TextBlock x:Uid="NewTabMenu_CurrentFolderTextBlock"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Name -->
<local:SettingContainer x:Name="CurrentFolderName"
x:Uid="NewTabMenu_CurrentFolderName"
CurrentValue="{x:Bind ViewModel.CurrentFolderName, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.CurrentFolderName, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Name="CurrentFolderIcon"
x:Uid="NewTabMenu_CurrentFolderIcon"
CurrentValueAccessibleName="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<Grid>
<ContentControl Width="16"
Height="16"
Content="{x:Bind ViewModel.CurrentFolderIconPreview, Mode=OneWay}"
IsTabStop="False"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.CurrentFolderUsingNoIcon), Mode=OneWay}" />
<TextBlock Margin="0,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
Visibility="{x:Bind ViewModel.CurrentFolderUsingNoIcon, Mode=OneWay}" />
</Grid>
</local:SettingContainer.CurrentValue>
<local:SettingContainer.Content>
<local:IconPicker CurrentIconPath="{x:Bind ViewModel.CurrentFolderIconPath, Mode=TwoWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneWay}" />
</local:SettingContainer.Content>
</local:SettingContainer>
<!-- Inlining -->
<local:SettingContainer x:Name="CurrentFolderInlining"
x:Uid="NewTabMenu_CurrentFolderInlining">
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderInlining, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Allow Empty -->
<local:SettingContainer x:Name="CurrentFolderAllowEmpty"
x:Uid="NewTabMenu_CurrentFolderAllowEmpty">
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderAllowEmpty, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Add Entries -->
<StackPanel Grid.Row="2">
<TextBlock x:Uid="NewTabMenu_AddEntriesTextBlock"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Add Profile -->
<local:SettingContainer x:Name="AddProfile"
x:Uid="NewTabMenu_AddProfile"
FontIconGlyph="&#xE756;"
Style="{StaticResource SettingContainerWithIcon}">
<StackPanel Orientation="Horizontal"
Spacing="4">
<!-- Select profile to add -->
<ComboBox x:Name="AddProfileComboBox"
MinWidth="{StaticResource StandardBoxMinWidth}"
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedProfile, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<ListView x:Name="NewTabMenuListView"
Grid.Row="0"
AllowDrop="True"
CanDragItems="True"
CanReorderItems="True"
ItemTemplateSelector="{StaticResource NewTabMenuEntryTemplateSelector}"
ItemsSource="{x:Bind ViewModel.CurrentView, Mode=OneWay}"
SelectionMode="Multiple" />
<!-- Preview Controls -->
<Border Grid.Row="1"
Padding="8"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="0,1,0,0">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="MoveToFolderButton"
Grid.Column="0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Click="MoveMultiple_Click"
IsEnabled="False">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon.Resolved), Mode=OneTime}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
<FontIcon Grid.Column="0"
VerticalAlignment="Center"
FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8DE;" />
<TextBlock x:Uid="NewTabMenu_MoveToFolderTextBlock"
Grid.Column="1"
VerticalAlignment="Center"
TextWrapping="WrapWholeWords" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Button>
<Button x:Name="DeleteMultipleButton"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Click="DeleteMultiple_Click"
IsEnabled="False"
Style="{StaticResource DeleteButtonStyle}">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<FontIcon Grid.Column="0"
VerticalAlignment="Center"
FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="NewTabMenu_DeleteMultipleTextBlock"
Grid.Column="1"
VerticalAlignment="Center"
TextWrapping="WrapWholeWords" />
</Grid>
</Button>
</Grid>
</Border>
</Grid>
</Border>
</Grid>
<Button x:Name="AddProfileButton"
x:Uid="NewTabMenu_AddProfileButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddProfileButton_Clicked">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
<ScrollViewer x:Name="ControlsArea"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="1"
HorizontalScrollMode="Disabled"
VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- Folder View Controls -->
<StackPanel Margin="0,0,0,24"
Visibility="{x:Bind ViewModel.IsFolderView, Mode=OneWay}">
<TextBlock x:Uid="NewTabMenu_CurrentFolderTextBlock"
Margin="0,4,0,4"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Name -->
<local:SettingContainer x:Name="CurrentFolderName"
x:Uid="NewTabMenu_CurrentFolderName"
CurrentValue="{x:Bind ViewModel.CurrentFolderName, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind ViewModel.CurrentFolderName, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Name="CurrentFolderIcon"
x:Uid="NewTabMenu_CurrentFolderIcon"
CurrentValueAccessibleName="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<Grid>
<ContentControl Width="16"
Height="16"
Content="{x:Bind ViewModel.CurrentFolderIconPreview, Mode=OneWay}"
IsTabStop="False"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.CurrentFolderUsingNoIcon), Mode=OneWay}" />
<TextBlock Margin="0,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
Visibility="{x:Bind ViewModel.CurrentFolderUsingNoIcon, Mode=OneWay}" />
</Grid>
</local:SettingContainer.CurrentValue>
<local:SettingContainer.Content>
<local:IconPicker CurrentIconPath="{x:Bind ViewModel.CurrentFolderIconPath, Mode=TwoWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneWay}" />
</local:SettingContainer.Content>
</local:SettingContainer>
<!-- Inlining -->
<local:SettingContainer x:Name="CurrentFolderInlining"
x:Uid="NewTabMenu_CurrentFolderInlining">
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderInlining, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Allow Empty -->
<local:SettingContainer x:Name="CurrentFolderAllowEmpty"
x:Uid="NewTabMenu_CurrentFolderAllowEmpty">
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderAllowEmpty, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Add Separator -->
<local:SettingContainer x:Name="AddSeparator"
x:Uid="NewTabMenu_AddSeparator"
FontIconGlyph="&#xE76f;"
Style="{StaticResource SettingContainerWithIcon}">
<Button x:Name="AddSeparatorButton"
x:Uid="NewTabMenu_AddSeparatorButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddSeparatorButton_Clicked">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
</local:SettingContainer>
<!-- Add Entries -->
<StackPanel>
<TextBlock x:Uid="NewTabMenu_AddEntriesTextBlock"
Margin="0,4,0,4"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Add Folder -->
<local:SettingContainer x:Name="AddFolder"
x:Uid="NewTabMenu_AddFolder"
FontIconGlyph="&#xF12B;"
Style="{StaticResource SettingContainerWithIcon}">
<StackPanel Orientation="Horizontal"
Spacing="5">
<TextBox x:Name="FolderNameTextBox"
x:Uid="NewTabMenu_AddFolder_FolderName"
MinWidth="{StaticResource StandardBoxMinWidth}"
KeyDown="AddFolderNameTextBox_KeyDown"
Text="{x:Bind ViewModel.AddFolderName, Mode=TwoWay}"
TextChanged="AddFolderNameTextBox_TextChanged" />
<Button x:Name="AddFolderButton"
x:Uid="NewTabMenu_AddFolderButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddFolderButton_Clicked"
IsEnabled="False">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
</StackPanel>
</local:SettingContainer>
<!-- Add Profile -->
<local:SettingContainer x:Name="AddProfile"
x:Uid="NewTabMenu_AddProfile"
FontIconGlyph="&#xE756;"
Style="{StaticResource SettingContainerWithIcon}">
<!-- Add Match Profiles -->
<local:SettingContainer x:Name="AddMatchProfiles"
x:Uid="NewTabMenu_AddMatchProfiles"
FontIconGlyph="&#xE748;"
Style="{StaticResource ExpanderSettingContainerStyleWithIcon}">
<StackPanel Spacing="8">
<HyperlinkButton x:Uid="NewTabMenu_AddMatchProfiles_Help"
NavigateUri="https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference" />
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Name"
Text="{x:Bind ViewModel.ProfileMatcherName, Mode=TwoWay}" />
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Source"
Text="{x:Bind ViewModel.ProfileMatcherSource, Mode=TwoWay}" />
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Commandline"
Text="{x:Bind ViewModel.ProfileMatcherCommandline, Mode=TwoWay}" />
<Button x:Name="AddMatchProfilesButton"
Click="AddMatchProfilesButton_Clicked">
<Button.Content>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal"
Spacing="4">
<!-- Select profile to add -->
<ComboBox x:Name="AddProfileComboBox"
MinWidth="{StaticResource StandardBoxMinWidth}"
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedProfile, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:Profile">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="16" />
<!-- profile name -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<IconSourceElement Grid.Column="0"
Width="16"
Height="16"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon.Resolved), Mode=OneTime}" />
<TextBlock Grid.Column="1"
Text="{x:Bind Name}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button x:Name="AddProfileButton"
x:Uid="NewTabMenu_AddProfileButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddProfileButton_Clicked">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
</StackPanel>
</local:SettingContainer>
<!-- Add Separator -->
<local:SettingContainer x:Name="AddSeparator"
x:Uid="NewTabMenu_AddSeparator"
FontIconGlyph="&#xE76f;"
Style="{StaticResource SettingContainerWithIcon}">
<Button x:Name="AddSeparatorButton"
x:Uid="NewTabMenu_AddSeparatorButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddSeparatorButton_Clicked">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="NewTabMenu_AddMatchProfilesTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
</local:SettingContainer>
</Button.Content>
</Button>
</local:SettingContainer>
<!-- Add Remaining Profiles -->
<local:SettingContainer x:Name="AddRemainingProfiles"
x:Uid="NewTabMenu_AddRemainingProfiles"
FontIconGlyph="&#xE902;"
Style="{StaticResource SettingContainerWithIcon}">
<Button x:Name="AddRemainingProfilesButton"
x:Uid="NewTabMenu_AddRemainingProfilesButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddRemainingProfilesButton_Clicked"
IsEnabled="{x:Bind ViewModel.IsRemainingProfilesEntryMissing, Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
</local:SettingContainer>
</StackPanel>
<!-- Add Folder -->
<local:SettingContainer x:Name="AddFolder"
x:Uid="NewTabMenu_AddFolder"
FontIconGlyph="&#xF12B;"
Style="{StaticResource SettingContainerWithIcon}">
<StackPanel Orientation="Horizontal"
Spacing="5">
<TextBox x:Name="FolderNameTextBox"
x:Uid="NewTabMenu_AddFolder_FolderName"
MinWidth="{StaticResource StandardBoxMinWidth}"
KeyDown="AddFolderNameTextBox_KeyDown"
Text="{x:Bind ViewModel.AddFolderName, Mode=TwoWay}"
TextChanged="AddFolderNameTextBox_TextChanged" />
<Button x:Name="AddFolderButton"
x:Uid="NewTabMenu_AddFolderButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddFolderButton_Clicked"
IsEnabled="False">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
</StackPanel>
</local:SettingContainer>
<!-- Add Match Profiles -->
<local:SettingContainer x:Name="AddMatchProfiles"
x:Uid="NewTabMenu_AddMatchProfiles"
FontIconGlyph="&#xE748;"
Style="{StaticResource ExpanderSettingContainerStyleWithIcon}">
<StackPanel Spacing="8">
<HyperlinkButton x:Uid="NewTabMenu_AddMatchProfiles_Help"
NavigateUri="https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference" />
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Name"
Text="{x:Bind ViewModel.ProfileMatcherName, Mode=TwoWay}" />
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Source"
Text="{x:Bind ViewModel.ProfileMatcherSource, Mode=TwoWay}" />
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Commandline"
Text="{x:Bind ViewModel.ProfileMatcherCommandline, Mode=TwoWay}" />
<Button x:Name="AddMatchProfilesButton"
Click="AddMatchProfilesButton_Clicked">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="NewTabMenu_AddMatchProfilesTextBlock"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
</local:SettingContainer>
<!-- Add Remaining Profiles -->
<local:SettingContainer x:Name="AddRemainingProfiles"
x:Uid="NewTabMenu_AddRemainingProfiles"
FontIconGlyph="&#xE902;"
Style="{StaticResource SettingContainerWithIcon}">
<Button x:Name="AddRemainingProfilesButton"
x:Uid="NewTabMenu_AddRemainingProfilesButton"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="AddRemainingProfilesButton_Clicked"
IsEnabled="{x:Bind ViewModel.IsRemainingProfilesEntryMissing, Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
</local:SettingContainer>
</StackPanel>
</StackPanel>
</ScrollViewer>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<!-- Wide: 2 columns, controls on left with leading icons, preview on right. -->
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1200" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="AddProfile.Style" Value="{StaticResource SettingContainerWithIcon}" />
<Setter Target="AddSeparator.Style" Value="{StaticResource SettingContainerWithIcon}" />
<Setter Target="AddFolder.Style" Value="{StaticResource SettingContainerWithIcon}" />
<Setter Target="AddMatchProfiles.Style" Value="{StaticResource ExpanderSettingContainerStyleWithIcon}" />
<Setter Target="AddRemainingProfiles.Style" Value="{StaticResource SettingContainerWithIcon}" />
</VisualState.Setters>
</VisualState>
<!-- Medium: 2 columns, controls on left WITHOUT leading icons, preview on right. -->
<VisualState x:Name="Medium">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="900" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="AddProfile.Style" Value="{StaticResource DefaultSettingContainer}" />
<Setter Target="AddSeparator.Style" Value="{StaticResource DefaultSettingContainer}" />
<Setter Target="AddFolder.Style" Value="{StaticResource DefaultSettingContainer}" />
<Setter Target="AddMatchProfiles.Style" Value="{StaticResource ExpanderSettingContainerStyle}" />
<Setter Target="AddRemainingProfiles.Style" Value="{StaticResource DefaultSettingContainer}" />
</VisualState.Setters>
</VisualState>
<!-- Narrow: single column, preview stacked on top, controls below, no icons. -->
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- Collapse the preview column and give the preview row real height so the rows are used instead of the columns. -->
<Setter Target="PreviewColumn.Width" Value="0" />
<Setter Target="PreviewRow.Height" Value="Auto" />
<!-- Move PreviewArea to row 0, spanning both columns. -->
<Setter Target="PreviewArea.(Grid.Row)" Value="0" />
<Setter Target="PreviewArea.(Grid.RowSpan)" Value="1" />
<Setter Target="PreviewArea.(Grid.Column)" Value="0" />
<Setter Target="PreviewArea.(Grid.ColumnSpan)" Value="2" />
<!-- Move ControlsArea to row 1, spanning both columns. -->
<Setter Target="ControlsArea.(Grid.Row)" Value="1" />
<Setter Target="ControlsArea.(Grid.RowSpan)" Value="1" />
<Setter Target="ControlsArea.(Grid.Column)" Value="0" />
<Setter Target="ControlsArea.(Grid.ColumnSpan)" Value="2" />
<!-- No icons in the narrow state either (progressive simplification). -->
<Setter Target="AddProfile.Style" Value="{StaticResource DefaultSettingContainer}" />
<Setter Target="AddSeparator.Style" Value="{StaticResource DefaultSettingContainer}" />
<Setter Target="AddFolder.Style" Value="{StaticResource DefaultSettingContainer}" />
<Setter Target="AddMatchProfiles.Style" Value="{StaticResource ExpanderSettingContainerStyle}" />
<Setter Target="AddRemainingProfiles.Style" Value="{StaticResource DefaultSettingContainer}" />
<!-- Hide the preview header placeholder in stacked mode (no controls beside the preview to align with). -->
<Setter Target="PreviewHeaderPlaceholder.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</Page>

View File

@@ -106,6 +106,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_NotifyChanges(L"CurrentPathTranslationStyle");
}
else if (viewModelProperty == L"NotifyOnActivity")
{
_NotifyChanges(L"IsNotifyOnActivityFlagSet", L"NotifyOnActivityPreview");
}
else if (viewModelProperty == L"NotifyOnNextPrompt")
{
_NotifyChanges(L"IsNotifyOnNextPromptFlagSet", L"NotifyOnNextPromptPreview");
}
else if (viewModelProperty == L"Padding")
{
_parsedPadding = StringToXamlThickness(_profile.Padding());
@@ -127,6 +135,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_NotifyChanges(L"TabColorPreview");
}
else if (viewModelProperty == L"Name" || viewModelProperty == L"IsBaseLayer")
{
_NotifyChanges(L"SectionHeaderText");
}
});
_defaultAppearanceViewModel.PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
@@ -357,6 +369,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return RS_(L"Profile_TabTitleNone");
}
hstring ProfileViewModel::SectionHeaderText() const
{
if (IsBaseLayer())
{
return RS_(L"Profile_DefaultsSectionHeader");
}
return hstring{ RS_fmt(L"Profile_NameSectionHeaderFormat", Name()) };
}
hstring ProfileViewModel::AnswerbackMessagePreview() const
{
if (const auto answerbackMessage{ AnswerbackMessage() }; !answerbackMessage.empty())
@@ -571,6 +592,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return iconPath.empty() || iconPath == IconPicker::HideIconValue;
}
#pragma region BellStyle
hstring ProfileViewModel::BellStylePreview() const
{
const auto bellStyle = BellStyle();
@@ -650,6 +672,147 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
WI_UpdateFlag(currentStyle, Model::BellStyle::Notification, winrt::unbox_value<bool>(on));
BellStyle(currentStyle);
}
#pragma endregion
#pragma region NotifyOnActivity
hstring ProfileViewModel::NotifyOnActivityPreview() const
{
using Ons = Control::OutputNotificationStyle;
const auto style = NotifyOnActivity();
if (WI_AreAllFlagsSet(style, Ons::Taskbar | Ons::Audible | Ons::Tab | Ons::Notification))
{
return RS_(L"Profile_OutputNotificationStyleAll/Content");
}
else if (style == Ons::None)
{
return RS_(L"Profile_OutputNotificationStyleNone/Content");
}
std::wstring result;
const auto appendIfFlagSet = [&](Ons flag, std::wstring_view resource) {
// WI_IsFlagSet requires a compile-time constant flag; `flag` is a runtime parameter here.
if ((WI_EnumValue(style) & WI_EnumValue(flag)) != 0)
{
if (!result.empty())
{
result.append(L", ");
}
result.append(resource);
}
};
appendIfFlagSet(Ons::Taskbar, RS_(L"Profile_OutputNotificationStyleTaskbar/Content"));
appendIfFlagSet(Ons::Audible, RS_(L"Profile_OutputNotificationStyleAudible/Content"));
appendIfFlagSet(Ons::Tab, RS_(L"Profile_OutputNotificationStyleTab/Content"));
appendIfFlagSet(Ons::Notification, RS_(L"Profile_OutputNotificationStyleNotification/Content"));
return hstring{ result };
}
bool ProfileViewModel::IsNotifyOnActivityFlagSet(const uint32_t flag)
{
return (WI_EnumValue(NotifyOnActivity()) & flag) == flag;
}
void ProfileViewModel::SetNotifyOnActivityTaskbar(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnActivity();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Taskbar, winrt::unbox_value<bool>(on));
NotifyOnActivity(currentStyle);
}
void ProfileViewModel::SetNotifyOnActivityAudible(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnActivity();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Audible, winrt::unbox_value<bool>(on));
NotifyOnActivity(currentStyle);
}
void ProfileViewModel::SetNotifyOnActivityTab(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnActivity();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Tab, winrt::unbox_value<bool>(on));
NotifyOnActivity(currentStyle);
}
void ProfileViewModel::SetNotifyOnActivityNotification(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnActivity();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Notification, winrt::unbox_value<bool>(on));
NotifyOnActivity(currentStyle);
}
#pragma endregion
#pragma region NotifyOnNextPrompt
hstring ProfileViewModel::NotifyOnNextPromptPreview() const
{
using Ons = Control::OutputNotificationStyle;
const auto style = NotifyOnNextPrompt();
if (WI_AreAllFlagsSet(style, Ons::Taskbar | Ons::Audible | Ons::Tab | Ons::Notification))
{
return RS_(L"Profile_OutputNotificationStyleAll/Content");
}
else if (style == Ons::None)
{
return RS_(L"Profile_OutputNotificationStyleNone/Content");
}
std::wstring result;
const auto appendIfFlagSet = [&](Ons flag, std::wstring_view resource) {
// WI_IsFlagSet requires a compile-time constant flag; `flag` is a runtime parameter here.
if ((WI_EnumValue(style) & WI_EnumValue(flag)) != 0)
{
if (!result.empty())
{
result.append(L", ");
}
result.append(resource);
}
};
appendIfFlagSet(Ons::Taskbar, RS_(L"Profile_OutputNotificationStyleTaskbar/Content"));
appendIfFlagSet(Ons::Audible, RS_(L"Profile_OutputNotificationStyleAudible/Content"));
appendIfFlagSet(Ons::Tab, RS_(L"Profile_OutputNotificationStyleTab/Content"));
appendIfFlagSet(Ons::Notification, RS_(L"Profile_OutputNotificationStyleNotification/Content"));
return hstring{ result };
}
bool ProfileViewModel::IsNotifyOnNextPromptFlagSet(const uint32_t flag)
{
return (WI_EnumValue(NotifyOnNextPrompt()) & flag) == flag;
}
void ProfileViewModel::SetNotifyOnNextPromptTaskbar(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Taskbar, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
void ProfileViewModel::SetNotifyOnNextPromptAudible(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Audible, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
void ProfileViewModel::SetNotifyOnNextPromptTab(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Tab, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
void ProfileViewModel::SetNotifyOnNextPromptNotification(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Notification, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
#pragma endregion
#pragma region BellSound
// Method Description:
// - Construct _CurrentBellSounds by importing the _inherited_ value from the model
@@ -788,6 +951,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_NotifyChanges(L"CurrentBellSounds");
}
}
#pragma endregion
void ProfileViewModel::DeleteProfile()
{

View File

@@ -48,6 +48,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on);
void SetBellStyleNotification(winrt::Windows::Foundation::IReference<bool> on);
// notify on activity bits
hstring NotifyOnActivityPreview() const;
bool IsNotifyOnActivityFlagSet(const uint32_t flag);
void SetNotifyOnActivityTaskbar(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnActivityAudible(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnActivityTab(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnActivityNotification(winrt::Windows::Foundation::IReference<bool> on);
// notify on next prompt bits
hstring NotifyOnNextPromptPreview() const;
bool IsNotifyOnNextPromptFlagSet(const uint32_t flag);
void SetNotifyOnNextPromptTaskbar(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnNextPromptAudible(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnNextPromptTab(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnNextPromptNotification(winrt::Windows::Foundation::IReference<bool> on);
hstring BellSoundPreview();
void RequestAddBellSound(hstring path);
void RequestDeleteBellSound(const Editor::BellSoundViewModel& vm);
@@ -100,6 +116,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
bool AutoMarkPromptsAvailable() const noexcept;
bool RepositionCursorWithMouseAvailable() const noexcept;
hstring SectionHeaderText() const;
bool Orphaned() const;
hstring TabTitlePreview() const;
hstring AnswerbackMessagePreview() const;
@@ -143,10 +160,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, AllowKittyKeyboardMode);
OBSERVABLE_PROJECTED_SETTING(_profile, AllowVtChecksumReport);
OBSERVABLE_PROJECTED_SETTING(_profile, AllowVtClipboardWrite);
OBSERVABLE_PROJECTED_SETTING(_profile, AllowOscNotifications);
OBSERVABLE_PROJECTED_SETTING(_profile, AnswerbackMessage);
OBSERVABLE_PROJECTED_SETTING(_profile, RainbowSuggestions);
OBSERVABLE_PROJECTED_SETTING(_profile, PathTranslationStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, DragDropDelimiter);
OBSERVABLE_PROJECTED_SETTING(_profile, NotifyOnActivity);
OBSERVABLE_PROJECTED_SETTING(_profile, NotifyOnNextPrompt);
OBSERVABLE_PROJECTED_SETTING(_profile, NotifyOnActivityThreshold);
OBSERVABLE_PROJECTED_SETTING(_profile, NotifyOnNextPromptThreshold);
OBSERVABLE_PROJECTED_SETTING(_profile, AutoDetectRunningCommand);
WINRT_PROPERTY(bool, IsBaseLayer, false);
WINRT_PROPERTY(bool, FocusDeleteButton, false);

View File

@@ -51,6 +51,20 @@ namespace Microsoft.Terminal.Settings.Editor
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleNotification(Windows.Foundation.IReference<Boolean> on);
String NotifyOnActivityPreview { get; };
Boolean IsNotifyOnActivityFlagSet(UInt32 flag);
void SetNotifyOnActivityTaskbar(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnActivityAudible(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnActivityTab(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnActivityNotification(Windows.Foundation.IReference<Boolean> on);
String NotifyOnNextPromptPreview { get; };
Boolean IsNotifyOnNextPromptFlagSet(UInt32 flag);
void SetNotifyOnNextPromptTaskbar(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnNextPromptAudible(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnNextPromptTab(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnNextPromptNotification(Windows.Foundation.IReference<Boolean> on);
String BellSoundPreview { get; };
Windows.Foundation.Collections.IObservableVector<BellSoundViewModel> CurrentBellSounds { get; };
void RequestAddBellSound(String path);
@@ -105,6 +119,7 @@ namespace Microsoft.Terminal.Settings.Editor
void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance();
String SectionHeaderText { get; };
Boolean Orphaned { get; };
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Name);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, Guid);
@@ -142,5 +157,11 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, DragDropDelimiter);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowOscNotifications);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnActivity);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnNextPrompt);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, NotifyOnActivityThreshold);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, NotifyOnNextPromptThreshold);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AutoDetectRunningCommand);
}
}

View File

@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Profiles.h"
#include "Profiles.g.cpp"
#include "ProfilesPageViewModel.g.cpp"
#include "ProfileViewModel.h"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles::Profiles()
{
InitializeComponent();
Automation::AutomationProperties::SetName(DefaultsNavigator(), RS_(L"Profiles_DefaultsNavigator_Title/Text"));
Automation::AutomationProperties::SetName(ColorSchemesNavigator(), RS_(L"Profiles_ColorSchemesNavigator_Title/Text"));
Automation::AutomationProperties::SetName(AddProfileButton(), RS_(L"Profiles_AddProfileButton/Text"));
}
void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
{
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
_ViewModel = args.ViewModel().as<Editor::ProfilesPageViewModel>();
BringIntoViewWhenLoaded(args.ElementToFocus());
TraceLoggingWrite(
g_hTerminalSettingsEditorProvider,
"NavigatedToPage",
TraceLoggingDescription("Event emitted when the user navigates to a page in the settings UI"),
TraceLoggingValue("profilesLanding", "PageId", "The identifier of the page that was navigated to"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
void Profiles::Defaults_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
{
_ViewModel.RequestOpenDefaults();
}
void Profiles::ColorSchemes_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
{
_ViewModel.RequestOpenColorSchemes();
}
void Profiles::AddProfile_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
{
_ViewModel.RequestAddProfile();
}
void Profiles::Profile_Click(const IInspectable& sender, const RoutedEventArgs& /*args*/)
{
// Profile navigators are buttons whose DataContext is the bound ProfileViewModel.
if (const auto element = sender.try_as<FrameworkElement>())
{
if (const auto profile = element.DataContext().try_as<Editor::ProfileViewModel>())
{
_ViewModel.RequestOpenProfile(profile);
}
}
}
ProfilesPageViewModel::ProfilesPageViewModel()
{
_setProfiles(single_threaded_observable_vector<Editor::ProfileViewModel>());
}
void ProfilesPageViewModel::RequestOpenDefaults()
{
OpenDefaultsRequested.raise(*this, nullptr);
}
void ProfilesPageViewModel::RequestOpenColorSchemes()
{
OpenColorSchemesRequested.raise(*this, nullptr);
}
void ProfilesPageViewModel::RequestAddProfile()
{
AddProfileRequested.raise(*this, nullptr);
}
void ProfilesPageViewModel::RequestOpenProfile(const Editor::ProfileViewModel& profile)
{
OpenProfileRequested.raise(*this, profile);
}
}

View File

@@ -0,0 +1,67 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- Profiles.h
Abstract:
- The Profiles landing page in the Settings UI. The page hosts entry points to
the list of individual profiles among other profile-related settings.
--*/
#pragma once
#include "Profiles.g.h"
#include "ProfilesPageViewModel.g.h"
#include "ProfileViewModel.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct ProfilesPageViewModel : ProfilesPageViewModelT<ProfilesPageViewModel>, ViewModelHelper<ProfilesPageViewModel>
{
public:
ProfilesPageViewModel();
void RequestOpenDefaults();
void RequestOpenColorSchemes();
void RequestAddProfile();
void RequestOpenProfile(const Editor::ProfileViewModel& profile);
// DON'T YOU DARE ADD A `WINRT_CALLBACK(PropertyChanged` TO A CLASS DERIVED FROM ViewModelHelper. Do this instead:
using ViewModelHelper<ProfilesPageViewModel>::PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::ProfileViewModel>, Profiles, _propertyChangedHandlers, nullptr);
public:
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> OpenDefaultsRequested;
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> OpenColorSchemesRequested;
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> AddProfileRequested;
til::typed_event<Windows::Foundation::IInspectable, Editor::ProfileViewModel> OpenProfileRequested;
};
struct Profiles : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
{
public:
Profiles();
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void Defaults_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
void ColorSchemes_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
void AddProfile_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
void Profile_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
til::property_changed_event PropertyChanged;
WINRT_PROPERTY(Editor::ProfilesPageViewModel, ViewModel, nullptr);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Profiles);
BASIC_FACTORY(ProfilesPageViewModel);
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "ProfileViewModel.idl";
import "ColorSchemeViewModel.idl";
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass ProfilesPageViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
ProfilesPageViewModel();
Windows.Foundation.Collections.IObservableVector<ProfileViewModel> Profiles { get; };
void RequestOpenDefaults();
void RequestOpenColorSchemes();
void RequestAddProfile();
void RequestOpenProfile(ProfileViewModel profile);
event Windows.Foundation.TypedEventHandler<Object, IInspectable> OpenDefaultsRequested;
event Windows.Foundation.TypedEventHandler<Object, IInspectable> OpenColorSchemesRequested;
event Windows.Foundation.TypedEventHandler<Object, IInspectable> AddProfileRequested;
event Windows.Foundation.TypedEventHandler<Object, ProfileViewModel> OpenProfileRequested;
}
[default_interface] runtimeclass Profiles : Windows.UI.Xaml.Controls.Page
{
Profiles();
ProfilesPageViewModel ViewModel { get; };
}
}

View File

@@ -0,0 +1,136 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Microsoft.Terminal.Settings.Model"
xmlns:mtu="using:Microsoft.Terminal.UI"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="ProfileNavigatorTemplate"
x:DataType="local:ProfileViewModel">
<Button HorizontalAlignment="Stretch"
AutomationProperties.Name="{x:Bind Name, Mode=OneWay}"
Click="Profile_Click"
Style="{StaticResource NavigatorButtonStyle}">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0"
Width="16"
Height="16"
VerticalAlignment="Center"
Content="{x:Bind IconPreview, Mode=OneWay}"
IsTabStop="False" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource BodyStrongTextBlockStyle}"
Text="{x:Bind Name, Mode=OneWay}"
TextTrimming="CharacterEllipsis" />
<muxc:InfoBadge Grid.Column="2"
Margin="0,0,8,0"
VerticalAlignment="Center"
Visibility="{x:Bind Hidden, Mode=OneWay}">
<muxc:InfoBadge.IconSource>
<muxc:FontIconSource FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
FontSize="12"
Glyph="&#xED1A;" />
</muxc:InfoBadge.IconSource>
</muxc:InfoBadge>
<muxc:InfoBadge Grid.Column="2"
Margin="0,0,8,0"
VerticalAlignment="Center"
Visibility="{x:Bind Orphaned, Mode=OneWay}">
<muxc:InfoBadge.IconSource>
<muxc:FontIconSource FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
FontSize="12"
Glyph="&#xE7BA;" />
</muxc:InfoBadge.IconSource>
</muxc:InfoBadge>
</Grid>
</Button>
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- General Profile Settings -->
<TextBlock x:Uid="Profiles_GeneralSettingsHeader"
Margin="0,0,0,4"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Defaults navigator -->
<Button x:Name="DefaultsNavigator"
Click="Defaults_Click"
Style="{StaticResource NavigatorButtonStyle}">
<StackPanel Orientation="Vertical">
<TextBlock x:Uid="Profiles_DefaultsNavigator_Title"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBlock x:Uid="Profiles_DefaultsNavigator_Description"
Margin="0,2,0,0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
TextWrapping="Wrap" />
</StackPanel>
</Button>
<!-- Color schemes navigator -->
<Button x:Name="ColorSchemesNavigator"
Click="ColorSchemes_Click"
Style="{StaticResource NavigatorButtonStyle}">
<StackPanel Orientation="Vertical">
<TextBlock x:Uid="Profiles_ColorSchemesNavigator_Title"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBlock x:Uid="Profiles_ColorSchemesNavigator_Description"
Margin="0,2,0,0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
TextWrapping="Wrap" />
</StackPanel>
</Button>
<!-- Terminal profiles section -->
<TextBlock x:Uid="Profiles_TerminalProfilesHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Add Profile accent button -->
<Button x:Name="AddProfileButton"
Margin="0,4,0,0"
Click="AddProfile_Click"
Style="{StaticResource AccentButtonStyle}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="Profiles_AddProfileButton"
Style="{StaticResource IconButtonTextBlockStyle}" />
</StackPanel>
</Button>
<!-- List of profiles. Each is a NavigatorButtonStyle button rendered by ProfileNavigatorTemplate. -->
<ItemsControl Margin="0,0,0,16"
ItemTemplate="{StaticResource ProfileNavigatorTemplate}"
ItemsSource="{x:Bind ViewModel.Profiles, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Page>

View File

@@ -198,6 +198,84 @@
</StackPanel>
</local:SettingContainer>
<!-- Notify On Activity -->
<local:SettingContainer x:Name="NotifyOnActivity"
x:Uid="Profile_NotifyOnActivity"
ClearSettingValue="{x:Bind Profile.ClearNotifyOnActivity}"
CurrentValue="{x:Bind Profile.NotifyOnActivityPreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasNotifyOnActivity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.NotifyOnActivityOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_OutputNotificationStyleTaskbar"
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(1), BindBack=Profile.SetNotifyOnActivityTaskbar, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleAudible"
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(2), BindBack=Profile.SetNotifyOnActivityAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleTab"
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(4), BindBack=Profile.SetNotifyOnActivityTab, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleNotification"
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(8), BindBack=Profile.SetNotifyOnActivityNotification, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Notify On Activity Minimum Duration -->
<local:SettingContainer x:Name="NotifyOnActivityThreshold"
x:Uid="Profile_NotifyOnActivityThreshold"
ClearSettingValue="{x:Bind Profile.ClearNotifyOnActivityThreshold}"
HasSettingValue="{x:Bind Profile.HasNotifyOnActivityThreshold, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.NotifyOnActivityThresholdOverrideSource, Mode=OneWay}">
<muxc:NumberBox AutomationProperties.Name="{Binding ElementName=NotifyOnActivityThreshold, Path=Header}"
LargeChange="10"
Minimum="0"
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind Profile.NotifyOnActivityThreshold, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Notify On Next Prompt -->
<local:SettingContainer x:Name="NotifyOnNextPrompt"
x:Uid="Profile_NotifyOnNextPrompt"
ClearSettingValue="{x:Bind Profile.ClearNotifyOnNextPrompt}"
CurrentValue="{x:Bind Profile.NotifyOnNextPromptPreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasNotifyOnNextPrompt, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.NotifyOnNextPromptOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_OutputNotificationStyleTaskbar"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(1), BindBack=Profile.SetNotifyOnNextPromptTaskbar, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleAudible"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(2), BindBack=Profile.SetNotifyOnNextPromptAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleTab"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(4), BindBack=Profile.SetNotifyOnNextPromptTab, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleNotification"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(8), BindBack=Profile.SetNotifyOnNextPromptNotification, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Notify On Next Prompt Minimum Duration -->
<local:SettingContainer x:Name="NotifyOnNextPromptThreshold"
x:Uid="Profile_NotifyOnNextPromptThreshold"
ClearSettingValue="{x:Bind Profile.ClearNotifyOnNextPromptThreshold}"
HasSettingValue="{x:Bind Profile.HasNotifyOnNextPromptThreshold, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.NotifyOnNextPromptThresholdOverrideSource, Mode=OneWay}">
<muxc:NumberBox AutomationProperties.Name="{Binding ElementName=NotifyOnNextPromptThreshold, Path=Header}"
LargeChange="10"
Minimum="0"
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind Profile.NotifyOnNextPromptThreshold, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Auto Detect Running Command -->
<local:SettingContainer x:Name="AutoDetectRunningCommand"
x:Uid="Profile_AutoDetectRunningCommand"
ClearSettingValue="{x:Bind Profile.ClearAutoDetectRunningCommand}"
HasSettingValue="{x:Bind Profile.HasAutoDetectRunningCommand, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AutoDetectRunningCommandOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.AutoDetectRunningCommand, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- RightClickContextMenu -->
<local:SettingContainer x:Name="RightClickContextMenu"
x:Uid="Profile_RightClickContextMenu"

View File

@@ -80,131 +80,124 @@
SourceProfile="{x:Bind Profile, Mode=OneWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
<!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_TransparencyHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Section: Window settings -->
<local:SettingContainer x:Uid="Profile_Section_Window"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Opacity -->
<local:SettingContainer x:Name="Opacity"
x:Uid="Profile_Opacity"
ClearSettingValue="{x:Bind Profile.ClearOpacity}"
HasSettingValue="{x:Bind Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.OpacityOverrideSource, Mode=OneWay}">
<StackPanel>
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Uid="Profile_OpacitySlider"
Grid.Column="0"
Value="{x:Bind mtu:Converters.PercentageToPercentageValue(Profile.Opacity), BindBack=Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind mtu:Converters.PercentageToPercentageString(Profile.Opacity), Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Opacity -->
<local:SettingContainer x:Name="Opacity"
x:Uid="Profile_Opacity"
ClearSettingValue="{x:Bind Profile.ClearOpacity}"
HasSettingValue="{x:Bind Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.OpacityOverrideSource, Mode=OneWay}">
<StackPanel>
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Uid="Profile_OpacitySlider"
Grid.Column="0"
Value="{x:Bind mtu:Converters.PercentageToPercentageValue(Profile.Opacity), BindBack=Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind mtu:Converters.PercentageToPercentageString(Profile.Opacity), Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Use Acrylic -->
<local:SettingContainer x:Name="UseAcrylic"
x:Uid="Profile_UseAcrylic"
ClearSettingValue="{x:Bind Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAcrylicOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Use Acrylic -->
<local:SettingContainer x:Name="UseAcrylic"
x:Uid="Profile_UseAcrylic"
ClearSettingValue="{x:Bind Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAcrylicOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Padding -->
<local:SettingContainer x:Name="Padding"
x:Uid="Profile_Padding"
ClearSettingValue="{x:Bind Profile.ClearPadding}"
CurrentValue="{x:Bind Profile.Padding, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.PaddingOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Border Margin="0,12,0,12"
Padding="2,0,2,0"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolidBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}">
<Grid>
</StackPanel>
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="48" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<!-- Grouping: Window -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_WindowHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<Grid.ColumnDefinitions>
<ColumnDefinition Width="72" />
<ColumnDefinition Width="72" />
<ColumnDefinition Width="72" />
</Grid.ColumnDefinitions>
<!-- Padding -->
<local:SettingContainer x:Name="Padding"
x:Uid="Profile_Padding"
ClearSettingValue="{x:Bind Profile.ClearPadding}"
CurrentValue="{x:Bind Profile.Padding, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.PaddingOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Border Margin="0,12,0,12"
Padding="2,0,2,0"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolidBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}">
<Grid>
<muxc:NumberBox Grid.Row="1"
Grid.Column="0"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.LeftPadding, Mode=TwoWay}" />
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="48" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<muxc:NumberBox Grid.Row="0"
Grid.Column="1"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.TopPadding, Mode=TwoWay}" />
<Grid.ColumnDefinitions>
<ColumnDefinition Width="72" />
<ColumnDefinition Width="72" />
<ColumnDefinition Width="72" />
</Grid.ColumnDefinitions>
<muxc:NumberBox Grid.Row="1"
Grid.Column="2"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.RightPadding, Mode=TwoWay}" />
<muxc:NumberBox Grid.Row="1"
Grid.Column="0"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.LeftPadding, Mode=TwoWay}" />
<muxc:NumberBox Grid.Row="2"
Grid.Column="1"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.BottomPadding, Mode=TwoWay}" />
<muxc:NumberBox Grid.Row="0"
Grid.Column="1"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.TopPadding, Mode=TwoWay}" />
</Grid>
</Border>
</local:SettingContainer>
<muxc:NumberBox Grid.Row="1"
Grid.Column="2"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.RightPadding, Mode=TwoWay}" />
<muxc:NumberBox Grid.Row="2"
Grid.Column="1"
LargeChange="10"
Maximum="100"
Minimum="0"
SmallChange="1"
Style="{StaticResource PaddingNumberBoxStyle}"
Value="{x:Bind Profile.BottomPadding, Mode=TwoWay}" />
</Grid>
</Border>
</local:SettingContainer>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Name="ScrollbarVisibility"
x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Name="ScrollbarVisibility"
x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<StackPanel MaxWidth="{StaticResource StandardControlMaxWidth}">
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind Profile.EditableUnfocusedAppearance, Mode=OneWay}">

View File

@@ -23,7 +23,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
AppearanceNavigator().Content(box_value(RS_(L"Profile_Appearance/Header")));
AppearanceNavigator().Tag(box_value(RS_(L"Profile_AppearanceNavigator/HelpText")));
TerminalNavigator().Content(box_value(RS_(L"Profile_Terminal/Header")));
TerminalNavigator().Tag(box_value(RS_(L"Profile_TerminalNavigator/HelpText")));
AdvancedNavigator().Content(box_value(RS_(L"Profile_Advanced/Header")));
}

View File

@@ -34,147 +34,161 @@
<StackPanel Grid.Row="1"
Style="{StaticResource SettingsStackStyle}">
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Name="Name"
x:Uid="Profile_Name"
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="Commandline"
x:Uid="Profile_Commandline"
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<!-- Section: {Profile.Name} profile (or "Profile defaults") -->
<local:SettingContainer x:Uid="Profile_Section_HeaderPlaceholder"
Header="{x:Bind Profile.SectionHeaderText, Mode=OneWay}"
StartExpanded="True"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<TextBox x:Uid="Profile_CommandlineBox"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Margin="0,8,0,0"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Name="Name"
x:Uid="Profile_Name"
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="Commandline"
x:Uid="Profile_Commandline"
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<StackPanel>
<TextBox x:Uid="Profile_CommandlineBox"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Margin="0,8,0,0"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectory"
x:Uid="Profile_StartingDirectory"
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
CurrentValue="{x:Bind Profile.CurrentStartingDirectoryPreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Vertical">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<StackPanel Orientation="Horizontal">
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Margin="0,12,12,0"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
Margin="0,4,0,0"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</StackPanel>
</local:SettingContainer>
<!-- Elevate -->
<local:SettingContainer x:Name="Elevate"
x:Uid="Profile_Elevate"
ClearSettingValue="{x:Bind Profile.ClearElevate}"
HasSettingValue="{x:Bind Profile.HasElevate, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ElevateOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Elevate, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectory"
x:Uid="Profile_StartingDirectory"
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
CurrentValue="{x:Bind Profile.CurrentStartingDirectoryPreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Vertical">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<StackPanel Orientation="Horizontal">
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Margin="0,12,12,0"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
Margin="0,4,0,0"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
<!-- Section: Visual/UI Affordance -->
<local:SettingContainer x:Uid="Profile_Section_VisualUI"
Style="{StaticResource SectionExpanderStyle}">
<StackPanel>
<!-- Tab Title -->
<local:SettingContainer x:Name="TabTitle"
x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
CurrentValue="{x:Bind Profile.TabTitlePreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Tab Color -->
<local:SettingContainer x:Name="TabColor"
x:Uid="Profile_TabColor"
ClearSettingValue="{x:Bind Profile.ClearTabColor}"
CurrentValue="{x:Bind Profile.TabColorPreview, Mode=OneWay}"
CurrentValueAccessibleName="{x:Bind Profile.TabColorPreview, Converter={StaticResource ColorToStringConverter}, Mode=OneWay}"
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Profile.HasTabColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabColorOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_TabColor_NullableColorPicker"
ColorSchemeVM="{x:Bind Profile.DefaultAppearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Profile.TabColor, Mode=TwoWay}"
NullColorPreview="{x:Bind Profile.TabThemeColorPreview, Mode=OneWay}" />
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Name="Icon"
x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind Profile.ClearIcon}"
CurrentValueAccessibleName="{x:Bind Profile.LocalizedIcon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<Grid>
<ContentControl Width="16"
Height="16"
Content="{x:Bind Profile.IconPreview, Mode=OneWay}"
IsTabStop="False"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.UsingNoIcon), Mode=OneWay}" />
<TextBlock Margin="0,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{x:Bind Profile.LocalizedIcon, Mode=OneWay}"
Visibility="{x:Bind Profile.UsingNoIcon, Mode=OneWay}" />
</Grid>
</local:SettingContainer.CurrentValue>
<local:SettingContainer.Content>
<local:IconPicker CurrentIconPath="{x:Bind Profile.IconPath, Mode=TwoWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneWay}" />
</local:SettingContainer.Content>
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Name="Hidden"
x:Uid="Profile_Hidden"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Name="Icon"
x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind Profile.ClearIcon}"
CurrentValueAccessibleName="{x:Bind Profile.LocalizedIcon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<Grid>
<ContentControl Width="16"
Height="16"
Content="{x:Bind Profile.IconPreview, Mode=OneWay}"
IsTabStop="False"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.UsingNoIcon), Mode=OneWay}" />
<TextBlock Margin="0,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{x:Bind Profile.LocalizedIcon, Mode=OneWay}"
Visibility="{x:Bind Profile.UsingNoIcon, Mode=OneWay}" />
</Grid>
</local:SettingContainer.CurrentValue>
<local:SettingContainer.Content>
<local:IconPicker CurrentIconPath="{x:Bind Profile.IconPath, Mode=TwoWay}"
WindowRoot="{x:Bind WindowRoot, Mode=OneWay}" />
</local:SettingContainer.Content>
</local:SettingContainer>
<!-- Tab Title -->
<local:SettingContainer x:Name="TabTitle"
x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
CurrentValue="{x:Bind Profile.TabTitlePreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Tab Color -->
<local:SettingContainer x:Name="TabColor"
x:Uid="Profile_TabColor"
ClearSettingValue="{x:Bind Profile.ClearTabColor}"
CurrentValue="{x:Bind Profile.TabColorPreview, Mode=OneWay}"
CurrentValueAccessibleName="{x:Bind Profile.TabColorPreview, Converter={StaticResource ColorToStringConverter}, Mode=OneWay}"
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Profile.HasTabColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabColorOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_TabColor_NullableColorPicker"
ColorSchemeVM="{x:Bind Profile.DefaultAppearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Profile.TabColor, Mode=TwoWay}"
NullColorPreview="{x:Bind Profile.TabThemeColorPreview, Mode=OneWay}" />
</local:SettingContainer>
<!-- Elevate -->
<local:SettingContainer x:Name="Elevate"
x:Uid="Profile_Elevate"
ClearSettingValue="{x:Bind Profile.ClearElevate}"
HasSettingValue="{x:Bind Profile.HasElevate, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ElevateOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Elevate, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Name="Hidden"
x:Uid="Profile_Hidden"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
Margin="0,32,0,4"
Style="{StaticResource TextBlockSubHeaderStyle}" />

View File

@@ -81,6 +81,16 @@
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Allow OSC 777 Desktop Notifications -->
<local:SettingContainer x:Name="AllowOscNotifications"
x:Uid="Profile_AllowOscNotifications"
ClearSettingValue="{x:Bind Profile.ClearAllowOscNotifications}"
HasSettingValue="{x:Bind Profile.HasAllowOscNotifications, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AllowOscNotificationsOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.AllowOscNotifications, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Answerback Message -->
<local:SettingContainer x:Name="AnswerbackMessage"
x:Uid="Profile_AnswerbackMessage"

View File

@@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Rendering.h"
#include "Rendering.g.cpp"
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Rendering::Rendering()
{
InitializeComponent();
}
void Rendering::OnNavigatedTo(const NavigationEventArgs& e)
{
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
_ViewModel = args.ViewModel().as<Editor::RenderingViewModel>();
BringIntoViewWhenLoaded(args.ElementToFocus());
TraceLoggingWrite(
g_hTerminalSettingsEditorProvider,
"NavigatedToPage",
TraceLoggingDescription("Event emitted when the user navigates to a page in the settings UI"),
TraceLoggingValue("rendering", "PageId", "The identifier of the page that was navigated to"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Rendering.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Rendering : public HasScrollViewer<Rendering>, RenderingT<Rendering>
{
Rendering();
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Editor::RenderingViewModel, ViewModel, PropertyChanged.raise, nullptr);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Rendering);
}

View File

@@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "RenderingViewModel.idl";
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass Rendering : Windows.UI.Xaml.Controls.Page
{
Rendering();
RenderingViewModel ViewModel { get; };
}
}

View File

@@ -1,48 +0,0 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Rendering"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="EnumComboBoxTemplate"
x:DataType="local:EnumEntry">
<TextBlock Text="{x:Bind EnumName}" />
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<local:SettingContainer x:Name="GraphicsAPI"
x:Uid="Globals_GraphicsAPI">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.GraphicsAPIList}"
SelectedItem="{x:Bind ViewModel.CurrentGraphicsAPI, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Name="DisablePartialInvalidation"
x:Uid="Globals_DisablePartialInvalidation">
<ToggleSwitch IsOn="{x:Bind ViewModel.DisablePartialInvalidation, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<local:SettingContainer x:Name="SoftwareRendering"
x:Uid="Globals_SoftwareRendering">
<ToggleSwitch IsOn="{x:Bind ViewModel.SoftwareRendering, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</Page>

View File

@@ -1,21 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "RenderingViewModel.h"
#include "EnumEntry.h"
#include "RenderingViewModel.g.cpp"
using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
RenderingViewModel::RenderingViewModel(CascadiaSettings settings) noexcept :
_settings{ std::move(settings) }
{
INITIALIZE_BINDABLE_ENUM_SETTING(GraphicsAPI, GraphicsAPI, winrt::Microsoft::Terminal::Control::GraphicsAPI, L"Globals_GraphicsAPI_", L"Text");
}
}

View File

@@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "RenderingViewModel.g.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct RenderingViewModel : RenderingViewModelT<RenderingViewModel>, ViewModelHelper<RenderingViewModel>
{
explicit RenderingViewModel(Model::CascadiaSettings settings) noexcept;
GETSET_BINDABLE_ENUM_SETTING(GraphicsAPI, winrt::Microsoft::Terminal::Control::GraphicsAPI, _settings.GlobalSettings().GraphicsAPI);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_settings.GlobalSettings(), DisablePartialInvalidation);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_settings.GlobalSettings(), SoftwareRendering);
private:
Model::CascadiaSettings _settings{ nullptr };
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(RenderingViewModel);
}

Some files were not shown because too many files have changed in this diff Show More