mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-21 06:18:34 +00:00
Compare commits
9 Commits
dev/cazamo
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f448beaa73 | ||
|
|
8fe6c21ef8 | ||
|
|
abeac1b135 | ||
|
|
12e3455bb2 | ||
|
|
fb71a0462e | ||
|
|
c829d4ca54 | ||
|
|
b991eb048e | ||
|
|
3e3b3ad883 | ||
|
|
d3f76e7acf |
3
.github/actions/spelling/expect/expect.txt
vendored
3
.github/actions/spelling/expect/expect.txt
vendored
@@ -1075,6 +1075,7 @@ NOCONTEXTHELP
|
||||
NOCOPYBITS
|
||||
nodiscard
|
||||
NODUP
|
||||
NODEFAULT
|
||||
noexcepts
|
||||
NOFONT
|
||||
NOHIDDENTEXT
|
||||
@@ -1105,6 +1106,7 @@ NOSIZE
|
||||
NOSNAPSHOT
|
||||
NOTHOUSANDS
|
||||
NOTICKS
|
||||
notif
|
||||
NOTIMEOUTIFNOTHUNG
|
||||
NOTIMPL
|
||||
NOTOPMOST
|
||||
@@ -1560,6 +1562,7 @@ SMARTQUOTE
|
||||
SMTO
|
||||
snapcx
|
||||
snapcy
|
||||
SND
|
||||
snk
|
||||
SOLIDBOX
|
||||
Solutiondir
|
||||
|
||||
@@ -475,6 +475,7 @@
|
||||
"toggleBlockSelection",
|
||||
"toggleFocusMode",
|
||||
"toggleFullscreen",
|
||||
"toggleOverview",
|
||||
"togglePaneZoom",
|
||||
"toggleReadOnlyMode",
|
||||
"toggleShaderEffects",
|
||||
@@ -2472,6 +2473,13 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"safeUriSchemes": {
|
||||
"description": "Specifies a list of URI schemes that are considered safe. No confirmation will be required to open URIs with these schemes.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"rendering.graphicsAPI": {
|
||||
"description": "Direct3D 11 provides a more performant and feature-rich experience, whereas Direct2D is more stable. The default option \"Automatic\" will pick the API that best fits your graphics hardware. If you experience significant issues, consider using Direct2D.",
|
||||
"type": "string",
|
||||
|
||||
@@ -604,6 +604,13 @@ namespace winrt::TerminalApp::implementation
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleOverview(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
ToggleOverview();
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSetFocusMode(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
||||
1178
src/cascadia/TerminalApp/OverviewPane.cpp
Normal file
1178
src/cascadia/TerminalApp/OverviewPane.cpp
Normal file
File diff suppressed because it is too large
Load Diff
119
src/cascadia/TerminalApp/OverviewPane.h
Normal file
119
src/cascadia/TerminalApp/OverviewPane.h
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
#include "OverviewPane.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct OverviewPane : OverviewPaneT<OverviewPane>
|
||||
{
|
||||
OverviewPane();
|
||||
~OverviewPane();
|
||||
|
||||
void UpdateTabContent(Windows::Foundation::Collections::IVector<TerminalApp::Tab> tabs, int32_t focusedIndex);
|
||||
void ClearTabContent();
|
||||
|
||||
int32_t SelectedIndex() const;
|
||||
void SelectedIndex(int32_t value);
|
||||
|
||||
bool UseMica() const;
|
||||
void UseMica(bool value);
|
||||
|
||||
hstring ControlName() const;
|
||||
|
||||
// Events
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IReference<int32_t>> TabSelected;
|
||||
til::typed_event<> Dismissed;
|
||||
|
||||
private:
|
||||
friend struct OverviewPaneT<OverviewPane>; // for Xaml to bind events
|
||||
|
||||
void _OnKeyDown(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void _OnPreviewKeyDown(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void _OnItemClicked(int32_t index);
|
||||
void _UpdateSelection();
|
||||
void _PlayEnterAnimation();
|
||||
void _PlayExitAnimation(std::function<void()> onComplete = nullptr);
|
||||
void _StartEnterZoomAnimation();
|
||||
std::optional<std::tuple<double, double, double>> _GetZoomParamsForCell(int32_t index);
|
||||
Windows::UI::Xaml::FrameworkElement _BuildPreviewCell(const TerminalApp::Tab& tab, int32_t index, int32_t totalCount, double previewWidth, double previewHeight, double referenceWidth, double referenceHeight);
|
||||
void _DetachContent(const Windows::UI::Xaml::FrameworkElement& content);
|
||||
|
||||
struct AdaptiveLayout
|
||||
{
|
||||
double cellWidth{ 0.0 };
|
||||
double cellHeight{ 0.0 };
|
||||
double previewWidth{ 0.0 };
|
||||
double previewHeight{ 0.0 };
|
||||
int32_t columnCount{ 1 };
|
||||
};
|
||||
AdaptiveLayout _ComputeAdaptiveLayout(int32_t tabCount, double viewportWidth, double viewportHeight, double aspect) const;
|
||||
void _ApplyAdaptiveLayout();
|
||||
static void _AddDoubleAnimation(
|
||||
const Windows::UI::Xaml::Media::Animation::Storyboard& storyboard,
|
||||
const Windows::UI::Xaml::Media::CompositeTransform& target,
|
||||
const hstring& property,
|
||||
double from,
|
||||
double to,
|
||||
const Windows::UI::Xaml::Duration& duration,
|
||||
const Windows::UI::Xaml::Media::Animation::EasingFunctionBase& easing);
|
||||
|
||||
int32_t _selectedIndex{ 0 };
|
||||
int32_t _columnCount{ 1 }; // updated at UpdateTabContent time to match the adaptive layout
|
||||
bool _pendingEnterAnimation{ false };
|
||||
bool _pendingAdaptiveLayout{ false };
|
||||
// Homogeneous-aspect assumption: every cell uses the active tab's
|
||||
// content aspect ratio. Per-tab aspect (e.g. one tab with a Settings
|
||||
// page that's narrow + tall, another with a TermControl that's wide)
|
||||
// would require a different layout pass — cells could no longer
|
||||
// share a single ItemWidth/ItemHeight on the WrapGrid.
|
||||
double _referenceAspect{ 16.0 / 10.0 };
|
||||
double _lastAppliedViewportWidth{ 0.0 };
|
||||
double _lastAppliedViewportHeight{ 0.0 };
|
||||
bool _useMica{ false };
|
||||
void _UpdateBackgroundForMica();
|
||||
winrt::event_token _exitAnimationToken{};
|
||||
Windows::UI::Xaml::Media::Animation::Storyboard _exitContentStoryboard{ nullptr };
|
||||
|
||||
// Subscriptions on our own owned children. Stored so the destructor
|
||||
// can explicitly revoke them before ClearTabContent runs — matches
|
||||
// the token-revoke pattern used in TerminalPage for overview events.
|
||||
winrt::event_token _layoutUpdatedToken{};
|
||||
winrt::event_token _sizeChangedToken{};
|
||||
|
||||
// Per-cell state for the adaptive layout pass. INVARIANT: there is
|
||||
// exactly one ReparentedEntry per cell in PreviewGrid().Items(), in
|
||||
// cell order. When the source tab had no live content,
|
||||
// `content` / `previewCanvas` are null and `layoutWidth` /
|
||||
// `layoutHeight` are zero — the cell still gets a previewBorder
|
||||
// + titleBlock sized by _ApplyAdaptiveLayout, but the
|
||||
// ScaleTransform / reparent path is skipped. _ApplyAdaptiveLayout
|
||||
// and ClearTabContent both null-check before touching content.
|
||||
struct ReparentedEntry
|
||||
{
|
||||
Windows::UI::Xaml::FrameworkElement content{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Panel originalParent{ nullptr };
|
||||
double originalWidth{ std::numeric_limits<double>::quiet_NaN() };
|
||||
double originalHeight{ std::numeric_limits<double>::quiet_NaN() };
|
||||
Windows::UI::Xaml::Media::Transform originalRenderTransform{ nullptr };
|
||||
Windows::Foundation::Point originalRenderTransformOrigin{ 0.0f, 0.0f };
|
||||
// Per-cell handles for adaptive resizing after the first layout pass.
|
||||
Windows::UI::Xaml::Controls::Border previewBorder{ nullptr };
|
||||
Windows::UI::Xaml::Controls::TextBlock titleBlock{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Canvas previewCanvas{ nullptr };
|
||||
double layoutWidth{ 0.0 };
|
||||
double layoutHeight{ 0.0 };
|
||||
};
|
||||
std::vector<ReparentedEntry> _reparentedContent;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(OverviewPane);
|
||||
}
|
||||
20
src/cascadia/TerminalApp/OverviewPane.idl
Normal file
20
src/cascadia/TerminalApp/OverviewPane.idl
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "Tab.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass OverviewPane : Windows.UI.Xaml.Controls.UserControl
|
||||
{
|
||||
OverviewPane();
|
||||
void UpdateTabContent(Windows.Foundation.Collections.IVector<Tab> tabs, Int32 focusedIndex);
|
||||
void ClearTabContent();
|
||||
Int32 SelectedIndex;
|
||||
Boolean UseMica;
|
||||
String ControlName { get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Windows.Foundation.IReference<Int32> > TabSelected;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Dismissed;
|
||||
}
|
||||
}
|
||||
90
src/cascadia/TerminalApp/OverviewPane.xaml
Normal file
90
src/cascadia/TerminalApp/OverviewPane.xaml
Normal file
@@ -0,0 +1,90 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="TerminalApp.OverviewPane"
|
||||
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"
|
||||
AllowFocusOnInteraction="True"
|
||||
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
|
||||
IsTabStop="True"
|
||||
KeyDown="_OnKeyDown"
|
||||
PreviewKeyDown="_OnPreviewKeyDown"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<Storyboard x:Key="BackgroundFadeIn">
|
||||
<DoubleAnimation Storyboard.TargetName="BackgroundOverlay"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="0.0"
|
||||
To="1.0"
|
||||
Duration="0:0:0.2">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseOut" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
|
||||
<Storyboard x:Key="BackgroundFadeOut">
|
||||
<DoubleAnimation Storyboard.TargetName="BackgroundOverlay"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="1.0"
|
||||
To="0.0"
|
||||
Duration="0:0:0.15">
|
||||
<DoubleAnimation.EasingFunction>
|
||||
<QuadraticEase EasingMode="EaseIn" />
|
||||
</DoubleAnimation.EasingFunction>
|
||||
</DoubleAnimation>
|
||||
</Storyboard>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="RootGrid"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
|
||||
<!-- Semi-transparent dark overlay -->
|
||||
<Border x:Name="BackgroundOverlay"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource SmokeFillColorDefaultBrush}" />
|
||||
|
||||
<!-- Zoom-animated wrapper around the scrollable content -->
|
||||
<Grid x:Name="ContentWrapper"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<Grid.RenderTransform>
|
||||
<CompositeTransform x:Name="ContentTransform" />
|
||||
</Grid.RenderTransform>
|
||||
|
||||
<ScrollViewer x:Name="PreviewScrollViewer"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
|
||||
<!-- WrapGrid-style layout using ItemsControl with WrapGrid panel -->
|
||||
<ItemsControl x:Name="PreviewGrid"
|
||||
Margin="12"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<!-- ItemWidth, ItemHeight, and MaximumRowsOrColumns are owned by -->
|
||||
<!-- OverviewPane.cpp (_ComputeAdaptiveLayout / _ApplyAdaptiveLayout) — -->
|
||||
<!-- they are reassigned on every UpdateTabContent and on every resize. -->
|
||||
<WrapGrid HorizontalChildrenAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
VerticalChildrenAlignment="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -606,6 +606,10 @@
|
||||
<data name="CommandPaletteControlName" xml:space="preserve">
|
||||
<value>Command palette</value>
|
||||
</data>
|
||||
<data name="OverviewPaneControlName" xml:space="preserve">
|
||||
<value>Tab Overview</value>
|
||||
<comment>The name announced by assistive technologies (e.g. Narrator) when the tab overview pane receives focus.</comment>
|
||||
</data>
|
||||
<data name="TabSwitcherControlName" xml:space="preserve">
|
||||
<value>Tab switcher</value>
|
||||
</data>
|
||||
|
||||
@@ -496,12 +496,48 @@
|
||||
<value>第三方通知</value>
|
||||
<comment>A hyperlink name for the Terminal's third-party notices</comment>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
|
||||
<value>取消</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
|
||||
<value>是否要关闭所有窗口?</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
|
||||
<value>全部关闭</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
|
||||
<value>是否要关闭所有标签页?</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
|
||||
<value>全部关闭</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
|
||||
<value>是否要关闭此选项卡?</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
|
||||
<value>关闭选项卡</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
|
||||
<value>是否要关闭此窗格?</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
|
||||
<value>关闭窗格</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
|
||||
<value>是否要关闭这些选项卡?</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
|
||||
<value>关闭选项卡</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
|
||||
<value>是否要关闭这些窗格?</value>
|
||||
</data>
|
||||
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
|
||||
<value>关闭窗格</value>
|
||||
</data>
|
||||
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
|
||||
<value>不再询问</value>
|
||||
</data>
|
||||
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
|
||||
<value>取消</value>
|
||||
</data>
|
||||
|
||||
@@ -1065,6 +1065,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void TerminalPage::_UpdatedSelectedTab(const winrt::TerminalApp::Tab& tab)
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _UpdatedSelectedTab enter, tab={}\n"), static_cast<bool>(tab)).c_str());
|
||||
// Unfocus all the tabs.
|
||||
for (const auto& tab : _tabs)
|
||||
{
|
||||
@@ -1074,7 +1075,12 @@ namespace winrt::TerminalApp::implementation
|
||||
try
|
||||
{
|
||||
_tabContent.Children().Clear();
|
||||
auto content = tab ? tab.Content() : nullptr;
|
||||
const bool hasContent = static_cast<bool>(content);
|
||||
const bool hasParent = hasContent && static_cast<bool>(WUX::Media::VisualTreeHelper::GetParent(content));
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _UpdatedSelectedTab: about to Append, hasContent={} hasParent={}\n"), hasContent, hasParent).c_str());
|
||||
_tabContent.Children().Append(tab.Content());
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: Append succeeded\n");
|
||||
|
||||
// GH#7409: If the tab switcher is open, then we _don't_ want to
|
||||
// automatically focus the new tab here. The tab switcher wants
|
||||
@@ -1089,6 +1095,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto p = CommandPaletteElement();
|
||||
if (!p || p.Visibility() != Visibility::Visible)
|
||||
{
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: calling tab.Focus(Programmatic)\n");
|
||||
tab.Focus(FocusState::Programmatic);
|
||||
_UpdateMRUTab(tab);
|
||||
_updateAllTabCloseButtons();
|
||||
@@ -1109,8 +1116,10 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: try-block finished cleanly\n");
|
||||
}
|
||||
CATCH_LOG();
|
||||
OutputDebugStringW(L"[OV] _UpdatedSelectedTab: exiting\n");
|
||||
}
|
||||
|
||||
void TerminalPage::_UpdateBackground(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile)
|
||||
@@ -1129,10 +1138,19 @@ namespace winrt::TerminalApp::implementation
|
||||
// - eventArgs: the event's constituent arguments
|
||||
void TerminalPage::_OnTabSelectionChanged(const IInspectable& sender, const WUX::Controls::SelectionChangedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _OnTabSelectionChanged: _rearranging={} _removing={} _isInOverviewMode={}\n"), _rearranging, _removing, _isInOverviewMode).c_str());
|
||||
if (!_rearranging && !_removing)
|
||||
{
|
||||
// If the user clicked a tab in the tab row while the overview is
|
||||
// open, the overview is still holding that tab's Content reparented
|
||||
// into one of its preview cells. Tear down the overview visuals
|
||||
// first so _UpdatedSelectedTab can mount the content into the
|
||||
// active content area without hitting the XAML single-parent rule.
|
||||
_DismissOverviewVisuals();
|
||||
|
||||
auto tabView = sender.as<MUX::Controls::TabView>();
|
||||
auto selectedIndex = tabView.SelectedIndex();
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _OnTabSelectionChanged: tabView.SelectedIndex={}\n"), selectedIndex).c_str());
|
||||
if (selectedIndex >= 0 && selectedIndex < gsl::narrow_cast<int32_t>(_tabs.Size()))
|
||||
{
|
||||
const auto tab{ _tabs.GetAt(selectedIndex) };
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
<Page Include="CommandPalette.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="OverviewPane.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="SuggestionsControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
@@ -132,6 +135,9 @@
|
||||
<ClInclude Include="CommandPalette.h">
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="OverviewPane.h">
|
||||
<DependentUpon>OverviewPane.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FilteredCommand.h" />
|
||||
<ClInclude Include="Pane.h" />
|
||||
<ClInclude Include="../fzf/fzf.h" />
|
||||
@@ -243,6 +249,9 @@
|
||||
<ClCompile Include="CommandPalette.cpp">
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OverviewPane.cpp">
|
||||
<DependentUpon>OverviewPane.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FilteredCommand.cpp" />
|
||||
<ClCompile Include="Pane.cpp" />
|
||||
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
|
||||
@@ -354,6 +363,10 @@
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="OverviewPane.idl">
|
||||
<DependentUpon>OverviewPane.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="SuggestionsControl.idl">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
||||
@@ -1790,6 +1790,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto vkey = gsl::narrow_cast<WORD>(e.OriginalKey());
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
|
||||
const auto modifiers = _GetPressedModifierKeys();
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_KeyDownHandler vkey={} handled={} overviewMode={}\n"), static_cast<uint32_t>(vkey), e.Handled(), _isInOverviewMode).c_str());
|
||||
|
||||
// GH#11076:
|
||||
// For some weird reason we sometimes receive a WM_KEYDOWN
|
||||
@@ -1835,8 +1836,22 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
if (!cmd)
|
||||
{
|
||||
OutputDebugStringW(L"[OV] TP::_KeyDownHandler: no cmd bound, returning\n");
|
||||
return;
|
||||
}
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_KeyDownHandler: cmd found, action={}\n"), static_cast<uint32_t>(cmd.ActionAndArgs().Action())).c_str());
|
||||
|
||||
// If the overview pane is open, most actions mutate tab state whose
|
||||
// Content() is currently reparented under the overview. Tear down the
|
||||
// overview's visuals first so the content is back under its original
|
||||
// parent before the action runs. ToggleOverview is the exception — it
|
||||
// handles its own exit.
|
||||
if (_isInOverviewMode &&
|
||||
cmd.ActionAndArgs().Action() != ShortcutAction::ToggleOverview)
|
||||
{
|
||||
OutputDebugStringW(L"[OV] TP::_KeyDownHandler: dismissing overview before action dispatch\n");
|
||||
_DismissOverviewVisuals();
|
||||
}
|
||||
|
||||
if (!_actionDispatch->DoAction(cmd.ActionAndArgs()))
|
||||
{
|
||||
@@ -3307,13 +3322,15 @@ namespace winrt::TerminalApp::implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminalPage::_IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri)
|
||||
bool TerminalPage::_IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri) const
|
||||
{
|
||||
if (parsedUri.SchemeName() == L"http" || parsedUri.SchemeName() == L"https")
|
||||
const auto& schemeName = parsedUri.SchemeName();
|
||||
|
||||
if (schemeName == L"http" || schemeName == L"https")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (parsedUri.SchemeName() == L"file")
|
||||
if (schemeName == L"file")
|
||||
{
|
||||
static const auto pathext{ wil::TryGetEnvironmentVariableW<std::wstring>(L"PATHEXT") };
|
||||
const auto filename = parsedUri.Path();
|
||||
@@ -3327,6 +3344,16 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
return true;
|
||||
}
|
||||
if (const auto& safeSchemes = _settings.GlobalSettings().SafeUriSchemes())
|
||||
{
|
||||
for (const auto& scheme : safeSchemes)
|
||||
{
|
||||
if (til::equals_insensitive_ascii(schemeName, scheme))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -4257,6 +4284,128 @@ namespace winrt::TerminalApp::implementation
|
||||
AlwaysOnTopChanged.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void TerminalPage::ToggleOverview()
|
||||
{
|
||||
if (_isInOverviewMode)
|
||||
{
|
||||
_ExitOverview(std::nullopt);
|
||||
}
|
||||
else
|
||||
{
|
||||
_EnterOverview();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_EnterOverview()
|
||||
{
|
||||
_isInOverviewMode = true;
|
||||
|
||||
// Use FindName to lazily load the OverviewPane (same pattern as CommandPalette)
|
||||
auto overview = FindName(L"OverviewPaneElement").try_as<OverviewPane>();
|
||||
if (!overview)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto focusedIdx = _GetFocusedTabIndex();
|
||||
const auto idx = focusedIdx.has_value() ? static_cast<int32_t>(focusedIdx.value()) : 0;
|
||||
|
||||
// Wire up events to handle tab selection and dismissal
|
||||
_overviewTabSelectedToken = overview.TabSelected([weakThis = get_weak()](auto&&, const auto& args) {
|
||||
if (auto self = weakThis.get())
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
self->_ExitOverview(static_cast<uint32_t>(args.Value()));
|
||||
}
|
||||
}
|
||||
});
|
||||
_overviewDismissedToken = overview.Dismissed([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto self = weakThis.get())
|
||||
{
|
||||
self->_ExitOverview(std::nullopt);
|
||||
}
|
||||
});
|
||||
|
||||
// _tabs is already IObservableVector<Tab>, which inherits from IVector<Tab>
|
||||
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
||||
const auto windowTheme = theme ? theme.Window() : nullptr;
|
||||
overview.UseMica(windowTheme ? windowTheme.UseMica() : false);
|
||||
overview.UpdateTabContent(_tabs, idx);
|
||||
overview.Visibility(WUX::Visibility::Visible);
|
||||
overview.Focus(WUX::FocusState::Programmatic);
|
||||
}
|
||||
|
||||
void TerminalPage::_ExitOverview(const std::optional<uint32_t>& selectedIndex)
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_ExitOverview enter, selectedIndex.has_value={} value={}\n"), selectedIndex.has_value(), selectedIndex.value_or(0xFFFFFFFFu)).c_str());
|
||||
auto overview = FindName(L"OverviewPaneElement").try_as<OverviewPane>();
|
||||
|
||||
// Determine which tab to switch to. Prefer the explicitly passed index
|
||||
// (from TabSelected event), but fall back to the overview pane's
|
||||
// current selection — this covers ToggleOverview and Dismiss paths so
|
||||
// the user always lands on whichever tab they navigated to.
|
||||
std::optional<uint32_t> tabToSelect = selectedIndex;
|
||||
if (!tabToSelect.has_value() && overview)
|
||||
{
|
||||
const auto overviewIdx = overview.SelectedIndex();
|
||||
if (overviewIdx >= 0 && overviewIdx < static_cast<int32_t>(_tabs.Size()))
|
||||
{
|
||||
tabToSelect = static_cast<uint32_t>(overviewIdx);
|
||||
}
|
||||
}
|
||||
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_ExitOverview before _DismissOverviewVisuals, tabToSelect.has_value={} value={}\n"), tabToSelect.has_value(), tabToSelect.value_or(0xFFFFFFFFu)).c_str());
|
||||
_DismissOverviewVisuals();
|
||||
|
||||
if (tabToSelect.has_value())
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] TP::_ExitOverview calling _SelectTab({})\n"), tabToSelect.value()).c_str());
|
||||
_SelectTab(tabToSelect.value());
|
||||
}
|
||||
|
||||
OutputDebugStringW(L"[OV] TP::_ExitOverview calling _UpdatedSelectedTab(_GetFocusedTab())\n");
|
||||
_UpdatedSelectedTab(_GetFocusedTab());
|
||||
OutputDebugStringW(L"[OV] TP::_ExitOverview returning\n");
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tears down the overview's reparented content and hides the overlay,
|
||||
// without changing tab selection. Safe to call when not in overview mode.
|
||||
// - Used by both _ExitOverview (which then selects a tab) and by
|
||||
// _OnTabSelectionChanged (where the TabView has already updated the
|
||||
// selection and we just need to release the reparented content before
|
||||
// _UpdatedSelectedTab tries to mount it back into the content area).
|
||||
void TerminalPage::_DismissOverviewVisuals()
|
||||
{
|
||||
OutputDebugStringW(fmt::format(FMT_COMPILE(L"[OV] _DismissOverviewVisuals enter, _isInOverviewMode={}\n"), _isInOverviewMode).c_str());
|
||||
if (!_isInOverviewMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto overview = FindName(L"OverviewPaneElement").try_as<OverviewPane>())
|
||||
{
|
||||
// Revoke event handlers to avoid stale callbacks
|
||||
overview.TabSelected(_overviewTabSelectedToken);
|
||||
overview.Dismissed(_overviewDismissedToken);
|
||||
_overviewTabSelectedToken = {};
|
||||
_overviewDismissedToken = {};
|
||||
|
||||
OutputDebugStringW(L"[OV] _DismissOverviewVisuals calling overview.ClearTabContent()\n");
|
||||
overview.ClearTabContent();
|
||||
overview.Visibility(WUX::Visibility::Collapsed);
|
||||
}
|
||||
|
||||
_isInOverviewMode = false;
|
||||
OutputDebugStringW(L"[OV] _DismissOverviewVisuals exit\n");
|
||||
}
|
||||
|
||||
bool TerminalPage::OverviewMode() const
|
||||
{
|
||||
return _isInOverviewMode;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the tab split button color when a new tab color is selected
|
||||
// Arguments:
|
||||
|
||||
@@ -138,9 +138,11 @@ namespace winrt::TerminalApp::implementation
|
||||
void ToggleFocusMode();
|
||||
void ToggleFullscreen();
|
||||
void ToggleAlwaysOnTop();
|
||||
void ToggleOverview();
|
||||
bool FocusMode() const;
|
||||
bool Fullscreen() const;
|
||||
bool AlwaysOnTop() const;
|
||||
bool OverviewMode() const;
|
||||
bool ShowTabsFullscreen() const;
|
||||
void SetShowTabsFullscreen(bool newShowTabsFullscreen);
|
||||
void SetFullscreen(bool);
|
||||
@@ -250,6 +252,9 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::Tab _settingsTab{ nullptr };
|
||||
|
||||
bool _isInFocusMode{ false };
|
||||
bool _isInOverviewMode{ false };
|
||||
winrt::event_token _overviewTabSelectedToken{};
|
||||
winrt::event_token _overviewDismissedToken{};
|
||||
bool _isFullscreen{ false };
|
||||
bool _isMaximized{ false };
|
||||
bool _isAlwaysOnTop{ false };
|
||||
@@ -375,6 +380,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _SelectNextTab(const bool bMoveRight, const Windows::Foundation::IReference<Microsoft::Terminal::Settings::Model::TabSwitcherMode>& customTabSwitcherMode);
|
||||
bool _SelectTab(uint32_t tabIndex);
|
||||
void _EnterOverview();
|
||||
void _ExitOverview(const std::optional<uint32_t>& selectedIndex);
|
||||
void _DismissOverviewVisuals();
|
||||
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);
|
||||
@@ -438,7 +446,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
safe_void_coroutine _OpenHyperlinkHandler(const IInspectable sender, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs);
|
||||
static bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
|
||||
static bool _IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri);
|
||||
bool _IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri) const;
|
||||
|
||||
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
|
||||
bool _CopyText(bool dismissSelection, bool singleLine, bool withControlSequences, Microsoft::Terminal::Control::CopyFormat formats);
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace TerminalApp
|
||||
Boolean FocusMode { get; };
|
||||
Boolean Fullscreen { get; };
|
||||
Boolean AlwaysOnTop { get; };
|
||||
Boolean OverviewMode { get; };
|
||||
|
||||
WindowProperties WindowProperties { get; };
|
||||
void IdentifyWindow();
|
||||
|
||||
@@ -155,6 +155,12 @@
|
||||
</TextBlock>
|
||||
</ContentDialog>
|
||||
|
||||
<local:OverviewPane x:Name="OverviewPaneElement"
|
||||
Grid.Row="2"
|
||||
x:Load="False"
|
||||
PreviewKeyDown="_KeyDownHandler"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<local:CommandPalette x:Name="CommandPaletteElement"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Stretch"
|
||||
|
||||
@@ -71,18 +71,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_removeControlEvents();
|
||||
|
||||
_control.Close();
|
||||
|
||||
// Clear out our media player callbacks, and stop any playing media. This
|
||||
// will prevent the callback from being triggered after we've closed, and
|
||||
// also make sure that our sound stops when we're closed.
|
||||
if (_bellPlayer)
|
||||
{
|
||||
_bellPlayer.Pause();
|
||||
_bellPlayer.Source(nullptr);
|
||||
_bellPlayer.Close();
|
||||
_bellPlayer = nullptr;
|
||||
_bellPlayerCreated = false;
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring TerminalPaneContent::Icon() const
|
||||
@@ -275,14 +263,15 @@ namespace winrt::TerminalApp::implementation
|
||||
auto sounds{ _profile.BellSound() };
|
||||
if (sounds && sounds.Size() > 0)
|
||||
{
|
||||
winrt::hstring soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
winrt::Windows::Foundation::Uri uri{ soundPath };
|
||||
_playBellSound(uri);
|
||||
// Sound paths are resolved and validated by CascadiaSettings
|
||||
// before we reach this point.
|
||||
auto soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
PlaySoundW(soundPath.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_SENTRY | SND_NODEFAULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
const auto soundAlias = reinterpret_cast<LPCWSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySoundW(soundAlias, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,33 +289,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await wil::resume_foreground(_control.Dispatcher());
|
||||
if (auto pane{ weakThis.get() })
|
||||
{
|
||||
if (!_bellPlayerCreated)
|
||||
{
|
||||
// The MediaPlayer might not exist on Windows N SKU.
|
||||
try
|
||||
{
|
||||
_bellPlayerCreated = true;
|
||||
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
|
||||
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
|
||||
_bellPlayer.CommandManager().IsEnabled(false);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
if (_bellPlayer)
|
||||
{
|
||||
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
|
||||
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
|
||||
_bellPlayer.Source(item);
|
||||
_bellPlayer.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
|
||||
@@ -76,9 +76,6 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<TerminalSettingsCache> _cache{};
|
||||
bool _isDefTermSession{ false };
|
||||
|
||||
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
|
||||
bool _bellPlayerCreated{ false };
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
|
||||
@@ -96,8 +93,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _setupControlEvents();
|
||||
void _removeControlEvents();
|
||||
|
||||
safe_void_coroutine _playBellSound(winrt::Windows::Foundation::Uri uri);
|
||||
|
||||
safe_void_coroutine _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& e);
|
||||
|
||||
@@ -925,7 +925,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Manually turn off acrylic if they turn off transparency.
|
||||
_runtimeUseAcrylic = _settings.Opacity() < 1.0 && _settings.UseAcrylic();
|
||||
|
||||
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize());
|
||||
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta);
|
||||
|
||||
// Update the terminal core with its new Core settings
|
||||
_terminal->UpdateSettings(_settings);
|
||||
@@ -1163,11 +1163,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - none
|
||||
void ControlCore::ResetFontSize()
|
||||
{
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
if (_setFontSizeUnderLock(_settings.FontSize()))
|
||||
if (std::exchange(_accumulatedFontSizeDelta, 0.f) != 0.f)
|
||||
{
|
||||
_refreshSizeUnderLock();
|
||||
// No point in doing this if there was no delta.
|
||||
AdjustFontSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,9 +1176,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - fontSizeDelta: The amount to increase or decrease the font size by.
|
||||
void ControlCore::AdjustFontSize(float fontSizeDelta)
|
||||
{
|
||||
_accumulatedFontSizeDelta += fontSizeDelta;
|
||||
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
if (_setFontSizeUnderLock(_desiredFont.GetFontSize() + fontSizeDelta))
|
||||
if (_setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta))
|
||||
{
|
||||
_refreshSizeUnderLock();
|
||||
}
|
||||
|
||||
@@ -391,6 +391,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool _colorGlyphs = true;
|
||||
CSSLengthPercentage _cellWidth;
|
||||
CSSLengthPercentage _cellHeight;
|
||||
float _accumulatedFontSizeDelta = 0.f; // Preserved across reloads to prevent user zoom from being overwritten.
|
||||
|
||||
// Rendering stuff.
|
||||
winrt::handle _lastSwapChainHandle{ nullptr };
|
||||
|
||||
@@ -2906,6 +2906,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
// Yes, this is reachable: when a pane is split, the new TermControl
|
||||
// is added to the XAML tree before its Loaded event fires, so
|
||||
// _initializedTerminal is still false when layout queries MinimumSize().
|
||||
// Return a small fallback — the real size will be used once initialized.
|
||||
return { 10, 10 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||
_answerbackMessage = settings.AnswerbackMessage();
|
||||
_wordDelimiters = settings.WordDelimiters();
|
||||
_suppressApplicationTitle = settings.SuppressApplicationTitle();
|
||||
_startingTitle = settings.StartingTitle();
|
||||
_trimBlockSelection = settings.TrimBlockSelection();
|
||||
_autoMarkPrompts = settings.AutoMarkPrompts();
|
||||
_rainbowSuggestions = settings.RainbowSuggestions();
|
||||
@@ -124,6 +123,11 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||
// Save the changes made above and in UpdateAppearance as the new default render settings.
|
||||
GetRenderSettings().SaveDefaultSettings();
|
||||
|
||||
if (!_startingTitle)
|
||||
{
|
||||
_startingTitle = settings.StartingTitle();
|
||||
}
|
||||
|
||||
if (!_startingTabColor && settings.StartingTabColor())
|
||||
{
|
||||
_startingTabColor = settings.StartingTabColor().Value();
|
||||
|
||||
@@ -349,7 +349,7 @@ private:
|
||||
::Microsoft::Console::VirtualTerminal::TerminalInput _terminalInput;
|
||||
|
||||
std::optional<std::wstring> _title;
|
||||
std::wstring _startingTitle;
|
||||
std::optional<std::wstring> _startingTitle;
|
||||
std::optional<til::color> _startingTabColor;
|
||||
|
||||
std::vector<til::point_span> _searchHighlights;
|
||||
|
||||
@@ -91,8 +91,12 @@ void Terminal::SetWindowTitle(const std::wstring_view title)
|
||||
_assertLocked();
|
||||
if (!_suppressApplicationTitle)
|
||||
{
|
||||
_title.emplace(title.empty() ? _startingTitle : title);
|
||||
_pfnTitleChanged(_title.value());
|
||||
_title.reset();
|
||||
if (!title.empty())
|
||||
{
|
||||
_title.emplace(title);
|
||||
}
|
||||
_pfnTitleChanged(GetConsoleTitle());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +116,13 @@ bool Terminal::ResizeWindow(const til::CoordType width, const til::CoordType hei
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto currentDimensions = _GetMutableViewport().Dimensions();
|
||||
|
||||
if (width == currentDimensions.width && height == currentDimensions.height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_pfnWindowSizeChanged)
|
||||
{
|
||||
_pfnWindowSizeChanged(width, height);
|
||||
|
||||
@@ -184,11 +184,18 @@ void Terminal::SelectNewRegion(const til::point coordStart, const til::point coo
|
||||
std::wstring_view Terminal::GetConsoleTitle() const noexcept
|
||||
{
|
||||
_assertLocked();
|
||||
if (_title.has_value())
|
||||
|
||||
if (_title)
|
||||
{
|
||||
return *_title;
|
||||
}
|
||||
return _startingTitle;
|
||||
|
||||
if (_startingTitle)
|
||||
{
|
||||
return *_startingTitle;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "ColorSchemes.h"
|
||||
#include "EditColorScheme.h"
|
||||
#include "AddProfile.h"
|
||||
#include "Profiles.h"
|
||||
#include "InteractionViewModel.h"
|
||||
#include "LaunchViewModel.h"
|
||||
#include "NewTabMenuViewModel.h"
|
||||
@@ -103,7 +102,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
MainPage::MainPage(const CascadiaSettings& settings) :
|
||||
_settingsSource{ settings },
|
||||
_settingsClone{ settings.Copy() },
|
||||
_profilesPageVM{ winrt::make<ProfilesPageViewModel>() }
|
||||
_profileVMs{ single_threaded_observable_vector<Editor::ProfileViewModel>() }
|
||||
{
|
||||
InitializeComponent();
|
||||
_UpdateBackgroundForMica();
|
||||
@@ -157,10 +156,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
});
|
||||
|
||||
_SetupProfilesPageEventHandling();
|
||||
|
||||
// Make sure to initialize the profiles _after_ we have initialized the color schemes page VM, because we pass
|
||||
// that VM into the appearance VMs within the profiles. The Profiles VM owns the per-profile list itself.
|
||||
// that VM into the appearance VMs within the profiles
|
||||
_InitializeProfilesList();
|
||||
|
||||
// Apply icons and tooltips (GH#19688, long names may be truncated) to static nav items
|
||||
@@ -208,17 +205,28 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
_UpdateBackgroundForMica();
|
||||
|
||||
// Capture data about where we are right now, so we can re-navigate to the same
|
||||
// place after we rebuild all the settings.
|
||||
IInspectable destination{ nullptr };
|
||||
auto subPage = BreadcrumbSubPage::None;
|
||||
if (const auto size = _breadcrumbs.Size(); size > 0)
|
||||
// Deduce information about the currently selected item
|
||||
IInspectable lastBreadcrumb;
|
||||
const auto size = _breadcrumbs.Size();
|
||||
if (size > 0)
|
||||
{
|
||||
const auto& crumb = _breadcrumbs.GetAt(size - 1).as<Breadcrumb>();
|
||||
destination = crumb->Tag();
|
||||
subPage = crumb->SubPage();
|
||||
lastBreadcrumb = _breadcrumbs.GetAt(size - 1);
|
||||
}
|
||||
|
||||
// Collect only the first items out of the menu item source, the static
|
||||
// ones that we don't want to regenerate.
|
||||
//
|
||||
// By manipulating a MenuItemsSource this way, rather than manipulating the
|
||||
// MenuItems directly, we avoid a crash in WinUI.
|
||||
//
|
||||
// By making the vector only _originalNumItems big to start, GetMany
|
||||
// will only fill that number of elements out of the current source.
|
||||
std::vector<IInspectable> menuItemsSTL(_originalNumItems, nullptr);
|
||||
_menuItemSource.GetMany(0, menuItemsSTL);
|
||||
// now, just stick them back in.
|
||||
_menuItemSource.ReplaceAll(menuItemsSTL);
|
||||
|
||||
// Repopulate profile-related menu items
|
||||
_InitializeProfilesList();
|
||||
|
||||
// Update the Nav State with the new version of the settings
|
||||
@@ -228,41 +236,64 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_extensionsVM.UpdateSettings(_settingsClone, _colorSchemesPageVM);
|
||||
_profileDefaultsVM = nullptr; // Lazy-loaded upon navigation
|
||||
|
||||
if (const auto& profileTag{ destination.try_as<Editor::ProfileViewModel>() })
|
||||
// Now that the menuItems are repopulated,
|
||||
// refresh the current page using the breadcrumb data we collected before the refresh
|
||||
if (const auto& crumb{ lastBreadcrumb.try_as<Breadcrumb>() }; crumb && crumb->Tag())
|
||||
{
|
||||
// Find the new profile VM by guid
|
||||
if (const auto newProfileVM = _FindProfileViewModelByGuid(profileTag.OriginalProfileGuid()))
|
||||
bool foundNavigationParams = false;
|
||||
auto destination = crumb->Tag();
|
||||
auto subPage = crumb->SubPage();
|
||||
for (const auto& item : _menuItemSource)
|
||||
{
|
||||
destination = newProfileVM;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fall back to the Profiles landing page
|
||||
destination = box_value(profilesTag);
|
||||
subPage = BreadcrumbSubPage::None;
|
||||
}
|
||||
}
|
||||
else if (destination.try_as<Editor::FolderEntryViewModel>())
|
||||
{
|
||||
destination = box_value(newTabMenuTag);
|
||||
subPage = BreadcrumbSubPage::NewTabMenu_Folder;
|
||||
}
|
||||
else if (destination.try_as<Editor::ExtensionPackageViewModel>())
|
||||
{
|
||||
destination = box_value(extensionsTag);
|
||||
subPage = BreadcrumbSubPage::Extensions_Extension;
|
||||
}
|
||||
else if (!destination.try_as<hstring>())
|
||||
{
|
||||
// Couldn't find a meaningful previous page. Fall back to the first menu item.
|
||||
if (_menuItemSource && _menuItemSource.Size() > 0)
|
||||
{
|
||||
destination = _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>().Tag();
|
||||
subPage = BreadcrumbSubPage::None;
|
||||
const auto menuItem = item.try_as<MUX::Controls::NavigationViewItem>();
|
||||
if (!menuItem)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& tag = menuItem.Tag();
|
||||
if (const auto& stringTag{ tag.try_as<hstring>() })
|
||||
{
|
||||
if (const auto& destString{ destination.try_as<hstring>() })
|
||||
{
|
||||
foundNavigationParams = (*stringTag == *destString);
|
||||
}
|
||||
else if (destination.try_as<Editor::FolderEntryViewModel>() && *stringTag == newTabMenuTag)
|
||||
{
|
||||
foundNavigationParams = true;
|
||||
subPage = BreadcrumbSubPage::NewTabMenu_Folder;
|
||||
}
|
||||
else if (destination.try_as<Editor::ExtensionPackageViewModel>() && *stringTag == extensionsTag)
|
||||
{
|
||||
foundNavigationParams = true;
|
||||
subPage = BreadcrumbSubPage::Extensions_Extension;
|
||||
}
|
||||
}
|
||||
else if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
|
||||
{
|
||||
const auto destProfile = destination.try_as<ProfileViewModel>();
|
||||
if (destProfile && profileTag->OriginalProfileGuid() == destProfile->OriginalProfileGuid())
|
||||
{
|
||||
// Use the new profile VM from the refreshed menu items
|
||||
destination = tag;
|
||||
foundNavigationParams = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundNavigationParams)
|
||||
{
|
||||
// found the one that was selected before the refresh
|
||||
_Navigate(destination, subPage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Navigate(destination, subPage);
|
||||
// Couldn't find the selected item, fall back to first menu item
|
||||
// This happens when the selected item was a profile which doesn't exist in the new configuration
|
||||
// We can use menuItemsSTL here because the only things they miss are profile entries.
|
||||
const auto& firstItem{ _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>() };
|
||||
_Navigate(firstItem.Tag(), BreadcrumbSubPage::None);
|
||||
|
||||
_UpdateSearchIndex();
|
||||
}
|
||||
@@ -294,6 +325,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// can be empty to indicate that we should create a fresh profile
|
||||
void MainPage::_AddProfileHandler(winrt::guid profileGuid)
|
||||
{
|
||||
uint32_t insertIndex;
|
||||
auto selectedItem{ SettingsNav().SelectedItem() };
|
||||
if (_menuItemSource)
|
||||
{
|
||||
_menuItemSource.IndexOf(selectedItem, insertIndex);
|
||||
}
|
||||
if (profileGuid != winrt::guid{})
|
||||
{
|
||||
// if we were given a non-empty guid, we want to duplicate the corresponding profile
|
||||
@@ -301,13 +338,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (profile)
|
||||
{
|
||||
const auto duplicated = _settingsClone.DuplicateProfile(profile);
|
||||
_CreateAndNavigateToNewProfile(duplicated);
|
||||
_CreateAndNavigateToNewProfile(insertIndex, duplicated);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we were given an empty guid, create a new profile
|
||||
_CreateAndNavigateToNewProfile(nullptr);
|
||||
_CreateAndNavigateToNewProfile(insertIndex, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,7 +521,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (currentPage == ProfileSubPage::Base)
|
||||
{
|
||||
_breadcrumbs.Clear();
|
||||
_AppendProfilesRootCrumb();
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None));
|
||||
}
|
||||
_NavigateToProfileSubPage(profile, currentPage, breadcrumbTag, {});
|
||||
@@ -580,15 +616,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
}
|
||||
else if (*clickedItemTag == profilesTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), winrt::make<NavigateToPageArgs>(_profilesPageVM, *this, elementToFocus));
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Profiles/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == globalProfileTag)
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
|
||||
// lazy load profile defaults VM
|
||||
if (!_profileDefaultsVM)
|
||||
{
|
||||
@@ -607,15 +636,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
// Register handler for future user-driven sub-page changes
|
||||
_SetupProfileEventHandling(_profileDefaultsVM);
|
||||
|
||||
// Keep the Profiles nav item selected.
|
||||
selectedNavTag = profilesTag;
|
||||
}
|
||||
else if (*clickedItemTag == colorSchemesTag)
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
selectedNavTag = profilesTag;
|
||||
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None));
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus));
|
||||
|
||||
@@ -631,53 +654,47 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else if (*clickedItemTag == addProfileTag)
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
|
||||
auto addProfileState{ winrt::make<AddProfilePageNavigationState>(_settingsClone) };
|
||||
addProfileState.AddNew({ get_weak(), &MainPage::_AddProfileHandler });
|
||||
contentFrame().Navigate(xaml_typename<Editor::AddProfile>(), winrt::make<NavigateToPageArgs>(addProfileState, *this, elementToFocus));
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_AddNewProfile/Content"), BreadcrumbSubPage::None));
|
||||
|
||||
// Keep the Profiles nav item selected.
|
||||
selectedNavTag = profilesTag;
|
||||
}
|
||||
}
|
||||
else if (const auto& profile = vm.try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
selectedNavTag = profilesTag;
|
||||
|
||||
if (profile.Orphaned())
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base_Orphaned>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
|
||||
profile.CurrentPage(ProfileSubPage::Base);
|
||||
_SetupProfileEventHandling(profile);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// Set CurrentPage before registering the handler to avoid double-navigation
|
||||
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
|
||||
profile.CurrentPage(profileSubPage);
|
||||
|
||||
// Navigate directly to the correct sub-page
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
|
||||
_NavigateToProfileSubPage(profile, profileSubPage, vm, elementToFocus);
|
||||
|
||||
if (const auto profileNavItem = _FindProfileNavItem(profile.OriginalProfileGuid()))
|
||||
{
|
||||
// Set CurrentPage before registering the handler to avoid double-navigation
|
||||
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
|
||||
profile.CurrentPage(profileSubPage);
|
||||
|
||||
// Navigate directly to the correct sub-page
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
|
||||
_NavigateToProfileSubPage(profile, profileSubPage, vm, elementToFocus);
|
||||
|
||||
// Register handler for future user-driven sub-page changes
|
||||
_SetupProfileEventHandling(profile);
|
||||
SettingsNav().SelectedItem(profileNavItem);
|
||||
}
|
||||
|
||||
// Register handler for future user-driven sub-page changes
|
||||
_SetupProfileEventHandling(profile);
|
||||
}
|
||||
else if (const auto& colorSchemeVM = vm.try_as<Editor::ColorSchemeViewModel>())
|
||||
{
|
||||
selectedNavTag = colorSchemesTag;
|
||||
const auto boxedColorSchemesTag = box_value(colorSchemesTag);
|
||||
|
||||
// Suppress the handler to avoid double-navigation
|
||||
_colorSchemesPageViewModelChangedRevoker.revoke();
|
||||
|
||||
_AppendProfilesRootCrumb();
|
||||
selectedNavTag = profilesTag;
|
||||
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedColorSchemesTag, RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None));
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
@@ -796,9 +813,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
|
||||
// Select the appropriate nav item
|
||||
// NOTE: profiles are special in that they have their own nav item, so those are handled in the profile branch above
|
||||
if (!selectedNavTag.empty())
|
||||
{
|
||||
_SelectNavItemByTag(selectedNavTag);
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
{
|
||||
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
if (const auto& tag{ navViewItem.Tag() })
|
||||
{
|
||||
if (const auto& stringTag{ tag.try_as<hstring>() })
|
||||
{
|
||||
if (*stringTag == selectedNavTag)
|
||||
{
|
||||
SettingsNav().SelectedItem(navViewItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,20 +872,35 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_MoveXamlParsedNavItemsIntoItemSource();
|
||||
}
|
||||
|
||||
// Populate the per-profile view models on the Profiles VM. The Profiles landing
|
||||
// page (and the search index) read this same list back through the VM.
|
||||
const auto& profileVMs = _profilesPageVM.Profiles();
|
||||
profileVMs.Clear();
|
||||
// Manually create a NavigationViewItem and view model for each profile
|
||||
// and keep a reference to them in a map so that we
|
||||
// can easily modify the correct one when the associated
|
||||
// profile changes.
|
||||
_profileVMs.Clear();
|
||||
for (const auto& profile : _settingsClone.AllProfiles())
|
||||
{
|
||||
if (!profile.Deleted())
|
||||
{
|
||||
auto profileVM = _viewModelForProfile(profile, _settingsClone, Dispatcher());
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
profileVM.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
profileVMs.Append(profileVM);
|
||||
auto navItem = _CreateProfileNavViewItem(profileVM);
|
||||
_menuItemSource.Append(navItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Top off (the end of the nav view) with the Add Profile item
|
||||
MUX::Controls::NavigationViewItem addProfileItem;
|
||||
const auto addProfileText = RS_(L"Nav_AddNewProfile/Content");
|
||||
addProfileItem.Content(box_value(addProfileText));
|
||||
addProfileItem.Tag(box_value(addProfileTag));
|
||||
WUX::Controls::ToolTipService::SetToolTip(addProfileItem, box_value(addProfileText));
|
||||
|
||||
FontIcon icon;
|
||||
// This is the "Add" symbol
|
||||
icon.Glyph(NavTagIconMap[addProfileTag]);
|
||||
addProfileItem.Icon(icon);
|
||||
|
||||
_menuItemSource.Append(addProfileItem);
|
||||
}
|
||||
|
||||
// BODGY
|
||||
@@ -887,17 +936,79 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
SettingsNav().MenuItemsSource(_menuItemSource);
|
||||
}
|
||||
|
||||
void MainPage::_CreateAndNavigateToNewProfile(const Model::Profile& profile)
|
||||
void MainPage::_CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile)
|
||||
{
|
||||
const auto newProfile{ profile ? profile : _settingsClone.CreateNewProfile() };
|
||||
const auto profileViewModel{ _viewModelForProfile(newProfile, _settingsClone, Dispatcher()) };
|
||||
profileViewModel.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
profileViewModel.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
const auto navItem{ _CreateProfileNavViewItem(profileViewModel) };
|
||||
|
||||
_profilesPageVM.Profiles().Append(profileViewModel);
|
||||
if (_menuItemSource)
|
||||
{
|
||||
_menuItemSource.InsertAt(index, navItem);
|
||||
}
|
||||
|
||||
// Select and navigate to the new profile
|
||||
_Navigate(profileViewModel);
|
||||
_Navigate(profileViewModel, BreadcrumbSubPage::None);
|
||||
}
|
||||
|
||||
static MUX::Controls::InfoBadge _createGlyphIconBadge(wil::zwstring_view glyph)
|
||||
{
|
||||
MUX::Controls::InfoBadge badge;
|
||||
MUX::Controls::FontIconSource icon;
|
||||
icon.FontFamily(winrt::Windows::UI::Xaml::Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(12);
|
||||
icon.Glyph(glyph);
|
||||
badge.IconSource(icon);
|
||||
return badge;
|
||||
}
|
||||
|
||||
MUX::Controls::NavigationViewItem MainPage::_CreateProfileNavViewItem(const Editor::ProfileViewModel& profile)
|
||||
{
|
||||
MUX::Controls::NavigationViewItem profileNavItem;
|
||||
profileNavItem.Content(box_value(profile.Name()));
|
||||
profileNavItem.Tag(box_value<Editor::ProfileViewModel>(profile));
|
||||
profileNavItem.Icon(UI::IconPathConverter::IconWUX(profile.EvaluatedIcon()));
|
||||
WUX::Controls::ToolTipService::SetToolTip(profileNavItem, box_value(profile.Name()));
|
||||
|
||||
if (profile.Orphaned())
|
||||
{
|
||||
profileNavItem.InfoBadge(_createGlyphIconBadge(L"\xE7BA") /* Warning Triangle */);
|
||||
}
|
||||
else if (profile.Hidden())
|
||||
{
|
||||
profileNavItem.InfoBadge(_createGlyphIconBadge(L"\xED1A") /* Hide */);
|
||||
}
|
||||
|
||||
// Update the menu item when the icon/name changes
|
||||
auto weakMenuItem{ make_weak(profileNavItem) };
|
||||
profile.PropertyChanged([weakMenuItem](const auto&, const WUX::Data::PropertyChangedEventArgs& args) {
|
||||
if (auto menuItem{ weakMenuItem.get() })
|
||||
{
|
||||
const auto& tag{ menuItem.Tag().as<Editor::ProfileViewModel>() };
|
||||
if (args.PropertyName() == L"Icon")
|
||||
{
|
||||
menuItem.Icon(UI::IconPathConverter::IconWUX(tag.EvaluatedIcon()));
|
||||
}
|
||||
else if (args.PropertyName() == L"Name")
|
||||
{
|
||||
menuItem.Content(box_value(tag.Name()));
|
||||
WUX::Controls::ToolTipService::SetToolTip(menuItem, box_value(tag.Name()));
|
||||
}
|
||||
else if (args.PropertyName() == L"Hidden")
|
||||
{
|
||||
menuItem.InfoBadge(tag.Hidden() ? _createGlyphIconBadge(L"\xED1A") /* Hide */ : nullptr);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add an event handler for when the user wants to delete a profile.
|
||||
profile.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
|
||||
// Register the VM so that it appears in the search index
|
||||
_profileVMs.Append(profile);
|
||||
|
||||
return profileNavItem;
|
||||
}
|
||||
|
||||
void MainPage::_DeleteProfile(const IInspectable /*sender*/, const Editor::DeleteProfileEventArgs& args)
|
||||
@@ -914,20 +1025,33 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the profile VM
|
||||
const auto& profileVMs = _profilesPageVM.Profiles();
|
||||
for (uint32_t i = 0; i < profileVMs.Size(); ++i)
|
||||
// remove selected item
|
||||
uint32_t index;
|
||||
auto selectedItem{ SettingsNav().SelectedItem() };
|
||||
if (_menuItemSource)
|
||||
{
|
||||
if (profileVMs.GetAt(i).OriginalProfileGuid() == guid)
|
||||
{
|
||||
profileVMs.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_menuItemSource.IndexOf(selectedItem, index);
|
||||
_menuItemSource.RemoveAt(index);
|
||||
|
||||
// Go back to the Profiles landing page
|
||||
_Navigate(box_value(profilesTag));
|
||||
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
|
||||
// Remove it from the list of VMs
|
||||
auto profileVM = selectedItem.as<MUX::Controls::NavigationViewItem>().Tag().as<Editor::ProfileViewModel>();
|
||||
uint32_t vmIndex;
|
||||
if (_menuItemSource.IndexOf(profileVM, vmIndex))
|
||||
{
|
||||
_profileVMs.RemoveAt(vmIndex);
|
||||
}
|
||||
|
||||
// navigate to the profile next to this one
|
||||
const auto newSelectedItem{ _menuItemSource.GetAt(index < _menuItemSource.Size() - 1 ? index : index - 1) };
|
||||
const auto newTag = newSelectedItem.as<MUX::Controls::NavigationViewItem>().Tag();
|
||||
if (const auto profileViewModel = newTag.try_as<ProfileViewModel>())
|
||||
{
|
||||
profileViewModel->FocusDeleteButton(true);
|
||||
}
|
||||
_Navigate(newTag, BreadcrumbSubPage::None);
|
||||
// Since we are navigating to a new profile after deletion, scroll up to the top
|
||||
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
IObservableVector<IInspectable> MainPage::Breadcrumbs() noexcept
|
||||
@@ -937,20 +1061,29 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void MainPage::_NavigateToProfileHandler(const IInspectable& /*sender*/, winrt::guid profileGuid)
|
||||
{
|
||||
if (const auto profileVM = _FindProfileViewModelByGuid(profileGuid))
|
||||
if (const auto profileNavItem = _FindProfileNavItem(profileGuid))
|
||||
{
|
||||
_Navigate(profileVM);
|
||||
_Navigate(profileNavItem.Tag(), BreadcrumbSubPage::None);
|
||||
}
|
||||
// Silently fail if the profile wasn't found
|
||||
}
|
||||
|
||||
Editor::ProfileViewModel MainPage::_FindProfileViewModelByGuid(winrt::guid profileGuid) const
|
||||
MUX::Controls::NavigationViewItem MainPage::_FindProfileNavItem(winrt::guid profileGuid) const
|
||||
{
|
||||
for (const auto& profileVM : _profilesPageVM.Profiles())
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
{
|
||||
if (profileVM.OriginalProfileGuid() == profileGuid)
|
||||
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
return profileVM;
|
||||
if (const auto& tag{ navViewItem.Tag() })
|
||||
{
|
||||
if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
|
||||
{
|
||||
if (profileTag->OriginalProfileGuid() == profileGuid)
|
||||
{
|
||||
return navViewItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -961,52 +1094,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_Navigate(box_value(hstring{ colorSchemesTag }), BreadcrumbSubPage::ColorSchemes_Edit);
|
||||
}
|
||||
|
||||
void MainPage::_AppendProfilesRootCrumb()
|
||||
{
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(profilesTag), RS_(L"Nav_Profiles/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
|
||||
void MainPage::_SelectNavItemByTag(std::wstring_view tag)
|
||||
{
|
||||
if (!_menuItemSource)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
{
|
||||
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
if (const auto& itemTag{ navViewItem.Tag() })
|
||||
{
|
||||
if (const auto& stringTag{ itemTag.try_as<hstring>() })
|
||||
{
|
||||
if (*stringTag == tag)
|
||||
{
|
||||
SettingsNav().SelectedItem(navViewItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_SetupProfilesPageEventHandling()
|
||||
{
|
||||
_profilesPageVM.OpenDefaultsRequested([this](const auto&, const auto&) {
|
||||
_Navigate(box_value(globalProfileTag));
|
||||
});
|
||||
_profilesPageVM.OpenColorSchemesRequested([this](const auto&, const auto&) {
|
||||
_Navigate(box_value(colorSchemesTag));
|
||||
});
|
||||
_profilesPageVM.AddProfileRequested([this](const auto&, const auto&) {
|
||||
_Navigate(box_value(addProfileTag));
|
||||
});
|
||||
_profilesPageVM.OpenProfileRequested([this](const auto&, const Editor::ProfileViewModel& profile) {
|
||||
_Navigate(profile);
|
||||
});
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush MainPage::BackgroundBrush()
|
||||
{
|
||||
return SettingsNav().Background();
|
||||
@@ -1109,7 +1196,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
co_return;
|
||||
}
|
||||
_currentSearch = SearchIndex::Instance().SearchAsync(sanitizedQuery,
|
||||
_profilesPageVM.Profiles().GetView(),
|
||||
_profileVMs.GetView(),
|
||||
get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList().GetView(),
|
||||
_colorSchemesPageVM.AllColorSchemes().GetView(),
|
||||
_extensionsVM.ExtensionPackages().GetView(),
|
||||
|
||||
@@ -84,24 +84,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
std::optional<HWND> _hostingHwnd;
|
||||
|
||||
void _InitializeProfilesList();
|
||||
void _CreateAndNavigateToNewProfile(const Model::Profile& profile);
|
||||
void _CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile);
|
||||
winrt::Microsoft::UI::Xaml::Controls::NavigationViewItem _CreateProfileNavViewItem(const Editor::ProfileViewModel& profile);
|
||||
void _DeleteProfile(const Windows::Foundation::IInspectable sender, const Editor::DeleteProfileEventArgs& args);
|
||||
void _AddProfileHandler(const winrt::guid profileGuid);
|
||||
|
||||
void _SetupProfileEventHandling(const winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel profile);
|
||||
void _SetupColorSchemesEventHandling();
|
||||
void _SetupActionsEventHandling();
|
||||
void _SetupProfilesPageEventHandling();
|
||||
void _NavigateToProfileSubPage(const Editor::ProfileViewModel& profile, ProfileSubPage page, const IInspectable& breadcrumbTag, const hstring& elementToFocus);
|
||||
|
||||
void _PreNavigateHelper();
|
||||
void _Navigate(const IInspectable& vm, BreadcrumbSubPage subPage = BreadcrumbSubPage::None, hstring elementToFocus = {});
|
||||
void _Navigate(const IInspectable& vm, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _NavigateToProfileHandler(const IInspectable& sender, winrt::guid profileGuid);
|
||||
void _NavigateToColorSchemeHandler(const IInspectable& sender, const IInspectable& args);
|
||||
Editor::ProfileViewModel _FindProfileViewModelByGuid(winrt::guid profileGuid) const;
|
||||
|
||||
void _AppendProfilesRootCrumb();
|
||||
void _SelectNavItemByTag(std::wstring_view tag);
|
||||
Microsoft::UI::Xaml::Controls::NavigationViewItem _FindProfileNavItem(winrt::guid profileGuid) const;
|
||||
|
||||
void _UpdateBackgroundForMica();
|
||||
void _MoveXamlParsedNavItemsIntoItemSource();
|
||||
@@ -109,11 +106,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
safe_void_coroutine _UpdateSearchIndex();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel _profileDefaultsVM{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel> _profileVMs{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ActionsViewModel _actionsVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::NewTabMenuViewModel _newTabMenuPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ExtensionsViewModel _extensionsVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ProfilesPageViewModel _profilesPageVM{ nullptr };
|
||||
|
||||
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable>> _currentSearch{ nullptr };
|
||||
|
||||
|
||||
@@ -162,6 +162,11 @@
|
||||
x:Uid="Nav_Appearance"
|
||||
Tag="GlobalAppearance_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="ColorSchemesNavItem"
|
||||
x:Uid="Nav_ColorSchemes"
|
||||
Tag="ColorSchemes_Nav" />
|
||||
|
||||
|
||||
<muxc:NavigationViewItem x:Name="RenderingNavItem"
|
||||
x:Uid="Nav_Rendering"
|
||||
Tag="Rendering_Nav" />
|
||||
@@ -187,9 +192,11 @@
|
||||
x:Uid="Nav_Extensions"
|
||||
Tag="Extensions_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="ProfilesNavItem"
|
||||
x:Uid="Nav_Profiles"
|
||||
Tag="Profiles_Nav" />
|
||||
<muxc:NavigationViewItemHeader x:Uid="Nav_Profiles" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="BaseLayerMenuItem"
|
||||
x:Uid="Nav_ProfileDefaults"
|
||||
Tag="GlobalProfile_Nav" />
|
||||
</muxc:NavigationView.MenuItems>
|
||||
|
||||
<muxc:NavigationView.FooterMenuItems>
|
||||
|
||||
@@ -119,10 +119,6 @@
|
||||
<DependentUpon>ColorSchemesPageViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Profiles.h">
|
||||
<DependentUpon>Profiles.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RenderingViewModel.h">
|
||||
<DependentUpon>RenderingViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -235,9 +231,6 @@
|
||||
<Page Include="Profiles_Base.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Profiles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Profiles_Base_Orphaned.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
@@ -338,10 +331,6 @@
|
||||
<DependentUpon>ColorSchemesPageViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Profiles.cpp">
|
||||
<DependentUpon>Profiles.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RenderingViewModel.cpp">
|
||||
<DependentUpon>RenderingViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -467,10 +456,6 @@
|
||||
<Midl Include="TerminalColorConverters.idl" />
|
||||
<Midl Include="ColorSchemeViewModel.idl" />
|
||||
<Midl Include="ColorSchemesPageViewModel.idl" />
|
||||
<Midl Include="Profiles.idl">
|
||||
<DependentUpon>Profiles.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="RenderingViewModel.idl" />
|
||||
<Midl Include="InteractionViewModel.idl" />
|
||||
<Midl Include="GlobalAppearanceViewModel.idl" />
|
||||
|
||||
@@ -57,6 +57,5 @@
|
||||
<Page Include="NullableColorPicker.xaml" />
|
||||
<Page Include="IconPicker.xaml" />
|
||||
<Page Include="NewTabMenu.xaml" />
|
||||
<Page Include="Profiles.xaml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -17,7 +17,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
inline constexpr std::wstring_view actionsTag{ L"Actions_Nav" };
|
||||
inline constexpr std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
|
||||
inline constexpr std::wstring_view extensionsTag{ L"Extensions_Nav" };
|
||||
inline constexpr std::wstring_view profilesTag{ L"Profiles_Nav" };
|
||||
inline constexpr std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
|
||||
inline constexpr std::wstring_view addProfileTag{ L"AddProfile" };
|
||||
inline constexpr std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
|
||||
@@ -34,7 +33,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
std::pair{ actionsTag, L"\xE765" }, /* Keyboard Classic */
|
||||
std::pair{ newTabMenuTag, L"\xE71D" }, /* All Apps */
|
||||
std::pair{ extensionsTag, L"\xEA86" }, /* Puzzle */
|
||||
std::pair{ profilesTag, L"\xE7EE" }, /* Other User */
|
||||
std::pair{ globalProfileTag, L"\xE81E" }, /* Map Layers */
|
||||
std::pair{ addProfileTag, L"\xE710" }, /* Add */
|
||||
std::pair{ openJsonTag, L"\xE713" }, /* Settings */
|
||||
|
||||
@@ -127,10 +127,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_NotifyChanges(L"TabColorPreview");
|
||||
}
|
||||
else if (viewModelProperty == L"Hidden")
|
||||
{
|
||||
_NotifyChanges(L"AccessibleStateDescription");
|
||||
}
|
||||
});
|
||||
|
||||
_defaultAppearanceViewModel.PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
||||
@@ -352,27 +348,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return _profile.Orphaned();
|
||||
}
|
||||
|
||||
hstring ProfileViewModel::AccessibleStateDescription() const
|
||||
{
|
||||
const auto hidden = Hidden();
|
||||
const auto orphaned = Orphaned();
|
||||
if (hidden && orphaned)
|
||||
{
|
||||
return til::hstring_format(FMT_COMPILE(L"{}, {}"),
|
||||
RS_(L"Profile_HiddenBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"),
|
||||
RS_(L"Profile_OrphanedBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
}
|
||||
if (hidden)
|
||||
{
|
||||
return RS_(L"Profile_HiddenBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip");
|
||||
}
|
||||
if (orphaned)
|
||||
{
|
||||
return RS_(L"Profile_OrphanedBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
hstring ProfileViewModel::TabTitlePreview() const
|
||||
{
|
||||
if (const auto tabTitle{ TabTitle() }; !tabTitle.empty())
|
||||
|
||||
@@ -101,7 +101,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
bool RepositionCursorWithMouseAvailable() const noexcept;
|
||||
|
||||
bool Orphaned() const;
|
||||
hstring AccessibleStateDescription() const;
|
||||
hstring TabTitlePreview() const;
|
||||
hstring AnswerbackMessagePreview() const;
|
||||
Windows::UI::Color TabColorPreview() const;
|
||||
|
||||
@@ -106,7 +106,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
void DeleteUnfocusedAppearance();
|
||||
|
||||
Boolean Orphaned { get; };
|
||||
String AccessibleStateDescription { get; };
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Name);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, Guid);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Source);
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "Profiles.h"
|
||||
#include "Profiles.g.cpp"
|
||||
#include "ProfilesPageViewModel.g.cpp"
|
||||
#include "ProfileViewModel.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
Profiles::Profiles()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Automation::AutomationProperties::SetName(DefaultsNavigator(), RS_(L"Profiles_DefaultsNavigator_Title/Text"));
|
||||
Automation::AutomationProperties::SetHelpText(DefaultsNavigator(), RS_(L"Profiles_DefaultsNavigator_Description/Text"));
|
||||
Automation::AutomationProperties::SetName(ColorSchemesNavigator(), RS_(L"Profiles_ColorSchemesNavigator_Title/Text"));
|
||||
Automation::AutomationProperties::SetHelpText(ColorSchemesNavigator(), RS_(L"Profiles_ColorSchemesNavigator_Description/Text"));
|
||||
Automation::AutomationProperties::SetName(AddProfileButton(), RS_(L"Profiles_AddProfileButton/Text"));
|
||||
}
|
||||
|
||||
void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::ProfilesPageViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
"NavigatedToPage",
|
||||
TraceLoggingDescription("Event emitted when the user navigates to a page in the settings UI"),
|
||||
TraceLoggingValue("profilesLanding", "PageId", "The identifier of the page that was navigated to"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
void Profiles::Defaults_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_ViewModel.RequestOpenDefaults();
|
||||
}
|
||||
|
||||
void Profiles::ColorSchemes_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_ViewModel.RequestOpenColorSchemes();
|
||||
}
|
||||
|
||||
void Profiles::AddProfile_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_ViewModel.RequestAddProfile();
|
||||
}
|
||||
|
||||
void Profiles::Profile_Click(const IInspectable& sender, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
// Profile navigators are buttons whose DataContext is the bound ProfileViewModel.
|
||||
if (const auto element = sender.try_as<FrameworkElement>())
|
||||
{
|
||||
if (const auto profile = element.DataContext().try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
_ViewModel.RequestOpenProfile(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfilesPageViewModel::ProfilesPageViewModel()
|
||||
{
|
||||
_setProfiles(single_threaded_observable_vector<Editor::ProfileViewModel>());
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestOpenDefaults()
|
||||
{
|
||||
OpenDefaultsRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestOpenColorSchemes()
|
||||
{
|
||||
OpenColorSchemesRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestAddProfile()
|
||||
{
|
||||
AddProfileRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestOpenProfile(const Editor::ProfileViewModel& profile)
|
||||
{
|
||||
OpenProfileRequested.raise(*this, profile);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- Profiles.h
|
||||
|
||||
Abstract:
|
||||
- The Profiles landing page in the Settings UI. The page hosts entry points to
|
||||
the list of individual profiles among other profile-related settings.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Profiles.g.h"
|
||||
#include "ProfilesPageViewModel.g.h"
|
||||
#include "ProfileViewModel.h"
|
||||
#include "Utils.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct ProfilesPageViewModel : ProfilesPageViewModelT<ProfilesPageViewModel>, ViewModelHelper<ProfilesPageViewModel>
|
||||
{
|
||||
public:
|
||||
ProfilesPageViewModel();
|
||||
|
||||
void RequestOpenDefaults();
|
||||
void RequestOpenColorSchemes();
|
||||
void RequestAddProfile();
|
||||
void RequestOpenProfile(const Editor::ProfileViewModel& profile);
|
||||
|
||||
// DON'T YOU DARE ADD A `WINRT_CALLBACK(PropertyChanged` TO A CLASS DERIVED FROM ViewModelHelper. Do this instead:
|
||||
using ViewModelHelper<ProfilesPageViewModel>::PropertyChanged;
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::ProfileViewModel>, Profiles, _propertyChangedHandlers, nullptr);
|
||||
|
||||
public:
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> OpenDefaultsRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> OpenColorSchemesRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> AddProfileRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Editor::ProfileViewModel> OpenProfileRequested;
|
||||
};
|
||||
|
||||
struct Profiles : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
|
||||
{
|
||||
public:
|
||||
Profiles();
|
||||
|
||||
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
|
||||
|
||||
void Defaults_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void ColorSchemes_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void AddProfile_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void Profile_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_PROPERTY(Editor::ProfilesPageViewModel, ViewModel, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(Profiles);
|
||||
BASIC_FACTORY(ProfilesPageViewModel);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "ProfileViewModel.idl";
|
||||
import "ColorSchemeViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass ProfilesPageViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
ProfilesPageViewModel();
|
||||
|
||||
Windows.Foundation.Collections.IObservableVector<ProfileViewModel> Profiles { get; };
|
||||
|
||||
void RequestOpenDefaults();
|
||||
void RequestOpenColorSchemes();
|
||||
void RequestAddProfile();
|
||||
void RequestOpenProfile(ProfileViewModel profile);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, IInspectable> OpenDefaultsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, IInspectable> OpenColorSchemesRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, IInspectable> AddProfileRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ProfileViewModel> OpenProfileRequested;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass Profiles : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
Profiles();
|
||||
ProfilesPageViewModel ViewModel { get; };
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="CommonResources.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<DataTemplate x:Key="ProfileNavigatorTemplate"
|
||||
x:DataType="local:ProfileViewModel">
|
||||
<Button HorizontalAlignment="Stretch"
|
||||
AutomationProperties.HelpText="{x:Bind AccessibleStateDescription, Mode=OneWay}"
|
||||
AutomationProperties.Name="{x:Bind Name, Mode=OneWay}"
|
||||
Click="Profile_Click"
|
||||
Style="{StaticResource NavigatorButtonStyle}">
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
VerticalAlignment="Center"
|
||||
Content="{x:Bind IconPreview, Mode=OneWay}"
|
||||
IsTabStop="False" />
|
||||
<TextBlock Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<muxc:InfoBadge x:Uid="Profile_HiddenBadge"
|
||||
Grid.Column="2"
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind Hidden, Mode=OneWay}">
|
||||
<muxc:InfoBadge.IconSource>
|
||||
<muxc:FontIconSource FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
</muxc:InfoBadge.IconSource>
|
||||
</muxc:InfoBadge>
|
||||
<muxc:InfoBadge x:Uid="Profile_OrphanedBadge"
|
||||
Grid.Column="2"
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind Orphaned, Mode=OneWay}">
|
||||
<muxc:InfoBadge.IconSource>
|
||||
<muxc:FontIconSource FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
</muxc:InfoBadge.IconSource>
|
||||
</muxc:InfoBadge>
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}"
|
||||
XYFocusKeyboardNavigation="Enabled">
|
||||
|
||||
<!-- General Profile Settings -->
|
||||
<TextBlock x:Uid="Profiles_GeneralSettingsHeader"
|
||||
Margin="0,0,0,4"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Defaults navigator -->
|
||||
<Button x:Name="DefaultsNavigator"
|
||||
Click="Defaults_Click"
|
||||
Style="{StaticResource NavigatorButtonStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock x:Uid="Profiles_DefaultsNavigator_Title" />
|
||||
<TextBlock x:Uid="Profiles_DefaultsNavigator_Description"
|
||||
Margin="0,2,0,0"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Color schemes navigator -->
|
||||
<Button x:Name="ColorSchemesNavigator"
|
||||
Click="ColorSchemes_Click"
|
||||
Style="{StaticResource NavigatorButtonStyle}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock x:Uid="Profiles_ColorSchemesNavigator_Title" />
|
||||
<TextBlock x:Uid="Profiles_ColorSchemesNavigator_Description"
|
||||
Margin="0,2,0,0"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Terminal profiles section -->
|
||||
<TextBlock x:Uid="Profiles_TerminalProfilesHeader"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Add Profile accent button -->
|
||||
<Button x:Name="AddProfileButton"
|
||||
Margin="0,4,0,0"
|
||||
Click="AddProfile_Click"
|
||||
Style="{StaticResource AccentButtonStyle}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="Profiles_AddProfileButton"
|
||||
Style="{StaticResource IconButtonTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- List of profiles. Each is a NavigatorButtonStyle button rendered by ProfileNavigatorTemplate. -->
|
||||
<ItemsControl Margin="0,0,0,16"
|
||||
IsTabStop="False"
|
||||
ItemTemplate="{StaticResource ProfileNavigatorTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.Profiles, Mode=OneWay}"
|
||||
XYFocusKeyboardNavigation="Enabled">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Page>
|
||||
@@ -1101,10 +1101,6 @@
|
||||
<value>If enabled, the profile will not appear in the list of profiles. This can be used to hide default profiles and dynamically generated profiles, while leaving them in your settings file.</value>
|
||||
<comment>A description for what the "hidden" setting does. Presented near "Profile_Hidden".</comment>
|
||||
</data>
|
||||
<data name="Profile_HiddenBadge.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Hidden from the dropdown menu</value>
|
||||
<comment>Tooltip shown when hovering the InfoBadge next to a profile name on the Profiles landing page when that profile is hidden from the dropdown menu.</comment>
|
||||
</data>
|
||||
<data name="Profile_Elevate.Header" xml:space="preserve">
|
||||
<value>Run this profile as Administrator</value>
|
||||
<comment>Header for a control to toggle whether the profile should always open elevated (in an admin window)</comment>
|
||||
@@ -1295,39 +1291,7 @@
|
||||
</data>
|
||||
<data name="Nav_Profiles.Content" xml:space="preserve">
|
||||
<value>Profiles</value>
|
||||
<comment>Header for the "profiles" menu item. Navigates to a landing page that lists profile-related settings (defaults, color schemes, the list of terminal profiles, and the add-profile button).</comment>
|
||||
</data>
|
||||
<data name="Nav_Profiles.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Profiles</value>
|
||||
<comment>Tooltip for the "profiles" menu item. Navigates to a landing page that lists profile-related settings.</comment>
|
||||
</data>
|
||||
<data name="Profiles_GeneralSettingsHeader.Text" xml:space="preserve">
|
||||
<value>General Profile Settings</value>
|
||||
<comment>Section header on the Profiles landing page. Introduces general-purpose profile settings such as the defaults shared by all profiles and the color schemes that profiles can use.</comment>
|
||||
</data>
|
||||
<data name="Profiles_TerminalProfilesHeader.Text" xml:space="preserve">
|
||||
<value>Terminal profiles</value>
|
||||
<comment>Section header on the Profiles landing page. Introduces the list of individual terminal profiles configured by the user.</comment>
|
||||
</data>
|
||||
<data name="Profiles_DefaultsNavigator_Title.Text" xml:space="preserve">
|
||||
<value>Defaults</value>
|
||||
<comment>Title for the "Defaults" navigator on the Profiles landing page. Clicking this opens the page where defaults shared by all profiles can be edited.</comment>
|
||||
</data>
|
||||
<data name="Profiles_DefaultsNavigator_Description.Text" xml:space="preserve">
|
||||
<value>Changes made here apply to all profiles unless overridden by a specific profile. These settings do not affect the Windows Terminal appearance.</value>
|
||||
<comment>Help text describing the "Defaults" navigator on the Profiles landing page. Clarifies that the defaults apply to every profile but are not the same as the global Windows Terminal appearance settings.</comment>
|
||||
</data>
|
||||
<data name="Profiles_ColorSchemesNavigator_Title.Text" xml:space="preserve">
|
||||
<value>Color schemes</value>
|
||||
<comment>Title for the "Color schemes" navigator on the Profiles landing page. Clicking this opens the same page reachable from the top-level Color schemes nav item.</comment>
|
||||
</data>
|
||||
<data name="Profiles_ColorSchemesNavigator_Description.Text" xml:space="preserve">
|
||||
<value>Add, edit, or remove the color schemes that your profiles can use.</value>
|
||||
<comment>Help text describing the "Color schemes" navigator on the Profiles landing page.</comment>
|
||||
</data>
|
||||
<data name="Profiles_AddProfileButton.Text" xml:space="preserve">
|
||||
<value>Add a new profile</value>
|
||||
<comment>Text on the accent-colored button on the Profiles landing page. Clicking this opens the page where users can add a new profile.</comment>
|
||||
<comment>Header for the "profiles" menu items. This acts as a divider to introduce profile-related menu items.</comment>
|
||||
</data>
|
||||
<data name="Globals_LaunchModeFocus.Content" xml:space="preserve">
|
||||
<value>Focus</value>
|
||||
@@ -2691,10 +2655,6 @@
|
||||
<data name="Profile_Delete_Orphaned.HelpText" xml:space="preserve">
|
||||
<value>This automatically-detected profile appears to have been uninstalled. Changes you have made to it are preserved, but it cannot be used until it has been reinstalled.</value>
|
||||
</data>
|
||||
<data name="Profile_OrphanedBadge.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Profile is no longer detected</value>
|
||||
<comment>Tooltip shown when hovering the InfoBadge next to a profile name on the Profiles landing page when that profile's source software is no longer installed.</comment>
|
||||
</data>
|
||||
<data name="Profile_Source_Orphaned.Header" xml:space="preserve">
|
||||
<value>Original Source</value>
|
||||
</data>
|
||||
|
||||
@@ -2201,10 +2201,26 @@
|
||||
<value>关闭多个选项卡时发出警告</value>
|
||||
<comment>Header for a control to toggle whether to show a confirm dialog box when closing the application with multiple tabs open.</comment>
|
||||
</data>
|
||||
<data name="Globals_ConfirmOnClose.Header" xml:space="preserve">
|
||||
<value>关闭时发出警告</value>
|
||||
<comment>Header for a dropdown controlling when to show a confirmation dialog before closing.</comment>
|
||||
</data>
|
||||
<data name="Globals_ConfirmOnClose.HelpText" xml:space="preserve">
|
||||
<value>控制在关闭选项卡或窗口之前何时显示确认对话框。“始终”在关闭任何窗格时显示对话框。</value>
|
||||
<comment>Help text associated with Globals_ConfirmOnClose. "Always" refers to Globals_ConfirmOnCloseAlways.Content.</comment>
|
||||
</data>
|
||||
<data name="Globals_ConfirmOnCloseNever.Content" xml:space="preserve">
|
||||
<value>从不</value>
|
||||
<comment>Option associated with Globals_ConfirmOnClose. "Never" means that the system will never display a warning when closing.</comment>
|
||||
</data>
|
||||
<data name="Globals_ConfirmOnCloseAlways.Content" xml:space="preserve">
|
||||
<value>始终</value>
|
||||
<comment>Option associated with Globals_ConfirmOnClose. "Always" means that the system will always display a warning when closing.</comment>
|
||||
</data>
|
||||
<data name="Globals_ConfirmOnCloseAutomatic.Content" xml:space="preserve">
|
||||
<value>多个选项卡或窗格</value>
|
||||
<comment>Option associated with Globals_ConfirmOnClose. The system will display a warning when multiple tabs or panes are present.</comment>
|
||||
</data>
|
||||
<data name="Globals_InputServiceWarning.Header" xml:space="preserve">
|
||||
<value>禁用“触摸键盘和手写面板服务”时发出警告</value>
|
||||
</data>
|
||||
|
||||
@@ -66,13 +66,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
hstring runtimeObjContext{};
|
||||
if (const auto profileVM = runtimeObj.try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
// No runtimeObjContext: profile name and icon should be enough
|
||||
runtimeObjLabel = profileVM.Name();
|
||||
runtimeObjContext = RS_(L"Nav_Profiles/Content");
|
||||
}
|
||||
else if (const auto colorSchemeVM = runtimeObj.try_as<Editor::ColorSchemeViewModel>())
|
||||
{
|
||||
// No runtimeObjContext: scheme name and generic icon should be enough
|
||||
runtimeObjLabel = colorSchemeVM.Name();
|
||||
runtimeObjContext = RS_(L"Nav_ColorSchemes/Content");
|
||||
}
|
||||
else if (const auto ntmFolderEntryVM = runtimeObj.try_as<Editor::FolderEntryViewModel>())
|
||||
{
|
||||
@@ -258,10 +258,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
localizedEntry.DisplayTextNeutral = EnglishOnlyResourceLoader().GetLocalizedString(entry.ResourceName);
|
||||
}
|
||||
if (!entry.SecondaryLabelResourceName.empty())
|
||||
{
|
||||
localizedEntry.SecondaryLabelLocalized = GetLibraryResourceString(entry.SecondaryLabelResourceName);
|
||||
}
|
||||
localizedIndex.emplace_back(std::move(localizedEntry));
|
||||
}
|
||||
return localizedIndex;
|
||||
@@ -346,7 +342,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
if (bestScore >= MinimumMatchScore)
|
||||
{
|
||||
scoredResults.emplace_back(bestScore, winrt::make<FilteredSearchResult>(index, &entry, nullptr, std::nullopt, entry.SecondaryLabelLocalized));
|
||||
scoredResults.emplace_back(bestScore, winrt::make<FilteredSearchResult>(index, &entry));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
winrt::hstring DisplayTextLocalized;
|
||||
std::optional<winrt::hstring> DisplayTextNeutral = std::nullopt;
|
||||
// No "Neutral" copy of SecondaryLabelLocalized: unlike DisplayText, the secondary
|
||||
// label is display-only (rendered in the search result row's caption). It is never
|
||||
// passed to the fuzzy matcher, so a single localized string is sufficient.
|
||||
winrt::hstring SecondaryLabelLocalized;
|
||||
const IndexEntry* Entry = nullptr;
|
||||
|
||||
std::array<std::pair<std::optional<winrt::hstring>, int>, 2> GetSearchableFields() const;
|
||||
|
||||
@@ -57,6 +57,7 @@ static constexpr std::string_view SuggestionsKey{ "showSuggestions" };
|
||||
static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" };
|
||||
static constexpr std::string_view SetFocusModeKey{ "setFocusMode" };
|
||||
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
|
||||
static constexpr std::string_view ToggleOverviewKey{ "toggleOverview" };
|
||||
static constexpr std::string_view SetFullScreenKey{ "setFullScreen" };
|
||||
static constexpr std::string_view SetMaximizedKey{ "setMaximized" };
|
||||
static constexpr std::string_view TogglePaneZoomKey{ "togglePaneZoom" };
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
ON_ALL_ACTIONS(ToggleShaderEffects) \
|
||||
ON_ALL_ACTIONS(ToggleFocusMode) \
|
||||
ON_ALL_ACTIONS(ToggleFullscreen) \
|
||||
ON_ALL_ACTIONS(ToggleOverview) \
|
||||
ON_ALL_ACTIONS(ToggleAlwaysOnTop) \
|
||||
ON_ALL_ACTIONS(OpenSettings) \
|
||||
ON_ALL_ACTIONS(SetFocusMode) \
|
||||
|
||||
@@ -102,6 +102,14 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||
globals->_DisabledProfileSources->Append(src);
|
||||
}
|
||||
}
|
||||
if (_SafeUriSchemes)
|
||||
{
|
||||
globals->_SafeUriSchemes = winrt::single_threaded_vector<hstring>();
|
||||
for (const auto& src : *_SafeUriSchemes)
|
||||
{
|
||||
globals->_SafeUriSchemes->Append(src);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& parent : _parents)
|
||||
{
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_SETTING(Boolean, EnableUnfocusedAcrylic);
|
||||
INHERITABLE_SETTING(Boolean, AllowHeadless);
|
||||
INHERITABLE_SETTING(String, SearchWebDefaultQueryUrl);
|
||||
INHERITABLE_SETTING(IVector<String>, SafeUriSchemes);
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
||||
void AddColorScheme(ColorScheme scheme);
|
||||
|
||||
@@ -63,6 +63,7 @@ Author(s):
|
||||
X(bool, MinimizeToNotificationArea, "minimizeToNotificationArea", false) \
|
||||
X(bool, AlwaysShowNotificationIcon, "alwaysShowNotificationIcon", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, SafeUriSchemes, "safeUriSchemes", nullptr) \
|
||||
X(bool, ShowAdminShield, "showAdminShield", true) \
|
||||
X(bool, TrimPaste, "trimPaste", true) \
|
||||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
|
||||
@@ -466,6 +466,9 @@
|
||||
<value>Toggle focus mode</value>
|
||||
<comment>"Focus mode" is a mode with minimal UI elements, for a distraction-free experience</comment>
|
||||
</data>
|
||||
<data name="ToggleOverviewCommandKey" xml:space="preserve">
|
||||
<value>Toggle overview mode</value>
|
||||
</data>
|
||||
<data name="EnableFocusModeCommandKey" xml:space="preserve">
|
||||
<value>Enable focus mode</value>
|
||||
</data>
|
||||
|
||||
@@ -517,6 +517,7 @@
|
||||
{ "command": "closeWindow", "id": "Terminal.CloseWindow" },
|
||||
{ "command": "toggleFullscreen", "id": "Terminal.ToggleFullscreen" },
|
||||
{ "command": "toggleFocusMode", "id": "Terminal.ToggleFocusMode" },
|
||||
{ "command": "toggleOverview", "id": "Terminal.ToggleOverview" },
|
||||
{ "command": "toggleAlwaysOnTop", "id": "Terminal.ToggleAlwaysOnTop" },
|
||||
{ "command": "openNewTabDropdown", "id": "Terminal.OpenNewTabDropdown" },
|
||||
{ "command": { "action": "openSettings", "target": "settingsUI" }, "id": "Terminal.OpenSettingsUI" },
|
||||
|
||||
@@ -467,6 +467,7 @@ namespace SettingsModelUnitTests
|
||||
"$schema" : "https://aka.ms/terminal-profiles-schema",
|
||||
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
|
||||
"safeUriSchemes": [ "vscode" ],
|
||||
"newTabMenu":
|
||||
[
|
||||
{
|
||||
|
||||
@@ -123,6 +123,7 @@ class ScreenBufferTests
|
||||
TEST_METHOD(VtResizePreservingAttributes);
|
||||
|
||||
TEST_METHOD(VtSoftResetCursorPosition);
|
||||
TEST_METHOD(VtSoftResetAltBufferCursorState);
|
||||
|
||||
TEST_METHOD(VtScrollMarginsNewlineColor);
|
||||
|
||||
@@ -1510,6 +1511,30 @@ void ScreenBufferTests::VtSoftResetCursorPosition()
|
||||
VERIFY_ARE_EQUAL(til::point(1, 1), cursor.GetPosition());
|
||||
}
|
||||
|
||||
void ScreenBufferTests::VtSoftResetAltBufferCursorState()
|
||||
{
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.LockConsole(); // Lock must be taken to manipulate buffer.
|
||||
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
|
||||
|
||||
auto& si = gci.GetActiveOutputBuffer();
|
||||
auto& stateMachine = si.GetStateMachine();
|
||||
|
||||
Log::Comment(L"Move cursor on the main buffer.");
|
||||
stateMachine.ProcessString(L"\x1b[4;7H");
|
||||
VERIFY_ARE_EQUAL(til::point(6, 3), si.GetTextBuffer().GetCursor().GetPosition());
|
||||
|
||||
Log::Comment(L"Enter alt buffer, soft reset, and return to main buffer.");
|
||||
stateMachine.ProcessString(L"\x1b[?1049h");
|
||||
VERIFY_IS_TRUE(gci.GetActiveOutputBuffer()._IsAltBuffer());
|
||||
stateMachine.ProcessString(L"\x1b[!p");
|
||||
stateMachine.ProcessString(L"\x1b[?1049l");
|
||||
VERIFY_IS_FALSE(gci.GetActiveOutputBuffer()._IsAltBuffer());
|
||||
|
||||
Log::Comment(L"Returning from alt buffer should restore the main cursor position.");
|
||||
VERIFY_ARE_EQUAL(til::point(6, 3), gci.GetActiveOutputBuffer().GetTextBuffer().GetCursor().GetPosition());
|
||||
}
|
||||
|
||||
void ScreenBufferTests::VtScrollMarginsNewlineColor()
|
||||
{
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
|
||||
@@ -90,7 +90,15 @@ std::function<bool(wchar_t)> SixelParser::DefineImage(const VTInt macroParameter
|
||||
_state = States::Normal;
|
||||
_parameters.clear();
|
||||
return [&](const auto ch) {
|
||||
_parseCommandChar(ch);
|
||||
try
|
||||
{
|
||||
_parseCommandChar(ch);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Ignore all further content.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
@@ -234,10 +242,18 @@ void SixelParser::_executeNextLine()
|
||||
_executeCarriageReturn();
|
||||
_imageLineCount++;
|
||||
_maybeFlushImageBuffer();
|
||||
_imageCursor.y += _sixelHeight;
|
||||
_availablePixelHeight -= _sixelHeight;
|
||||
_resizeImageBuffer(_sixelHeight);
|
||||
_fillImageBackgroundWhenScrolled();
|
||||
// If we don't have any available pixel height, that means the image has
|
||||
// extended beyond the bottom of the display and we haven't triggered a
|
||||
// a scroll (because sixel display mode is enabled). In this state, there
|
||||
// is no point in extending the image any further, because the additional
|
||||
// content will never be seen, so we'll just be wasting memory.
|
||||
if (_availablePixelHeight > 0)
|
||||
{
|
||||
_imageCursor.y += _sixelHeight;
|
||||
_availablePixelHeight -= _sixelHeight;
|
||||
_resizeImageBuffer(_sixelHeight);
|
||||
_fillImageBackgroundWhenScrolled();
|
||||
}
|
||||
}
|
||||
|
||||
void SixelParser::_executeMoveToHome()
|
||||
|
||||
@@ -3002,17 +3002,15 @@ void AdaptDispatch::SoftReset()
|
||||
SetGraphicsRendition({}); // Normal rendition.
|
||||
SetCharacterProtectionAttribute({}); // Default (unprotected)
|
||||
|
||||
// Reset the saved cursor state.
|
||||
// Note that XTerm only resets the main buffer state, but that
|
||||
// seems likely to be a bug. Most other terminals reset both.
|
||||
_savedCursorState.at(0) = {}; // Main buffer
|
||||
_savedCursorState.at(1) = {}; // Alt buffer
|
||||
// Reset only the active saved cursor state.
|
||||
// This matches xterm behavior when DECSTR is processed while using
|
||||
// the alternate screen buffer (GH#19918).
|
||||
_savedCursorState.at(_usingAltBuffer ? 1 : 0) = {};
|
||||
|
||||
// The TerminalOutput state in these buffers must be reset to
|
||||
// The TerminalOutput state in this buffer must be reset to
|
||||
// the same state as the _termOutput instance, which is not
|
||||
// necessarily equivalent to a full reset.
|
||||
_savedCursorState.at(0).TermOutput = _termOutput;
|
||||
_savedCursorState.at(1).TermOutput = _termOutput;
|
||||
_savedCursorState.at(_usingAltBuffer ? 1 : 0).TermOutput = _termOutput;
|
||||
|
||||
// Soft reset the Sixel parser if in use.
|
||||
if (_sixelParser)
|
||||
|
||||
@@ -85,7 +85,6 @@ $ClassMap = @{
|
||||
ResourceName = "Nav_ProfileDefaults/Content"
|
||||
NavigationParam = "GlobalProfile_Nav"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
SecondaryLabel = "Nav_Profiles/Content"
|
||||
}
|
||||
"Microsoft::Terminal::Settings::Editor::Profiles_Appearance" = @{
|
||||
ResourceName = "Nav_ProfileDefaults/Content"
|
||||
@@ -106,12 +105,6 @@ $ClassMap = @{
|
||||
ResourceName = "Nav_AddNewProfile/Content"
|
||||
NavigationParam = "AddProfile"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
SecondaryLabel = "Nav_Profiles/Content"
|
||||
}
|
||||
"Microsoft::Terminal::Settings::Editor::Profiles" = @{
|
||||
ResourceName = "Nav_Profiles/Content"
|
||||
NavigationParam = "Profiles_Nav"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +156,6 @@ foreach ($xamlFile in Get-ChildItem -Path $SourceDir -Filter *.xaml)
|
||||
NavigationParam = $ClassMap[$pageClass].NavigationParam
|
||||
SubPage = $ClassMap[$pageClass].SubPage
|
||||
ElementName = $null # No specific element to navigate to, for the page itself
|
||||
SecondaryLabel = $ClassMap[$pageClass].SecondaryLabel # Resource name for the result's sub-text (i.e. parent page name); $null if none
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
@@ -197,7 +189,6 @@ foreach ($xamlFile in Get-ChildItem -Path $SourceDir -Filter *.xaml)
|
||||
NavigationParam = $ClassMap[$pageClass].NavigationParam
|
||||
SubPage = $ClassMap[$pageClass].SubPage
|
||||
ElementName = "AddNewButton"
|
||||
SecondaryLabel = $ClassMap[$pageClass].SecondaryLabel
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
@@ -294,9 +285,8 @@ function FormatEntry($e)
|
||||
$formattedResourceName = 'USES_RESOURCE(L"{0}")' -f $e.ResourceName
|
||||
$formattedNavigationParam = 'L"{0}"' -f $e.NavigationParam # null Navigation param resolves to empty string
|
||||
$formattedElementName = 'L"{0}"' -f $e.ElementName
|
||||
$formattedSecondaryLabel = [string]::IsNullOrEmpty($e.SecondaryLabel) ? 'L""' : ('USES_RESOURCE(L"{0}")' -f $e.SecondaryLabel)
|
||||
|
||||
return " IndexEntry{{ {0}, {1}, {2}, {3}, {4} }}, // {5}" -f ($formattedResourceName, $formattedNavigationParam, $e.SubPage, $formattedElementName, $formattedSecondaryLabel, $e.File)
|
||||
return " IndexEntry{{ {0}, {1}, {2}, {3} }}, // {4}" -f ($formattedResourceName, $formattedNavigationParam, $e.SubPage, $formattedElementName, $e.File)
|
||||
}
|
||||
|
||||
function FormatEntries($es) {
|
||||
@@ -304,7 +294,7 @@ function FormatEntries($es) {
|
||||
}
|
||||
|
||||
# Sort and remove duplicates
|
||||
$entries = $entries | Sort-Object ResourceName, ParentPage, NavigationParam, SubPage, ElementName, SecondaryLabel, File -Unique
|
||||
$entries = $entries | Sort-Object ResourceName, ParentPage, NavigationParam, SubPage, ElementName, File -Unique
|
||||
|
||||
$buildTimeEntries = @()
|
||||
$profileEntries = @()
|
||||
@@ -360,11 +350,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
// x:Name of the SettingContainer to navigate to on the page (i.e. "DefaultProfile")
|
||||
wil::zwstring_view ElementName;
|
||||
|
||||
// Resource name of the search result's secondary label (i.e. parent page name like "Nav_Profiles/Content").
|
||||
// Empty if the entry has no secondary label.
|
||||
// NOTE: wrapped in USES_RESOURCE() like ResourceName when non-empty.
|
||||
wil::zwstring_view SecondaryLabelResourceName;
|
||||
};
|
||||
|
||||
const std::array<IndexEntry, $($buildTimeEntries.Count)>& LoadBuildTimeIndex();
|
||||
|
||||
Reference in New Issue
Block a user