Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/cascadia/TerminalSettingsEditor/Appearances.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
CurrentValueAccessibleName="{x:Bind Appearance.CurrentColorScheme.Name, Mode=OneWay}"
HasSettingValue="{x:Bind Appearance.HasDarkColorSchemeName, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.DarkColorSchemeNameOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
Style="{StaticResource ExpanderSettingContainerStyle}">
<local:SettingContainer.CurrentValue>
<ComboBox Padding="4"
ItemsSource="{x:Bind Appearance.SchemesList, Mode=OneWay}"
Expand Down Expand Up @@ -220,7 +220,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasForeground, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.ForegroundOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
Style="{StaticResource ExpanderSettingContainerStyle}">
<local:NullableColorPicker x:Uid="Profile_Foreground_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.Foreground, Mode=TwoWay}"
Expand All @@ -236,7 +236,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasBackground, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.BackgroundOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
Style="{StaticResource ExpanderSettingContainerStyle}">
<local:NullableColorPicker x:Uid="Profile_Background_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.Background, Mode=TwoWay}"
Expand All @@ -252,7 +252,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasSelectionBackground, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.SelectionBackgroundOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
Style="{StaticResource ExpanderSettingContainerStyle}">
<local:NullableColorPicker x:Uid="Profile_SelectionBackground_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.SelectionBackground, Mode=TwoWay}"
Expand Down Expand Up @@ -536,7 +536,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasCursorColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.CursorColorOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
Style="{StaticResource ExpanderSettingContainerStyle}">
<local:NullableColorPicker x:Uid="Profile_CursorColor_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.CursorColor, Mode=TwoWay}"
Expand Down
84 changes: 2 additions & 82 deletions src/cascadia/TerminalSettingsEditor/CommonResources.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
xmlns:mtu="using:Microsoft.Terminal.UI"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">

<!-- Merge SettingContainerStyle here to give every page access to the SettingContainer -->
<!-- Merge SettingsControls and SettingContainer styles here to give every page access to them -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SettingsControlsStyle.xaml" />
<ResourceDictionary Source="SettingContainerStyle.xaml" />
</ResourceDictionary.MergedDictionaries>

Expand Down Expand Up @@ -1200,87 +1201,6 @@
</Setter>
</Style>

<Style x:Key="NavigatorButtonStyle"
TargetType="Button">
<Setter Property="Background" Value="{ThemeResource ExpanderHeaderBackground}" />
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />
<Setter Property="Padding" Value="16,0,8,0" />
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="Grid"
Padding="{TemplateBinding Padding}"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="ContentPresenter"
Grid.Column="0"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<FontIcon Grid.Column="1"
Margin="20,0,8,0"
HorizontalAlignment="Right"
FontSize="10"
FontWeight="Black"
Glyph="&#xE76C;" />

<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="NewInfoBadge"
TargetType="muxc:InfoBadge">
<Setter Property="Padding" Value="5,1,5,2" />
Expand Down
139 changes: 139 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ControlSizeTrigger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "ControlSizeTrigger.h"
#include "ControlSizeTrigger.g.cpp"

#include <limits>

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DependencyProperty ControlSizeTrigger::_CanTriggerProperty{ nullptr };
DependencyProperty ControlSizeTrigger::_MinWidthProperty{ nullptr };
DependencyProperty ControlSizeTrigger::_MaxWidthProperty{ nullptr };
DependencyProperty ControlSizeTrigger::_MinHeightProperty{ nullptr };
DependencyProperty ControlSizeTrigger::_MaxHeightProperty{ nullptr };
DependencyProperty ControlSizeTrigger::_TargetElementProperty{ nullptr };

ControlSizeTrigger::ControlSizeTrigger()
{
_InitializeProperties();
}

void ControlSizeTrigger::_InitializeProperties()
{
// Defaults mirror the toolkit: trigger is always evaluatable, bounds
// are wide open, no target element until one is bound.
if (!_CanTriggerProperty)
{
_CanTriggerProperty = DependencyProperty::Register(
L"CanTrigger",
xaml_typename<bool>(),
xaml_typename<Editor::ControlSizeTrigger>(),
PropertyMetadata{ box_value(true), PropertyChangedCallback{ &ControlSizeTrigger::_OnTriggerInputChanged } });
}
if (!_MinWidthProperty)
{
_MinWidthProperty = DependencyProperty::Register(
L"MinWidth",
xaml_typename<double>(),
xaml_typename<Editor::ControlSizeTrigger>(),
PropertyMetadata{ box_value(0.0), PropertyChangedCallback{ &ControlSizeTrigger::_OnTriggerInputChanged } });
}
if (!_MaxWidthProperty)
{
_MaxWidthProperty = DependencyProperty::Register(
L"MaxWidth",
xaml_typename<double>(),
xaml_typename<Editor::ControlSizeTrigger>(),
PropertyMetadata{ box_value(std::numeric_limits<double>::infinity()), PropertyChangedCallback{ &ControlSizeTrigger::_OnTriggerInputChanged } });
}
if (!_MinHeightProperty)
{
_MinHeightProperty = DependencyProperty::Register(
L"MinHeight",
xaml_typename<double>(),
xaml_typename<Editor::ControlSizeTrigger>(),
PropertyMetadata{ box_value(0.0), PropertyChangedCallback{ &ControlSizeTrigger::_OnTriggerInputChanged } });
}
if (!_MaxHeightProperty)
{
_MaxHeightProperty = DependencyProperty::Register(
L"MaxHeight",
xaml_typename<double>(),
xaml_typename<Editor::ControlSizeTrigger>(),
PropertyMetadata{ box_value(std::numeric_limits<double>::infinity()), PropertyChangedCallback{ &ControlSizeTrigger::_OnTriggerInputChanged } });
}
if (!_TargetElementProperty)
{
_TargetElementProperty = DependencyProperty::Register(
L"TargetElement",
xaml_typename<FrameworkElement>(),
xaml_typename<Editor::ControlSizeTrigger>(),
PropertyMetadata{ nullptr, PropertyChangedCallback{ &ControlSizeTrigger::_OnTargetElementChanged } });
}
}

