Compare commits

...

26 Commits

Author SHA1 Message Date
Leonard Hecker
532b3a72dc Improve error checking around AttachThreadInput 2025-08-01 14:48:15 +02:00
zwJimRaynor
a5d916f5d3 Update the version of WinUI required by the Canary appinstaller (#19048) 2025-07-29 14:12:13 -05:00
Leonard Hecker
dfcc8f3c62 Fix use-after-free when disabling the ASB (#19186)
Closes #17515

## Validation Steps Performed
* Disable the ASB while there's a pending cooked read
* Type some text
* No crash 
2025-07-29 13:48:33 -05:00
Quaylyn Rimer
e818dafa6d Fix scrollbar marks not appearing until scroll or resize (#19185)
This PR resolves an issue where scrollbar marks created by shell
integration sequences (OSC 133 FTCS, OSC 1337 iTerm2, and OSC 9;12
ConEmu sequences) were not visible on the scrollbar until the user
manually scrolled.

The problem was that while marks were being created in the buffer
correctly, the UI wasn't being notified to refresh the scrollbar
display. The fix adds a new NotifyShellIntegrationMark() method to the
ITerminalApi interface that calls _NotifyScrollEvent() to trigger
scrollbar refresh, and updates all shell integration sequence handlers
in AdaptDispatch to call this notification method after creating marks.
This ensures scrollbar marks appear immediately when shell integration
sequences are processed, bringing feature parity between auto-detected
and shell-integration-based marks.

Closes #19104
2025-07-29 12:20:47 -05:00
Leonard Hecker
0c3002c1b9 Remove ColorHelper (#19187)
Most of `ColorHelper` was unused and one of them had UB.

Related to #19183

## Validation Steps Performed
* Set a custom tabRow theme color
  Split button looks similar to before 
* White/black FG color decision for colored
  tabs is similar to before 
2025-07-29 11:35:48 -05:00
Weichen Li
7d6e0c8b8e Fix WSLENV environment variable duplication in ConptyConnection (#19167)
This PR fixes issue #7130 where WT_SESSION and WT_PROFILE_ID environment
variables were being duplicated in the WSLENV environment variable when
multiple terminal sessions were created.

The previous implementation always appended WT_SESSION:WT_PROFILE_ID: to
WSLENV without checking if these variables already existed, causing
duplication.

Closes #7130

Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
2025-07-29 01:47:06 +00:00
Dustin L. Howett
65788d9099 Filter Command Palette in English in addition to local language (#19166)
The bulk of this work is changing `Command::Name` (and its descendants
like `GenerateName`) to support looking up names in English and in the
local language.

When matching a "palette item" with a "subtitle" (a new field introduced
to store the English command name when the current language is not
English), the weight of the subtitle is used only if it is greater than
the weight of the name. This ensures that we do not penalize or
over-promote results that contain similar Latin letters in both fields.

Refs #19130, #19131, #19132, #19165
Closes #7039
2025-07-28 19:08:48 +00:00
Windows Console Service Bot
671440206c Localization Updates - main - 07/25/2025 16:15:20 (#19174)
scroll to zoom + scroll to do opacity
2025-07-25 16:52:27 +00:00
Dustin L. Howett
482980c336 Command: realize resource-key names when they are requested, not at load (#19165)
Right now, when a Command's name is `{"key": "ResourceName"}` we resolve
the resource immediately at load time. That prevents us from looking it
up later in another language if we need to.

This pull request introduces an intermediate representation for command
names which is be resolved during `Command::Name`.

Refs #7039
2025-07-24 12:53:09 -05:00
Carlos Zamora
7ab5978b58 Partially revert the key chord styling in actions page (#19164)
Reverts most of the styling changes done in #19001 to the key chords
displayed in the SUI's Actions page. The `CornerRadius` was kept at the
updated value of `ControlCornerRadius` for consistency.

The only other changes in #19001 that were kept for this page include:
- `EditButtonIconSize`: 15 --> 14
- `AccentEditButtonStyle` > `Padding`: 3 --> 4
- Command name's `FontWeight` reduced to `Normal`
- `AddNewButton` > `Margin` added (set to `0,12,0,0` to provide spacing
between breadcrumb header and button)
2025-07-23 18:21:23 -05:00
Niels Laute
48b796f102 [UX] Settings UI refinements (#19001)
This PR is a (first) design pass on the Terminal settings UX to bring
consistency and alignment with the rest of the OS and other settings
surfaces.

High-level changes include:
- Using WinUI brushes vs. UWP/OS brushes. [See brushes overview in the
WinUI 3 Gallery:](winui3gallery://item/Color).
- Updating pixel values for margins, fontsizes, paddings etc. using
units of 4. See [the design guidelines for more
info](https://learn.microsoft.com/en-us/windows/apps/design/basics/content-basics).
- Adding rounded corners on various elements to be consistent with the
Windows 11 look and feel (using the ControlCornerRadius or
OverlayCornerRadius WinUI resources as much as possible).
- Decreasing the page header titles / breadcrumb so it feels a bit less
cramped.
- Fixing a bug where the title of the page was not aligned with the
content when resizing the window (note to self: should fix this in
PowerToys too):
- Ensuring the subheader texts for settings categories are inline with
the rest of the OS (== decreasing the fontsize).

---------

Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2025-07-23 10:07:11 -07:00
Dustin L. Howett
f22295ef2c Merge TabBase+TerminalTab into just Tab (#19136)
This removes the need to construct two objects per tab (TabBase, Actual
Tab) and the other overhead inherent in WinRT composition-based
inheritance.

Important renames:

- `GetTerminalTabImpl` -> `GetTabImpl`

This pull request does not rename `TerminalTabStatus`; that is left as
work for a future PR.

Closes #17529
2025-07-22 08:04:19 -07:00
HO-COOH
cb0289fff2 Center text in the Default Terminal dropdown (#19072)
This is a small UI fix so that we center the default terminal application ComboBox text.
2025-07-21 17:35:09 -05:00
Carlos Zamora
8c20d2052d Add telemetry for new tab menu traffic (#19142)
## Summary of the Pull Request
Adds new telemetry events to track traffic through the new tab menu.
Specifically, the following events are added:
- `NewTabMenuDefaultButtonClicked`: Event emitted when the default
button from the new tab split button is invoked
- `NewTabMenuOpened`: Event emitted when the new tab menu is opened
- `NewTabMenuClosed`: Event emitted when the new tab menu is closed
- `NewTabMenuItemClicked`: Event emitted when an item from the new tab
menu is invoked
- Has an `ItemType` parameter that can be set to `Settings`,
`CommandPalette`, `About, `Profile`, `Action`
- Has a `TabCount` parameter that keeps tracked of the number of tabs in
the window before changing the state
- `NewTabMenuCreatedNewTerminalSession`: Event emitted when a new
terminal was created via the new tab menu
- Has a `SessionType` parameter that can be set to `ElevatedWindow`,
`Window`, `Pane`, `Tab`
- Instead of `TabCount`, has a `NewTabCount` that keeps track of the
_new_ number of tabs after the session has been created
- `NewTabMenuItemElevateSubmenuItemClicked`: Event emitted when the
elevate submenu item from the new tab menu is invoked

## Validation Steps Performed
Used TVPP to see events generated from interacting with the new tab
menu.
2025-07-21 15:33:52 -07:00
Paulina Kalicka
452fa87937 feat: add option to adjust opacity with Ctrl+Shift+scroll (#19151)
## Summary of the Pull Request
This PR introduces an experimental setting that allows to toggle opacity
changes with scrolling.

## References and Relevant Issues
#3793

## Detailed Description of the Pull Request / Additional comments
By default, holding Ctrl + Shift while scrolling changes the terminal's
opacity. This PR adds an option to disable that behavior.

## Validation Steps Performed
I built the project locally and verified that the new feature works as
intended.

## PR Checklist
- [x] Resolves
https://github.com/microsoft/terminal/issues/3793#issuecomment-3085684640
- [x] Tests ~~added/~~ passed
- [x] Documentation updated
- If checked, please file a pull request on [our docs
repo](https://github.com/MicrosoftDocs/terminal) and link it here:
https://github.com/MicrosoftDocs/terminal/pull/873
- [X] Schema updated (if necessary)
2025-07-21 15:24:46 -07:00
Dustin L. Howett
3979e82c2b Remove IconElement caching from PaletteItem (#19149)
In #19132, we introduced caching for BasePaletteItem::ResolvedIcon as a
late optimization.

We actually can't cache those, because they're UI elements, with parents
and relationships and all. When you filter a list with icons and the
list elements change physical position, they're assigned new templates--
and new parents.

Fixes e7939bb4e

Co-authored-by: Eric Nelson <e82.eric@gmail.com>
2025-07-21 15:11:26 -07:00
Dustin L. Howett
fedf7b3b6c Undo the damage done to FilteredCommand in #17330 (#19148)
PR #17330 changed FilteredCommand so that FilteredTask could derive from
it. It also **did not** implement FilteredTask as a derived class.

We've been carrying around the debt of a decision we un-decided for like
a year.
2025-07-18 17:09:12 -07:00
Paulina Kalicka
a04e410a39 feat: add option to enable zoom with ctrl + scroll (#19127)
This PR adds a new global setting `scrollToZoom` that allows users to
enable font zooming with scrolling. When disabled, **this setting
prevents accidental font size changes** that can occur when users scroll
while holding the Ctrl key.

Note: after disabling this setting, users may still change font size
using `Ctrl+` and `Ctrl-` keyboard shortcuts. Other Ctrl+Scroll
functionality (like transparency adjustments) remains unaffected.

## Validation Steps Performed

- Verified the setting can be toggled in the Settings UI (Interaction
tab)
- Confirmed that when disabled, holding Ctrl and scrolling no longer
changes font size
- Validated that the setting persists across terminal restarts

---

Note: I used the existing `FocusFollowMouse` setting as a reference for
implementing this.

Closes #11710
Closes #3793
Closes #11906
Closes #3990
2025-07-17 22:09:52 +00:00
Dustin L. Howett
7b841628df Re-enable web-source icons in Stable and Preview builds (#19137)
Disables a controversial part of #19044.

Refs #19075
2025-07-17 02:13:12 +00:00
Dustin L. Howett
5b63e24c73 ci: turn on SARIF reporting unconditionally for check-spelling (#19135)
The logic currently present occasionally fails to enable reporting for
some PRs.
2025-07-16 15:10:06 -07:00
Dustin L. Howett
e7939bb4e3 Remove WinRT composition (inheritance) from PaletteItem (#19132)
Right now, we construct **two objects** for every palette item: the
derived type and the base type. It's unnnecessary.

This pull request replaces WinRT composition with a good old-fashioned
`enum ThingType`.

This also removes many of our palette items from our IDL. The only ones
that are necessary to expose via our WinRT API surface are the ones that
are used in XAML documents.

I originally removed the caching for `Command.Name`, but it turns out
that something calls `Name` roughly 17 times **per command** and having
the generator running that often is a serious waste of CPU.

## Validation Steps
- [x] Tab Switcher still live-updates when it is in use
- [x] Command searching still works
- [x] Commandline mode still works
- [x] Suggestions control still works
2025-07-16 15:09:17 -05:00
Dustin L. Howett
bdf44322f8 Expose a library's Resource Loader, allow a user to "subset" it (#19131)
This pull request elevates ScopedResourceLoader to the API surface of
LibraryResources, which will allow any library resource consumer to
directly interact with its resource loader.

One of those new interactions is to make a sub-context with a specific
narrowed-down qualifier. Like this:

```c++
auto englishOnlyLoader = GetLibraryResourceLoader().WithQualifier(L"language", L"en-us");
/* auto foo = */ englishOnlyLoader.GetLocalizedString(USES_RESOURCE(L"AppName"));
```
2025-07-14 22:43:48 +00:00
Leonard Hecker
f2b30b4e1e Improve TSF color filtering logic (re: QQPinyin) (#19117)
If an IME provider sets both `crText` and `crBk` we should respect this,
but the previous logic would incorrectly assert for `crLine !=
TF_CT_NONE`.

## Validation Steps Performed
 I'm not aware which TSF even sets these colors in a
way that's compatible with us in the first place...
2025-07-14 17:19:10 -05:00
Dustin L. Howett
0cbb6b1f2f Rewrite HighlightedTextControl and remove HighlightedText (#19130)
`HighlightedTextControl` is a XAML user control that contains a text
block and takes vector of `HighlightedText`. `HighlightedText` uses
tuples `(string, boolean)`. Allocating an entire object to store a
string and an integer felt like a waste, especially when we were doing
it thousands of times for the command palette _and just to pass them
into another object that stores a string and a few more integers
(`Run`)._

The new `HighlightedTextControl` is a standard templated control, and
supports styling of both the inner text block and of the highlighted
runs.

It no longer takes a `HighlightedText`, but rather a standard string and
a set of runs (tuple `(int start, int end)`); these can be stored more
efficiently, and this change moves the construction of text and runs
directly into `HighlightedTextControl` itself as an implementation
detail rather than an API contract.

### XAML Properties

- `Text`: the string to highlight
- `HighlightedRuns`: a vector of `(start, end)` pairs, indicating which
  regions are intended to be highlighted. Can be empty (which indicates
  there is no highlight and that the entire string is styled normally.)
- `TextBlockStyle`: the `Style` applied to the inner text block;
  optional; allows consumers to change how both normal and highlighted
  text looks.
- `HighlightedRunStyle`: a `Style` applied only to the highlighted runs;
  optional; allows consumers to change how highlighted text looks. If
  left NULL, highlighted runs will be bold.

`HighlightedRunStyle` is a little bodgy. It only applies to `Run`
objects (which is fine, and XAML somewhat supports), but since `Run` is
not a `FrameworkElement`, it _doesn't actually have a `Style` member._
We need to crack open the style and apply it manually, entry by entry.
`FontWeight` is special because XAML is a special little flower.
2025-07-14 20:40:20 +00:00
Dustin L. Howett
f14718f738 version: fix the LCID in our VERSIONINFO, add descriptions to each file (#19114)
Closes #19106
2025-07-09 16:36:13 -05:00
Dustin L. Howett
c4fbb58f69 During session save, use the profile's GUID rather than its Name (#19113)
This will prevent Terminal from erroneously selecting a hidden (deleted,
disabled or otherwise) profile of the same name during restoration and
subsequently using the wrong settings.

I am not certain why we used the name at all!

Closes #19105
2025-07-09 15:42:23 -05:00
158 changed files with 2914 additions and 2901 deletions

View File

@@ -2,6 +2,7 @@ aaaaabbb
aabbcc
ABANDONFONT
abbcc
abcc
abgr
ABORTIFHUNG
ACCESSTOKEN

View File

@@ -104,7 +104,7 @@ jobs:
report-timing: 1
warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check,unclosed-block-ignore-begin,unclosed-block-ignore-end
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }}
use_sarif: 1
check_extra_dictionaries: ""
dictionary_source_prefixes: >
{

View File

@@ -14,21 +14,21 @@
<Package
Name="Microsoft.UI.Xaml.2.8"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="8.2305.5001.0"
Version="8.2306.22001.0"
ProcessorArchitecture="x64"
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.x64.appx" />
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.5/Microsoft.UI.Xaml.2.8.x64.appx" />
<Package
Name="Microsoft.UI.Xaml.2.8"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="8.2305.5001.0"
Version="8.2306.22001.0"
ProcessorArchitecture="x86"
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.x86.appx" />
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.5/Microsoft.UI.Xaml.2.8.x86.appx" />
<Package
Name="Microsoft.UI.Xaml.2.8"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="8.2305.5001.0"
Version="8.2306.22001.0"
ProcessorArchitecture="arm64"
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.arm64.appx" />
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.5/Microsoft.UI.Xaml.2.8.arm64.appx" />
</Dependencies>
<UpdateSettings>

View File

@@ -7,5 +7,8 @@
<VersionMajor>1</VersionMajor>
<VersionMinor>24</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
<VersionInfoCulture>1033</VersionInfoCulture>
<!-- The default has a spacing problem -->
<VersionInfoCopyRight>\xa9 Microsoft Corporation. All rights reserved.</VersionInfoCopyRight>
</PropertyGroup>
</Project>

View File

@@ -2376,6 +2376,16 @@
"description": "When set to true, the terminal will focus the pane on mouse hover.",
"type": "boolean"
},
"experimental.scrollToZoom": {
"default": true,
"description": "When set to true, holding the Ctrl key while scrolling will increase or decrease the terminal font size.",
"type": "boolean"
},
"experimental.scrollToChangeOpacity": {
"default": true,
"description": "When set to true, holding the Ctrl and Shift keys while scrolling will change the window opacity.",
"type": "boolean"
},
"compatibility.allowHeadless": {
"default": false,
"description": "When set to true, Windows Terminal will run in the background. This allows globalSummon and quakeMode actions to work even when no windows are open.",

View File

@@ -7,6 +7,7 @@
<ProjectName>elevate-shim</ProjectName>
<TargetName>elevate-shim</TargetName>
<ConfigurationType>Application</ConfigurationType>
<VersionInfoFileDescription>Windows Terminal Administrator Launch Helper</VersionInfoFileDescription>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />

View File

@@ -2,8 +2,8 @@
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalApp/CommandLinePaletteItem.h"
#include "../TerminalApp/CommandPalette.h"
#include "../TerminalApp/BasePaletteItem.h"
#include "CppWinrtTailored.h"
using namespace Microsoft::Console;
@@ -15,6 +15,20 @@ using namespace winrt::Microsoft::Terminal::Control;
namespace TerminalAppLocalTests
{
struct StringPaletteItem : winrt::implements<StringPaletteItem, winrt::TerminalApp::IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>, winrt::TerminalApp::implementation::BasePaletteItem<StringPaletteItem, winrt::TerminalApp::PaletteItemType::CommandLine>
{
StringPaletteItem(std::wstring_view value) :
_value{ value } {}
winrt::hstring Name() { return _value; }
winrt::hstring Subtitle() { return {}; }
winrt::hstring KeyChordText() { return {}; }
winrt::hstring Icon() { return {}; }
private:
winrt::hstring _value;
};
class FilteredCommandTests
{
BEGIN_TEST_CLASS(FilteredCommandTests)
@@ -28,74 +42,81 @@ namespace TerminalAppLocalTests
TEST_METHOD(VerifyCompareIgnoreCase);
};
static void _verifySegment(auto&& segments, uint32_t index, uint64_t start, uint64_t end)
{
const auto& segment{ segments.GetAt(index) };
VERIFY_ARE_EQUAL(segment.Start, start, NoThrowString().Format(L"segment %zu", index));
VERIFY_ARE_EQUAL(segment.End, end, NoThrowString().Format(L"segment %zu", index));
}
void FilteredCommandTests::VerifyHighlighting()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const WEX::TestExecution::DisableVerifyExceptions disableExceptionsScope;
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
{
Log::Comment(L"Testing command name segmentation with no filter");
auto segments = filteredCommand->HighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_IS_NULL(segments); // No matches = no segments
}
{
Log::Comment(L"Testing command name segmentation with empty filter");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"")));
auto segments = filteredCommand->HighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_IS_NULL(segments); // No matches = no segments
}
{
Log::Comment(L"Testing command name segmentation with filter equal to the string");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"AAAAAABBBBBBCCC")));
auto segments = filteredCommand->HighlightedName().Segments();
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
_verifySegment(segments, 0, 0, 14); // one segment for the entire string
}
{
Log::Comment(L"Testing command name segmentation with filter with first character matching");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"A")));
auto segments = filteredCommand->HighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 2u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u); // only one bold segment
_verifySegment(segments, 0, 0, 0); // it only covers the first character
}
{
Log::Comment(L"Testing command name segmentation with filter with other case");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"a")));
auto segments = filteredCommand->HighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 2u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u); // only one bold segment
_verifySegment(segments, 0, 0, 0); // it only covers the first character
}
{
Log::Comment(L"Testing command name segmentation with filter matching several characters");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"ab")));
auto segments = filteredCommand->HighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 3u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAA");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AB");
VERIFY_IS_TRUE(segments.GetAt(1).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(2).TextSegment(), L"BBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(2).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u); // one bold segment
_verifySegment(segments, 0, 5, 6); // middle 'ab'
}
{
Log::Comment(L"Testing command name segmentation with filter matching several regions");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"abcc")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 2u); // two bold segments
_verifySegment(segments, 0, 5, 6); // middle 'ab'
_verifySegment(segments, 1, 12, 13); // start of 'cc'
}
{
Log::Comment(L"Testing command name segmentation with non matching filter");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"abcd")));
auto segments = filteredCommand->HighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_IS_NULL(segments); // No matches = no segments
}
});
@@ -105,7 +126,7 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyWeight()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
const auto weigh = [&](const wchar_t* str) {
@@ -145,8 +166,8 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyCompare()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"BBBBBCCC") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem2{ winrt::make<StringPaletteItem>(L"BBBBBCCC") };
{
Log::Comment(L"Testing comparison of commands with no filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
@@ -185,8 +206,8 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyCompareIgnoreCase()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"a") };
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"B") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"a") };
const auto paletteItem2{ winrt::make<StringPaletteItem>(L"B") };
{
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);

View File

@@ -8,7 +8,7 @@
#include "../TerminalApp/MinMaxCloseControl.h"
#include "../TerminalApp/TabRowControl.h"
#include "../TerminalApp/ShortcutActionDispatch.h"
#include "../TerminalApp/TerminalTab.h"
#include "../TerminalApp/Tab.h"
#include "../TerminalApp/CommandPalette.h"
#include "../TerminalApp/ContentManager.h"
#include "CppWinrtTailored.h"
@@ -307,7 +307,7 @@ namespace TerminalAppLocalTests
// reliably in the unit tests.
Log::Comment(L"Ensure we set the first tab as the selected one.");
auto tab = page->_tabs.GetAt(0);
auto tabImpl = page->_GetTerminalTabImpl(tab);
auto tabImpl = page->_GetTabImpl(tab);
page->_tabView.SelectedItem(tabImpl->TabViewItem());
page->_UpdatedSelectedTab(tab);
});
@@ -510,7 +510,7 @@ namespace TerminalAppLocalTests
result = RunOnUIThread([&page]() {
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(1, tab->GetLeafPaneCount());
});
VERIFY_SUCCEEDED(result);
@@ -520,7 +520,7 @@ namespace TerminalAppLocalTests
page->_SplitPane(nullptr, SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, tab->GetLeafPaneCount());
});
VERIFY_SUCCEEDED(result);
@@ -538,7 +538,7 @@ namespace TerminalAppLocalTests
page->_SplitPane(nullptr, SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(3,
tab->GetLeafPaneCount(),
L"We should successfully duplicate a pane hosting a deleted profile.");
@@ -706,7 +706,7 @@ namespace TerminalAppLocalTests
SplitPaneArgs args{ SplitType::Duplicate };
ActionEventArgs eventArgs{ args };
page->_HandleSplitPane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
@@ -717,7 +717,7 @@ namespace TerminalAppLocalTests
result = RunOnUIThread([&page]() {
ActionEventArgs eventArgs{};
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@@ -727,7 +727,7 @@ namespace TerminalAppLocalTests
result = RunOnUIThread([&page]() {
ActionEventArgs eventArgs{};
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
});
@@ -744,7 +744,7 @@ namespace TerminalAppLocalTests
SplitPaneArgs args{ SplitType::Duplicate };
ActionEventArgs eventArgs{ args };
page->_HandleSplitPane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
@@ -758,7 +758,7 @@ namespace TerminalAppLocalTests
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@@ -772,7 +772,7 @@ namespace TerminalAppLocalTests
page->_HandleMoveFocus(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@@ -789,7 +789,7 @@ namespace TerminalAppLocalTests
SplitPaneArgs args{ SplitType::Duplicate };
ActionEventArgs eventArgs{ args };
page->_HandleSplitPane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
@@ -803,7 +803,7 @@ namespace TerminalAppLocalTests
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@@ -816,7 +816,7 @@ namespace TerminalAppLocalTests
page->_HandleClosePane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_IS_FALSE(firstTab->IsZoomed());
});
VERIFY_SUCCEEDED(result);
@@ -827,7 +827,7 @@ namespace TerminalAppLocalTests
Log::Comment(L"Check to ensure there's only one pane left.");
result = RunOnUIThread([&page]() {
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(1, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
});
@@ -850,7 +850,7 @@ namespace TerminalAppLocalTests
uint32_t firstId = 0, secondId = 0, thirdId = 0, fourthId = 0;
TestOnUIThread([&]() {
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
firstId = tab->_activePane->Id().value();
// We start with 1 tab, split vertically to get
// -------------------
@@ -876,7 +876,7 @@ namespace TerminalAppLocalTests
// | | |
// -------------------
page->_SplitPane(nullptr, SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
// Split again to make the 3rd tab
thirdId = tab->_activePane->Id().value();
});
@@ -896,13 +896,13 @@ namespace TerminalAppLocalTests
// | | |
// -------------------
page->_SplitPane(nullptr, SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
fourthId = tab->_activePane->Id().value();
});
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// just to be complete, make sure we actually have 4 different ids
VERIFY_ARE_NOT_EQUAL(firstId, fourthId);
@@ -936,7 +936,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@@ -967,7 +967,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@@ -998,7 +998,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@@ -1029,7 +1029,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@@ -1174,16 +1174,16 @@ namespace TerminalAppLocalTests
Log::Comment(L"give alphabetical names to all switch tab actions");
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(0))->Title(L"a");
page->_GetTabImpl(page->_tabs.GetAt(0))->Title(L"a");
});
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(1))->Title(L"b");
page->_GetTabImpl(page->_tabs.GetAt(1))->Title(L"b");
});
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(2))->Title(L"c");
page->_GetTabImpl(page->_tabs.GetAt(2))->Title(L"c");
});
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(3))->Title(L"d");
page->_GetTabImpl(page->_tabs.GetAt(3))->Title(L"d");
});
TestOnUIThread([&page]() {

View File

@@ -10,6 +10,7 @@
<SubSystem>Console</SubSystem>
<!-- suppress a bunch of Windows Universal properties from cppwinrt.props -->
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
<VersionInfoFileDescription>Windows Terminal Open Here Shell Extension</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>

View File

@@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include <LibraryResources.h>
#include "ActionPaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
ActionPaletteItem::ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText) :
_Command(command)
{
Name(command.Name());
KeyChordText(keyChordText);
Icon(command.IconPath());
}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "ActionPaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct ActionPaletteItem : ActionPaletteItemT<ActionPaletteItem, PaletteItem>
{
ActionPaletteItem() = default;
ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText);
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(ActionPaletteItem);
}

View File

@@ -1,14 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
namespace TerminalApp
{
[default_interface] runtimeclass ActionPaletteItem : PaletteItem
{
ActionPaletteItem(Microsoft.Terminal.Settings.Model.Command command, String keyChordText);
Microsoft.Terminal.Settings.Model.Command Command { get; };
}
}

View File

@@ -243,6 +243,8 @@
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
<ResourceDictionary Source="ms-resource:///Files/TerminalApp/HighlightedTextControlStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@@ -41,13 +41,13 @@ namespace winrt::TerminalApp::implementation
}
return _GetActiveControl();
}
winrt::com_ptr<TerminalTab> TerminalPage::_senderOrFocusedTab(const IInspectable& sender)
winrt::com_ptr<Tab> TerminalPage::_senderOrFocusedTab(const IInspectable& sender)
{
if (sender)
{
if (auto tab{ sender.try_as<TerminalApp::TerminalTab>() })
if (auto tab = sender.try_as<TerminalApp::Tab>())
{
return _GetTerminalTabImpl(tab);
return _GetTabImpl(tab);
}
}
return _GetFocusedTabImpl();
@@ -193,17 +193,17 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleCloseOtherPanes(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& terminalTab{ _senderOrFocusedTab(sender) })
if (const auto& activeTab{ _senderOrFocusedTab(sender) })
{
const auto activePane = terminalTab->GetActivePane();
if (terminalTab->GetRootPane() != activePane)
const auto activePane = activeTab->GetActivePane();
if (activeTab->GetRootPane() != activePane)
{
_UnZoomIfNeeded();
// Accumulate list of all unfocused leaf panes, ignore read-only panes
std::vector<uint32_t> unfocusedPaneIds;
const auto activePaneId = activePane->Id();
terminalTab->GetRootPane()->WalkTree([&](auto&& p) {
activeTab->GetRootPane()->WalkTree([&](auto&& p) {
const auto id = p->Id();
if (id.has_value() && id != activePaneId && !p->ContainsReadOnly())
{
@@ -215,7 +215,7 @@ namespace winrt::TerminalApp::implementation
{
// Start by removing the panes that were least recently added
sort(begin(unfocusedPaneIds), end(unfocusedPaneIds), std::less<uint32_t>());
_ClosePanes(terminalTab->get_weak(), std::move(unfocusedPaneIds));
_ClosePanes(activeTab->get_weak(), std::move(unfocusedPaneIds));
args.Handled(true);
return;
}
@@ -281,9 +281,9 @@ namespace winrt::TerminalApp::implementation
const auto& duplicateFromTab{ realArgs.SplitMode() == SplitType::Duplicate ? _GetFocusedTab() : nullptr };
const auto& terminalTab{ _senderOrFocusedTab(sender) };
const auto& activeTab{ _senderOrFocusedTab(sender) };
_SplitPane(terminalTab,
_SplitPane(activeTab,
realArgs.SplitDirection(),
// This is safe, we're already filtering so the value is (0, 1)
realArgs.SplitSize(),
@@ -302,14 +302,14 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleTogglePaneZoom(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto terminalTab{ _senderOrFocusedTab(sender) })
if (const auto activeTab{ _senderOrFocusedTab(sender) })
{
// Don't do anything if there's only one pane. It's already zoomed.
if (terminalTab->GetLeafPaneCount() > 1)
if (activeTab->GetLeafPaneCount() > 1)
{
// Togging the zoom on the tab will cause the tab to inform us of
// the new root Content for this tab.
terminalTab->ToggleZoom();
activeTab->ToggleZoom();
}
}
@@ -783,7 +783,7 @@ namespace winrt::TerminalApp::implementation
}
// Since _RemoveTabs is asynchronous, create a snapshot of the tabs we want to remove
std::vector<winrt::TerminalApp::TabBase> tabsToRemove;
std::vector<winrt::TerminalApp::Tab> tabsToRemove;
if (index > 0)
{
std::copy(begin(_tabs), begin(_tabs) + index, std::back_inserter(tabsToRemove));
@@ -822,7 +822,7 @@ namespace winrt::TerminalApp::implementation
}
// Since _RemoveTabs is asynchronous, create a snapshot of the tabs we want to remove
std::vector<winrt::TerminalApp::TabBase> tabsToRemove;
std::vector<winrt::TerminalApp::Tab> tabsToRemove;
std::copy(begin(_tabs) + index + 1, end(_tabs), std::back_inserter(tabsToRemove));
_RemoveTabs(tabsToRemove);
@@ -1559,7 +1559,6 @@ namespace winrt::TerminalApp::implementation
activeTab->ToggleBroadcastInput();
args.Handled(true);
}
// If the focused tab wasn't a TerminalTab, then leave handled=false
}
void TerminalPage::_HandleRestartConnection(const IInspectable& sender,

View File

@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
namespace winrt::TerminalApp::implementation
{
template<typename T, winrt::TerminalApp::PaletteItemType Ty>
struct BasePaletteItem
{
public:
winrt::TerminalApp::PaletteItemType Type() { return Ty; }
Windows::UI::Xaml::Controls::IconElement ResolvedIcon()
{
const auto icon{ static_cast<T*>(this)->Icon() };
if (!icon.empty())
{
const auto resolvedIcon{ Microsoft::Terminal::UI::IconPathConverter::IconWUX(icon) };
resolvedIcon.Width(16);
resolvedIcon.Height(16);
return resolvedIcon;
}
return nullptr;
}
til::property_changed_event PropertyChanged;
protected:
void BaseRaisePropertyChanged(wil::zwstring_view property)
{
PropertyChanged.raise(*static_cast<T*>(this), winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs{ property });
}
void InvalidateResolvedIcon()
{
BaseRaisePropertyChanged(L"ResolvedIcon");
}
};
}

View File

@@ -1,267 +0,0 @@
#include "ColorHelper.h"
using namespace winrt::TerminalApp;
// Method Description:
// Determines whether or not a given color is light
// Arguments:
// - color: this color is going to be examined whether it
// is light or not
// Return Value:
// - true if light, false if dark
bool ColorHelper::IsBrightColor(const winrt::Windows::UI::Color& color)
{
// https://www.w3.org/TR/AERT#color-contrast
auto brightness = (color.R * 299 + color.G * 587 + color.B * 114) / 1000.f;
return brightness > 128.f;
}
// Method Description:
// Converts a rgb color to an hsl one
// Arguments:
// - color: the rgb color, which is going to be converted
// Return Value:
// - a hsl color with the following ranges
// - H: [0.f -360.f]
// - L: [0.f - 1.f] (rounded to the third decimal place)
// - S: [0.f - 1.f] (rounded to the third decimal place)
HSL ColorHelper::RgbToHsl(const winrt::Windows::UI::Color& color)
{
// https://www.rapidtables.com/convert/color/rgb-to-hsl.html
auto epsilon = std::numeric_limits<float>::epsilon();
auto r = color.R / 255.f;
auto g = color.G / 255.f;
auto b = color.B / 255.f;
auto max = std::max(r, std::max(g, b));
auto min = std::min(r, std::min(g, b));
auto delta = max - min;
auto h = 0.f;
auto s = 0.f;
auto l = (max + min) / 2;
if (delta < epsilon || max < epsilon) /* delta == 0 || max == 0*/
{
l = std::roundf(l * 1000) / 1000;
return HSL{ h, s, l };
}
s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
if (max - r < epsilon) // max == r
{
h = (g - b) / delta + (g < b ? 6 : 0);
}
else if (max - g < epsilon) // max == g
{
h = (b - r) / delta + 2;
}
else if (max - b < epsilon) // max == b
{
h = (r - g) / delta + 4;
}
// three decimal places after the comma ought
// to be enough for everybody - Bill Gates, 1981
auto finalH = std::roundf(h * 60);
auto finalS = std::roundf(s * 1000) / 1000;
auto finalL = std::roundf(l * 1000) / 1000;
return HSL{ finalH, finalS, finalL };
}
// Method Description:
// Converts a hsl color to rgb one
// Arguments:
// - color: the hsl color, which is going to be converted
// Return Value:
// - the rgb color (r,g,b - [0, 255] range)
winrt::Windows::UI::Color ColorHelper::HslToRgb(const HSL& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
auto h = (color.H - 1.f > epsilon) ? color.H / 360.f : color.H;
auto s = (color.S - 1.f > epsilon) ? color.S / 100.f : color.S;
auto l = (color.L - 1.f > epsilon) ? color.L / 100.f : color.L;
auto r = l;
auto g = l;
auto b = l;
if (s > epsilon)
{
auto q = l < 0.5 ? l * (1 + s) : l + s - l * s;
auto p = 2 * l - q;
r = HueToRgb(p, q, h + 1.f / 3.f);
g = HueToRgb(p, q, h);
b = HueToRgb(p, q, h - 1.f / 3.f);
}
auto finalR = static_cast<uint8_t>(std::roundf(r * 255));
auto finalG = static_cast<uint8_t>(std::roundf(g * 255));
auto finalB = static_cast<uint8_t>(std::roundf(b * 255));
uint8_t finalA = 255; //opaque
return winrt::Windows::UI::ColorHelper::FromArgb(finalA, finalR, finalG, finalB);
}
float ColorHelper::HueToRgb(float p, float q, float t)
{
auto epsilon = std::numeric_limits<float>::epsilon();
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t - (1.f / 6.f) < epsilon)
return p + (q - p) * 6 * t;
if (t - .5f < epsilon)
return q;
if (t - 2.f / 3.f < epsilon)
return p + (q - p) * (2.f / 3.f - t) * 6;
return p;
}
// Method Description:
// Lightens a color by a given amount
// Arguments:
// - color: the color which is going to be lightened
// - amount: the lighten amount (0-100)
// Return Value:
// - the lightened color in RGB format
winrt::Windows::UI::Color ColorHelper::Lighten(const winrt::Windows::UI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L += amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}
// Method Description:
// Darkens a color by a given amount
// Arguments:
// - color: the color which is going to be darkened
// - amount: the darken amount (0-100)
// Return Value:
// - the darkened color in RGB format
winrt::Windows::UI::Color ColorHelper::Darken(const winrt::Windows::UI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L -= amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}
// Method Description:
// Gets an accent color to a given color. Basically, generates
// 16 shades of the color and finds the first which has a good
// contrast according to https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Readability ratio of 3.5 seems to look quite nicely
// Arguments:
// - color: the color for which we need an accent
// Return Value:
// - the accent color in RGB format
winrt::Windows::UI::Color ColorHelper::GetAccentColor(const winrt::Windows::UI::Color& color)
{
auto accentColor = RgbToHsl(color);
if (accentColor.S < 0.15)
{
accentColor.S = 0.15f;
}
constexpr auto shadeCount = 16;
constexpr auto shadeStep = 1.f / shadeCount;
auto shades = std::map<float, HSL>();
for (auto i = 0; i < 15; i++)
{
auto shade = HSL{ accentColor.H, accentColor.S, i * shadeStep };
auto contrast = GetReadability(shade, accentColor);
shades.insert(std::make_pair(contrast, shade));
}
// 3f is quite nice if the whole non-client area is painted
constexpr auto readability = 1.75f;
for (auto shade : shades)
{
if (shade.first >= readability)
{
return HslToRgb(shade.second);
}
}
return HslToRgb(shades.end()->second);
}
// Method Description:
// Gets the readability of two colors according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (hsl)
// - secondColor: the second color for the readability check (hsl)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const HSL& first, const HSL& second)
{
return GetReadability(HslToRgb(first), HslToRgb(second));
}
// Method Description:
// Gets the readability of two colors according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (rgb)
// - secondColor: the second color for the readability check (rgb)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const winrt::Windows::UI::Color& first, const winrt::Windows::UI::Color& second)
{
auto l1 = GetLuminance(first);
auto l2 = GetLuminance(second);
return (std::max(l1, l2) + 0.05f) / std::min(l1, l2) + 0.05f;
}
// Method Description:
// Calculates the luminance of a given color according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
// Arguments:
// - color: its luminance is going to be calculated
// Return Value:
// - the luminance of the color
float ColorHelper::GetLuminance(const winrt::Windows::UI::Color& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
float R, G, B;
auto RsRGB = color.R / 255.f;
auto GsRGB = color.G / 255.f;
auto BsRGB = color.B / 255.f;
if (RsRGB - 0.03928f <= epsilon)
{
R = RsRGB / 12.92f;
}
else
{
R = std::pow(((RsRGB + 0.055f) / 1.055f), 2.4f);
}
if (GsRGB - 0.03928f <= epsilon)
{
G = GsRGB / 12.92f;
}
else
{
G = std::pow(((GsRGB + 0.055f) / 1.055f), 2.4f);
}
if (BsRGB - 0.03928f <= epsilon)
{
B = BsRGB / 12.92f;
}
else
{
B = std::pow(((BsRGB + 0.055f) / 1.055f), 2.4f);
}
auto luminance = (0.2126f * R) + (0.7152f * G) + (0.0722f * B);
return std::roundf(luminance * 10000) / 10000.f;
}

View File

@@ -1,31 +0,0 @@
#pragma once
#include <winrt/Windows.UI.h>
namespace winrt::TerminalApp
{
class HSL
{
public:
float H;
float S;
float L;
};
class ColorHelper
{
public:
static bool IsBrightColor(const Windows::UI::Color& color);
static HSL RgbToHsl(const Windows::UI::Color& color);
static Windows::UI::Color HslToRgb(const HSL& color);
static Windows::UI::Color Lighten(const Windows::UI::Color& color, float amount = 10.f);
static Windows::UI::Color Darken(const Windows::UI::Color& color, float amount = 10.f);
static Windows::UI::Color GetAccentColor(const Windows::UI::Color& color);
static float GetLuminance(const Windows::UI::Color& color);
static float GetReadability(const Windows::UI::Color& first, const Windows::UI::Color& second);
static float GetReadability(const HSL& first, const HSL& second);
private:
static float HueToRgb(float p, float q, float t);
};
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "CommandLinePaletteItem.h"
#include <LibraryResources.h>
#include "CommandLinePaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
CommandLinePaletteItem::CommandLinePaletteItem(const winrt::hstring& commandLine) :
_CommandLine(commandLine)
{
Name(commandLine);
}
}

View File

@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "CommandLinePaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct CommandLinePaletteItem : CommandLinePaletteItemT<CommandLinePaletteItem, PaletteItem>
{
CommandLinePaletteItem() = default;
CommandLinePaletteItem(const winrt::hstring& commandLine);
WINRT_PROPERTY(winrt::hstring, CommandLine);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(CommandLinePaletteItem);
}

View File

@@ -1,12 +0,0 @@
import "PaletteItem.idl";
import "TabBase.idl";
namespace TerminalApp
{
[default_interface] runtimeclass CommandLinePaletteItem : PaletteItem
{
CommandLinePaletteItem(String commandLine);
String CommandLine { get; };
}
}

View File

@@ -2,10 +2,8 @@
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include "TabPaletteItem.h"
#include "CommandLinePaletteItem.h"
#include "CommandPalette.h"
#include "CommandPaletteItems.h"
#include <LibraryResources.h>
#include "CommandPalette.g.cpp"
@@ -233,9 +231,11 @@ namespace winrt::TerminalApp::implementation
}
else if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand != nullptr)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
else if (_currentMode == CommandPaletteMode::CommandlineMode)
@@ -555,10 +555,11 @@ namespace winrt::TerminalApp::implementation
const auto enteredItem = listViewItem.Content();
if (const auto filteredCommand{ enteredItem.try_as<winrt::TerminalApp::FilteredCommand>() })
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
// immediately preview the hovered command
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
}
@@ -589,9 +590,11 @@ namespace winrt::TerminalApp::implementation
{
if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
}
@@ -617,7 +620,7 @@ namespace winrt::TerminalApp::implementation
const auto selectedCommand = selectedList.GetAt(0);
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
{
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
if (const auto paletteItem = filteredCmd.Item())
{
automationPeer.RaiseNotificationEvent(
Automation::Peers::AutomationNotificationKind::ItemAdded,
@@ -652,10 +655,13 @@ namespace winrt::TerminalApp::implementation
if (_nestedActionStack.Size() > 0)
{
const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
const auto actionPaletteItem{ newPreviousAction.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
const auto item{ newPreviousAction.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
ParentCommandName(actionPaletteItem->Command().Name());
_updateCurrentNestedCommands(actionPaletteItem->Command());
}
}
else
{
@@ -757,16 +763,19 @@ namespace winrt::TerminalApp::implementation
}
else if (filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
auto command{ actionPaletteItem->Command() };
if (command.HasNestedCommands())
{
// If this Command had subcommands, then don't dispatch the
// action. Instead, display a new list of commands for the user
// to pick from.
_nestedActionStack.Append(filteredCommand);
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
ParentCommandName(command.Name());
_updateCurrentNestedCommands(command);
_updateUIForStackChange();
}
@@ -785,9 +794,9 @@ namespace winrt::TerminalApp::implementation
// But make an exception for the Toggle Command Palette action: we don't want the dispatch
// make the command palette - that was just closed - visible again.
// All other actions can just be dispatched.
if (actionPaletteItem.Command().ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
if (command.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
DispatchCommandRequested.raise(*this, command);
}
TraceLoggingWrite(
@@ -837,9 +846,11 @@ namespace winrt::TerminalApp::implementation
{
if (filteredCommand)
{
if (const auto tabPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Tab)
{
if (const auto tab{ tabPaletteItem.Tab() })
const auto tabPaletteItem{ winrt::get_self<TabPaletteItem>(item) };
if (const auto tab{ tabPaletteItem->Tab() })
{
SwitchToTabRequested.raise(*this, tab);
}
@@ -867,9 +878,11 @@ namespace winrt::TerminalApp::implementation
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
const auto item{ filteredCommand->Item() };
if (item.Type() == PaletteItemType::CommandLine)
{
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem.CommandLine());
const auto commandLinePaletteItem{ winrt::get_self<CommandLinePaletteItem>(item) };
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem->CommandLine());
_close();
}
}
@@ -1059,7 +1072,7 @@ namespace winrt::TerminalApp::implementation
// Return Value:
// - <none>
void CommandPalette::_bindTabs(
const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& source,
const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& source,
const Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand>& target)
{
target.Clear();
@@ -1071,7 +1084,7 @@ namespace winrt::TerminalApp::implementation
}
}
void CommandPalette::SetTabs(const Collections::IObservableVector<TabBase>& tabs, const Collections::IObservableVector<TabBase>& mruTabs)
void CommandPalette::SetTabs(const Collections::IObservableVector<Tab>& tabs, const Collections::IObservableVector<Tab>& mruTabs)
{
_bindTabs(tabs, _tabActions);
_bindTabs(mruTabs, _mruTabActions);

View File

@@ -31,7 +31,7 @@ namespace winrt::TerminalApp::implementation
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
void SetTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& tabs, const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& mruTabs);
void SetTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& tabs, const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& mruTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
@@ -48,7 +48,7 @@ namespace winrt::TerminalApp::implementation
void EnableTabSearchMode();
til::property_changed_event PropertyChanged;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase> SwitchToTabRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::TerminalApp::Tab> SwitchToTabRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::hstring> CommandLineExecutionRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
til::typed_event<Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> PreviewAction;
@@ -135,7 +135,7 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::Settings::Model::TabSwitcherMode _tabSwitcherMode;
uint32_t _switcherStartIdx;
void _bindTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& source, const Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand>& target);
void _bindTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& source, const Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand>& target);
void _anchorKeyUpHandler();
winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker;

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TabBase.idl";
import "Tab.idl";
import "HighlightedTextControl.idl";
import "FilteredCommand.idl";
@@ -20,7 +20,7 @@ namespace TerminalApp
Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };
void SetTabs(Windows.Foundation.Collections.IObservableVector<TabBase> tabs, Windows.Foundation.Collections.IObservableVector<TabBase> mruTabs);
void SetTabs(Windows.Foundation.Collections.IObservableVector<Tab> tabs, Windows.Foundation.Collections.IObservableVector<Tab> mruTabs);
void SetActionMap(Microsoft.Terminal.Settings.Model.IActionMapView actionMap);
@@ -30,7 +30,7 @@ namespace TerminalApp
void EnableTabSwitcherMode(UInt32 startIdx, Microsoft.Terminal.Settings.Model.TabSwitcherMode tabSwitcherMode);
void EnableTabSearchMode();
event Windows.Foundation.TypedEventHandler<CommandPalette, TabBase> SwitchToTabRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, Tab> SwitchToTabRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, String> CommandLineExecutionRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Command> PreviewAction;

View File

@@ -44,6 +44,12 @@
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
</Style>
<Style x:Key="SubtitleTextStyle"
TargetType="TextBlock">
<Setter Property="FontSize" Value="10" />
<Setter Property="Foreground" Value="{ThemeResource SystemBaseMediumColor}" />
</Style>
<DataTemplate x:Key="ListItemTemplate"
x:DataType="local:FilteredCommand">
<ListViewItem HorizontalContentAlignment="Stretch"
@@ -71,10 +77,19 @@
Height="16"
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
<StackPanel Grid.Column="1"
HorizontalAlignment="Left"
Orientation="Vertical">
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind SubtitleHighlights, Mode=OneWay}"
Text="{x:Bind Item.Subtitle, Mode=OneWay}"
TextBlockStyle="{StaticResource SubtitleTextStyle}"
Visibility="{x:Bind HasSubtitle, Mode=OneWay}" />
</StackPanel>
<!--
The block for the key chord is only visible
when there's actual text set as the label.
@@ -121,9 +136,19 @@
Height="16"
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
<StackPanel Grid.Column="1"
HorizontalAlignment="Left"
Orientation="Vertical">
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind SubtitleHighlights, Mode=OneWay}"
Text="{x:Bind Item.Subtitle, Mode=OneWay}"
TextBlockStyle="{StaticResource SubtitleTextStyle}"
Visibility="{x:Bind HasSubtitle, Mode=OneWay}" />
</StackPanel>
<!--
The block for the key chord is only visible
@@ -192,7 +217,8 @@
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<StackPanel Grid.Column="2"
HorizontalAlignment="Right"

View File

@@ -2,11 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "TabPaletteItem.h"
#include "TerminalTab.h"
#include "Tab.h"
#include <LibraryResources.h>
#include "TabPaletteItem.g.cpp"
#include "CommandPaletteItems.h"
using namespace winrt;
using namespace winrt::TerminalApp;
@@ -19,42 +19,31 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
TabPaletteItem::TabPaletteItem(const winrt::TerminalApp::TabBase& tab) :
_tab(tab)
TabPaletteItem::TabPaletteItem(const winrt::TerminalApp::Tab& tab) :
_tab{ tab }
{
Name(tab.Title());
Icon(tab.Icon());
_tabChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& sender, auto& e) {
auto item{ weakThis.get() };
auto senderTab{ sender.try_as<winrt::TerminalApp::TabBase>() };
if (item && senderTab)
_tabChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [=](auto& sender, auto& e) {
if (auto senderTab{ sender.try_as<winrt::TerminalApp::Tab>() })
{
auto changedProperty = e.PropertyName();
if (changedProperty == L"Title")
{
item->Name(senderTab.Title());
BaseRaisePropertyChanged(L"Name");
}
else if (changedProperty == L"Icon")
{
item->Icon(senderTab.Icon());
BaseRaisePropertyChanged(L"Icon");
InvalidateResolvedIcon();
}
}
});
if (const auto terminalTab{ tab.try_as<winrt::TerminalApp::TerminalTab>() })
if (const auto status = tab.TabStatus())
{
const auto status = terminalTab.TabStatus();
TabStatus(status);
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& /*e*/) {
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [=](auto& /*sender*/, auto& /*e*/) {
// Sometimes nested bindings do not get updated,
// thus let's notify property changed on TabStatus when one of its properties changes
if (auto item{ weakThis.get() })
{
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
}
BaseRaisePropertyChanged(L"TabStatus");
});
}
}

View File

@@ -0,0 +1,159 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "BasePaletteItem.h"
#include "TabPaletteItem.g.h"
#include "../inc/cppwinrt_utils.h"
namespace winrt::TerminalApp::implementation
{
struct ActionPaletteItem :
public winrt::implements<ActionPaletteItem, IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>,
BasePaletteItem<ActionPaletteItem, winrt::TerminalApp::PaletteItemType::Action>
{
ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText) :
_Command{ command }, _name{ command.Name() }, _keyChordText{ keyChordText }
{
static bool shouldShowSubtitles = [] {
try
{
const auto context{ winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::GetForViewIndependentUse() };
const auto qualifiers{ context.QualifierValues() };
if (const auto language{ qualifiers.TryLookup(L"language") })
{
return !til::starts_with_insensitive_ascii(*language, L"en-");
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
return false;
}();
if (shouldShowSubtitles)
{
const auto subtitle = _Command.LanguageNeutralName();
if (subtitle != _name)
{
_subtitle = std::move(subtitle);
}
}
}
winrt::hstring Name()
{
return _name;
}
winrt::hstring Subtitle()
{
return _subtitle;
}
winrt::hstring KeyChordText()
{
return _keyChordText;
}
winrt::hstring Icon()
{
return _Command.IconPath();
}
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
winrt::hstring _name;
winrt::hstring _subtitle;
winrt::hstring _keyChordText;
};
struct CommandLinePaletteItem :
public winrt::implements<CommandLinePaletteItem, IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>,
BasePaletteItem<CommandLinePaletteItem, winrt::TerminalApp::PaletteItemType::CommandLine>
{
CommandLinePaletteItem(const winrt::hstring& commandLine) :
_CommandLine{ commandLine } {}
winrt::hstring Name()
{
return _CommandLine;
}
winrt::hstring Subtitle()
{
return {};
}
winrt::hstring KeyChordText()
{
return {};
}
winrt::hstring Icon()
{
return {};
}
WINRT_PROPERTY(winrt::hstring, CommandLine);
};
struct TabPaletteItem :
public TabPaletteItemT<TabPaletteItem>,
BasePaletteItem<TabPaletteItem, winrt::TerminalApp::PaletteItemType::Tab>
{
TabPaletteItem(const winrt::TerminalApp::Tab& tab);
winrt::TerminalApp::Tab Tab() const noexcept
{
return _tab.get();
}
winrt::hstring Name()
{
if (auto tab = _tab.get())
{
return tab.Title();
}
return {};
}
winrt::hstring Subtitle()
{
return {};
}
winrt::hstring KeyChordText()
{
return {};
}
winrt::hstring Icon()
{
if (auto tab = _tab.get())
{
return tab.Icon();
}
return {};
}
winrt::TerminalApp::TerminalTabStatus TabStatus()
{
if (auto tab = _tab.get())
{
return tab.TabStatus();
}
return { nullptr };
}
private:
winrt::weak_ref<winrt::TerminalApp::Tab> _tab;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabStatusChangedRevoker;
};
}

View File

@@ -3,7 +3,6 @@
#include "pch.h"
#include "CommandPalette.h"
#include "HighlightedText.h"
#include <LibraryResources.h>
#include "fzf/fzf.h"
@@ -20,32 +19,23 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
// This class is a wrapper of PaletteItem, that is used as an item of a filterable list in CommandPalette.
// This class is a wrapper of IPaletteItem, that is used as an item of a filterable list in CommandPalette.
// It manages a highlighted text that is computed by matching search filter characters to item name
FilteredCommand::FilteredCommand(const winrt::TerminalApp::PaletteItem& item)
FilteredCommand::FilteredCommand(const winrt::TerminalApp::IPaletteItem& item) :
_Item{ item }, _Weight{ 0 }
{
// Actually implement the ctor in _constructFilteredCommand
_constructFilteredCommand(item);
}
// We need to actually implement the ctor in a separate helper. This is
// because we have a FilteredTask class which derives from FilteredCommand.
// HOWEVER, for cppwinrt ~ r e a s o n s ~, it doesn't actually derive from
// FilteredCommand directly, so we can't just use the FilteredCommand ctor
// directly in the base class.
void FilteredCommand::_constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item)
{
_Item = item;
_Weight = 0;
_update();
// Recompute the highlighted name if the item name changes
_itemChangedRevoker = _Item.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& e) {
auto filteredCommand{ weakThis.get() };
if (filteredCommand && e.PropertyName() == L"Name")
// Our Item will not change, so we don't need to update the revoker if it does.
_itemChangedRevoker = _Item.as<winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>().PropertyChanged(winrt::auto_revoke, [=](auto& /*sender*/, auto& e) {
const auto property{ e.PropertyName() };
if (property == L"Name")
{
filteredCommand->_update();
_update();
}
else if (property == L"Subtitle")
{
_update();
PropertyChanged.raise(*this, winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"HasSubtitle" });
}
});
}
@@ -61,49 +51,63 @@ namespace winrt::TerminalApp::implementation
}
}
void FilteredCommand::_update()
bool FilteredCommand::HasSubtitle()
{
std::vector<winrt::TerminalApp::HighlightedTextSegment> segments;
const auto commandName = _Item.Name();
return !_Item.Subtitle().empty();
}
static std::tuple<std::vector<winrt::TerminalApp::HighlightedRun>, int32_t> _matchedSegmentsAndWeight(const std::shared_ptr<fzf::matcher::Pattern>& pattern, const winrt::hstring& haystack)
{
std::vector<winrt::TerminalApp::HighlightedRun> segments;
int32_t weight = 0;
if (!_pattern || _pattern->terms.empty())
if (pattern && !pattern->terms.empty())
{
segments.emplace_back(winrt::TerminalApp::HighlightedTextSegment(commandName, false));
if (auto match = fzf::matcher::Match(haystack, *pattern.get()); match)
{
auto& matchResult = *match;
weight = matchResult.Score;
segments.resize(matchResult.Runs.size());
std::transform(matchResult.Runs.begin(), matchResult.Runs.end(), segments.begin(), [](auto&& run) -> winrt::TerminalApp::HighlightedRun {
return { run.Start, run.End };
});
}
}
else if (auto match = fzf::matcher::Match(commandName, *_pattern.get()); !match)
return { std::move(segments), weight };
}
void FilteredCommand::_update()
{
auto itemName = _Item.Name();
auto [segments, weight] = _matchedSegmentsAndWeight(_pattern, itemName);
decltype(segments) subtitleSegments;
if (HasSubtitle())
{
segments.emplace_back(winrt::TerminalApp::HighlightedTextSegment(commandName, false));
auto itemSubtitle = _Item.Subtitle();
int32_t subtitleWeight = 0;
std::tie(subtitleSegments, subtitleWeight) = _matchedSegmentsAndWeight(_pattern, itemSubtitle);
weight = std::max(weight, subtitleWeight);
}
if (segments.empty())
{
NameHighlights(nullptr);
}
else
{
auto& matchResult = *match;
weight = matchResult.Score;
size_t lastPos = 0;
for (const auto& run : matchResult.Runs)
{
const auto& [start, end] = run;
if (start > lastPos)
{
hstring nonMatch{ til::safe_slice_abs(commandName, lastPos, start) };
segments.emplace_back(winrt::TerminalApp::HighlightedTextSegment(nonMatch, false));
}
hstring matchSeg{ til::safe_slice_abs(commandName, start, end + 1) };
segments.emplace_back(winrt::TerminalApp::HighlightedTextSegment(matchSeg, true));
lastPos = end + 1;
}
if (lastPos < commandName.size())
{
hstring tail{ til::safe_slice_abs(commandName, lastPos, SIZE_T_MAX) };
segments.emplace_back(winrt::TerminalApp::HighlightedTextSegment(tail, false));
}
NameHighlights(winrt::single_threaded_vector(std::move(segments)));
}
if (subtitleSegments.empty())
{
SubtitleHighlights(nullptr);
}
else
{
SubtitleHighlights(winrt::single_threaded_vector(std::move(subtitleSegments)));
}
HighlightedName(winrt::make<HighlightedText>(winrt::single_threaded_observable_vector(std::move(segments))));
Weight(weight);
}

View File

@@ -18,19 +18,19 @@ namespace winrt::TerminalApp::implementation
struct FilteredCommand : FilteredCommandT<FilteredCommand>
{
FilteredCommand() = default;
FilteredCommand(const winrt::TerminalApp::PaletteItem& item);
FilteredCommand(const winrt::TerminalApp::IPaletteItem& item);
virtual void UpdateFilter(std::shared_ptr<fzf::matcher::Pattern> pattern);
void UpdateFilter(std::shared_ptr<fzf::matcher::Pattern> pattern);
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
bool HasSubtitle();
protected:
void _constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::IPaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, NameHighlights, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, SubtitleHighlights, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
private:
std::shared_ptr<fzf::matcher::Pattern> _pattern;

View File

@@ -1,18 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
import "IPaletteItem.idl";
import "HighlightedTextControl.idl";
namespace TerminalApp
{
[default_interface] unsealed runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
FilteredCommand();
FilteredCommand(PaletteItem item);
FilteredCommand(IPaletteItem item);
PaletteItem Item { get; };
HighlightedText HighlightedName { get; };
IPaletteItem Item { get; };
IVector<HighlightedRun> NameHighlights { get; };
IVector<HighlightedRun> SubtitleHighlights { get; };
Boolean HasSubtitle { get; };
Int32 Weight;
}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "HighlightedText.h"
#include "HighlightedTextSegment.g.cpp"
#include "HighlightedText.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
HighlightedTextSegment::HighlightedTextSegment(const winrt::hstring& textSegment, bool isHighlighted) :
_TextSegment(textSegment),
_IsHighlighted(isHighlighted)
{
}
HighlightedText::HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments) :
_Segments(segments)
{
}
}

View File

@@ -1,35 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "HighlightedTextSegment.g.h"
#include "HighlightedText.g.h"
namespace winrt::TerminalApp::implementation
{
struct HighlightedTextSegment : HighlightedTextSegmentT<HighlightedTextSegment>
{
HighlightedTextSegment() = default;
HighlightedTextSegment(const winrt::hstring& text, bool isHighlighted);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, TextSegment, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsHighlighted, PropertyChanged.raise);
};
struct HighlightedText : HighlightedTextT<HighlightedText>
{
HighlightedText() = default;
HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, PropertyChanged.raise);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(HighlightedTextSegment);
BASIC_FACTORY(HighlightedText);
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
[default_interface] runtimeclass HighlightedTextSegment : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
HighlightedTextSegment();
HighlightedTextSegment(String text, Boolean isMatched);
String TextSegment { get; };
Boolean IsHighlighted { get; };
}
[default_interface] runtimeclass HighlightedText : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
HighlightedText();
HighlightedText(Windows.Foundation.Collections.IObservableVector<HighlightedTextSegment> segments);
Windows.Foundation.Collections.IObservableVector<HighlightedTextSegment> Segments;
}
}

View File

@@ -22,70 +22,152 @@ namespace winrt::TerminalApp::implementation
// Our control exposes a "Text" property to be used with Data Binding
// To allow this we need to register a Dependency Property Identifier to be used by the property system
// (https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/custom-dependency-properties)
DependencyProperty HighlightedTextControl::_textProperty = DependencyProperty::Register(
L"Text",
xaml_typename<winrt::TerminalApp::HighlightedText>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onTextChanged));
DependencyProperty HighlightedTextControl::_TextProperty{ nullptr };
DependencyProperty HighlightedTextControl::_HighlightedRunsProperty{ nullptr };
DependencyProperty HighlightedTextControl::_TextBlockStyleProperty{ nullptr };
DependencyProperty HighlightedTextControl::_HighlightedRunStyleProperty{ nullptr };
HighlightedTextControl::HighlightedTextControl()
{
InitializeComponent();
_InitializeProperties();
}
// Method Description:
// - Returns the Identifier of the "Text" dependency property
DependencyProperty HighlightedTextControl::TextProperty()
void HighlightedTextControl::_InitializeProperties()
{
return _textProperty;
static auto [[maybe_unused]] registered = [] {
_TextProperty = DependencyProperty::Register(
L"Text",
xaml_typename<winrt::hstring>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onPropertyChanged));
_HighlightedRunsProperty = DependencyProperty::Register(
L"HighlightedRuns",
xaml_typename<winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onPropertyChanged));
_TextBlockStyleProperty = DependencyProperty::Register(
L"TextBlockStyle",
xaml_typename<winrt::Windows::UI::Xaml::Style>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata{ nullptr });
_HighlightedRunStyleProperty = DependencyProperty::Register(
L"HighlightedRunStyle",
xaml_typename<winrt::Windows::UI::Xaml::Style>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onPropertyChanged));
return true;
}();
}
// Method Description:
// - Returns the TextBlock view used to render the highlighted text
// Can be used when the Text property change is triggered by the event system to update the view
// We need to expose it rather than simply bind a data source because we update the runs in code-behind
Controls::TextBlock HighlightedTextControl::TextView()
{
return _textView();
}
winrt::TerminalApp::HighlightedText HighlightedTextControl::Text()
{
return winrt::unbox_value<winrt::TerminalApp::HighlightedText>(GetValue(_textProperty));
}
void HighlightedTextControl::Text(const winrt::TerminalApp::HighlightedText& value)
{
SetValue(_textProperty, winrt::box_value(value));
}
// Method Description:
// - This callback is triggered when the Text property is changed. Responsible for updating the view
// Arguments:
// - o - dependency object that was modified, expected to be an instance of this control
// - e - event arguments of the property changed event fired by the event system upon Text property change.
// The new value is expected to be an instance of HighlightedText
void HighlightedTextControl::_onTextChanged(const DependencyObject& o, const DependencyPropertyChangedEventArgs& e)
void HighlightedTextControl::_onPropertyChanged(const DependencyObject& o, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto control = o.try_as<winrt::TerminalApp::HighlightedTextControl>();
const auto highlightedText = e.NewValue().try_as<winrt::TerminalApp::HighlightedText>();
if (control && highlightedText)
if (control)
{
// Replace all the runs on the TextBlock
// Use IsHighlighted to decide if the run should be highlighted.
// To do - export the highlighting style into XAML
const auto inlinesCollection = control.TextView().Inlines();
inlinesCollection.Clear();
winrt::get_self<HighlightedTextControl>(control)->_updateTextAndStyle();
}
}
for (const auto& match : highlightedText.Segments())
void HighlightedTextControl::OnApplyTemplate()
{
_updateTextAndStyle();
}
static void _applyStyleToObject(const winrt::Windows::UI::Xaml::Style& style, const winrt::Windows::UI::Xaml::DependencyObject& object)
{
if (!style)
{
return;
}
static const auto fontWeightProperty{ winrt::Windows::UI::Xaml::Documents::TextElement::FontWeightProperty() };
const auto setters{ style.Setters() };
for (auto&& setterBase : setters)
{
const auto setter = setterBase.as<winrt::Windows::UI::Xaml::Setter>();
const auto property = setter.Property();
auto value = setter.Value();
if (property == fontWeightProperty) [[unlikely]]
{
const auto matchText = match.TextSegment();
const auto fontWeight = match.IsHighlighted() ? FontWeights::Bold() : FontWeights::Normal();
// BODGY - The XAML compiler emits a boxed int32, but the dependency property
// here expects a boxed FontWeight (which also requires a u16. heh.)
// FontWeight is one of the few properties that is broken like this, and on Run it's the
// only one... so we can trivially check this case.
const auto weight{ winrt::unbox_value_or<int32_t>(value, static_cast<int32_t>(400)) };
value = winrt::box_value(winrt::Windows::UI::Text::FontWeight{ static_cast<uint16_t>(weight) });
}
object.SetValue(property, value);
}
}
void HighlightedTextControl::_updateTextAndStyle()
{
const auto textBlock = GetTemplateChild(L"TextView").try_as<winrt::Windows::UI::Xaml::Controls::TextBlock>();
if (!textBlock)
{
return;
}
const auto text = Text();
const auto runs = HighlightedRuns();
const auto inlinesCollection = textBlock.Inlines();
inlinesCollection.Clear();
// The code below constructs local hstring instances because hstring is required to be null-terminated
// and slicing _does not_ guarantee null termination. Passing a sliced wstring_view directly into run.Text()
// (which is a winrt::param::hstring--different thing!--will result in an exception when the sliced portion
// is not null-terminated.
if (!text.empty())
{
size_t lastPos = 0;
if (runs && runs.Size())
{
const auto runStyle = HighlightedRunStyle();
for (const auto& [start, end] : runs)
{
if (start > lastPos)
{
const hstring nonMatch{ til::safe_slice_abs(text, lastPos, static_cast<size_t>(start)) };
Documents::Run run;
run.Text(nonMatch);
inlinesCollection.Append(run);
}
const hstring matchSeg{ til::safe_slice_abs(text, static_cast<size_t>(start), static_cast<size_t>(end + 1)) };
Documents::Run run;
run.Text(matchSeg);
if (runStyle) [[unlikely]]
{
_applyStyleToObject(runStyle, run);
}
else
{
// Default style: bold
run.FontWeight(FontWeights::Bold());
}
inlinesCollection.Append(run);
lastPos = static_cast<size_t>(end + 1);
}
}
// This will also be true if there are no runs at all
if (lastPos < text.size())
{
// checking lastPos here prevents a needless deep copy of the whole text in the no-match case
const hstring tail{ lastPos == 0 ? text : hstring{ til::safe_slice_abs(text, lastPos, SIZE_T_MAX) } };
Documents::Run run;
run.Text(matchText);
run.FontWeight(fontWeight);
run.Text(tail);
inlinesCollection.Append(run);
}
}

View File

@@ -3,8 +3,6 @@
#pragma once
#include "winrt/Microsoft.UI.Xaml.Controls.h"
#include "HighlightedTextControl.g.h"
namespace winrt::TerminalApp::implementation
@@ -13,16 +11,17 @@ namespace winrt::TerminalApp::implementation
{
HighlightedTextControl();
static Windows::UI::Xaml::DependencyProperty TextProperty();
void OnApplyTemplate();
winrt::TerminalApp::HighlightedText Text();
void Text(const winrt::TerminalApp::HighlightedText& value);
Windows::UI::Xaml::Controls::TextBlock TextView();
DEPENDENCY_PROPERTY(winrt::hstring, Text);
DEPENDENCY_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, HighlightedRuns);
DEPENDENCY_PROPERTY(winrt::Windows::UI::Xaml::Style, TextBlockStyle);
DEPENDENCY_PROPERTY(winrt::Windows::UI::Xaml::Style, HighlightedRunStyle);
private:
static Windows::UI::Xaml::DependencyProperty _textProperty;
static void _onTextChanged(const Windows::UI::Xaml::DependencyObject& o, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _InitializeProperties();
static void _onPropertyChanged(const Windows::UI::Xaml::DependencyObject& o, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
void _updateTextAndStyle();
};
}

View File

@@ -1,15 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "HighlightedText.idl";
namespace TerminalApp
{
struct HighlightedRun
{
UInt64 Start;
UInt64 End;
};
[default_interface] runtimeclass HighlightedTextControl : Windows.UI.Xaml.Controls.Control
{
HighlightedTextControl();
String Text;
Windows.UI.Xaml.DependencyProperty TextProperty { get; };
HighlightedText Text;
Windows.UI.Xaml.Controls.TextBlock TextView { get; };
IVector<HighlightedRun> HighlightedRuns;
Windows.UI.Xaml.DependencyProperty HighlightedRunsProperty { get; };
Windows.UI.Xaml.Style TextBlockStyle;
Windows.UI.Xaml.DependencyProperty TextBlockStyleProperty { get; };
Windows.UI.Xaml.Style HighlightedRunStyle;
Windows.UI.Xaml.DependencyProperty HighlightedRunStyleProperty { get; };
}
}

View File

@@ -1,11 +0,0 @@
<UserControl x:Class="TerminalApp.HighlightedTextControl"
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:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="Transparent"
mc:Ignorable="d">
<TextBlock x:Name="_textView" />
</UserControl>

View File

@@ -0,0 +1,23 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<ResourceDictionary 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:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Style TargetType="local:HighlightedTextControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:HighlightedTextControl">
<TextBlock x:Name="TextView"
Style="{TemplateBinding TextBlockStyle}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TerminalTabStatus.idl";
namespace TerminalApp
{
enum PaletteItemType
{
Action,
CommandLine,
Tab,
};
interface IPaletteItem requires Windows.UI.Xaml.Data.INotifyPropertyChanged
{
PaletteItemType Type { get; };
String Name { get; };
String Subtitle { get; };
String KeyChordText { get; };
String Icon { get; };
Windows.UI.Xaml.Controls.IconElement ResolvedIcon { get; };
}
runtimeclass TabPaletteItem : [default] IPaletteItem, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
TerminalTabStatus TabStatus{ get; };
}
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <LibraryResources.h>
#include "PaletteItem.h"
#include "PaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::System;
namespace winrt::TerminalApp::implementation
{
Controls::IconElement PaletteItem::ResolvedIcon()
{
const auto icon = Microsoft::Terminal::UI::IconPathConverter::IconWUX(Icon());
icon.Width(16);
icon.Height(16);
return icon;
}
}

View File

@@ -1,20 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct PaletteItem : PaletteItemT<PaletteItem>
{
public:
Windows::UI::Xaml::Controls::IconElement ResolvedIcon();
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, PropertyChanged.raise);
};
}

View File

@@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
unsealed runtimeclass PaletteItem : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Name;
String KeyChordText;
String Icon;
Windows.UI.Xaml.Controls.IconElement ResolvedIcon { get; };
}
}

View File

@@ -2,10 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "TabPaletteItem.h"
#include "PaletteItemTemplateSelector.h"
#include "PaletteItemTemplateSelector.g.cpp"
#include "CommandPaletteItems.h"
namespace winrt::TerminalApp::implementation
{
Windows::UI::Xaml::DataTemplate PaletteItemTemplateSelector::SelectTemplateCore(const winrt::Windows::Foundation::IInspectable& item, const winrt::Windows::UI::Xaml::DependencyObject& /*container*/)
@@ -26,16 +27,22 @@ namespace winrt::TerminalApp::implementation
{
if (const auto filteredCommand{ item.try_as<winrt::TerminalApp::FilteredCommand>() })
{
if (filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>())
switch (filteredCommand.Item().Type())
{
case PaletteItemType::Tab:
return TabItemTemplate();
}
else if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
case PaletteItemType::Action:
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(filteredCommand.Item()) };
if (actionPaletteItem->Command().HasNestedCommands())
{
return NestedItemTemplate();
}
break; // Fall back to the general template
}
case PaletteItemType::CommandLine:
default:
break; // Fall back to the general template
}
}

View File

@@ -2429,7 +2429,7 @@ std::optional<uint32_t> Pane::Id() noexcept
// Method Description:
// - Sets this pane's ID
// - Panes are given IDs upon creation by TerminalTab
// - Panes are given IDs upon creation by Tab
// Arguments:
// - The number to set this pane's ID to
void Pane::Id(uint32_t id) noexcept

View File

@@ -31,7 +31,7 @@ namespace TerminalAppLocalTests
namespace winrt::TerminalApp::implementation
{
struct TerminalTab;
struct Tab;
}
enum class Borders : int
@@ -398,6 +398,6 @@ private:
LayoutSizeNode& operator=(const LayoutSizeNode& other);
};
friend struct winrt::TerminalApp::implementation::TerminalTab;
friend struct winrt::TerminalApp::implementation::Tab;
friend class ::TerminalAppLocalTests::TabTests;
};

View File

@@ -6,7 +6,7 @@
#include "FilteredTask.g.h"
#include "BasicPaneEvents.h"
#include "FilteredCommand.h"
#include "ActionPaletteItem.h"
#include "CommandPaletteItems.h"
#include <LibraryResources.h>
namespace winrt::TerminalApp::implementation
@@ -62,7 +62,7 @@ namespace winrt::TerminalApp::implementation
FilteredTask(const winrt::Microsoft::Terminal::Settings::Model::Command& command)
{
_filteredCommand = winrt::make_self<implementation::FilteredCommand>(winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(command, winrt::hstring{}));
_filteredCommand = winrt::make_self<implementation::FilteredCommand>(winrt::make<ActionPaletteItem>(command, winrt::hstring{}));
_command = command;
// The Children() method must always return a non-null vector
@@ -92,14 +92,13 @@ namespace winrt::TerminalApp::implementation
winrt::hstring Input()
{
if (const auto& actionItem{ _filteredCommand->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
// **SAFETY GUARANTEE** We constructed this filtered command ourselves; we know what's inside it.
const auto actionItem{ winrt::get_self<ActionPaletteItem>(_filteredCommand->Item()) };
if (const auto& command{ actionItem->Command() })
{
if (const auto& command{ actionItem.Command() })
if (const auto& sendInput{ command.ActionAndArgs().Args().try_as<winrt::Microsoft::Terminal::Settings::Model::SendInputArgs>() })
{
if (const auto& sendInput{ command.ActionAndArgs().Args().try_as<winrt::Microsoft::Terminal::Settings::Model::SendInputArgs>() })
{
return winrt::hstring{ til::visualize_nonspace_control_codes(std::wstring{ sendInput.Input() }) };
}
return winrt::hstring{ til::visualize_nonspace_control_codes(std::wstring{ sendInput.Input() }) };
}
}
return winrt::hstring{};

View File

@@ -170,8 +170,9 @@
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
HighlightedRuns="{x:Bind FilteredCommand.NameHighlights, Mode=OneWay}"
IsTabStop="False"
Text="{x:Bind FilteredCommand.HighlightedName, Mode=OneWay}" />
Text="{x:Bind FilteredCommand.Item.Name, Mode=OneWay}" />
<!--
BODGY: I can't choose different templates if this item is nested or not.

View File

@@ -2,11 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include "CommandLinePaletteItem.h"
#include "SuggestionsControl.h"
#include <LibraryResources.h>
#include "CommandPaletteItems.h"
#include "SuggestionsControl.g.cpp"
#include "../../types/inc/utils.hpp"
@@ -282,9 +282,11 @@ namespace winrt::TerminalApp::implementation
if (filteredCommand != nullptr &&
isVisible)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto& cmd = actionPaletteItem.Command();
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
const auto& cmd = actionPaletteItem->Command();
PreviewAction.raise(*this, cmd);
const auto description{ cmd.Description() };
@@ -575,7 +577,7 @@ namespace winrt::TerminalApp::implementation
const auto selectedCommand = selectedList.GetAt(0);
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
{
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
if (const auto paletteItem = filteredCmd.Item())
{
automationPeer.RaiseNotificationEvent(
Automation::Peers::AutomationNotificationKind::ItemAdded,
@@ -609,10 +611,14 @@ namespace winrt::TerminalApp::implementation
if (_nestedActionStack.Size() > 0)
{
const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
const auto actionPaletteItem{ newPreviousAction.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
const auto item{ newPreviousAction.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
ParentCommandName(actionPaletteItem->Command().Name());
_updateCurrentNestedCommands(actionPaletteItem->Command());
}
}
else
{
@@ -693,16 +699,19 @@ namespace winrt::TerminalApp::implementation
{
if (filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
const auto command{ actionPaletteItem->Command() };
if (command.HasNestedCommands())
{
// If this Command had subcommands, then don't dispatch the
// action. Instead, display a new list of commands for the user
// to pick from.
_nestedActionStack.Append(filteredCommand);
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
ParentCommandName(command.Name());
_updateCurrentNestedCommands(command);
_updateUIForStackChange();
}
@@ -722,9 +731,9 @@ namespace winrt::TerminalApp::implementation
// "ToggleCommandPalette" actions. We may want to do the
// same with "Suggestions" actions in the future, should we
// ever allow non-sendInput actions.
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
DispatchCommandRequested.raise(*this, command);
if (const auto& sendInputCmd = actionPaletteItem.Command().ActionAndArgs().Args().try_as<SendInputArgs>())
if (const auto& sendInputCmd = command.ActionAndArgs().Args().try_as<SendInputArgs>())
{
if (til::starts_with(sendInputCmd.Input(), L"winget"))
{

View File

@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TabBase.idl";
import "HighlightedTextControl.idl";
import "FilteredCommand.idl";

View File

@@ -57,7 +57,8 @@
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
</Grid>
</DataTemplate>
@@ -84,7 +85,8 @@
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<FontIcon Grid.Column="2"
HorizontalAlignment="Right"

View File

@@ -4,8 +4,8 @@
#pragma once
#include "Pane.h"
#include "ColorPickupFlyout.h"
#include "TabBase.h"
#include "TerminalTab.g.h"
#include "Tab.h"
#include "Tab.g.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@@ -15,10 +15,10 @@ namespace TerminalAppLocalTests
namespace winrt::TerminalApp::implementation
{
struct TerminalTab : TerminalTabT<TerminalTab, TabBase>
struct Tab : TabT<Tab>
{
public:
TerminalTab(std::shared_ptr<Pane> rootPane);
Tab(std::shared_ptr<Pane> rootPane);
// Called after construction to perform the necessary setup, which relies on weak_ptr
void Initialize();
@@ -27,7 +27,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile() const noexcept;
winrt::TerminalApp::IPaneContent GetActiveContent() const;
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
void Focus(winrt::Windows::UI::Xaml::FocusState focusState);
void Scroll(const int delta);
@@ -61,7 +61,7 @@ namespace winrt::TerminalApp::implementation
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
void UpdateTitle();
void Shutdown() override;
void Shutdown();
void ClosePane();
void SetTabText(winrt::hstring title);
@@ -69,7 +69,7 @@ namespace winrt::TerminalApp::implementation
void ResetTabText();
void ActivateTabRenamer();
virtual std::optional<winrt::Windows::UI::Color> GetTabColor() override;
std::optional<winrt::Windows::UI::Color> GetTabColor();
void SetRuntimeTabColor(const winrt::Windows::UI::Color& color);
void ResetRuntimeTabColor();
@@ -79,7 +79,7 @@ namespace winrt::TerminalApp::implementation
void EnterZoom();
void ExitZoom();
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(BuildStartupKind kind) const override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(BuildStartupKind kind) const;
int GetLeafPaneCount() const noexcept;
@@ -98,16 +98,62 @@ namespace winrt::TerminalApp::implementation
return _tabStatus;
}
void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& unfocused,
const til::color& tabRowColor);
Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility CloseButtonVisibility();
void CloseButtonVisibility(Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility visible);
til::event<winrt::delegate<void()>> RequestFocusActiveControl;
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> Closed;
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> CloseRequested;
til::property_changed_event PropertyChanged;
til::typed_event<TerminalApp::TerminalPaneContent> RestartTerminalRequested;
til::typed_event<TerminalApp::TerminalTab, IInspectable> ActivePaneChanged;
til::typed_event<TerminalApp::Tab, IInspectable> ActivePaneChanged;
til::event<winrt::delegate<>> TabRaiseVisualBell;
til::typed_event<IInspectable, IInspectable> TaskbarProgressChanged;
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
WINRT_PROPERTY(uint32_t, TabViewIndex, 0);
// The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector.
WINRT_PROPERTY(uint32_t, TabViewNumTabs, 0);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, ReadOnly, PropertyChanged.raise, false);
WINRT_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, PropertyChanged.raise, nullptr);
private:
static constexpr double HeaderRenameBoxWidthDefault{ 165 };
static constexpr double HeaderRenameBoxWidthTitleLength{ std::numeric_limits<double>::infinity() };
winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused };
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveToNewWindowMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveRightMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveLeftMenuItem{};
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
winrt::hstring _keyChord{};
winrt::Microsoft::Terminal::Settings::Model::ThemeColor _themeColor{ nullptr };
winrt::Microsoft::Terminal::Settings::Model::ThemeColor _unfocusedThemeColor{ nullptr };
til::color _tabRowColor;
Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility _closeButtonVisibility{ Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility::Always };
std::shared_ptr<Pane> _rootPane{ nullptr };
std::shared_ptr<Pane> _activePane{ nullptr };
std::shared_ptr<Pane> _zoomedPane{ nullptr };
@@ -163,12 +209,10 @@ namespace winrt::TerminalApp::implementation
SafeDispatcherTimer _bellIndicatorTimer;
void _BellIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
void _MakeTabViewItem() override;
void _UpdateHeaderControlMaxWidth();
void _CreateContextMenu() override;
virtual winrt::hstring _CreateToolTipTitle() override;
void _CreateContextMenu();
winrt::hstring _CreateToolTipTitle();
void _DetachEventHandlersFromContent(const uint32_t paneId);
void _AttachEventHandlersToContent(const uint32_t paneId, const winrt::TerminalApp::IPaneContent& content);
@@ -187,7 +231,23 @@ namespace winrt::TerminalApp::implementation
void _DuplicateTab();
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush();
void _MakeTabViewItem();
void _AppendMoveMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _AppendCloseMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
void _EnableMenuItems();
void _UpdateSwitchToTabKeyChord();
void _UpdateToolTip();
void _RecalculateAndApplyTabColor();
void _ApplyTabColorOnUIThread(const winrt::Windows::UI::Color& color);
void _ClearTabBackgroundColor();
void _RefreshVisualState();
bool _focused() const noexcept;
void _updateIsClosable();
void _addBroadcastHandlers(const winrt::Microsoft::Terminal::Control::TermControl& control, ContentEventTokens& events);

View File

@@ -1,10 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "ShortcutActionDispatch.idl";
import "TerminalTabStatus.idl";
namespace TerminalApp
{
unsealed runtimeclass TabBase : Windows.UI.Xaml.Data.INotifyPropertyChanged
runtimeclass Tab : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Title { get; };
String Icon { get; };
@@ -14,6 +15,9 @@ namespace TerminalApp
Microsoft.UI.Xaml.Controls.TabViewItem TabViewItem { get; };
Windows.UI.Xaml.FrameworkElement Content { get; };
// May be Null
TerminalTabStatus TabStatus { get; };
UInt32 TabViewIndex;
UInt32 TabViewNumTabs;

View File

@@ -1,753 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <LibraryResources.h>
#include "TabBase.h"
#include "TabBase.g.cpp"
#include "Utils.h"
#include "ColorHelper.h"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::System;
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
}
#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess())
namespace winrt::TerminalApp::implementation
{
// Method Description:
// - Prepares this tab for being removed from the UI hierarchy
void TabBase::Shutdown()
{
ASSERT_UI_THREAD();
// NOTE: `TerminalPage::_HandleCloseTabRequested` relies on the content being null after this call.
Content(nullptr);
}
// Method Description:
// - Creates a context menu attached to the tab.
// Currently contains elements allowing the user to close the selected tab
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_CreateContextMenu()
{
auto weakThis{ get_weak() };
// Build the menu
Controls::MenuFlyout contextMenuFlyout;
// GH#5750 - When the context menu is dismissed with ESC, toss the focus
// back to our control.
contextMenuFlyout.Closed([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->RequestFocusActiveControl.raise();
}
});
_AppendMoveMenuItems(contextMenuFlyout);
_AppendCloseMenuItems(contextMenuFlyout);
TabViewItem().ContextFlyout(contextMenuFlyout);
}
void TabBase::_AppendMoveMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout)
{
auto weakThis{ get_weak() };
// Move to new window
{
Controls::FontIcon moveTabToNewWindowTabSymbol;
moveTabToNewWindowTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
moveTabToNewWindowTabSymbol.Glyph(L"\xE8A7");
_moveToNewWindowMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
MoveTabArgs args{ L"new", MoveTabDirection::Forward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
tab->_dispatch.DoAction(*tab, actionAndArgs);
}
});
_moveToNewWindowMenuItem.Text(RS_(L"MoveTabToNewWindowText"));
_moveToNewWindowMenuItem.Icon(moveTabToNewWindowTabSymbol);
const auto moveTabToNewWindowToolTip = RS_(L"MoveTabToNewWindowToolTip");
WUX::Controls::ToolTipService::SetToolTip(_moveToNewWindowMenuItem, box_value(moveTabToNewWindowToolTip));
Automation::AutomationProperties::SetHelpText(_moveToNewWindowMenuItem, moveTabToNewWindowToolTip);
}
// Move left
{
_moveLeftMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
MoveTabArgs args{ hstring{}, MoveTabDirection::Backward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
tab->_dispatch.DoAction(*tab, actionAndArgs);
}
});
_moveLeftMenuItem.Text(RS_(L"TabMoveLeft"));
}
// Move right
{
_moveRightMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
MoveTabArgs args{ hstring{}, MoveTabDirection::Forward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
tab->_dispatch.DoAction(*tab, actionAndArgs);
}
});
_moveRightMenuItem.Text(RS_(L"TabMoveRight"));
}
// Create a sub-menu for our extended move tab items.
Controls::MenuFlyoutSubItem moveSubMenu;
moveSubMenu.Text(RS_(L"TabMoveSubMenu"));
moveSubMenu.Items().Append(_moveToNewWindowMenuItem);
moveSubMenu.Items().Append(_moveRightMenuItem);
moveSubMenu.Items().Append(_moveLeftMenuItem);
flyout.Items().Append(moveSubMenu);
}
// Method Description:
// - Append the close menu items to the context menu flyout
// Arguments:
// - flyout - the menu flyout to which the close items must be appended
// Return Value:
// - the sub-item that we use for all the nested "close" entries. This
// enables subclasses to add their own entries to this menu.
winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem TabBase::_AppendCloseMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout)
{
auto weakThis{ get_weak() };
// Close tabs after
_closeTabsAfterMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
CloseTabsAfterArgs args{ tab->_TabViewIndex };
ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args };
tab->_dispatch.DoAction(*tab, closeTabsAfter);
}
});
_closeTabsAfterMenuItem.Text(RS_(L"TabCloseAfter"));
const auto closeTabsAfterToolTip = RS_(L"TabCloseAfterToolTip");
WUX::Controls::ToolTipService::SetToolTip(_closeTabsAfterMenuItem, box_value(closeTabsAfterToolTip));
Automation::AutomationProperties::SetHelpText(_closeTabsAfterMenuItem, closeTabsAfterToolTip);
// Close other tabs
_closeOtherTabsMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
CloseOtherTabsArgs args{ tab->_TabViewIndex };
ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args };
tab->_dispatch.DoAction(*tab, closeOtherTabs);
}
});
_closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther"));
const auto closeOtherTabsToolTip = RS_(L"TabCloseOtherToolTip");
WUX::Controls::ToolTipService::SetToolTip(_closeOtherTabsMenuItem, box_value(closeOtherTabsToolTip));
Automation::AutomationProperties::SetHelpText(_closeOtherTabsMenuItem, closeOtherTabsToolTip);
// Close
Controls::MenuFlyoutItem closeTabMenuItem;
Controls::FontIcon closeSymbol;
closeSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
closeSymbol.Glyph(L"\xE711");
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->CloseRequested.raise(nullptr, nullptr);
}
});
closeTabMenuItem.Text(RS_(L"TabClose"));
closeTabMenuItem.Icon(closeSymbol);
const auto closeTabToolTip = RS_(L"TabCloseToolTip");
WUX::Controls::ToolTipService::SetToolTip(closeTabMenuItem, box_value(closeTabToolTip));
Automation::AutomationProperties::SetHelpText(closeTabMenuItem, closeTabToolTip);
// Create a sub-menu for our extended close items.
Controls::MenuFlyoutSubItem closeSubMenu;
closeSubMenu.Text(RS_(L"TabCloseSubMenu"));
closeSubMenu.Items().Append(_closeTabsAfterMenuItem);
closeSubMenu.Items().Append(_closeOtherTabsMenuItem);
flyout.Items().Append(closeSubMenu);
flyout.Items().Append(closeTabMenuItem);
return closeSubMenu;
}
// Method Description:
// - Enable menu items based on tab index and total number of tabs
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_EnableMenuItems()
{
const auto tabIndex = TabViewIndex();
const auto numOfTabs = TabViewNumTabs();
// enabled if there are other tabs
_closeOtherTabsMenuItem.IsEnabled(numOfTabs > 1);
// enabled if there are other tabs on the right
_closeTabsAfterMenuItem.IsEnabled(tabIndex < numOfTabs - 1);
// enabled if not left-most tab
_moveLeftMenuItem.IsEnabled(tabIndex > 0);
// enabled if not last tab
_moveRightMenuItem.IsEnabled(tabIndex < numOfTabs - 1);
}
void TabBase::UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs)
{
ASSERT_UI_THREAD();
TabViewIndex(idx);
TabViewNumTabs(numTabs);
_EnableMenuItems();
_UpdateSwitchToTabKeyChord();
}
void TabBase::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
{
ASSERT_UI_THREAD();
_dispatch = dispatch;
}
void TabBase::SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap)
{
ASSERT_UI_THREAD();
_actionMap = actionMap;
_UpdateSwitchToTabKeyChord();
}
// Method Description:
// - Sets the key chord resulting in switch to the current tab.
// Updates tool tip if required
// Arguments:
// - keyChord - string representation of the key chord that switches to the current tab
// Return Value:
// - <none>
void TabBase::_UpdateSwitchToTabKeyChord()
{
const auto id = fmt::format(FMT_COMPILE(L"Terminal.SwitchToTab{}"), _TabViewIndex);
const auto keyChord{ _actionMap.GetKeyBindingForAction(id) };
const auto keyChordText = keyChord ? KeyChordSerialization::ToString(keyChord) : L"";
if (_keyChord == keyChordText)
{
return;
}
_keyChord = keyChordText;
_UpdateToolTip();
}
// Method Description:
// - Creates a text for the title run in the tool tip by returning tab title
// Arguments:
// - <none>
// Return Value:
// - The value to populate in the title run of the tool tip
winrt::hstring TabBase::_CreateToolTipTitle()
{
return _Title;
}
// Method Description:
// - Sets tab tool tip to a concatenation of title and key chord
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_UpdateToolTip()
{
auto titleRun = WUX::Documents::Run();
titleRun.Text(_CreateToolTipTitle());
auto textBlock = WUX::Controls::TextBlock{};
textBlock.TextWrapping(WUX::TextWrapping::Wrap);
textBlock.TextAlignment(WUX::TextAlignment::Center);
textBlock.Inlines().Append(titleRun);
if (!_keyChord.empty())
{
auto keyChordRun = WUX::Documents::Run();
keyChordRun.Text(_keyChord);
keyChordRun.FontStyle(winrt::Windows::UI::Text::FontStyle::Italic);
textBlock.Inlines().Append(WUX::Documents::LineBreak{});
textBlock.Inlines().Append(keyChordRun);
}
WUX::Controls::ToolTip toolTip{};
toolTip.Content(textBlock);
WUX::Controls::ToolTipService::SetToolTip(TabViewItem(), toolTip);
}
// Method Description:
// - Initializes a TabViewItem for this Tab instance.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_MakeTabViewItem()
{
TabViewItem(::winrt::MUX::Controls::TabViewItem{});
// GH#3609 If the tab was tapped, and no one else was around to handle
// it, then ask our parent to toss focus into the active control.
TabViewItem().Tapped([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->RequestFocusActiveControl.raise();
}
});
// BODGY: When the tab is drag/dropped, the TabView gets a
// TabDragStarting. However, the way it is implemented[^1], the
// TabViewItem needs either an Item or a Content for the event to
// include the correct TabViewItem. Otherwise, it will just return the
// first TabViewItem in the TabView with the same Content as the dragged
// tab (which, if the Content is null, will be the _first_ tab).
//
// So here, we'll stick an empty border in, just so that every tab has a
// Content which is not equal to the others.
//
// [^1]: microsoft-ui-xaml/blob/92fbfcd55f05c92ac65569f5d284c5b36492091e/dev/TabView/TabView.cpp#L751-L758
TabViewItem().Content(winrt::WUX::Controls::Border{});
}
std::optional<winrt::Windows::UI::Color> TabBase::GetTabColor()
{
ASSERT_UI_THREAD();
return std::nullopt;
}
void TabBase::ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& unfocused,
const til::color& tabRowColor)
{
ASSERT_UI_THREAD();
_themeColor = focused;
_unfocusedThemeColor = unfocused;
_tabRowColor = tabRowColor;
_RecalculateAndApplyTabColor();
}
// Method Description:
// - This function dispatches a function to the UI thread to recalculate
// what this tab's current background color should be. If a color is set,
// it will apply the given color to the tab's background. Otherwise, it
// will clear the tab's background color.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_RecalculateAndApplyTabColor()
{
// GetTabColor will return the color set by the color picker, or the
// color specified in the profile. If neither of those were set,
// then look to _themeColor to see if there's a value there.
// Otherwise, clear our color, falling back to the TabView defaults.
const auto currentColor = GetTabColor();
if (currentColor.has_value())
{
_ApplyTabColorOnUIThread(currentColor.value());
}
else if (_themeColor != nullptr)
{
// Safely get the active control's brush.
const Media::Brush terminalBrush{ _BackgroundBrush() };
if (const auto themeBrush{ _themeColor.Evaluate(Application::Current().Resources(), terminalBrush, false) })
{
// ThemeColor.Evaluate will get us a Brush (because the
// TermControl could have an acrylic BG, for example). Take
// that brush, and get the color out of it. We don't really
// want to have the tab items themselves be acrylic.
_ApplyTabColorOnUIThread(til::color{ ThemeColor::ColorFromBrush(themeBrush) });
}
else
{
_ClearTabBackgroundColor();
}
}
else
{
_ClearTabBackgroundColor();
}
}
// Method Description:
// - Applies the given color to the background of this tab's TabViewItem.
// - Sets the tab foreground color depending on the luminance of
// the background color
// - This method should only be called on the UI thread.
// Arguments:
// - color: the color the user picked for their tab
// Return Value:
// - <none>
void TabBase::_ApplyTabColorOnUIThread(const winrt::Windows::UI::Color& color)
{
Media::SolidColorBrush selectedTabBrush{};
Media::SolidColorBrush deselectedTabBrush{};
Media::SolidColorBrush fontBrush{};
Media::SolidColorBrush deselectedFontBrush{};
Media::SolidColorBrush secondaryFontBrush{};
Media::SolidColorBrush hoverTabBrush{};
Media::SolidColorBrush subtleFillColorSecondaryBrush;
Media::SolidColorBrush subtleFillColorTertiaryBrush;
// calculate the luminance of the current color and select a font
// color based on that
// see https://www.w3.org/TR/WCAG20/#relativeluminancedef
if (TerminalApp::ColorHelper::IsBrightColor(color))
{
auto subtleFillColorSecondary = winrt::Windows::UI::Colors::Black();
subtleFillColorSecondary.A = 0x09;
subtleFillColorSecondaryBrush.Color(subtleFillColorSecondary);
auto subtleFillColorTertiary = winrt::Windows::UI::Colors::Black();
subtleFillColorTertiary.A = 0x06;
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
}
else
{
auto subtleFillColorSecondary = winrt::Windows::UI::Colors::White();
subtleFillColorSecondary.A = 0x0F;
subtleFillColorSecondaryBrush.Color(subtleFillColorSecondary);
auto subtleFillColorTertiary = winrt::Windows::UI::Colors::White();
subtleFillColorTertiary.A = 0x0A;
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
}
// The tab font should be based on the evaluated appearance of the tab color layered on tab row.
const auto layeredTabColor = til::color{ color }.layer_over(_tabRowColor);
if (TerminalApp::ColorHelper::IsBrightColor(layeredTabColor))
{
fontBrush.Color(winrt::Windows::UI::Colors::Black());
auto secondaryFontColor = winrt::Windows::UI::Colors::Black();
// For alpha value see: https://github.com/microsoft/microsoft-ui-xaml/blob/7a33ad772d77d908aa6b316ec24e6d2eb3ebf571/dev/CommonStyles/Common_themeresources_any.xaml#L269
secondaryFontColor.A = 0x9E;
secondaryFontBrush.Color(secondaryFontColor);
}
else
{
fontBrush.Color(winrt::Windows::UI::Colors::White());
auto secondaryFontColor = winrt::Windows::UI::Colors::White();
// For alpha value see: https://github.com/microsoft/microsoft-ui-xaml/blob/7a33ad772d77d908aa6b316ec24e6d2eb3ebf571/dev/CommonStyles/Common_themeresources_any.xaml#L14
secondaryFontColor.A = 0xC5;
secondaryFontBrush.Color(secondaryFontColor);
}
selectedTabBrush.Color(color);
// Start with the current tab color, set to Opacity=.3
til::color deselectedTabColor{ color };
deselectedTabColor = deselectedTabColor.with_alpha(77); // 255 * .3 = 77
// If we DON'T have a color set from the color picker, or the profile's
// tabColor, but we do have a unfocused color in the theme, use the
// unfocused theme color here instead.
if (!GetTabColor().has_value() &&
_unfocusedThemeColor != nullptr)
{
// Safely get the active control's brush.
const Media::Brush terminalBrush{ _BackgroundBrush() };
// Get the color of the brush.
if (const auto themeBrush{ _unfocusedThemeColor.Evaluate(Application::Current().Resources(), terminalBrush, false) })
{
// We did figure out the brush. Get the color out of it. If it
// was "accent" or "terminalBackground", then we're gonna set
// the alpha to .3 manually here.
// (ThemeColor::UnfocusedTabOpacity will do this for us). If the
// user sets both unfocused and focused tab.background to
// terminalBackground, this will allow for some differentiation
// (and is generally just sensible).
deselectedTabColor = til::color{ ThemeColor::ColorFromBrush(themeBrush) }.with_alpha(_unfocusedThemeColor.UnfocusedTabOpacity());
}
}
// currently if a tab has a custom color, a deselected state is
// signified by using the same color with a bit of transparency
deselectedTabBrush.Color(deselectedTabColor.with_alpha(255));
deselectedTabBrush.Opacity(deselectedTabColor.a / 255.f);
hoverTabBrush.Color(color);
hoverTabBrush.Opacity(0.6);
// Account for the color of the tab row when setting the color of text
// on inactive tabs. Consider:
// * black active tabs
// * on a white tab row
// * with a transparent inactive tab color
//
// We don't want that to result in white text on a white tab row for
// inactive tabs.
const auto deselectedActualColor = deselectedTabColor.layer_over(_tabRowColor);
if (TerminalApp::ColorHelper::IsBrightColor(deselectedActualColor))
{
deselectedFontBrush.Color(winrt::Windows::UI::Colors::Black());
}
else
{
deselectedFontBrush.Color(winrt::Windows::UI::Colors::White());
}
// Add the empty theme dictionaries
const auto& tabItemThemeResources{ TabViewItem().Resources().ThemeDictionaries() };
ResourceDictionary lightThemeDictionary;
ResourceDictionary darkThemeDictionary;
ResourceDictionary highContrastThemeDictionary;
tabItemThemeResources.Insert(winrt::box_value(L"Light"), lightThemeDictionary);
tabItemThemeResources.Insert(winrt::box_value(L"Dark"), darkThemeDictionary);
tabItemThemeResources.Insert(winrt::box_value(L"HighContrast"), highContrastThemeDictionary);
// Apply the color to the tab
TabViewItem().Background(deselectedTabBrush);
// Now actually set the resources we want in them.
// Before, we used to put these on the ResourceDictionary directly.
// However, HighContrast mode may require some adjustments. So let's just add
// all three so we can make those adjustments on the HighContrast version.
for (const auto& [k, v] : tabItemThemeResources)
{
const bool isHighContrast = winrt::unbox_value<hstring>(k) == L"HighContrast";
const auto& currentDictionary = v.as<ResourceDictionary>();
// TabViewItem.Background
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), isHighContrast ? fontBrush : hoverTabBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush);
// TabViewItem.Foreground (aka text)
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderForeground"), deselectedFontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderForegroundSelected"), fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderForegroundPointerOver"), isHighContrast ? selectedTabBrush : fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderForegroundPressed"), fontBrush);
// TabViewItem.CloseButton.Foreground (aka X)
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonForeground"), deselectedFontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonForegroundPressed"), isHighContrast ? deselectedFontBrush : secondaryFontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonForegroundPointerOver"), isHighContrast ? deselectedFontBrush : fontBrush);
// TabViewItem.CloseButton.Foreground _when_ interacting with the tab
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderPressedCloseButtonForeground"), fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderPointerOverCloseButtonForeground"), isHighContrast ? selectedTabBrush : fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderSelectedCloseButtonForeground"), fontBrush);
// TabViewItem.CloseButton.Background (aka X button)
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBackgroundPressed"), isHighContrast ? selectedTabBrush : subtleFillColorTertiaryBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBackgroundPointerOver"), isHighContrast ? selectedTabBrush : subtleFillColorSecondaryBrush);
// A few miscellaneous resources that WinUI said may be removed in the future
currentDictionary.Insert(winrt::box_value(L"TabViewButtonForegroundActiveTab"), fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewButtonForegroundPressed"), fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewButtonForegroundPointerOver"), fontBrush);
// Add a few extra ones for high contrast mode
// BODGY: contrary to the docs, Insert() seems to throw if the value already exists
// Make sure you don't touch any that already exist here!
if (isHighContrast)
{
// TabViewItem.CloseButton.Border: in HC mode, the border makes the button more clearly visible
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBorderBrushPressed"), fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBorderBrushPointerOver"), fontBrush);
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBorderBrushSelected"), fontBrush);
}
}
_RefreshVisualState();
}
// Method Description:
// - Clear out any color we've set for the TabViewItem.
// - This method should only be called on the UI thread.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_ClearTabBackgroundColor()
{
static const winrt::hstring keys[] = {
// TabViewItem.Background
L"TabViewItemHeaderBackground",
L"TabViewItemHeaderBackgroundSelected",
L"TabViewItemHeaderBackgroundPointerOver",
L"TabViewItemHeaderBackgroundPressed",
// TabViewItem.Foreground (aka text)
L"TabViewItemHeaderForeground",
L"TabViewItemHeaderForegroundSelected",
L"TabViewItemHeaderForegroundPointerOver",
L"TabViewItemHeaderForegroundPressed",
// TabViewItem.CloseButton.Foreground (aka X)
L"TabViewItemHeaderCloseButtonForeground",
L"TabViewItemHeaderForegroundSelected",
L"TabViewItemHeaderCloseButtonForegroundPointerOver",
L"TabViewItemHeaderCloseButtonForegroundPressed",
// TabViewItem.CloseButton.Foreground _when_ interacting with the tab
L"TabViewItemHeaderPressedCloseButtonForeground",
L"TabViewItemHeaderPointerOverCloseButtonForeground",
L"TabViewItemHeaderSelectedCloseButtonForeground",
// TabViewItem.CloseButton.Background (aka X button)
L"TabViewItemHeaderCloseButtonBackground",
L"TabViewItemHeaderCloseButtonBackgroundPressed",
L"TabViewItemHeaderCloseButtonBackgroundPointerOver",
// A few miscellaneous resources that WinUI said may be removed in the future
L"TabViewButtonForegroundActiveTab",
L"TabViewButtonForegroundPressed",
L"TabViewButtonForegroundPointerOver",
// TabViewItem.CloseButton.Border: in HC mode, the border makes the button more clearly visible
L"TabViewItemHeaderCloseButtonBorderBrushPressed",
L"TabViewItemHeaderCloseButtonBorderBrushPointerOver",
L"TabViewItemHeaderCloseButtonBorderBrushSelected"
};
const auto& tabItemThemeResources{ TabViewItem().Resources().ThemeDictionaries() };
// simply clear any of the colors in the tab's dict
for (const auto& keyString : keys)
{
const auto key = winrt::box_value(keyString);
for (const auto& [_, v] : tabItemThemeResources)
{
const auto& themeDictionary = v.as<ResourceDictionary>();
themeDictionary.Remove(key);
}
}
// GH#11382 DON'T set the background to null. If you do that, then the
// tab won't be hit testable at all. Transparent, however, is a totally
// valid hit test target. That makes sense.
TabViewItem().Background(WUX::Media::SolidColorBrush{ Windows::UI::Colors::Transparent() });
_RefreshVisualState();
}
// Method Description:
// BODGY
// - Toggles the requested theme of the tab view item,
// so that changes to the tab color are reflected immediately
// - Prior to MUX 2.8, we only toggled the visual state here, but that seemingly
// doesn't work in 2.8.
// - Just changing the Theme also doesn't seem to work by itself - there
// seems to be a way for the tab to set the deselected foreground onto
// itself as it becomes selected. If the mouse isn't over the tab, that
// can result in mismatched fg/bg's (see GH#15184). So that's right, we
// need to do both.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_RefreshVisualState()
{
const auto& item{ TabViewItem() };
const auto& reqTheme = TabViewItem().RequestedTheme();
item.RequestedTheme(ElementTheme::Light);
item.RequestedTheme(ElementTheme::Dark);
item.RequestedTheme(reqTheme);
if (TabViewItem().IsSelected())
{
VisualStateManager::GoToState(item, L"Normal", true);
VisualStateManager::GoToState(item, L"Selected", true);
}
else
{
VisualStateManager::GoToState(item, L"Selected", true);
VisualStateManager::GoToState(item, L"Normal", true);
}
}
TabCloseButtonVisibility TabBase::CloseButtonVisibility()
{
return _closeButtonVisibility;
}
// Method Description:
// - set our internal state to track if we were requested to have a visible
// tab close button or not.
// - This is called every time the active tab changes. That way, the changes
// in focused tab can be reflected for the "ActiveOnly" state.
void TabBase::CloseButtonVisibility(TabCloseButtonVisibility visibility)
{
_closeButtonVisibility = visibility;
_updateIsClosable();
}
// Method Description:
// - Update our close button's visibility, to reflect both the ReadOnly
// state of the tab content, and also if if we were told to have a visible
// close button at all.
// - the tab being read-only takes precedence. That will always suppress
// the close button.
// - Otherwise we'll use the state set in CloseButtonVisibility to control
// the tab's visibility.
void TabBase::_updateIsClosable()
{
bool isClosable = true;
if (ReadOnly())
{
isClosable = false;
}
else
{
switch (_closeButtonVisibility)
{
case TabCloseButtonVisibility::Never:
isClosable = false;
break;
case TabCloseButtonVisibility::Hover:
isClosable = true;
break;
case TabCloseButtonVisibility::ActiveOnly:
isClosable = _focused();
break;
default:
isClosable = true;
break;
}
}
TabViewItem().IsClosable(isClosable);
}
bool TabBase::_focused() const noexcept
{
return _focusState != FocusState::Unfocused;
}
}

View File

@@ -1,92 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "TabBase.g.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
{
class TabTests;
};
namespace winrt::TerminalApp::implementation
{
struct TabBase : TabBaseT<TabBase>
{
public:
virtual void Focus(winrt::Windows::UI::Xaml::FocusState focusState) = 0;
virtual void Shutdown();
void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(BuildStartupKind kind) const = 0;
virtual std::optional<winrt::Windows::UI::Color> GetTabColor();
void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& unfocused,
const til::color& tabRowColor);
Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility CloseButtonVisibility();
void CloseButtonVisibility(Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility visible);
til::event<winrt::delegate<void()>> RequestFocusActiveControl;
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> Closed;
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> CloseRequested;
til::property_changed_event PropertyChanged;
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
WINRT_PROPERTY(uint32_t, TabViewIndex, 0);
// The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector.
WINRT_PROPERTY(uint32_t, TabViewNumTabs, 0);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, ReadOnly, PropertyChanged.raise, false);
WINRT_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, PropertyChanged.raise, nullptr);
protected:
winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused };
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveToNewWindowMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveRightMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveLeftMenuItem{};
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
winrt::hstring _keyChord{};
winrt::Microsoft::Terminal::Settings::Model::ThemeColor _themeColor{ nullptr };
winrt::Microsoft::Terminal::Settings::Model::ThemeColor _unfocusedThemeColor{ nullptr };
til::color _tabRowColor;
Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility _closeButtonVisibility{ Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility::Always };
virtual void _CreateContextMenu();
virtual winrt::hstring _CreateToolTipTitle();
virtual void _MakeTabViewItem();
void _AppendMoveMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _AppendCloseMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
void _EnableMenuItems();
void _UpdateSwitchToTabKeyChord();
void _UpdateToolTip();
void _RecalculateAndApplyTabColor();
void _ApplyTabColorOnUIThread(const winrt::Windows::UI::Color& color);
void _ClearTabBackgroundColor();
void _RefreshVisualState();
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() = 0;
bool _focused() const noexcept;
void _updateIsClosable();
friend class ::TerminalAppLocalTests::TabTests;
};
}

View File

@@ -18,7 +18,6 @@
#include <LibraryResources.h>
#include "TabRowControl.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "..\TerminalSettingsModel\FileUtils.h"
@@ -99,7 +98,7 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - newTabImpl: the uninitialized tab.
// - insertPosition: Optional parameter to indicate the position of tab.
void TerminalPage::_InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl, uint32_t insertPosition)
void TerminalPage::_InitializeTab(winrt::com_ptr<Tab> newTabImpl, uint32_t insertPosition)
{
newTabImpl->Initialize();
@@ -206,11 +205,11 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - pane: The pane to use as the root.
// - insertPosition: Optional parameter to indicate the position of tab.
TerminalApp::TerminalTab TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition)
TerminalApp::Tab TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition)
{
if (pane)
{
auto newTabImpl = winrt::make_self<TerminalTab>(pane);
auto newTabImpl = winrt::make_self<Tab>(pane);
_InitializeTab(newTabImpl, insertPosition);
return *newTabImpl;
}
@@ -222,7 +221,7 @@ namespace winrt::TerminalApp::implementation
// tab's icon to that icon.
// Arguments:
// - tab: the Tab to update the title for.
void TerminalPage::_UpdateTabIcon(TerminalTab& tab)
void TerminalPage::_UpdateTabIcon(Tab& tab)
{
if (const auto content{ tab.GetActiveContent() })
{
@@ -272,9 +271,9 @@ namespace winrt::TerminalApp::implementation
// - Duplicates the current focused tab
void TerminalPage::_DuplicateFocusedTab()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto activeTab{ _GetFocusedTabImpl() })
{
_DuplicateTab(*terminalTab);
_DuplicateTab(*activeTab);
}
}
@@ -282,7 +281,7 @@ namespace winrt::TerminalApp::implementation
// - Duplicates specified tab
// Arguments:
// - tab: tab to duplicate
void TerminalPage::_DuplicateTab(const TerminalTab& tab)
void TerminalPage::_DuplicateTab(const Tab& tab)
{
try
{
@@ -315,7 +314,7 @@ namespace winrt::TerminalApp::implementation
// - Exports the content of the Terminal Buffer inside the tab
// Arguments:
// - tab: tab to export
safe_void_coroutine TerminalPage::_ExportTab(const TerminalTab& tab, winrt::hstring filepath)
safe_void_coroutine TerminalPage::_ExportTab(const Tab& tab, winrt::hstring filepath)
{
// This will be used to set up the file picker "filter", to select .txt
// files by default.
@@ -401,7 +400,7 @@ namespace winrt::TerminalApp::implementation
// - Removes the tab (both TerminalControl and XAML) after prompting for approval
// Arguments:
// - tab: the tab to remove
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::TabBase tab)
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab)
{
if (tab.ReadOnly())
{
@@ -414,7 +413,7 @@ namespace winrt::TerminalApp::implementation
}
}
auto t = winrt::get_self<implementation::TabBase>(tab);
auto t = winrt::get_self<implementation::Tab>(tab);
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));
@@ -425,7 +424,7 @@ namespace winrt::TerminalApp::implementation
// - Removes the tab (both TerminalControl and XAML)
// Arguments:
// - tab: the tab to remove
void TerminalPage::_RemoveTab(const winrt::TerminalApp::TabBase& tab)
void TerminalPage::_RemoveTab(const winrt::TerminalApp::Tab& tab)
{
uint32_t tabIndex{};
if (!_tabs.IndexOf(tab, tabIndex))
@@ -597,7 +596,7 @@ namespace winrt::TerminalApp::implementation
// - tab - tab to select
// Return Value:
// - <none>
void TerminalPage::_OnSwitchToTabRequested(const IInspectable& /*sender*/, const winrt::TerminalApp::TabBase& tab)
void TerminalPage::_OnSwitchToTabRequested(const IInspectable& /*sender*/, const winrt::TerminalApp::Tab& tab)
{
uint32_t index{};
if (_tabs.IndexOf(tab, index))
@@ -628,7 +627,7 @@ namespace winrt::TerminalApp::implementation
// no tab is currently selected, returns nullopt.
// Return Value:
// - the index of the currently focused tab if there is one, else nullopt
std::optional<uint32_t> TerminalPage::_GetTabIndex(const TerminalApp::TabBase& tab) const noexcept
std::optional<uint32_t> TerminalPage::_GetTabIndex(const TerminalApp::Tab& tab) const noexcept
{
uint32_t i;
if (_tabs.IndexOf(tab, i))
@@ -641,7 +640,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - returns the currently focused tab. This might return null,
// so make sure to check the result!
winrt::TerminalApp::TabBase TerminalPage::_GetFocusedTab() const noexcept
winrt::TerminalApp::Tab TerminalPage::_GetFocusedTab() const noexcept
{
if (auto index{ _GetFocusedTabIndex() })
{
@@ -653,11 +652,11 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - returns a com_ptr to the currently focused tab implementation. This might return null,
// so make sure to check the result!
winrt::com_ptr<TerminalTab> TerminalPage::_GetFocusedTabImpl() const noexcept
winrt::com_ptr<Tab> TerminalPage::_GetFocusedTabImpl() const noexcept
{
if (auto tab{ _GetFocusedTab() })
{
return _GetTerminalTabImpl(tab);
return _GetTabImpl(tab);
}
return nullptr;
}
@@ -665,7 +664,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - returns a tab corresponding to a view item. This might return null,
// so make sure to check the result!
winrt::TerminalApp::TabBase TerminalPage::_GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept
winrt::TerminalApp::Tab TerminalPage::_GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept
{
uint32_t tabIndexFromControl{};
const auto items{ _tabView.TabItems() };
@@ -687,7 +686,7 @@ namespace winrt::TerminalApp::implementation
// - tab: tab to focus.
// Return Value:
// - <none>
safe_void_coroutine TerminalPage::_SetFocusedTab(const winrt::TerminalApp::TabBase tab)
safe_void_coroutine TerminalPage::_SetFocusedTab(const winrt::TerminalApp::Tab tab)
{
// GH#1117: This is a workaround because _tabView.SelectedIndex(tabIndex)
// sometimes set focus to an incorrect tab after removing some tabs
@@ -774,11 +773,11 @@ namespace winrt::TerminalApp::implementation
// tab's Closed event.
safe_void_coroutine TerminalPage::_CloseFocusedPane()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto activeTab{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
if (const auto pane{ terminalTab->GetActivePane() })
if (const auto pane{ activeTab->GetActivePane() })
{
if (co_await _PaneConfirmCloseReadOnly(pane))
{
@@ -793,7 +792,7 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - weakTab: weak reference to the tab that the pane belongs to.
// - paneIds: collection of the IDs of the panes that are marked for removal.
void TerminalPage::_ClosePanes(weak_ref<TerminalTab> weakTab, std::vector<uint32_t> paneIds)
void TerminalPage::_ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
{
if (auto strongTab{ weakTab.get() })
{
@@ -838,7 +837,7 @@ namespace winrt::TerminalApp::implementation
// - Closes provided tabs one by one
// Arguments:
// - tabs - tabs to remove
safe_void_coroutine TerminalPage::_RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs)
safe_void_coroutine TerminalPage::_RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs)
{
for (auto& tab : tabs)
{
@@ -926,7 +925,7 @@ namespace winrt::TerminalApp::implementation
}
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
// `TabViewItem` that still contains a `TabBase` which has actually already been removed.
// `TabViewItem` that still contains a `Tab` which has actually already been removed.
// First we must yield once, to flush out whatever TabView is currently doing.
const auto strong = get_strong();
co_await wil::resume_foreground(Dispatcher());
@@ -966,7 +965,7 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_UpdatedSelectedTab(const winrt::TerminalApp::TabBase& tab)
void TerminalPage::_UpdatedSelectedTab(const winrt::TerminalApp::Tab& tab)
{
// Unfocus all the tabs.
for (const auto& tab : _tabs)
@@ -1007,10 +1006,10 @@ namespace winrt::TerminalApp::implementation
_updateThemeColors();
auto tab_impl = _GetTerminalTabImpl(tab);
if (tab_impl)
auto tabImpl = _GetTabImpl(tab);
if (tabImpl)
{
auto profile = tab_impl->GetFocusedProfile();
auto profile = tabImpl->GetFocusedProfile();
_UpdateBackground(profile);
}
}
@@ -1057,7 +1056,7 @@ namespace winrt::TerminalApp::implementation
for (uint32_t i = 0; i < size; ++i)
{
auto tab{ _tabs.GetAt(i) };
auto tabImpl{ winrt::get_self<TabBase>(tab) };
auto tabImpl{ winrt::get_self<Tab>(tab) };
tabImpl->UpdateTabViewIndex(i, size);
}
}
@@ -1068,7 +1067,7 @@ namespace winrt::TerminalApp::implementation
// - tab: tab to bump.
// Return Value:
// - <none>
void TerminalPage::_UpdateMRUTab(const winrt::TerminalApp::TabBase& tab)
void TerminalPage::_UpdateMRUTab(const winrt::TerminalApp::Tab& tab)
{
uint32_t mruIndex;
if (_mruTabs.IndexOf(tab, mruIndex))

View File

@@ -1,33 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "TabPaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct TabPaletteItem : TabPaletteItemT<TabPaletteItem, PaletteItem>
{
TabPaletteItem() = default;
TabPaletteItem(const winrt::TerminalApp::TabBase& tab);
winrt::TerminalApp::TabBase Tab() const noexcept
{
return _tab.get();
}
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, PropertyChanged.raise);
private:
winrt::weak_ref<winrt::TerminalApp::TabBase> _tab;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabStatusChangedRevoker;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TabPaletteItem);
}

View File

@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
import "TabBase.idl";
import "TerminalTabStatus.idl";
namespace TerminalApp
{
[default_interface] runtimeclass TabPaletteItem : PaletteItem
{
TabPaletteItem(TabBase tab);
TabBase Tab { get; };
TerminalTabStatus TabStatus { get; };
}
}

View File

@@ -60,7 +60,8 @@
<Page Include="TabHeaderControl.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="HighlightedTextControl.xaml">
<Page Include="HighlightedTextControlStyle.xaml">
<Type>DefaultStyle</Type>
<SubType>Designer</SubType>
</Page>
<Page Include="ColorPickupFlyout.xaml">
@@ -81,11 +82,10 @@
</ItemGroup>
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="ActionPaletteItem.h" />
<ClInclude Include="App.base.h" />
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="CommandLinePaletteItem.h" />
<ClInclude Include="CommandPaletteItems.h" />
<ClInclude Include="Jumplist.h" />
<ClInclude Include="LanguageProfileNotifier.h" />
<ClInclude Include="MinMaxCloseControl.h">
@@ -98,17 +98,13 @@
<DependentUpon>PaletteItemTemplateSelector.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="PaletteItem.h" />
<ClInclude Include="TabBase.h">
<DependentUpon>TabBase.idl</DependentUpon>
<ClInclude Include="BasePaletteItem.h" />
<ClInclude Include="Tab.h">
<DependentUpon>Tab.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TabPaletteItem.h" />
<ClInclude Include="TaskbarState.h">
<DependentUpon>TaskbarState.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TerminalTab.h">
<DependentUpon>TerminalTab.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TerminalPage.h">
<DependentUpon>TerminalPage.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -127,9 +123,8 @@
<DependentUpon>TabHeaderControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="HighlightedTextControl.h">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
<DependentUpon>HighlightedTextControl.idl</DependentUpon>
</ClInclude>
<ClInclude Include="HighlightedText.h" />
<ClInclude Include="ColorPickupFlyout.h">
<DependentUpon>ColorPickupFlyout.xaml</DependentUpon>
</ClInclude>
@@ -139,7 +134,6 @@
<ClInclude Include="FilteredCommand.h" />
<ClInclude Include="Pane.h" />
<ClInclude Include="fzf/fzf.h" />
<ClInclude Include="ColorHelper.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ShortcutActionDispatch.h">
<DependentUpon>ShortcutActionDispatch.idl</DependentUpon>
@@ -192,11 +186,10 @@
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="ActionPaletteItem.cpp" />
<ClCompile Include="CommandLinePaletteItem.cpp" />
<ClCompile Include="init.cpp" />
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="CommandPaletteItems.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="LanguageProfileNotifier.cpp" />
<ClCompile Include="MinMaxCloseControl.cpp">
@@ -209,18 +202,13 @@
<DependentUpon>PaletteItemTemplateSelector.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="PaletteItem.cpp" />
<ClCompile Include="TabBase.cpp">
<DependentUpon>TabBase.idl</DependentUpon>
<ClCompile Include="Tab.cpp">
<DependentUpon>Tab.idl</DependentUpon>
</ClCompile>
<ClCompile Include="fzf/fzf.cpp" />
<ClCompile Include="TabPaletteItem.cpp" />
<ClCompile Include="TaskbarState.cpp">
<DependentUpon>TaskbarState.idl</DependentUpon>
</ClCompile>
<ClCompile Include="TerminalTab.cpp">
<DependentUpon>TerminalTab.idl</DependentUpon>
</ClCompile>
<ClCompile Include="TerminalPage.cpp">
<DependentUpon>TerminalPage.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -247,9 +235,8 @@
<DependentUpon>TabHeaderControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="HighlightedTextControl.cpp">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
<DependentUpon>HighlightedTextControl.idl</DependentUpon>
</ClCompile>
<ClCompile Include="HighlightedText.cpp" />
<ClCompile Include="ColorPickupFlyout.cpp">
<DependentUpon>ColorPickupFlyout.xaml</DependentUpon>
</ClCompile>
@@ -259,9 +246,6 @@
<ClCompile Include="FilteredCommand.cpp" />
<ClCompile Include="Pane.cpp" />
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
<ClCompile Include="ColorHelper.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="DebugTapConnection.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
@@ -320,8 +304,6 @@
<ItemGroup>
<!-- If you add idl files here, make sure to include their implementation's
header in TerminalApp.vcxproj (as well as in this file) -->
<Midl Include="ActionPaletteItem.idl" />
<Midl Include="CommandLinePaletteItem.idl" />
<Midl Include="AboutDialog.idl">
<DependentUpon>AboutDialog.xaml</DependentUpon>
</Midl>
@@ -332,7 +314,7 @@
<Midl Include="PaletteItemTemplateSelector.idl">
<SubType>Designer</SubType>
</Midl>
<Midl Include="PaletteItem.idl" />
<Midl Include="IPaletteItem.idl" />
<Midl Include="ShortcutActionDispatch.idl" />
<Midl Include="AppKeyBindings.idl" />
<Midl Include="AppLogic.idl" />
@@ -341,10 +323,8 @@
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="TabBase.idl" />
<Midl Include="TabPaletteItem.idl" />
<Midl Include="Tab.idl" />
<Midl Include="TaskbarState.idl" />
<Midl Include="TerminalTab.idl" />
<Midl Include="TerminalPage.idl">
<DependentUpon>TerminalPage.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -365,10 +345,8 @@
<SubType>Code</SubType>
</Midl>
<Midl Include="HighlightedTextControl.idl">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="HighlightedText.idl" />
<Midl Include="ColorPickupFlyout.idl">
<DependentUpon>ColorPickupFlyout.xaml</DependentUpon>
<SubType>Code</SubType>

View File

@@ -20,27 +20,14 @@
</ClCompile>
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="ColorHelper.cpp" />
<ClCompile Include="DebugTapConnection.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="FilteredCommand.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="ActionPaletteItem.cpp">
<ClCompile Include="CommandPaletteItems.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="PaletteItem.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="TabPaletteItem.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="CommandLinePaletteItem.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="HighlightedText.cpp">
<Filter>highlightedText</Filter>
</ClCompile>
<ClCompile Include="fzf/fzf.cpp">
<Filter>fzf</Filter>
</ClCompile>
@@ -60,26 +47,16 @@
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="DebugTapConnection.h" />
<ClInclude Include="ColorHelper.h" />
<ClInclude Include="Jumplist.h" />
<ClInclude Include="FilteredCommand.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="ActionPaletteItem.h">
<ClInclude Include="CommandPaletteItems.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="PaletteItem.h">
<ClInclude Include="BasePaletteItem.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="TabPaletteItem.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="CommandLinePaletteItem.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="HighlightedText.h">
<Filter>highlightedText</Filter>
</ClInclude>
<ClInclude Include="fzf/fzf.h">
<Filter>fzf</Filter>
</ClInclude>
@@ -102,20 +79,14 @@
<Midl Include="ShortcutActionDispatch.idl">
<Filter>settings</Filter>
</Midl>
<Midl Include="TerminalTab.idl">
<Filter>tab</Filter>
</Midl>
<Midl Include="FilteredCommand.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="HighlightedText.idl">
<Filter>highlightedText</Filter>
</Midl>
<Midl Include="TerminalTabStatus.idl">
<Filter>tab</Filter>
</Midl>
<Midl Include="PaletteItemTemplateSelector.idl" />
<Midl Include="TabBase.idl" />
<Midl Include="Tab.idl" />
<Midl Include="TerminalWindow.idl" />
<Midl Include="TaskbarState.idl" />
<Midl Include="IPaneContent.idl" />
@@ -144,19 +115,10 @@
<Page Include="CommandPalette.xaml">
<Filter>commandPalette</Filter>
</Page>
<Midl Include="PaletteItem.idl">
<Midl Include="IPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="TabPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="ActionPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="CommandLinePaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Page Include="HighlightedTextControl.xaml">
<Page Include="HighlightedTextControlStyle.xaml">
<Filter>highlightedText</Filter>
</Page>
<Page Include="AboutDialog.xaml" />

View File

@@ -6,24 +6,24 @@
#include "TerminalPage.h"
#include <LibraryResources.h>
#include <TerminalCore/ControlKeyStates.hpp>
#include <Utils.h>
#include <TerminalCore/ControlKeyStates.hpp>
#include "../../types/inc/utils.hpp"
#include "App.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "SettingsPaneContent.h"
#include "ScratchpadContent.h"
#include "SnippetsPaneContent.h"
#include "MarkdownPaneContent.h"
#include "TabRowControl.h"
#include "Remoting.h"
#include "ScratchpadContent.h"
#include "SettingsPaneContent.h"
#include "SnippetsPaneContent.h"
#include "TabRowControl.h"
#include "../../types/inc/ColorFix.hpp"
#include "../../types/inc/utils.hpp"
#include "TerminalPage.g.cpp"
#include "LaunchPositionRequest.g.cpp"
#include "RenameWindowRequestedArgs.g.cpp"
#include "RequestMoveContentArgs.g.cpp"
#include "LaunchPositionRequest.g.cpp"
#include "TerminalPage.g.cpp"
using namespace winrt;
using namespace winrt::Microsoft::Management::Deployment;
@@ -59,8 +59,8 @@ namespace winrt
namespace winrt::TerminalApp::implementation
{
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::Tab>() },
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::Tab>() },
_manager{ manager },
_hostingHwnd{},
_WindowProperties{ std::move(properties) }
@@ -84,9 +84,9 @@ namespace winrt::TerminalApp::implementation
// GH#13211 - if we haven't yet set the owning hwnd, reparent all the controls now.
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
if (auto tabImpl{ _GetTabImpl(tab) })
{
terminalTab->GetRootPane()->WalkTree([&](auto&& pane) {
tabImpl->GetRootPane()->WalkTree([&](auto&& pane) {
if (const auto& term{ pane->GetTerminalControl() })
{
term.OwningHwnd(reinterpret_cast<uint64_t>(hwnd));
@@ -237,6 +237,14 @@ namespace winrt::TerminalApp::implementation
_newTabButton.Click([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuDefaultButtonClicked",
TraceLoggingDescription("Event emitted when the default button from the new tab split button is invoked"),
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
page->_OpenNewTerminalViaDropdown(NewTerminalArgs());
}
});
@@ -558,9 +566,9 @@ namespace winrt::TerminalApp::implementation
// GH#6586: now that we're done processing all startup commands,
// focus the active control. This will work as expected for both
// commandline invocations and for `wt` action invocations.
if (const auto& terminalTab{ _GetFocusedTabImpl() })
if (const auto& tabImpl{ _GetFocusedTabImpl() })
{
if (const auto& content{ terminalTab->GetActiveContent() })
if (const auto& content{ tabImpl->GetActiveContent() })
{
content.Focus(FocusState::Programmatic);
}
@@ -834,14 +842,36 @@ namespace winrt::TerminalApp::implementation
// Since the previous focus location might be discarded in the background,
// e.g., the command palette will be dismissed by the menu,
// and then closing the fly-out will move the focus to wrong location.
newTabFlyout.Opening([this](auto&&, auto&&) {
_FocusCurrentTab(true);
newTabFlyout.Opening([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
page->_FocusCurrentTab(true);
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuOpened",
TraceLoggingDescription("Event emitted when the new tab menu is opened"),
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The Count of tabs currently opened in this window"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
});
// Necessary for fly-out sub items to get focus on a tab before collapsing. Related to #15049
newTabFlyout.Closing([this](auto&&, auto&&) {
if (!_commandPaletteIs(Visibility::Visible))
newTabFlyout.Closing([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
_FocusCurrentTab(true);
if (!page->_commandPaletteIs(Visibility::Visible))
{
page->_FocusCurrentTab(true);
}
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuClosed",
TraceLoggingDescription("Event emitted when the new tab menu is closed"),
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The Count of tabs currently opened in this window"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
});
_newTabButton.Flyout(newTabFlyout);
@@ -1047,6 +1077,15 @@ namespace winrt::TerminalApp::implementation
profileMenuItem.Click([profileIndex, weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuItemClicked",
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingValue("Profile", "ItemType", "The type of item that was clicked in the new tab menu"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
NewTerminalArgs newTerminalArgs{ profileIndex };
page->_OpenNewTerminalViaDropdown(newTerminalArgs);
}
@@ -1093,6 +1132,15 @@ namespace winrt::TerminalApp::implementation
actionMenuItem.Click([action, weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuItemClicked",
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingValue("Action", "ItemType", "The type of item that was clicked in the new tab menu"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
page->_actionDispatch->DoAction(action.ActionAndArgs());
}
});
@@ -1154,6 +1202,7 @@ namespace winrt::TerminalApp::implementation
const auto dispatchToElevatedWindow = ctrlPressed && !IsRunningElevated();
auto sessionType = "";
if ((shiftPressed || dispatchToElevatedWindow) && !debugTap)
{
// Manually fill in the evaluated profile.
@@ -1171,10 +1220,12 @@ namespace winrt::TerminalApp::implementation
if (dispatchToElevatedWindow)
{
_OpenElevatedWT(newTerminalArgs);
sessionType = "ElevatedWindow";
}
else
{
_OpenNewWindow(newTerminalArgs);
sessionType = "Window";
}
}
else
@@ -1193,12 +1244,23 @@ namespace winrt::TerminalApp::implementation
SplitDirection::Automatic,
0.5f,
newPane);
sessionType = "Pane";
}
else
{
_CreateNewTabFromPane(newPane);
sessionType = "Tab";
}
}
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuCreatedNewTerminalSession",
TraceLoggingDescription("Event emitted when a new terminal was created via the new tab menu"),
TraceLoggingValue(NumberOfTabs(), "NewTabCount", "The count of tabs currently opened in this window"),
TraceLoggingValue(sessionType, "SessionType", "The type of session that was created"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
std::wstring TerminalPage::_evaluatePathForCwd(const std::wstring_view path)
@@ -1405,6 +1467,30 @@ namespace winrt::TerminalApp::implementation
{
target = SettingsTarget::DefaultsFile;
}
const auto targetAsString = [&target]() {
switch (target)
{
case SettingsTarget::SettingsFile:
return "SettingsFile";
case SettingsTarget::DefaultsFile:
return "DefaultsFile";
case SettingsTarget::SettingsUI:
default:
return "UI";
}
}();
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuItemClicked",
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
TraceLoggingValue(NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingValue("Settings", "ItemType", "The type of item that was clicked in the new tab menu"),
TraceLoggingValue(targetAsString, "SettingsTarget", "The target settings file or UI"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_LaunchSettings(target);
}
@@ -1416,6 +1502,15 @@ namespace winrt::TerminalApp::implementation
auto p = LoadCommandPalette();
p.EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
p.Visibility(Visibility::Visible);
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuItemClicked",
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
TraceLoggingValue(NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingValue("CommandPalette", "ItemType", "The type of item that was clicked in the new tab menu"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
// Method Description:
@@ -1428,6 +1523,15 @@ namespace winrt::TerminalApp::implementation
const RoutedEventArgs&)
{
_ShowAboutDialog();
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuItemClicked",
TraceLoggingDescription("Event emitted when an item from the new tab menu is invoked"),
TraceLoggingValue(NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingValue("About", "ItemType", "The type of item that was clicked in the new tab menu"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
// Method Description:
@@ -1651,7 +1755,7 @@ namespace winrt::TerminalApp::implementation
// TitleChanged event.
// Arguments:
// - tab: the Tab to update the title for.
void TerminalPage::_UpdateTitle(const TerminalTab& tab)
void TerminalPage::_UpdateTitle(const Tab& tab)
{
auto newTabTitle = tab.Title();
@@ -1729,13 +1833,13 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Connects event handlers to the TerminalTab for events that we want to
// - Connects event handlers to the Tab for events that we want to
// handle. This includes:
// * the TitleChanged event, for changing the text of the tab
// * the Color{Selected,Cleared} events to change the color of a tab.
// Arguments:
// - hostingTab: The Tab that's hosting this TermControl instance
void TerminalPage::_RegisterTabEvents(TerminalTab& hostingTab)
void TerminalPage::_RegisterTabEvents(Tab& hostingTab)
{
auto weakTab{ hostingTab.get_weak() };
auto weakThis{ get_weak() };
@@ -1818,9 +1922,9 @@ namespace winrt::TerminalApp::implementation
// to the terminal when no other panes are present (GH#6219)
bool TerminalPage::_MoveFocus(const FocusDirection& direction)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
return terminalTab->NavigateFocus(direction);
return tabImpl->NavigateFocus(direction);
}
return false;
}
@@ -1834,19 +1938,19 @@ namespace winrt::TerminalApp::implementation
// - true if panes were swapped.
bool TerminalPage::_SwapPane(const FocusDirection& direction)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
return terminalTab->SwapPane(direction);
return tabImpl->SwapPane(direction);
}
return false;
}
TermControl TerminalPage::_GetActiveControl()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
return terminalTab->GetActiveTerminalControl();
return tabImpl->GetActiveTerminalControl();
}
return nullptr;
}
@@ -1953,7 +2057,7 @@ namespace winrt::TerminalApp::implementation
for (auto tab : _tabs)
{
auto t = winrt::get_self<implementation::TabBase>(tab);
auto t = winrt::get_self<implementation::Tab>(tab);
auto tabActions = t->BuildStartupActions(serializeBuffer ? BuildStartupKind::PersistAll : BuildStartupKind::PersistLayout);
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
}
@@ -2048,14 +2152,14 @@ namespace winrt::TerminalApp::implementation
// - rowsToScroll: a number of lines to move the viewport. If not provided we will use a system default.
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
uint32_t realRowsToScroll;
if (rowsToScroll == nullptr)
{
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
terminalTab->GetActiveTerminalControl().ViewHeight() :
tabImpl->GetActiveTerminalControl().ViewHeight() :
_systemRowsToScroll;
}
else
@@ -2064,7 +2168,7 @@ namespace winrt::TerminalApp::implementation
realRowsToScroll = rowsToScroll.Value();
}
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
terminalTab->Scroll(scrollDelta);
tabImpl->Scroll(scrollDelta);
}
}
@@ -2095,9 +2199,9 @@ namespace winrt::TerminalApp::implementation
// specified window instead of moving it in our tab row.
if (!windowId.empty())
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
if (const auto pane{ terminalTab->GetActivePane() })
if (const auto pane{ tabImpl->GetActivePane() })
{
auto startupActions = pane->BuildStartupActions(0, 1, BuildStartupKind::MovePane);
_DetachPaneFromWindow(pane);
@@ -2136,7 +2240,7 @@ namespace winrt::TerminalApp::implementation
// tab before its index changes.
if (tabIdx < _tabs.Size())
{
auto targetTab = _GetTerminalTabImpl(_tabs.GetAt(tabIdx));
auto targetTab = _GetTabImpl(_tabs.GetAt(tabIdx));
// if the selected tab is not a host of terminals (e.g. settings)
// don't attempt to add a pane to it.
if (!targetTab)
@@ -2184,15 +2288,12 @@ namespace winrt::TerminalApp::implementation
});
}
void TerminalPage::_DetachTabFromWindow(const winrt::com_ptr<TabBase>& tab)
void TerminalPage::_DetachTabFromWindow(const winrt::com_ptr<Tab>& tab)
{
if (const auto terminalTab = tab.try_as<TerminalTab>())
// Detach the root pane, which will act like the whole tab got detached.
if (const auto rootPane = tab->GetRootPane())
{
// Detach the root pane, which will act like the whole tab got detached.
if (const auto rootPane = terminalTab->GetRootPane())
{
_DetachPaneFromWindow(rootPane);
}
_DetachPaneFromWindow(rootPane);
}
}
@@ -2220,7 +2321,7 @@ namespace winrt::TerminalApp::implementation
RequestMoveContent.raise(*this, *request);
}
bool TerminalPage::_MoveTab(winrt::com_ptr<TerminalTab> tab, MoveTabArgs args)
bool TerminalPage::_MoveTab(winrt::com_ptr<Tab> tab, MoveTabArgs args)
{
if (!tab)
{
@@ -2288,10 +2389,10 @@ namespace winrt::TerminalApp::implementation
// When the tab's active pane changes, we'll want to lookup a new icon
// for it. The Title change will be propagated upwards through the tab's
// PropertyChanged event handler.
void TerminalPage::_activePaneChanged(winrt::TerminalApp::TerminalTab sender,
void TerminalPage::_activePaneChanged(winrt::TerminalApp::Tab sender,
Windows::Foundation::IInspectable /*args*/)
{
if (const auto tab{ _GetTerminalTabImpl(sender) })
if (const auto tab{ _GetTabImpl(sender) })
{
// Possibly update the icon of the tab.
_UpdateTabIcon(*tab);
@@ -2380,7 +2481,7 @@ namespace winrt::TerminalApp::implementation
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
// new pane should be split from its parent.
// - splitSize: the size of the split
void TerminalPage::_SplitPane(const winrt::com_ptr<TerminalTab>& tab,
void TerminalPage::_SplitPane(const winrt::com_ptr<Tab>& tab,
const SplitDirection splitDirection,
const float splitSize,
std::shared_ptr<Pane> newPane)
@@ -2461,10 +2562,10 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalPage::_ToggleSplitOrientation()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
terminalTab->ToggleSplitOrientation();
tabImpl->ToggleSplitOrientation();
}
}
@@ -2478,10 +2579,10 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalPage::_ResizePane(const ResizeDirection& direction)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
terminalTab->ResizePane(direction);
tabImpl->ResizePane(direction);
}
}
@@ -2493,23 +2594,23 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_ScrollPage(ScrollDirection scrollDirection)
{
// Do nothing if for some reason, there's no terminal tab in focus. We don't want to crash.
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
if (const auto& control{ _GetActiveControl() })
{
const auto termHeight = control.ViewHeight();
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
terminalTab->Scroll(scrollDelta);
tabImpl->Scroll(scrollDelta);
}
}
}
void TerminalPage::_ScrollToBufferEdge(ScrollDirection scrollDirection)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
auto scrollDelta = _ComputeScrollDelta(scrollDirection, INT_MAX);
terminalTab->Scroll(scrollDelta);
tabImpl->Scroll(scrollDelta);
}
}
@@ -2621,9 +2722,9 @@ namespace winrt::TerminalApp::implementation
{
if (_settings && _settings.GlobalSettings().SnapToGridOnResize())
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
return terminalTab->CalcSnappedDimension(widthOrHeight, dimension);
return tabImpl->CalcSnappedDimension(widthOrHeight, dimension);
}
}
return dimension;
@@ -3239,7 +3340,7 @@ namespace winrt::TerminalApp::implementation
// connection, then we'll return nullptr. Otherwise, we'll return a new
// Pane for this connection.
std::shared_ptr<Pane> TerminalPage::_MakeTerminalPane(const NewTerminalArgs& newTerminalArgs,
const winrt::TerminalApp::TabBase& sourceTab,
const winrt::TerminalApp::Tab& sourceTab,
TerminalConnection::ITerminalConnection existingConnection)
{
// First things first - Check for making a pane from content ID.
@@ -3257,15 +3358,15 @@ namespace winrt::TerminalApp::implementation
TerminalSettingsCreateResult controlSettings{ nullptr };
Profile profile{ nullptr };
if (const auto& terminalTab{ _GetTerminalTabImpl(sourceTab) })
if (const auto& tabImpl{ _GetTabImpl(sourceTab) })
{
profile = terminalTab->GetFocusedProfile();
profile = tabImpl->GetFocusedProfile();
if (profile)
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
const auto workingDirectory = terminalTab->GetActiveTerminalControl().WorkingDirectory();
const auto workingDirectory = tabImpl->GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
@@ -3329,7 +3430,7 @@ namespace winrt::TerminalApp::implementation
auto debugContent{ winrt::make<TerminalPaneContent>(profile, _terminalSettingsCache, newControl) };
auto debugPane = std::make_shared<Pane>(debugContent);
// Since we're doing this split directly on the pane (instead of going through TerminalTab,
// Since we're doing this split directly on the pane (instead of going through Tab,
// we need to handle the panes 'active' states
// Set the pane we're splitting to active (otherwise Split will not do anything)
@@ -3347,7 +3448,7 @@ namespace winrt::TerminalApp::implementation
// NOTE: callers of _MakePane should be able to accept nullptr as a return
// value gracefully.
std::shared_ptr<Pane> TerminalPage::_MakePane(const INewContentArgs& contentArgs,
const winrt::TerminalApp::TabBase& sourceTab,
const winrt::TerminalApp::Tab& sourceTab,
TerminalConnection::ITerminalConnection existingConnection)
{
@@ -3381,9 +3482,9 @@ namespace winrt::TerminalApp::implementation
// Prevent the user from opening a bunch of snippets panes.
//
// Look at the focused tab, and if it already has one, then just focus it.
if (const auto& focusedTab{ _GetFocusedTab() })
if (const auto& focusedTab{ _GetFocusedTabImpl() })
{
const auto rootPane{ focusedTab.try_as<TerminalTab>()->GetRootPane() };
const auto rootPane{ focusedTab->GetRootPane() };
const bool found = rootPane == nullptr ? false : rootPane->WalkTree([](const auto& p) -> bool {
if (const auto& snippets{ p->GetContent().try_as<SnippetsPaneContent>() })
{
@@ -3539,21 +3640,21 @@ namespace winrt::TerminalApp::implementation
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
if (auto tabImpl{ _GetTabImpl(tab) })
{
// Let the tab know that there are new settings. It's up to each content to decide what to do with them.
terminalTab->UpdateSettings(_settings);
tabImpl->UpdateSettings(_settings);
// Update the icon of the tab for the currently focused profile in that tab.
// Only do this for TerminalTabs. Other types of tabs won't have multiple panes
// and profiles so the Title and Icon will be set once and only once on init.
_UpdateTabIcon(*terminalTab);
_UpdateTabIcon(*tabImpl);
// Force the TerminalTab to re-grab its currently active control's title.
terminalTab->UpdateTitle();
tabImpl->UpdateTitle();
}
auto tabImpl{ winrt::get_self<TabBase>(tab) };
auto tabImpl{ winrt::get_self<Tab>(tab) };
tabImpl->SetActionMap(_settings.ActionMap());
}
@@ -3672,7 +3773,7 @@ namespace winrt::TerminalApp::implementation
for (const auto& tab : _tabs)
{
if (auto tabImpl{ _GetTerminalTabImpl(tab) })
if (auto tabImpl{ _GetTabImpl(tab) })
{
auto tabState{ tabImpl->GetCombinedTaskbarState() };
// lowest priority wins
@@ -3715,11 +3816,11 @@ namespace winrt::TerminalApp::implementation
_visible = showOrHide;
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
if (auto tabImpl{ _GetTabImpl(tab) })
{
// Manually enumerate the panes in each tab; this will let us recycle TerminalSettings
// objects but only have to iterate one time.
terminalTab->GetRootPane()->WalkTree([&](auto&& pane) {
tabImpl->GetRootPane()->WalkTree([&](auto&& pane) {
if (auto control = pane->GetTerminalControl())
{
control.WindowVisibilityChanged(showOrHide);
@@ -3737,7 +3838,7 @@ namespace winrt::TerminalApp::implementation
// - tab: the tab where the search box should be created
// Return Value:
// - <none>
void TerminalPage::_Find(const TerminalTab& tab)
void TerminalPage::_Find(const Tab& tab)
{
if (const auto& control{ tab.GetActiveTerminalControl() })
{
@@ -3803,36 +3904,18 @@ namespace winrt::TerminalApp::implementation
// and the non-client are behind it
// Return Value:
// - <none>
void TerminalPage::_SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor)
void TerminalPage::_SetNewTabButtonColor(const til::color color, const til::color accentColor)
{
constexpr auto lightnessThreshold = 0.6f;
// TODO GH#3327: Look at what to do with the tab button when we have XAML theming
auto IsBrightColor = ColorHelper::IsBrightColor(color);
auto isLightAccentColor = ColorHelper::IsBrightColor(accentColor);
winrt::Windows::UI::Color pressedColor{};
winrt::Windows::UI::Color hoverColor{};
winrt::Windows::UI::Color foregroundColor{};
const auto hoverColorAdjustment = 5.f;
const auto pressedColorAdjustment = 7.f;
const auto IsBrightColor = ColorFix::GetLightness(color) >= lightnessThreshold;
const auto isLightAccentColor = ColorFix::GetLightness(accentColor) >= lightnessThreshold;
const auto hoverColorAdjustment = isLightAccentColor ? -0.05f : 0.05f;
const auto pressedColorAdjustment = isLightAccentColor ? -0.1f : 0.1f;
if (IsBrightColor)
{
foregroundColor = winrt::Windows::UI::Colors::Black();
}
else
{
foregroundColor = winrt::Windows::UI::Colors::White();
}
if (isLightAccentColor)
{
hoverColor = ColorHelper::Darken(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Darken(accentColor, pressedColorAdjustment);
}
else
{
hoverColor = ColorHelper::Lighten(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Lighten(accentColor, pressedColorAdjustment);
}
const auto foregroundColor = IsBrightColor ? Colors::Black() : Colors::White();
const auto hoverColor = til::color{ ColorFix::AdjustLightness(accentColor, hoverColorAdjustment) };
const auto pressedColor = til::color{ ColorFix::AdjustLightness(accentColor, pressedColorAdjustment) };
Media::SolidColorBrush backgroundBrush{ accentColor };
Media::SolidColorBrush backgroundHoverBrush{ hoverColor };
@@ -3855,7 +3938,7 @@ namespace winrt::TerminalApp::implementation
_newTabButton.Background(backgroundBrush);
_newTabButton.Foreground(foregroundBrush);
// This is just like what we do in TabBase::_RefreshVisualState. We need
// This is just like what we do in Tab::_RefreshVisualState. We need
// to manually toggle the visual state, so the setters in the visual
// state group will re-apply, and set our currently selected colors in
// the resources.
@@ -4106,25 +4189,18 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Returns a com_ptr to the implementation type of the given tab if it's a TerminalTab.
// - Returns a com_ptr to the implementation type of the given tab if it's a Tab.
// If the tab is not a TerminalTab, returns nullptr.
// Arguments:
// - tab: the projected type of a Tab
// Return Value:
// - If the tab is a TerminalTab, a com_ptr to the implementation type.
// If the tab is not a TerminalTab, nullptr
winrt::com_ptr<TerminalTab> TerminalPage::_GetTerminalTabImpl(const TerminalApp::TabBase& tab)
winrt::com_ptr<Tab> TerminalPage::_GetTabImpl(const TerminalApp::Tab& tab)
{
if (auto terminalTab = tab.try_as<TerminalApp::TerminalTab>())
{
winrt::com_ptr<TerminalTab> tabImpl;
tabImpl.copy_from(winrt::get_self<TerminalTab>(terminalTab));
return tabImpl;
}
else
{
return nullptr;
}
winrt::com_ptr<Tab> tabImpl;
tabImpl.copy_from(winrt::get_self<Tab>(tab));
return tabImpl;
}
// Method Description:
@@ -4611,10 +4687,10 @@ namespace winrt::TerminalApp::implementation
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
if (auto tabImpl{ _GetTabImpl(tab) })
{
// The root pane will propagate the theme change to all its children.
if (const auto& rootPane{ terminalTab->GetRootPane() })
if (const auto& rootPane{ tabImpl->GetRootPane() })
{
rootPane->UpdateResources(_paneResources);
}
@@ -4675,7 +4751,7 @@ namespace winrt::TerminalApp::implementation
}
// Second: Update the colors of our individual TabViewItems. This
// applies tab.background to the tabs via TerminalTab::ThemeColor.
// applies tab.background to the tabs via Tab::ThemeColor.
//
// Do this second, so that we already know the bgColor of the titlebar.
{
@@ -4683,8 +4759,8 @@ namespace winrt::TerminalApp::implementation
const auto tabUnfocusedBackground = theme.Tab() ? theme.Tab().UnfocusedBackground() : nullptr;
for (const auto& tab : _tabs)
{
winrt::com_ptr<TabBase> tabImpl;
tabImpl.copy_from(winrt::get_self<TabBase>(tab));
winrt::com_ptr<Tab> tabImpl;
tabImpl.copy_from(winrt::get_self<Tab>(tab));
tabImpl->ThemeColor(tabBackground, tabUnfocusedBackground, bgColor);
}
}
@@ -5153,8 +5229,8 @@ namespace winrt::TerminalApp::implementation
// Get the tab impl from this event.
const auto eventTab = e.Tab();
const auto tabBase = _GetTabByTabViewItem(eventTab);
winrt::com_ptr<TabBase> tabImpl;
tabImpl.copy_from(winrt::get_self<TabBase>(tabBase));
winrt::com_ptr<Tab> tabImpl;
tabImpl.copy_from(winrt::get_self<Tab>(tabBase));
if (tabImpl)
{
// First: stash the tab we started dragging.
@@ -5365,6 +5441,14 @@ namespace winrt::TerminalApp::implementation
runAsAdminItem.Click([profileIndex, weakThis{ get_weak() }](auto&&, auto&&) {
if (auto page{ weakThis.get() })
{
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabMenuItemElevateSubmenuItemClicked",
TraceLoggingDescription("Event emitted when the elevate submenu item from the new tab menu is invoked"),
TraceLoggingValue(page->NumberOfTabs(), "TabCount", "The count of tabs currently opened in this window"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
NewTerminalArgs args{ profileIndex };
args.Elevate(true);
page->_OpenNewTerminalViaDropdown(args);

View File

@@ -4,7 +4,7 @@
#pragma once
#include "TerminalPage.g.h"
#include "TerminalTab.h"
#include "Tab.h"
#include "AppKeyBindings.h"
#include "AppCommandlineArgs.h"
#include "RenameWindowRequestedArgs.g.h"
@@ -219,13 +219,13 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
Windows::Foundation::Collections::IObservableVector<TerminalApp::TabBase> _tabs;
Windows::Foundation::Collections::IObservableVector<TerminalApp::TabBase> _mruTabs;
static winrt::com_ptr<TerminalTab> _GetTerminalTabImpl(const TerminalApp::TabBase& tab);
Windows::Foundation::Collections::IObservableVector<TerminalApp::Tab> _tabs;
Windows::Foundation::Collections::IObservableVector<TerminalApp::Tab> _mruTabs;
static winrt::com_ptr<Tab> _GetTabImpl(const TerminalApp::Tab& tab);
void _UpdateTabIndices();
TerminalApp::TerminalTab _settingsTab{ nullptr };
TerminalApp::Tab _settingsTab{ nullptr };
bool _isInFocusMode{ false };
bool _isFullscreen{ false };
@@ -277,7 +277,7 @@ namespace winrt::TerminalApp::implementation
struct StashedDragData
{
winrt::com_ptr<winrt::TerminalApp::implementation::TabBase> draggedTab{ nullptr };
winrt::com_ptr<winrt::TerminalApp::implementation::Tab> draggedTab{ nullptr };
winrt::Windows::Foundation::Point dragOffset{ 0, 0 };
} _stashed;
@@ -305,7 +305,7 @@ namespace winrt::TerminalApp::implementation
void _OpenNewTabDropdown();
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::INewContentArgs& newContentArgs);
TerminalApp::TerminalTab _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
TerminalApp::Tab _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
std::wstring _evaluatePathForCwd(std::wstring_view path);
@@ -328,25 +328,25 @@ namespace winrt::TerminalApp::implementation
void _HookupKeyBindings(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap) noexcept;
void _RegisterActionCallbacks();
void _UpdateTitle(const TerminalTab& tab);
void _UpdateTabIcon(TerminalTab& tab);
void _UpdateTitle(const Tab& tab);
void _UpdateTabIcon(Tab& tab);
void _UpdateTabView();
void _UpdateTabWidthMode();
void _SetBackgroundImage(const winrt::Microsoft::Terminal::Settings::Model::IAppearanceConfig& newAppearance);
void _DuplicateFocusedTab();
void _DuplicateTab(const TerminalTab& tab);
void _DuplicateTab(const Tab& tab);
safe_void_coroutine _ExportTab(const TerminalTab& tab, winrt::hstring filepath);
safe_void_coroutine _ExportTab(const Tab& tab, winrt::hstring filepath);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::Tab tab);
void _CloseTabAtIndex(uint32_t index);
void _RemoveTab(const winrt::TerminalApp::TabBase& tab);
safe_void_coroutine _RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs);
void _RemoveTab(const winrt::TerminalApp::Tab& tab);
safe_void_coroutine _RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs);
void _InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl, uint32_t insertPosition = -1);
void _InitializeTab(winrt::com_ptr<Tab> newTabImpl, uint32_t insertPosition = -1);
void _RegisterTerminalEvents(Microsoft::Terminal::Control::TermControl term);
void _RegisterTabEvents(TerminalTab& hostingTab);
void _RegisterTabEvents(Tab& hostingTab);
void _DismissTabContextMenus();
void _FocusCurrentTab(const bool focusAlways);
@@ -357,7 +357,7 @@ namespace winrt::TerminalApp::implementation
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
bool _MoveTab(winrt::com_ptr<TerminalTab> tab, const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
bool _MoveTab(winrt::com_ptr<Tab> tab, const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
template<typename F>
bool _ApplyToActiveControls(F f)
@@ -381,21 +381,21 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
std::optional<uint32_t> _GetTabIndex(const TerminalApp::TabBase& tab) const noexcept;
TerminalApp::TabBase _GetFocusedTab() const noexcept;
winrt::com_ptr<TerminalTab> _GetFocusedTabImpl() const noexcept;
TerminalApp::TabBase _GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept;
std::optional<uint32_t> _GetTabIndex(const TerminalApp::Tab& tab) const noexcept;
TerminalApp::Tab _GetFocusedTab() const noexcept;
winrt::com_ptr<Tab> _GetFocusedTabImpl() const noexcept;
TerminalApp::Tab _GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept;
void _HandleClosePaneRequested(std::shared_ptr<Pane> pane);
safe_void_coroutine _SetFocusedTab(const winrt::TerminalApp::TabBase tab);
safe_void_coroutine _SetFocusedTab(const winrt::TerminalApp::Tab tab);
safe_void_coroutine _CloseFocusedPane();
void _ClosePanes(weak_ref<TerminalTab> weakTab, std::vector<uint32_t> paneIds);
void _ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
winrt::Windows::Foundation::IAsyncOperation<bool> _PaneConfirmCloseReadOnly(std::shared_ptr<Pane> pane);
void _AddPreviouslyClosedPaneOrTab(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>&& args);
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
void _SplitPane(const winrt::com_ptr<TerminalTab>& tab,
void _SplitPane(const winrt::com_ptr<Tab>& tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
std::shared_ptr<Pane> newPane);
@@ -439,14 +439,14 @@ namespace winrt::TerminalApp::implementation
void _OnTabItemsChanged(const IInspectable& sender, const Windows::Foundation::Collections::IVectorChangedEventArgs& eventArgs);
void _OnTabCloseRequested(const IInspectable& sender, const Microsoft::UI::Xaml::Controls::TabViewTabCloseRequestedEventArgs& eventArgs);
void _OnFirstLayout(const IInspectable& sender, const IInspectable& eventArgs);
void _UpdatedSelectedTab(const winrt::TerminalApp::TabBase& tab);
void _UpdatedSelectedTab(const winrt::TerminalApp::Tab& tab);
void _UpdateBackground(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
void _OnDispatchCommandRequested(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::Command& command);
void _OnCommandLineExecutionRequested(const IInspectable& sender, const winrt::hstring& commandLine);
void _OnSwitchToTabRequested(const IInspectable& sender, const winrt::TerminalApp::TabBase& tab);
void _OnSwitchToTabRequested(const IInspectable& sender, const winrt::TerminalApp::Tab& tab);
void _Find(const TerminalTab& tab);
void _Find(const Tab& tab);
winrt::Microsoft::Terminal::Control::TermControl _CreateNewControlAndContent(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
@@ -455,15 +455,15 @@ namespace winrt::TerminalApp::implementation
TerminalApp::IPaneContent _makeSettingsContent();
std::shared_ptr<Pane> _MakeTerminalPane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
const winrt::TerminalApp::TabBase& sourceTab = nullptr,
const winrt::TerminalApp::Tab& sourceTab = nullptr,
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::INewContentArgs& newContentArgs = nullptr,
const winrt::TerminalApp::TabBase& sourceTab = nullptr,
const winrt::TerminalApp::Tab& sourceTab = nullptr,
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _RefreshUIForSettingsReload();
void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
void _SetNewTabButtonColor(til::color color, til::color accentColor);
void _ClearNewTabButtonColor();
safe_void_coroutine _CompleteInitialization();
@@ -475,7 +475,7 @@ namespace winrt::TerminalApp::implementation
static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
static uint32_t _ReadSystemRowsToScroll();
void _UpdateMRUTab(const winrt::TerminalApp::TabBase& tab);
void _UpdateMRUTab(const winrt::TerminalApp::Tab& tab);
void _TryMoveTab(const uint32_t currentTabIndex, const int32_t suggestedNewTabIndex);
@@ -534,7 +534,7 @@ namespace winrt::TerminalApp::implementation
void _onTabDroppedOutside(winrt::Windows::Foundation::IInspectable sender, winrt::Microsoft::UI::Xaml::Controls::TabViewTabDroppedOutsideEventArgs e);
void _DetachPaneFromWindow(std::shared_ptr<Pane> pane);
void _DetachTabFromWindow(const winrt::com_ptr<TabBase>& terminalTab);
void _DetachTabFromWindow(const winrt::com_ptr<Tab>& tabImpl);
void _MoveContent(std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>&& actions,
const winrt::hstring& windowName,
const uint32_t tabIndex,
@@ -546,9 +546,9 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::Controls::MenuFlyout _CreateRunAsAdminFlyout(int profileIndex);
winrt::Microsoft::Terminal::Control::TermControl _senderOrActiveControl(const winrt::Windows::Foundation::IInspectable& sender);
winrt::com_ptr<TerminalTab> _senderOrFocusedTab(const IInspectable& sender);
winrt::com_ptr<Tab> _senderOrFocusedTab(const IInspectable& sender);
void _activePaneChanged(winrt::TerminalApp::TerminalTab tab, Windows::Foundation::IInspectable args);
void _activePaneChanged(winrt::TerminalApp::Tab tab, Windows::Foundation::IInspectable args);
safe_void_coroutine _doHandleSuggestions(Microsoft::Terminal::Settings::Model::SuggestionsArgs realArgs);
#pragma region ActionHandlers

View File

@@ -95,7 +95,7 @@ namespace winrt::TerminalApp::implementation
NewTerminalArgs args{};
const auto& controlSettings = _control.Settings();
args.Profile(controlSettings.ProfileName());
args.Profile(::Microsoft::Console::Utils::GuidToString(_profile.Guid()));
// If we know the user's working directory use it instead of the profile.
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
{

View File

@@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TabBase.idl";
import "TerminalTabStatus.idl";
namespace TerminalApp
{
[default_interface] runtimeclass TerminalTab : TabBase
{
TerminalTabStatus TabStatus { get; };
}
}

View File

@@ -7,8 +7,7 @@
#include "pch.h"
#include "TitlebarControl.h"
#include "ColorHelper.h"
#include "../../types/inc/ColorFix.hpp"
#include "TitlebarControl.g.cpp"
@@ -189,7 +188,8 @@ namespace winrt::TerminalApp::implementation
return;
}
const auto isBrightColor = ColorHelper::IsBrightColor(c);
constexpr auto lightnessThreshold = 0.6f;
const auto isBrightColor = ColorFix::GetLightness(c) >= lightnessThreshold;
MinMaxCloseControl().RequestedTheme(isBrightColor ? winrt::Windows::UI::Xaml::ElementTheme::Light :
winrt::Windows::UI::Xaml::ElementTheme::Dark);
}

View File

@@ -11,6 +11,7 @@
<!-- sets a bunch of Windows Universal properties -->
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
<PgoTarget>true</PgoTarget>
<VersionInfoFileDescription>Windows Terminal Main UI Library</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
@@ -35,7 +36,6 @@
<ClInclude Include="../TitlebarControl.h" />
<ClInclude Include="../TabRowControl.h" />
<ClInclude Include="../App.h" />
<ClInclude Include="../TerminalTab.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>

View File

@@ -11,6 +11,7 @@
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
<ApplicationType>Windows Store</ApplicationType>
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
<VersionInfoFileDescription>Windows Terminal Azure Cloud Shell Connector</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">

View File

@@ -66,10 +66,41 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// WSLENV is a colon-delimited list of environment variables (+flags) that should appear inside WSL
// https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
std::wstring wslEnv{ L"WT_SESSION:WT_PROFILE_ID:" };
// WSLENV.1: Get a handle to the WSLENV environment variable.
auto& wslEnv = environment.as_map()[L"WSLENV"];
std::wstring additionalWslEnv;
// WSLENV.2: Figure out what variables are already in WSLENV.
std::unordered_set<std::wstring_view> wslEnvVars;
for (const auto& part : til::split_iterator{ std::wstring_view{ wslEnv }, L':' })
{
// Each part may contain a variable name and flags (e.g., /p, /l, etc.)
// We only care about the variable name for WSLENV.
const auto key = til::safe_slice_len(part, 0, part.rfind(L'/'));
wslEnvVars.emplace(key);
}
// WSLENV.3: Add our terminal-specific environment variables to WSLENV.
static constexpr std::wstring_view builtinWslEnvVars[] = {
L"WT_SESSION",
L"WT_PROFILE_ID",
};
// Misdiagnosis in MSVC 14.44.35207. No pointer arithmetic in sight.
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
for (const auto& key : builtinWslEnvVars)
{
if (wslEnvVars.emplace(key).second)
{
additionalWslEnv.append(key);
additionalWslEnv.push_back(L':');
}
}
if (_environment)
{
// Order the environment variable names so that resolution order is consistent
// NOTE(lhecker): I'm like 99% sure that this is unnecessary.
std::set<std::wstring, til::env_key_sorter> keys{};
for (const auto item : _environment)
{
@@ -85,18 +116,39 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
environment.set_user_environment_var(key.c_str(), value.c_str());
// For each environment variable added to the environment, also add it to WSLENV
wslEnv += key + L":";
// WSLENV.4: Add custom user environment variables to WSLENV.
if (wslEnvVars.emplace(key).second)
{
additionalWslEnv.append(key);
additionalWslEnv.push_back(L':');
}
}
CATCH_LOG();
}
}
// We want to prepend new environment variables to WSLENV - that way if a variable already
// exists in WSLENV but with a flag, the flag will be respected.
// (This behaviour was empirically observed)
wslEnv += environment.as_map()[L"WSLENV"];
environment.as_map().insert_or_assign(L"WSLENV", wslEnv);
if (!additionalWslEnv.empty())
{
// WSLENV.5: In the next step we'll prepend `additionalWslEnv` to `wslEnv`,
// so make sure that we have a single colon in between them.
const auto hasColon = additionalWslEnv.ends_with(L':');
const auto needsColon = !wslEnv.starts_with(L':');
if (hasColon != needsColon)
{
if (hasColon)
{
additionalWslEnv.pop_back();
}
else
{
additionalWslEnv.push_back(L':');
}
}
// WSLENV.6: Prepend our additional environment variables to WSLENV.
wslEnv.insert(0, additionalWslEnv);
}
}
auto newEnvVars = environment.to_string();

View File

@@ -8,6 +8,7 @@
<SubSystem>Console</SubSystem>
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
<PgoTarget>true</PgoTarget>
<VersionInfoFileDescription>Windows Terminal Connection Library</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>

View File

@@ -515,11 +515,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto ctrlPressed = modifiers.IsCtrlPressed();
const auto shiftPressed = modifiers.IsShiftPressed();
if (ctrlPressed && shiftPressed)
if (ctrlPressed && shiftPressed && _core->Settings().ScrollToChangeOpacity())
{
_mouseTransparencyHandler(delta);
}
else if (ctrlPressed)
else if (ctrlPressed && !shiftPressed && _core->Settings().ScrollToZoom())
{
_mouseZoomHandler(delta);
}

View File

@@ -60,6 +60,8 @@ namespace Microsoft.Terminal.Control
Boolean CopyOnSelect { get; };
Microsoft.Terminal.Control.CopyFormat CopyFormatting { get; };
Boolean FocusFollowMouse { get; };
Boolean ScrollToZoom { get; };
Boolean ScrollToChangeOpacity { get; };
String Commandline { get; };
String StartingDirectory { get; };

View File

@@ -21,6 +21,7 @@
projects compile properly when they depend on this "Microsoft.winmd."
-->
<CppWinRTNamespaceMergeDepth>3</CppWinRTNamespaceMergeDepth>
<VersionInfoFileDescription>Windows Terminal Control Library</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">

View File

@@ -156,6 +156,7 @@ public:
bool IsVtInputEnabled() const noexcept override;
void NotifyAccessibilityChange(const til::rect& changedRect) noexcept override;
void NotifyBufferRotation(const int delta) override;
void NotifyShellIntegrationMark() override;
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;

View File

@@ -404,3 +404,9 @@ void Terminal::NotifyBufferRotation(const int delta)
_NotifyScrollEvent();
}
}
void Terminal::NotifyShellIntegrationMark()
{
// Notify the scrollbar that marks have been added so it can refresh the mark indicators
_NotifyScrollEvent();
}

View File

@@ -56,7 +56,7 @@
<Style x:Key="KeyChordBorderStyle"
TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="1" />
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
@@ -97,7 +97,8 @@
<Style x:Key="KeyChordBorderStyle"
TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" 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>
@@ -138,7 +139,7 @@
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<x:Int32 x:Key="EditButtonSize">32</x:Int32>
<x:Double x:Key="EditButtonIconSize">15</x:Double>
<x:Double x:Key="EditButtonIconSize">14</x:Double>
<Style x:Key="EditButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
@@ -150,7 +151,7 @@
<Style x:Key="AccentEditButtonStyle"
BasedOn="{StaticResource AccentButtonStyle}"
TargetType="Button">
<Setter Property="Padding" Value="3" />
<Setter Property="Padding" Value="4" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Height" Value="{StaticResource EditButtonSize}" />
<Setter Property="Width" Value="{StaticResource EditButtonSize}" />
@@ -191,6 +192,7 @@
<!-- Command Name -->
<TextBlock Grid.Column="0"
FontWeight="Normal"
Style="{StaticResource KeyBindingNameTextBlockStyle}"
Text="{x:Bind Name, Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}" />
@@ -317,7 +319,6 @@
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</Grid>
</ListViewItem>
@@ -332,6 +333,7 @@
Style="{StaticResource SettingsStackStyle}">
<!-- Add New Button -->
<Button x:Name="AddNewButton"
Margin="0,12,0,0"
Click="AddNew_Click">
<Button.Content>
<StackPanel Orientation="Horizontal">

View File

@@ -32,25 +32,24 @@
<!-- Loosely based on NonExpanderGrid style -->
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="Padding" Value="16,0,8,0" />
<Setter Property="Padding" Value="0,0,8,0" />
</Style>
</ResourceDictionary>
</Page.Resources>
<Grid Margin="0,0,0,8"
<Grid MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="0,0,0,8"
RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Spacing="8">
<TextBlock x:Uid="ColorSchemesDisclaimer"
Style="{StaticResource DisclaimerStyle}" />
<Button x:Name="AddNewButton"
Margin="4,0,0,0"
Margin="0"
Click="AddNew_Click"
Style="{StaticResource BrowseButtonStyle}">
<StackPanel Orientation="Horizontal">
@@ -65,6 +64,7 @@
<ListView x:Name="ColorSchemeListView"
Grid.Row="1"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="-16,0,0,0"
IsItemClickEnabled="True"
ItemClick="{x:Bind ViewModel.SchemeListItemClicked}"
ItemsSource="{x:Bind ViewModel.AllColorSchemes, Mode=OneWay}"
@@ -88,11 +88,11 @@
<!-- Set the height of the inner grid as 48 to be 3/4 of the ListViewItem height -->
<Grid Grid.Column="0"
Height="48"
Padding="12,11,8,8"
Padding="12,12,8,8"
VerticalAlignment="Center"
Background="{x:Bind mtu:Converters.ColorToBrush(BackgroundColor.Color), Mode=OneWay}"
ColumnSpacing="2"
CornerRadius="4"
CornerRadius="{StaticResource ControlCornerRadius}"
RowSpacing="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -200,19 +200,19 @@
Text="{x:Bind Name, Mode=OneWay}" />
</Grid>
<Border Grid.Column="1"
Margin="10,0,0,0"
Padding="2,0,2,0"
Margin="12,0,0,0"
Padding="8,4"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="{ThemeResource SystemAltMediumLowColor}"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumBrush}"
Background="{ThemeResource SubtleFillColorSecondaryBrush}"
BorderBrush="{ThemeResource ControlStrongStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="1"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind IsDefaultScheme, Mode=OneWay}">
<TextBlock x:Uid="ColorScheme_DefaultTag"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</Border>
</Grid>
</DataTemplate>

View File

@@ -68,24 +68,23 @@
<Color x:Key="DeleteButtonColor">Firebrick</Color>
<x:Double x:Key="StandardIconSize">14.0</x:Double>
<Thickness x:Key="StandardIndentMargin">13,0,0,0</Thickness>
<Thickness x:Key="StandardControlMargin">0,24,0,0</Thickness>
<x:Double x:Key="StandardBoxMinWidth">250</x:Double>
<x:Double x:Key="StandardBoxMinWidth">248</x:Double>
<x:Double x:Key="StandardControlMaxWidth">1000</x:Double>
<Thickness x:Key="SettingStackMargin">13,0,13,48</Thickness>
<Thickness x:Key="SettingStackMargin">0,0,0,0</Thickness>
<!-- We're purposefully not providing a DataType here.
This is expected to be used with an IReference<Microsoft::Terminal::Core::Color>.
We're doing all the data type handling in the used converters.-->
<DataTemplate x:Key="ColorPreviewTemplate">
<Grid ColumnSpacing="5">
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0"
Width="13"
Height="13"
Width="12"
Height="12"
VerticalAlignment="Center"
Fill="{Binding Converter={StaticResource ColorToBrushConverter}}"
RadiusX="2"
@@ -112,13 +111,13 @@
<!-- Used to stack a group of settings -->
<Style x:Key="SettingsStackStyle"
TargetType="StackPanel">
<Setter Property="Margin" Value="{StaticResource SettingStackMargin}" />
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
</Style>
<!-- Used to stack a group of settings inside a pivot -->
<Style x:Key="PivotStackStyle"
TargetType="StackPanel">
<Setter Property="Margin" Value="{StaticResource SettingStackMargin}" />
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
</Style>
<!-- Combo Box -->
@@ -145,7 +144,7 @@
<!-- Text Block -->
<Style x:Key="TextBlockSettingStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
BasedOn="{StaticResource BodyTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="MinWidth" Value="{StaticResource StandardBoxMinWidth}" />
<Setter Property="MaxWidth" Value="400" />
@@ -155,24 +154,27 @@
</Style>
<Style x:Key="TextBlockSubHeaderStyle"
BasedOn="{StaticResource SubtitleTextBlockStyle}"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
<Setter Property="Margin" Value="0,32,0,4" />
</Style>
<!-- Used for disclaimers -->
<Style x:Key="DisclaimerStyle"
TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}" />
<Setter Property="Margin" Value="0,0,0,8" />
</Style>
<!-- Used for flyout messages -->
<Style x:Key="CustomFlyoutTextStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,0,0,10" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="Margin" Value="0,0,0,8" />
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
@@ -200,8 +202,8 @@
<Style x:Key="BrowseButtonStyle"
BasedOn="{StaticResource BaseButtonStyle}"
TargetType="Button">
<Setter Property="Margin" Value="10,0,0,0" />
<Setter Property="MinHeight" Value="33" />
<Setter Property="Margin" Value="8,0,0,0" />
<Setter Property="MinHeight" Value="32" />
</Style>
<!-- Delete button based on Accent button template -->
@@ -306,8 +308,8 @@
<Style x:Key="ExtraSmallButtonStyle"
BasedOn="{StaticResource BrowseButtonStyle}"
TargetType="Button">
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="25" />
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="MinHeight" Value="0" />
@@ -317,25 +319,25 @@
<Style x:Key="SmallButtonStyle"
BasedOn="{StaticResource BrowseButtonStyle}"
TargetType="Button">
<Setter Property="Height" Value="33" />
<Setter Property="Width" Value="33" />
<Setter Property="Padding" Value="5" />
<Setter Property="Height" Value="32" />
<Setter Property="Width" Value="32" />
<Setter Property="Padding" Value="4" />
</Style>
<Style x:Key="AccentBrowseButtonStyle"
BasedOn="{StaticResource AccentButtonStyle}"
TargetType="Button">
<Setter Property="Margin" Value="10,0,0,0" />
<Setter Property="Margin" Value="8,0,0,0" />
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
<Style x:Key="AccentSmallButtonStyle"
BasedOn="{StaticResource AccentButtonStyle}"
TargetType="Button">
<Setter Property="Margin" Value="10,0,0,0" />
<Setter Property="Margin" Value="8,0,0,0" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Height" Value="33" />
<Setter Property="Width" Value="33" />
<Setter Property="Height" Value="32" />
<Setter Property="Width" Value="32" />
<Setter Property="Padding" Value="5" />
</Style>
@@ -350,8 +352,8 @@
<Style x:Key="DeleteExtraSmallButtonStyle"
BasedOn="{StaticResource DeleteButtonStyle}"
TargetType="Button">
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="25" />
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="MinHeight" Value="0" />
@@ -360,7 +362,7 @@
<Style x:Key="IconButtonTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Margin" Value="10,0,0,0" />
<Setter Property="Margin" Value="8,0,0,0" />
</Style>
<Style x:Key="BIAlignmentToggleButtonStyle"
@@ -1195,7 +1197,6 @@
TargetType="Button">
<Setter Property="Background" Value="{ThemeResource ExpanderHeaderBackground}" />
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />

View File

@@ -84,16 +84,18 @@
</Page.Resources>
<StackPanel Style="{StaticResource SettingsStackStyle}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}"
CornerRadius="{StaticResource ControlCornerRadius}">
<!-- Preview of the selected scheme -->
<Grid Width="350"
Height="160"
<Grid Width="348"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="4"
Margin="0,12"
Padding="8"
HorizontalAlignment="Left"
Background="{x:Bind mtu:Converters.ColorToBrush(ViewModel.BackgroundColor.Color), Mode=OneWay}"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1">
BorderBrush="{ThemeResource ControlStrongStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
@@ -468,8 +470,7 @@
</StackPanel>
</local:SettingContainer>
<Grid MaxWidth="1000"
Margin="2,6,0,0"
<Grid Margin="2,6,0,0"
ColumnSpacing="4"
Visibility="{x:Bind ViewModel.IsEditable, Mode=OneWay}">
<Grid.ColumnDefinitions>

View File

@@ -216,7 +216,7 @@
Orientation="Horizontal">
<IconSourceElement Width="16"
Height="16"
Margin="0,0,8,0"
Margin="0,0,12,0"
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Profile.EvaluatedIcon), Mode=OneWay}" />
<TextBlock Text="{x:Bind Profile.Name, Mode=OneWay}" />
@@ -248,7 +248,6 @@
<!-- This styling matches that of ExpanderSettingContainerStyle for consistency -->
<Style x:Key="ExpanderStyle"
TargetType="muxc:Expander">
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
@@ -289,8 +288,8 @@
Padding="8"
VerticalAlignment="Center"
Background="{x:Bind mtu:Converters.ColorToBrush(BackgroundColor.Color), Mode=OneWay}"
ColumnSpacing="1"
CornerRadius="2"
ColumnSpacing="2"
CornerRadius="{StaticResource ControlCornerRadius}"
RowSpacing="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -451,10 +450,12 @@
<!-- Learn more about fragment extensions -->
<HyperlinkButton x:Uid="Extensions_DisclaimerHyperlink"
Margin="-12,0,0,0"
NavigateUri="https://go.microsoft.com/fwlink/?linkid=2321753" />
<!-- Grouping: Active Extensions -->
<TextBlock x:Uid="Extensions_ActiveExtensionsHeader"
Margin="0,12,0,8"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<ItemsControl x:Name="ActiveExtensionsList"
IsTabStop="False"
@@ -513,9 +514,11 @@
</StackPanel>
<!-- Grouping: Modified Profiles -->
<StackPanel Margin="{x:Bind CalculateMargin(ViewModel.NoProfilesModified), Mode=OneWay}"
<StackPanel MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="{x:Bind CalculateMargin(ViewModel.NoProfilesModified), Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.NoProfilesModified), Mode=OneWay}">
<TextBlock x:Uid="Extensions_ModifiedProfilesHeader"
Margin="0,0,0,8"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<ItemsControl x:Name="ModifiedProfilesList"
IsTabStop="False"
@@ -525,9 +528,11 @@
</StackPanel>
<!-- Grouping: Added Profiles -->
<StackPanel Margin="{x:Bind CalculateMargin(ViewModel.NoProfilesAdded), Mode=OneWay}"
<StackPanel MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="{x:Bind CalculateMargin(ViewModel.NoProfilesAdded), Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.NoProfilesAdded), Mode=OneWay}">
<TextBlock x:Uid="Extensions_AddedProfilesHeader"
Margin="0,0,0,8"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<ItemsControl x:Name="AddedProfilesList"
IsTabStop="False"
@@ -537,9 +542,11 @@
</StackPanel>
<!-- Grouping: Added Color Schemes -->
<StackPanel Margin="{x:Bind CalculateMargin(ViewModel.NoProfilesAdded), Mode=OneWay}"
<StackPanel MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="{x:Bind CalculateMargin(ViewModel.NoProfilesAdded), Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.NoSchemesAdded), Mode=OneWay}">
<TextBlock x:Uid="Extensions_AddedColorSchemesHeader"
Margin="0,0,0,8"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<ItemsControl x:Name="AddedColorSchemesList"
IsTabStop="False"

View File

@@ -83,6 +83,18 @@
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Enable Font Size Changes with Scrolling -->
<local:SettingContainer 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:Uid="Globals_ScrollToChangeOpacity">
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToChangeOpacity, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Detect URLs -->
<local:SettingContainer x:Uid="Globals_DetectURLs">
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"

View File

@@ -25,6 +25,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, TrimPaste);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, SnapToGridOnResize);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, FocusFollowMouse);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ScrollToZoom);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ScrollToChangeOpacity);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, DetectURLs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, SearchWebDefaultQueryUrl);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WordDelimiters);

View File

@@ -22,6 +22,8 @@ namespace Microsoft.Terminal.Settings.Editor
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, TrimPaste);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, SnapToGridOnResize);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, FocusFollowMouse);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ScrollToZoom);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ScrollToChangeOpacity);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, DetectURLs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(String, SearchWebDefaultQueryUrl);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(String, WordDelimiters);

View File

@@ -116,6 +116,7 @@
<TextBlock Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Text="{x:Bind Name}" />
@@ -192,8 +193,8 @@
<local:SettingContainer x:Uid="Globals_LaunchSize"
CurrentValue="{x:Bind ViewModel.LaunchSizeCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid ColumnSpacing="10"
RowSpacing="10">
<Grid ColumnSpacing="12"
RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -235,7 +236,7 @@
<local:SettingContainer x:Uid="Globals_LaunchParameters"
CurrentValue="{x:Bind ViewModel.LaunchParametersCurrentValue, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<Grid RowSpacing="10">
<Grid RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />

View File

@@ -17,7 +17,6 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
@@ -60,7 +59,6 @@
<Thickness x:Key="NavigationViewContentGridBorderThickness">0</Thickness>
<Thickness x:Key="NavigationViewMinimalContentGridBorderThickness">0</Thickness>
</ResourceDictionary>
</Page.Resources>
@@ -73,28 +71,32 @@
TabFocusNavigation="Cycle">
<muxc:NavigationView.Resources>
<ResourceDictionary>
<Thickness x:Key="NavigationViewHeaderMargin">15,0,0,0</Thickness>
<Thickness x:Key="NavigationViewHeaderMargin">0,4,0,0</Thickness>
</ResourceDictionary>
</muxc:NavigationView.Resources>
<muxc:NavigationView.Header>
<muxc:BreadcrumbBar x:Name="NavigationBreadcrumbBar"
MaxWidth="{StaticResource StandardControlMaxWidth}"
ItemClicked="BreadcrumbBar_ItemClicked"
ItemsSource="{x:Bind Breadcrumbs}">
<muxc:BreadcrumbBar.ItemTemplate>
<DataTemplate x:DataType="local:Breadcrumb">
<TextBlock Text="{x:Bind Label}" />
</DataTemplate>
</muxc:BreadcrumbBar.ItemTemplate>
<muxc:BreadcrumbBar.Resources>
<ResourceDictionary>
<x:Double x:Key="BreadcrumbBarItemThemeFontSize">28</x:Double>
<Thickness x:Key="BreadcrumbBarChevronPadding">11,4,12,0</Thickness>
<FontWeight x:Key="BreadcrumbBarItemFontWeight">SemiBold</FontWeight>
<x:Double x:Key="BreadcrumbBarChevronFontSize">16</x:Double>
</ResourceDictionary>
</muxc:BreadcrumbBar.Resources>
</muxc:BreadcrumbBar>
<Grid Padding="16,0">
<!-- Wrapping the BreadcrumbBar in a Grid to avoid the title to drift (and no longer being aligned with the content of the page) when resizing the window. It's weird, I know. I believe it has to do with https://github.com/microsoft/microsoft-ui-xaml/issues/3842 doing funky things when setting a MaxWidth -->
<muxc:BreadcrumbBar x:Name="NavigationBreadcrumbBar"
MaxWidth="1000"
ItemClicked="BreadcrumbBar_ItemClicked"
ItemsSource="{x:Bind Breadcrumbs}">
<muxc:BreadcrumbBar.ItemTemplate>
<DataTemplate x:DataType="local:Breadcrumb">
<TextBlock Text="{x:Bind Label}" />
</DataTemplate>
</muxc:BreadcrumbBar.ItemTemplate>
<muxc:BreadcrumbBar.Resources>
<ResourceDictionary>
<x:Double x:Key="BreadcrumbBarItemThemeFontSize">20</x:Double>
<Thickness x:Key="BreadcrumbBarChevronPadding">8,4,8,0</Thickness>
<FontWeight x:Key="BreadcrumbBarItemFontWeight">SemiBold</FontWeight>
<x:Double x:Key="BreadcrumbBarChevronFontSize">16</x:Double>
</ResourceDictionary>
</muxc:BreadcrumbBar.Resources>
</muxc:BreadcrumbBar>
</Grid>
</muxc:NavigationView.Header>
<muxc:NavigationView.MenuItems>
@@ -191,7 +193,7 @@
</muxc:NavigationViewItem>
</muxc:NavigationView.FooterMenuItems>
<Grid Margin="0,0,0,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
@@ -199,7 +201,8 @@
<ScrollViewer x:Name="SettingsMainPage_ScrollViewer"
Grid.Row="0">
<Frame x:Name="contentFrame"
Grid.Row="0">
Grid.Row="0"
Padding="16,0,16,48">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition>
@@ -213,13 +216,13 @@
</ScrollViewer>
<!-- Explicitly set the background color on grid to prevent the navigation animation from overflowing it -->
<Grid Grid.Row="1"
Height="55"
Height="56"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,1,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Margin="30,0,0,0"
<StackPanel Margin="32,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Vertical">
@@ -242,7 +245,7 @@
</TextBlock>
</StackPanel>
</StackPanel>
<StackPanel Margin="0,0,30,0"
<StackPanel Margin="0,0,32,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Orientation="Horizontal">
@@ -252,7 +255,7 @@
Style="{StaticResource AccentButtonStyle}" />
<Button x:Name="ResetButton"
x:Uid="Settings_ResetSettingsButton"
Margin="10,0,0,0"
Margin="8,0,0,0"
Click="ResetButton_Click" />
</StackPanel>
</Grid>

View File

@@ -31,6 +31,7 @@
-->
<CppWinRTNamespaceMergeDepth>4</CppWinRTNamespaceMergeDepth>
<XamlComponentResourceLocation>nested</XamlComponentResourceLocation>
<VersionInfoFileDescription>Windows Terminal Settings UI Library</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>

View File

@@ -227,8 +227,7 @@
</ResourceDictionary>
</Page.Resources>
<Grid Margin="{StaticResource SettingStackMargin}"
RowSpacing="10">
<Grid RowSpacing="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -271,7 +270,7 @@
<!-- New Tab Menu Content -->
<StackPanel Grid.Row="0"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Spacing="10">
Spacing="8">
<Border Height="300"
MaxWidth="{StaticResource StandardControlMaxWidth}"
Margin="0,12,0,0"
@@ -297,7 +296,7 @@
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE8DE;" />
<TextBlock x:Uid="NewTabMenu_MoveToFolderTextBlock"
Margin="10,0,0,0" />
Margin="8,0,0,0" />
</StackPanel>
</Button>
<Button x:Name="DeleteMultipleButton"
@@ -308,7 +307,7 @@
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="NewTabMenu_DeleteMultipleTextBlock"
Margin="10,0,0,0" />
Margin="8,0,0,0" />
</StackPanel>
</Button>
</StackPanel>
@@ -359,7 +358,7 @@
Style="{StaticResource SettingContainerWithIcon}">
<StackPanel Orientation="Horizontal"
Spacing="5">
Spacing="4">
<!-- Select profile to add -->
<ComboBox x:Name="AddProfileComboBox"
MinWidth="{StaticResource StandardBoxMinWidth}"
@@ -448,7 +447,7 @@
<local:SettingContainer x:Uid="NewTabMenu_AddMatchProfiles"
FontIconGlyph="&#xE748;"
Style="{StaticResource ExpanderSettingContainerStyleWithIcon}">
<StackPanel Spacing="10">
<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"

View File

@@ -123,11 +123,11 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Spacing="5">
<StackPanel Spacing="4">
<ToggleButton AutomationProperties.Name="{x:Bind NullColorButtonLabel}"
Click="NullColorButton_Clicked"
IsChecked="{x:Bind IsNull(CurrentColor), Mode=OneWay}">
<Grid ColumnSpacing="5">
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
@@ -138,7 +138,7 @@
Height="20"
Background="{x:Bind mtu:Converters.ColorToBrush(NullColorPreview), Mode=OneWay}"
BorderThickness="1"
CornerRadius="{ThemeResource ControlCornerRadius}" />
CornerRadius="{StaticResource ControlCornerRadius}" />
<TextBlock Grid.Column="1"
Text="{x:Bind NullColorButtonLabel}" />

View File

@@ -32,8 +32,6 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Grid.Row="1"
@@ -123,7 +121,7 @@
<ItemsControl ItemsSource="{x:Bind Profile.CurrentBellSounds, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="5" />
<StackPanel Spacing="4" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
@@ -156,7 +154,7 @@
</StackPanel>
<Button x:Uid="Profile_BellSoundAudioPreview"
Grid.Column="1"
Margin="5,0,0,0"
Margin="4,0,0,0"
VerticalAlignment="Stretch"
Click="BellSoundAudioPreview_Click"
IsEnabled="{x:Bind FileExists, Mode=OneWay}"
@@ -167,7 +165,7 @@
</Button>
<Button x:Uid="Profile_BellSoundDelete"
Grid.Column="2"
Margin="5,0,0,0"
Margin="4,0,0,0"
VerticalAlignment="Stretch"
Click="BellSoundDelete_Click"
Style="{StaticResource DeleteButtonStyle}"
@@ -185,7 +183,7 @@
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE948;" />
<TextBlock x:Uid="Profile_AddBellSound"
Margin="10,0,0,0" />
Margin="8,0,0,0" />
</StackPanel>
</Button>
</StackPanel>

View File

@@ -50,27 +50,28 @@
</ResourceDictionary>
</Page.Resources>
<Grid>
<Grid MaxWidth="{StaticResource StandardControlMaxWidth}">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Grid.Row="1"
Margin="0,12,0,0"
Style="{StaticResource SettingsStackStyle}">
<!-- Control Preview -->
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Border MaxWidth="{StaticResource StandardControlMaxWidth}"
CornerRadius="{StaticResource ControlCornerRadius}">
<Border x:Name="ControlPreview"
Width="400"
Height="180"
Margin="0,12,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
BorderBrush="{ThemeResource ControlStrongStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}" />
</Border>
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
@@ -131,9 +132,9 @@
<Border Margin="0,12,0,12"
Padding="2,0,2,0"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolidBrush}"
BorderThickness="1"
CornerRadius="8">
CornerRadius="{StaticResource OverlayCornerRadius}">
<Grid>
<Grid.RowDefinitions>
@@ -206,23 +207,23 @@
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
Style="{StaticResource TitleTextBlockStyle}" />
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
Margin="10,0,0,0"
Margin="8,0,0,0"
Click="CreateUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon Margin="0,3,0,0"
<FontIcon Margin="0,4,0,0"
FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
<TextBlock x:Uid="Profile_AddAppearanceButton"
Margin="10,0,0,0"
Margin="8,0,0,0"
FontSize="{StaticResource StandardIconSize}" />
</StackPanel>
</Button.Content>
</Button>
<Button x:Uid="Profile_DeleteUnfocusedAppearanceButton"
Margin="10,0,0,0"
Margin="8,0,0,0"
Click="DeleteUnfocusedAppearance_Click"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind Profile.HasUnfocusedAppearance, Mode=OneWay}">
@@ -231,7 +232,7 @@
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteAppearanceButton"
Margin="10,0,0,0"
Margin="8,0,0,0"
FontSize="{StaticResource StandardIconSize}" />
</StackPanel>
</Button.Content>

View File

@@ -22,14 +22,13 @@
</Page.Resources>
<!-- Use a Grid instead of a StackPanel. StackPanel suppresses the inner ScrollViewer. -->
<Grid>
<Grid MaxWidth="{StaticResource StandardControlMaxWidth}">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Grid.Row="1"
@@ -64,7 +63,7 @@
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Margin="0,10,0,0"
Margin="0,8,0,0"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
@@ -87,13 +86,13 @@
<StackPanel Orientation="Horizontal">
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Margin="0,10,10,0"
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,5,0,0"
Margin="0,4,0,0"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</StackPanel>
@@ -123,7 +122,7 @@
</Grid>
</local:SettingContainer.CurrentValue>
<local:SettingContainer.Content>
<Grid ColumnSpacing="10">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
@@ -150,7 +149,7 @@
Visibility="{x:Bind Profile.UsingBuiltInIcon, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:EnumEntry">
<Grid ColumnSpacing="10">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<ColumnDefinition Width="*" />
@@ -226,7 +225,7 @@
</local:SettingContainer>
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
Margin="0,48,0,0"
Margin="0,32,0,4"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<Button x:Name="AppearanceNavigator"
@@ -249,7 +248,7 @@
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
Margin="8,0,0,0" />
</StackPanel>
</Button.Content>
<Button.Flyout>

View File

@@ -33,7 +33,7 @@
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
Margin="8,0,0,0" />
</StackPanel>
</Button.Content>
</Button>

View File

@@ -26,8 +26,6 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<StackPanel Grid.Row="1"

View File

@@ -1736,6 +1736,14 @@
<value>Bereich automatisch mit dem Mauszeiger fokussieren</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Passen Sie die Schriftgröße des Terminals an, indem Sie die STRG-TASTE gedrückt halten und scrollen</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Passen Sie die Deckkraft des Terminals an, indem Sie scrollen, während Sie die STRG- und UMSCHALTTASTE gedrückt halten</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Bereichsanimationen</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>Automatically focus pane on mouse hover</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Adjust terminal font size by scrolling while holding the Ctrl key</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Adjust terminal opacity by scrolling while holding the Ctrl and Shift keys</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Pane animations</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>Centrarse automáticamente en el panel al pasar el mouse</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Ajuste el tamaño de fuente del terminal desplazándose mientras mantiene presionada la tecla Ctrl</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Ajuste la opacidad del terminal desplazándose mientras mantiene presionadas las teclas CTRL y Mayús</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Animaciones de panel</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>Mise au point automatique du volet au survol de la souris</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Ajustez la taille de police du terminal en faisant défiler tout en maintenant la touche Ctrl enfoncée</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Ajustez lopacité du terminal en faisant défiler tout en maintenant les touches Ctrl et Maj enfoncées</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Animations du volet</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>Riquadro di messa a fuoco automatica al passaggio del mouse</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Regola le dimensioni del carattere del terminale scorrendo tenendo premuto il tasto CTRL</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Regola l'opacità del terminale scorrendo mentre tieni premuti i tasti CTRL e MAIUSC</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Riquadro animazioni</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>マウスをポイントしたときにフォーカス ウィンドウを自動的に表示する</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Ctrl キーを押しながらスクロールして、ターミナルのフォント サイズを調整します</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Ctrl キーと Shift キーを押しながらスクロールして、ターミナルの不透明度を調整します</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>ウィンドウのアニメーション</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>마우스를 위에 가져다 대면 자동으로 포커스 창이 실행됨</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Ctrl 키를 누른 상태에서 스크롤하여 터미널 글꼴 크기 조정</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Ctrl 키와 Shift 키를 누른 상태에서 스크롤하여 터미널 불투명도 조정</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>창 애니메이션</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>Focalizar painel automaticamente ao passar o mouse</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Ajustar o tamanho da fonte do terminal rolando enquanto mantém a tecla Ctrl pressionada</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Ajustar a opacidade do terminal ao rolar enquanto mantém as teclas Ctrl e Shift</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Animações do painel</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

View File

@@ -1736,6 +1736,14 @@
<value>Áϋτомàţīćąłłý ƒόćŭś рåπę öń мõùšě ђöνëŗ !!! !!! !!! !!!</value>
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
</data>
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
<value>Аδĵŭŝт ţєŗмιņăℓ ƒøпť ѕįżε вỳ şċѓοℓℓíńğ ẃħïĺє ĥöľδīйģ τђе €ŧřŀ ќëÿ !!! !!! !!! !!! !!! !!! !</value>
<comment>Header for a control to toggle font size changes with scrolling. When enabled, holding the Ctrl key while scrolling will increase or decrease the terminal font size.</comment>
</data>
<data name="Globals_ScrollToChangeOpacity.Header" xml:space="preserve">
<value>Ąδĵüšţ ŧęřмìńąĺ ôрǻčĩτў ьγ šćřοļĺįήĝ ẅђϊłę ħōļδîʼnğ ťђз Çťгł àиδ Śђĭƒт ķęÿŝ !!! !!! !!! !!! !!! !!! !!! !</value>
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
</data>
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
<value>Ρǻйě ǻйϊмäţіőηş !!! !</value>
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>

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