void ControlSizeTrigger::_OnTriggerInputChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
if (const auto obj{ d.try_as<Editor::ControlSizeTrigger>() })
{
get_self<ControlSizeTrigger>(obj)->_UpdateTrigger();
}
}

void ControlSizeTrigger::_OnTargetElementChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& e)
{
const auto obj{ d.try_as<Editor::ControlSizeTrigger>() };
if (!obj)
{
return;
}
const auto oldElement = e.OldValue().try_as<FrameworkElement>();
const auto newElement = e.NewValue().try_as<FrameworkElement>();
get_self<ControlSizeTrigger>(obj)->_UpdateTargetElement(oldElement, newElement);
}

void ControlSizeTrigger::_UpdateTargetElement(const FrameworkElement& /*oldValue*/, const FrameworkElement& newValue)
{
// Revoking handles both unhooking the previous element and a null `newValue`.
_sizeChangedRevoker.revoke();
if (newValue)
{
_sizeChangedRevoker = newValue.SizeChanged(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_UpdateTrigger();
}
});
}
_UpdateTrigger();
}

void ControlSizeTrigger::_UpdateTrigger()
{
const auto target = TargetElement();
if (!target || !CanTrigger())
{
_isActive = false;
SetActive(false);
return;
}

const auto width = target.ActualWidth();
const auto height = target.ActualHeight();

const bool activate =
MinWidth() <= width &&
width < MaxWidth() &&
MinHeight() <= height &&
height < MaxHeight();

_isActive = activate;
SetActive(activate);
}
}
64 changes: 64 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ControlSizeTrigger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.

Module Name:
- ControlSizeTrigger

Abstract:
- A conditional state trigger that activates based on the size (width and/or
height) of a target FrameworkElement. Lets XAML visual states swap based on
the live size of a templated part. Ported from the Windows Community Toolkit
primitive `CommunityToolkit.WinUI.ControlSizeTrigger`.

The trigger is "active" when:
MinWidth <= TargetElement.ActualWidth < MaxWidth AND
MinHeight <= TargetElement.ActualHeight < MaxHeight

Defaults: MinWidth = MinHeight = 0; MaxWidth = MaxHeight = +inf, which makes
the trigger always active unless `CanTrigger` is false or `TargetElement` is
null.

Author(s):
- Carlos Zamora - May 2026 (port from CommunityToolkit.WinUI.ControlSizeTrigger)

--*/

#pragma once

#include "ControlSizeTrigger.g.h"
#include "Utils.h"

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct ControlSizeTrigger : ControlSizeTriggerT<ControlSizeTrigger>
{
public:
ControlSizeTrigger();

bool IsActive() const { return _isActive; }

DEPENDENCY_PROPERTY(bool, CanTrigger);
DEPENDENCY_PROPERTY(double, MinWidth);
DEPENDENCY_PROPERTY(double, MaxWidth);
DEPENDENCY_PROPERTY(double, MinHeight);
DEPENDENCY_PROPERTY(double, MaxHeight);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::FrameworkElement, TargetElement);

private:
static void _InitializeProperties();
static void _OnTriggerInputChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnTargetElementChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);

void _UpdateTargetElement(const Windows::UI::Xaml::FrameworkElement& oldValue, const Windows::UI::Xaml::FrameworkElement& newValue);
void _UpdateTrigger();

Windows::UI::Xaml::FrameworkElement::SizeChanged_revoker _sizeChangedRevoker;
bool _isActive{ false };
};
}

namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(ControlSizeTrigger);
}
30 changes: 30 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ControlSizeTrigger.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass ControlSizeTrigger : Windows.UI.Xaml.StateTriggerBase
{
ControlSizeTrigger();

Boolean CanTrigger;
static Windows.UI.Xaml.DependencyProperty CanTriggerProperty { get; };

Double MinWidth;
static Windows.UI.Xaml.DependencyProperty MinWidthProperty { get; };

Double MaxWidth;
static Windows.UI.Xaml.DependencyProperty MaxWidthProperty { get; };

Double MinHeight;
static Windows.UI.Xaml.DependencyProperty MinHeightProperty { get; };

Double MaxHeight;
static Windows.UI.Xaml.DependencyProperty MaxHeightProperty { get; };

Windows.UI.Xaml.FrameworkElement TargetElement;
static Windows.UI.Xaml.DependencyProperty TargetElementProperty { get; };

Boolean IsActive { get; };
}
}
Loading
Loading