mirror of
https://github.com/microsoft/terminal.git
synced 2026-02-04 05:35:20 +00:00
PRE-MERGE #19591 Add IconPicker to New Tab Menu folders in SUI
This commit is contained in:
330
src/cascadia/TerminalSettingsEditor/IconPicker.cpp
Normal file
330
src/cascadia/TerminalSettingsEditor/IconPicker.cpp
Normal file
@@ -0,0 +1,330 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "IconPicker.h"
|
||||
#include "IconPicker.g.cpp"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include "SegoeFluentIconList.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "../WinRTUtils/inc/Utils.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::UI;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml::Media;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Microsoft::UI::Xaml::Controls;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
static constexpr std::wstring_view HideIconValue{ L"none" };
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> IconPicker::_BuiltInIcons{ nullptr };
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> IconPicker::_IconTypes{ nullptr };
|
||||
DependencyProperty IconPicker::_CurrentIconPathProperty{ nullptr };
|
||||
DependencyProperty IconPicker::_WindowRootProperty{ nullptr };
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> IconPicker::BuiltInIcons() noexcept
|
||||
{
|
||||
if (!_BuiltInIcons)
|
||||
{
|
||||
// lazy load the built-in icons
|
||||
std::vector<Editor::EnumEntry> builtInIcons;
|
||||
for (auto& [val, name] : s_SegoeFluentIcons)
|
||||
{
|
||||
builtInIcons.emplace_back(make<EnumEntry>(hstring{ name }, box_value(val)));
|
||||
}
|
||||
_BuiltInIcons = single_threaded_observable_vector<Editor::EnumEntry>(std::move(builtInIcons));
|
||||
}
|
||||
return _BuiltInIcons;
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> IconPicker::IconTypes() noexcept
|
||||
{
|
||||
if (!_IconTypes)
|
||||
{
|
||||
// lazy load the icon types
|
||||
std::vector<Editor::EnumEntry> iconTypes;
|
||||
iconTypes.reserve(4);
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"IconPicker_IconTypeNone"), box_value(IconType::None)));
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"IconPicker_IconTypeFontIcon"), box_value(IconType::FontIcon)));
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"IconPicker_IconTypeEmoji"), box_value(IconType::Emoji)));
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"IconPicker_IconTypeImage"), box_value(IconType::Image)));
|
||||
_IconTypes = winrt::single_threaded_observable_vector<Editor::EnumEntry>(std::move(iconTypes));
|
||||
}
|
||||
return _IconTypes;
|
||||
}
|
||||
|
||||
IconPicker::IconPicker()
|
||||
{
|
||||
_InitializeProperties();
|
||||
InitializeComponent();
|
||||
|
||||
_DeduceCurrentIconType();
|
||||
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
||||
const auto propertyName{ args.PropertyName() };
|
||||
// "CurrentIconPath" changes are handled by _OnCurrentIconPathChanged()
|
||||
if (propertyName == L"CurrentIconType")
|
||||
{
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"UsingNoIcon" });
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"UsingBuiltInIcon" });
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"UsingEmojiIcon" });
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"UsingImageIcon" });
|
||||
}
|
||||
else if (propertyName == L"CurrentBuiltInIcon")
|
||||
{
|
||||
CurrentIconPath(unbox_value<hstring>(_CurrentBuiltInIcon.EnumValue()));
|
||||
}
|
||||
else if (propertyName == L"CurrentEmojiIcon")
|
||||
{
|
||||
CurrentIconPath(CurrentEmojiIcon());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void IconPicker::_InitializeProperties()
|
||||
{
|
||||
// Initialize any dependency properties here.
|
||||
// This performs a lazy load on these properties, instead of
|
||||
// initializing them when the DLL loads.
|
||||
if (!_CurrentIconPathProperty)
|
||||
{
|
||||
_CurrentIconPathProperty =
|
||||
DependencyProperty::Register(
|
||||
L"CurrentIconPath",
|
||||
xaml_typename<hstring>(),
|
||||
xaml_typename<Editor::IconPicker>(),
|
||||
PropertyMetadata{ nullptr, PropertyChangedCallback{ &IconPicker::_OnCurrentIconPathChanged } });
|
||||
}
|
||||
if (!_WindowRootProperty)
|
||||
{
|
||||
_WindowRootProperty =
|
||||
DependencyProperty::Register(
|
||||
L"WindowRoot",
|
||||
xaml_typename<IHostedInWindow>(),
|
||||
xaml_typename<Editor::IconPicker>(),
|
||||
PropertyMetadata{ nullptr });
|
||||
}
|
||||
}
|
||||
|
||||
void IconPicker::_OnCurrentIconPathChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
|
||||
{
|
||||
d.as<IconPicker>()->_DeduceCurrentIconType();
|
||||
}
|
||||
|
||||
safe_void_coroutine IconPicker::Icon_Click(const IInspectable&, const RoutedEventArgs&)
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(WindowRoot().GetHostingWindow()) };
|
||||
auto file = co_await OpenImagePicker(parentHwnd);
|
||||
if (!file.empty())
|
||||
{
|
||||
CurrentIconPath(file);
|
||||
}
|
||||
}
|
||||
|
||||
void IconPicker::BuiltInIconPicker_GotFocus(const IInspectable& sender, const RoutedEventArgs& /*e*/)
|
||||
{
|
||||
_updateIconFilter({});
|
||||
sender.as<AutoSuggestBox>().IsSuggestionListOpen(true);
|
||||
}
|
||||
|
||||
void IconPicker::BuiltInIconPicker_QuerySubmitted(const AutoSuggestBox& /*sender*/, const AutoSuggestBoxQuerySubmittedEventArgs& e)
|
||||
{
|
||||
const auto iconEntry = unbox_value_or<Editor::EnumEntry>(e.ChosenSuggestion(), nullptr);
|
||||
if (!iconEntry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CurrentBuiltInIcon(iconEntry);
|
||||
}
|
||||
|
||||
void IconPicker::BuiltInIconPicker_TextChanged(const AutoSuggestBox& sender, const AutoSuggestBoxTextChangedEventArgs& e)
|
||||
{
|
||||
if (e.Reason() != AutoSuggestionBoxTextChangeReason::UserInput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::wstring_view filter{ sender.Text() };
|
||||
filter = til::trim(filter, L' ');
|
||||
_updateIconFilter(filter);
|
||||
}
|
||||
|
||||
void IconPicker::_updateIconFilter(std::wstring_view filter)
|
||||
{
|
||||
if (_iconFilter != filter)
|
||||
{
|
||||
_filteredBuiltInIcons = nullptr;
|
||||
_iconFilter = filter;
|
||||
_updateFilteredIconList();
|
||||
PropertyChanged.raise(*this, PropertyChangedEventArgs{ L"FilteredBuiltInIconList" });
|
||||
}
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> IconPicker::FilteredBuiltInIconList()
|
||||
{
|
||||
if (!_filteredBuiltInIcons)
|
||||
{
|
||||
_updateFilteredIconList();
|
||||
}
|
||||
return _filteredBuiltInIcons;
|
||||
}
|
||||
|
||||
void IconPicker::_updateFilteredIconList()
|
||||
{
|
||||
_filteredBuiltInIcons = BuiltInIcons();
|
||||
if (_iconFilter.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find matching icons and populate the filtered list
|
||||
std::vector<Editor::EnumEntry> filtered;
|
||||
filtered.reserve(_filteredBuiltInIcons.Size());
|
||||
for (const auto& icon : _filteredBuiltInIcons)
|
||||
{
|
||||
if (til::contains_linguistic_insensitive(icon.EnumName(), _iconFilter))
|
||||
{
|
||||
filtered.emplace_back(icon);
|
||||
}
|
||||
}
|
||||
_filteredBuiltInIcons = winrt::single_threaded_observable_vector(std::move(filtered));
|
||||
}
|
||||
|
||||
void IconPicker::CurrentIconType(const Windows::Foundation::IInspectable& value)
|
||||
{
|
||||
if (_currentIconType != value)
|
||||
{
|
||||
// Switching from...
|
||||
if (_currentIconType && unbox_value<IconType>(_currentIconType.as<Editor::EnumEntry>().EnumValue()) == IconType::Image)
|
||||
{
|
||||
// Stash the current value of Icon. If the user
|
||||
// switches out of then back to IconType::Image, we want
|
||||
// the path that we display in the text box to remain unchanged.
|
||||
_lastIconPath = CurrentIconPath();
|
||||
}
|
||||
|
||||
// Set the member here instead of after setting Icon() below!
|
||||
// We have an Icon property changed handler defined for when we discard changes.
|
||||
// Inadvertently, that means that we call this setter again.
|
||||
// Setting the member here means that we early exit at the beginning of the function
|
||||
// because _currentIconType == value.
|
||||
_currentIconType = value;
|
||||
|
||||
// Switched to...
|
||||
switch (unbox_value<IconType>(value.as<Editor::EnumEntry>().EnumValue()))
|
||||
{
|
||||
case IconType::None:
|
||||
{
|
||||
CurrentIconPath(winrt::hstring{ HideIconValue });
|
||||
break;
|
||||
}
|
||||
case IconType::Image:
|
||||
{
|
||||
if (!_lastIconPath.empty())
|
||||
{
|
||||
// Conversely, if we switch to Image,
|
||||
// retrieve that saved value and apply it
|
||||
CurrentIconPath(_lastIconPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IconType::FontIcon:
|
||||
{
|
||||
if (_CurrentBuiltInIcon)
|
||||
{
|
||||
CurrentIconPath(unbox_value<hstring>(_CurrentBuiltInIcon.EnumValue()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IconType::Emoji:
|
||||
{
|
||||
// Don't set Icon here!
|
||||
// Clear out the text box so we direct the user to use the emoji picker.
|
||||
CurrentEmojiIcon({});
|
||||
}
|
||||
}
|
||||
// We're not using the VM's Icon() setter above,
|
||||
// so notify HasIcon changed manually
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"CurrentIconType" });
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"HasIcon" });
|
||||
}
|
||||
}
|
||||
|
||||
bool IconPicker::UsingNoIcon() const
|
||||
{
|
||||
return _currentIconType == IconTypes().GetAt(0);
|
||||
}
|
||||
|
||||
bool IconPicker::UsingBuiltInIcon() const
|
||||
{
|
||||
return _currentIconType == IconTypes().GetAt(1);
|
||||
}
|
||||
|
||||
bool IconPicker::UsingEmojiIcon() const
|
||||
{
|
||||
return _currentIconType == IconTypes().GetAt(2);
|
||||
}
|
||||
|
||||
bool IconPicker::UsingImageIcon() const
|
||||
{
|
||||
return _currentIconType == IconTypes().GetAt(3);
|
||||
}
|
||||
|
||||
void IconPicker::_DeduceCurrentIconType()
|
||||
{
|
||||
const auto icon = CurrentIconPath();
|
||||
if (icon.empty() || icon == HideIconValue)
|
||||
{
|
||||
_currentIconType = IconTypes().GetAt(0);
|
||||
}
|
||||
else if (icon.size() == 1 && (L'\uE700' <= til::at(icon, 0) && til::at(icon, 0) <= L'\uF8B3'))
|
||||
{
|
||||
_currentIconType = IconTypes().GetAt(1);
|
||||
_DeduceCurrentBuiltInIcon();
|
||||
}
|
||||
else if (::Microsoft::Console::Utils::IsLikelyToBeEmojiOrSymbolIcon(icon))
|
||||
{
|
||||
// We already did a range check for MDL2 Assets in the previous one,
|
||||
// so if we're out of that range but still short, assume we're an emoji
|
||||
_currentIconType = IconTypes().GetAt(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentIconType = IconTypes().GetAt(3);
|
||||
}
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"CurrentIconType" });
|
||||
}
|
||||
|
||||
void IconPicker::_DeduceCurrentBuiltInIcon()
|
||||
{
|
||||
const auto icon = CurrentIconPath();
|
||||
for (uint32_t i = 0; i < BuiltInIcons().Size(); i++)
|
||||
{
|
||||
const auto& builtIn = BuiltInIcons().GetAt(i);
|
||||
if (icon == unbox_value<hstring>(builtIn.EnumValue()))
|
||||
{
|
||||
CurrentBuiltInIcon(builtIn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
CurrentBuiltInIcon(BuiltInIcons().GetAt(0));
|
||||
}
|
||||
|
||||
WUX::Controls::IconSource IconPicker::BuiltInIconConverter(const IInspectable& iconVal)
|
||||
{
|
||||
return Microsoft::Terminal::UI::IconPathConverter::IconSourceWUX(unbox_value<hstring>(iconVal));
|
||||
}
|
||||
}
|
||||
64
src/cascadia/TerminalSettingsEditor/IconPicker.h
Normal file
64
src/cascadia/TerminalSettingsEditor/IconPicker.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IconPicker.g.h"
|
||||
#include "EnumEntry.h"
|
||||
#include "Utils.h"
|
||||
#include "cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct IconPicker : public HasScrollViewer<IconPicker>, IconPickerT<IconPicker>
|
||||
{
|
||||
public:
|
||||
IconPicker();
|
||||
|
||||
static Windows::UI::Xaml::Controls::IconSource BuiltInIconConverter(const Windows::Foundation::IInspectable& iconVal);
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> BuiltInIcons() noexcept;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> IconTypes() noexcept;
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> FilteredBuiltInIconList();
|
||||
safe_void_coroutine Icon_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void BuiltInIconPicker_GotFocus(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void BuiltInIconPicker_TextChanged(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxTextChangedEventArgs& e);
|
||||
void BuiltInIconPicker_QuerySubmitted(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxQuerySubmittedEventArgs& e);
|
||||
|
||||
Windows::Foundation::IInspectable CurrentIconType() const noexcept { return _currentIconType; }
|
||||
void CurrentIconType(const Windows::Foundation::IInspectable& value);
|
||||
|
||||
bool UsingNoIcon() const;
|
||||
bool UsingBuiltInIcon() const;
|
||||
bool UsingEmojiIcon() const;
|
||||
bool UsingImageIcon() const;
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(hstring, CurrentEmojiIcon, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(Editor::EnumEntry, CurrentBuiltInIcon, PropertyChanged.raise, nullptr);
|
||||
|
||||
DEPENDENCY_PROPERTY(hstring, CurrentIconPath);
|
||||
DEPENDENCY_PROPERTY(IHostedInWindow, WindowRoot);
|
||||
|
||||
private:
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> _BuiltInIcons;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> _IconTypes;
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> _filteredBuiltInIcons;
|
||||
std::wstring _iconFilter;
|
||||
Windows::Foundation::IInspectable _currentIconType{};
|
||||
winrt::hstring _lastIconPath;
|
||||
|
||||
static void _InitializeProperties();
|
||||
static void _OnCurrentIconPathChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
|
||||
|
||||
void _DeduceCurrentIconType();
|
||||
void _DeduceCurrentBuiltInIcon();
|
||||
void _updateIconFilter(std::wstring_view filter);
|
||||
void _updateFilteredIconList();
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(IconPicker);
|
||||
}
|
||||
42
src/cascadia/TerminalSettingsEditor/IconPicker.idl
Normal file
42
src/cascadia/TerminalSettingsEditor/IconPicker.idl
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "EnumEntry.idl";
|
||||
import "MainPage.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
enum IconType
|
||||
{
|
||||
None = 0,
|
||||
FontIcon,
|
||||
Image,
|
||||
Emoji
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass IconPicker : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
IconPicker();
|
||||
|
||||
IInspectable CurrentIconType;
|
||||
Windows.Foundation.Collections.IObservableVector<EnumEntry> IconTypes { get; };
|
||||
|
||||
Boolean UsingBuiltInIcon { get; };
|
||||
Boolean UsingEmojiIcon { get; };
|
||||
Boolean UsingImageIcon { get; };
|
||||
|
||||
String CurrentEmojiIcon;
|
||||
|
||||
EnumEntry CurrentBuiltInIcon;
|
||||
Windows.Foundation.Collections.IObservableVector<EnumEntry> BuiltInIcons { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<EnumEntry> FilteredBuiltInIconList { get; };
|
||||
|
||||
static Windows.UI.Xaml.Controls.IconSource BuiltInIconConverter(IInspectable iconVal);
|
||||
|
||||
String CurrentIconPath;
|
||||
static Windows.UI.Xaml.DependencyProperty CurrentIconPathProperty { get; };
|
||||
|
||||
IHostedInWindow WindowRoot;
|
||||
static Windows.UI.Xaml.DependencyProperty WindowRootProperty { get; };
|
||||
}
|
||||
}
|
||||
100
src/cascadia/TerminalSettingsEditor/IconPicker.xaml
Normal file
100
src/cascadia/TerminalSettingsEditor/IconPicker.xaml
Normal file
@@ -0,0 +1,100 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="Microsoft.Terminal.Settings.Editor.IconPicker"
|
||||
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">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="CommonResources.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Icon Type -->
|
||||
<ComboBox x:Uid="IconPicker_IconType"
|
||||
Grid.Column="0"
|
||||
ItemsSource="{x:Bind IconTypes}"
|
||||
SelectedItem="{x:Bind CurrentIconType, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:EnumEntry">
|
||||
<TextBlock Text="{x:Bind EnumName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<!-- Built-In Icon -->
|
||||
<AutoSuggestBox x:Uid="IconPicker_BuiltInIcon"
|
||||
Grid.Column="1"
|
||||
GotFocus="BuiltInIconPicker_GotFocus"
|
||||
ItemsSource="{x:Bind FilteredBuiltInIconList, Mode=OneWay}"
|
||||
QuerySubmitted="BuiltInIconPicker_QuerySubmitted"
|
||||
Text="{x:Bind CurrentBuiltInIcon.EnumName, Mode=OneWay}"
|
||||
TextBoxStyle="{StaticResource TextBoxSettingStyle}"
|
||||
TextChanged="BuiltInIconPicker_TextChanged"
|
||||
Visibility="{x:Bind UsingBuiltInIcon, Mode=OneWay}">
|
||||
<AutoSuggestBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:EnumEntry">
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<IconSourceElement Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind local:IconPicker.BuiltInIconConverter(EnumValue), Mode=OneTime}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind EnumName}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</AutoSuggestBox.ItemTemplate>
|
||||
</AutoSuggestBox>
|
||||
|
||||
<!-- Image (File) Icon -->
|
||||
<TextBox x:Uid="IconPicker_ImagePathBox"
|
||||
Grid.Column="1"
|
||||
MaxWidth="Infinity"
|
||||
HorizontalAlignment="Stretch"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind CurrentIconPath, Mode=TwoWay}"
|
||||
Visibility="{x:Bind UsingImageIcon, Mode=OneWay}" />
|
||||
<Button x:Uid="IconPicker_IconBrowse"
|
||||
Grid.Column="2"
|
||||
Margin="0"
|
||||
VerticalAlignment="Top"
|
||||
Click="Icon_Click"
|
||||
Style="{StaticResource BrowseButtonStyle}"
|
||||
Visibility="{x:Bind UsingImageIcon, Mode=OneWay}" />
|
||||
|
||||
<!-- Emoji Icon -->
|
||||
<TextBox x:Uid="IconPicker_EmojiBox"
|
||||
Grid.Column="1"
|
||||
MaxWidth="Infinity"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind CurrentEmojiIcon, Mode=TwoWay}"
|
||||
Visibility="{x:Bind UsingEmojiIcon, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -69,6 +69,10 @@
|
||||
<DependentUpon>NullableColorPicker.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IconPicker.h">
|
||||
<DependentUpon>IconPicker.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EditColorScheme.h">
|
||||
<DependentUpon>EditColorScheme.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -194,6 +198,9 @@
|
||||
<Page Include="NullableColorPicker.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="IconPicker.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="EditColorScheme.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
@@ -270,6 +277,10 @@
|
||||
<DependentUpon>NullableColorPicker.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IconPicker.cpp">
|
||||
<DependentUpon>IconPicker.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EditColorScheme.cpp">
|
||||
<DependentUpon>EditColorScheme.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -399,6 +410,10 @@
|
||||
<DependentUpon>NullableColorPicker.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="IconPicker.idl">
|
||||
<DependentUpon>IconPicker.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="EditColorScheme.idl">
|
||||
<DependentUpon>EditColorScheme.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
<Page Include="AddProfile.xaml" />
|
||||
<Page Include="KeyChordListener.xaml" />
|
||||
<Page Include="NullableColorPicker.xaml" />
|
||||
<Page Include="IconPicker.xaml" />
|
||||
<Page Include="NewTabMenu.xaml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "NewTabMenu.h"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "NewTabMenu.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "NewTabMenuEntryTemplateSelector.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
|
||||
@@ -44,6 +45,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::NewTabMenuViewModel>();
|
||||
_windowRoot = args.WindowRoot();
|
||||
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
|
||||
@@ -38,11 +38,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void AddFolderNameTextBox_KeyDown(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void AddFolderNameTextBox_TextChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Controls::TextChangedEventArgs& e);
|
||||
|
||||
Editor::IHostedInWindow WindowRoot() const noexcept { return _windowRoot; }
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(Editor::NewTabMenuViewModel, ViewModel, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
private:
|
||||
Editor::NewTabMenuEntryViewModel _draggedEntry{ nullptr };
|
||||
Editor::IHostedInWindow _windowRoot;
|
||||
|
||||
void _ScrollToEntry(const Editor::NewTabMenuEntryViewModel& entry);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
NewTabMenu();
|
||||
NewTabMenuViewModel ViewModel { get; };
|
||||
IHostedInWindow WindowRoot { get; };
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass NewTabMenuEntryTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
|
||||
|
||||
@@ -319,32 +319,51 @@
|
||||
Visibility="{x:Bind ViewModel.IsFolderView, Mode=OneWay}">
|
||||
<TextBlock x:Uid="NewTabMenu_CurrentFolderTextBlock"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- TODO GH #18281: Icon -->
|
||||
<!-- Once PR #17965 merges, we can add that kind of control to set an icon -->
|
||||
|
||||
<!-- Name -->
|
||||
<local:SettingContainer x:Name="CurrentFolderName"
|
||||
x:Uid="NewTabMenu_CurrentFolderName"
|
||||
Grid.Row="0"
|
||||
CurrentValue="{x:Bind ViewModel.CurrentFolderName, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<TextBox Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind ViewModel.CurrentFolderName, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Icon -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_CurrentFolderIcon"
|
||||
CurrentValueAccessibleName="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
|
||||
<local:SettingContainer.CurrentValue>
|
||||
<Grid>
|
||||
<ContentControl Width="16"
|
||||
Height="16"
|
||||
Content="{x:Bind ViewModel.CurrentFolderIconPreview, Mode=OneWay}"
|
||||
IsTabStop="False"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.CurrentFolderUsingNoIcon), Mode=OneWay}" />
|
||||
<TextBlock Margin="0,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Style="{StaticResource SettingsPageItemDescriptionStyle}"
|
||||
Text="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.CurrentFolderUsingNoIcon, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</local:SettingContainer.CurrentValue>
|
||||
<local:SettingContainer.Content>
|
||||
<local:IconPicker CurrentIconPath="{x:Bind ViewModel.CurrentFolderIconPath, Mode=TwoWay}"
|
||||
WindowRoot="{x:Bind WindowRoot, Mode=OneWay}" />
|
||||
</local:SettingContainer.Content>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Inlining -->
|
||||
<local:SettingContainer x:Name="CurrentFolderInlining"
|
||||
x:Uid="NewTabMenu_CurrentFolderInlining"
|
||||
Grid.Row="1">
|
||||
x:Uid="NewTabMenu_CurrentFolderInlining">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderInlining, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Allow Empty -->
|
||||
<local:SettingContainer x:Name="CurrentFolderAllowEmpty"
|
||||
x:Uid="NewTabMenu_CurrentFolderAllowEmpty"
|
||||
Grid.Row="2">
|
||||
x:Uid="NewTabMenu_CurrentFolderAllowEmpty">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderAllowEmpty, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
@@ -22,6 +22,8 @@ using namespace winrt::Windows::UI::Xaml::Data;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
static constexpr std::wstring_view HideIconValue{ L"none" };
|
||||
|
||||
static IObservableVector<Editor::NewTabMenuEntryViewModel> _ConvertToViewModelEntries(const IVector<Model::NewTabMenuEntry>& settingsModelEntries, const Model::CascadiaSettings& settings)
|
||||
{
|
||||
std::vector<Editor::NewTabMenuEntryViewModel> result{};
|
||||
@@ -160,6 +162,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// FolderTree needs to be updated when a folder is renamed
|
||||
_folderTreeCache = nullptr;
|
||||
}
|
||||
else if (viewModelProperty == L"Icon")
|
||||
{
|
||||
_NotifyChanges(L"CurrentFolderIconPreview", L"CurrentFolderLocalizedIcon", L"CurrentFolderIconPath", L"CurrentFolderUsingNoIcon");
|
||||
}
|
||||
}
|
||||
|
||||
hstring NewTabMenuViewModel::CurrentFolderName() const
|
||||
@@ -216,6 +222,60 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
Windows::UI::Xaml::Controls::IconElement NewTabMenuViewModel::CurrentFolderIconPreview() const
|
||||
{
|
||||
if (!_CurrentFolder)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
// IconWUX sets the icon width/height to 32 by default
|
||||
auto icon = Microsoft::Terminal::UI::IconPathConverter::IconWUX(_CurrentFolder.Icon());
|
||||
icon.Width(16);
|
||||
icon.Height(16);
|
||||
return icon;
|
||||
}
|
||||
|
||||
winrt::hstring NewTabMenuViewModel::CurrentFolderLocalizedIcon() const
|
||||
{
|
||||
if (!_CurrentFolder)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
if (CurrentFolderUsingNoIcon())
|
||||
{
|
||||
return RS_(L"IconPicker_IconTypeNone");
|
||||
}
|
||||
return _CurrentFolder.Icon(); // For display as a string
|
||||
}
|
||||
|
||||
winrt::hstring NewTabMenuViewModel::CurrentFolderIconPath() const
|
||||
{
|
||||
if (!_CurrentFolder)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return _CurrentFolder.Icon();
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::CurrentFolderIconPath(const winrt::hstring& path)
|
||||
{
|
||||
if (_CurrentFolder && _CurrentFolder.Icon() != path)
|
||||
{
|
||||
_CurrentFolder.Icon(path);
|
||||
_NotifyChanges(L"CurrentFolderIconPath", L"CurrentFolderIconPreview", L"UsingNoIcon");
|
||||
}
|
||||
}
|
||||
|
||||
bool NewTabMenuViewModel::CurrentFolderUsingNoIcon() const noexcept
|
||||
{
|
||||
if (!_CurrentFolder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const auto icon{ _CurrentFolder.Icon() };
|
||||
return icon.empty() || icon == HideIconValue;
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::NewTabMenuEntryViewModel> NewTabMenuViewModel::CurrentView() const
|
||||
{
|
||||
if (!_CurrentFolder)
|
||||
|
||||
@@ -47,6 +47,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
bool CurrentFolderAllowEmpty() const;
|
||||
void CurrentFolderAllowEmpty(bool value);
|
||||
|
||||
Windows::UI::Xaml::Controls::IconElement CurrentFolderIconPreview() const;
|
||||
winrt::hstring CurrentFolderLocalizedIcon() const;
|
||||
winrt::hstring CurrentFolderIconPath() const;
|
||||
void CurrentFolderIconPath(const winrt::hstring& path);
|
||||
bool CurrentFolderUsingNoIcon() const noexcept;
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Model::Profile> AvailableProfiles() const { return _Settings.AllProfiles(); }
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::FolderTreeViewEntry> FolderTree() const;
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::FolderEntryViewModel> FolderTreeFlatList() const;
|
||||
@@ -136,6 +142,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void Inlining(bool value);
|
||||
|
||||
hstring Icon() const { return _FolderEntry.Icon().Path(); }
|
||||
void Icon(const hstring& value)
|
||||
{
|
||||
_FolderEntry.Icon(Model::MediaResourceHelper::FromString(value));
|
||||
_NotifyChanges(L"Icon");
|
||||
}
|
||||
|
||||
GETSET_OBSERVABLE_PROJECTED_SETTING(_FolderEntry, Name);
|
||||
GETSET_OBSERVABLE_PROJECTED_SETTING(_FolderEntry, AllowEmpty);
|
||||
|
||||
@@ -41,6 +41,11 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
String ProfileMatcherCommandline;
|
||||
String AddFolderName;
|
||||
|
||||
Windows.UI.Xaml.Controls.IconElement CurrentFolderIconPreview { get; };
|
||||
String CurrentFolderLocalizedIcon { get; };
|
||||
String CurrentFolderIconPath;
|
||||
Boolean CurrentFolderUsingNoIcon { get; };
|
||||
|
||||
void RequestReorderEntry(NewTabMenuEntryViewModel vm, Boolean goingUp);
|
||||
void RequestDeleteEntry(NewTabMenuEntryViewModel vm);
|
||||
void RequestMoveEntriesToFolder(IVector<NewTabMenuEntryViewModel> entries, FolderEntryViewModel folderEntry);
|
||||
@@ -83,7 +88,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
FolderEntryViewModel(Microsoft.Terminal.Settings.Model.FolderEntry folderEntry, Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
|
||||
|
||||
String Name;
|
||||
String Icon { get; };
|
||||
String Icon;
|
||||
Boolean Inlining;
|
||||
Boolean AllowEmpty;
|
||||
IObservableVector<Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel> Entries;
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
#include "pch.h"
|
||||
#include "ProfileViewModel.h"
|
||||
#include "ProfileViewModel.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
#include "Appearances.h"
|
||||
#include "EnumEntry.h"
|
||||
|
||||
#include "../WinRTUtils/inc/Utils.h"
|
||||
#include "../../renderer/base/FontCache.h"
|
||||
#include "../TerminalSettingsAppAdapterLib/TerminalSettings.h"
|
||||
#include "SegoeFluentIconList.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
@@ -24,13 +22,11 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
static constexpr std::wstring_view HideIconValue{ L"none" };
|
||||
static Editor::Font fontObjectForDWriteFont(IDWriteFontFamily* family, const wchar_t* locale);
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> ProfileViewModel::_BuiltInIcons{ nullptr };
|
||||
|
||||
static constexpr std::wstring_view HideIconValue{ L"none" };
|
||||
|
||||
ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings, const Windows::UI::Core::CoreDispatcher& dispatcher) :
|
||||
_profile{ profile },
|
||||
@@ -47,17 +43,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
_InitializeCurrentBellSounds();
|
||||
|
||||
// set up IconTypes
|
||||
std::vector<IInspectable> iconTypes;
|
||||
iconTypes.reserve(4);
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"Profile_IconTypeNone"), box_value(IconType::None)));
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"Profile_IconTypeFontIcon"), box_value(IconType::FontIcon)));
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"Profile_IconTypeEmoji"), box_value(IconType::Emoji)));
|
||||
iconTypes.emplace_back(make<EnumEntry>(RS_(L"Profile_IconTypeImage"), box_value(IconType::Image)));
|
||||
_IconTypes = winrt::single_threaded_vector<IInspectable>(std::move(iconTypes));
|
||||
_DeduceCurrentIconType();
|
||||
_DeduceCurrentBuiltInIcon();
|
||||
|
||||
// Add a property changed handler to our own property changed event.
|
||||
// This propagates changes from the settings model to anybody listening to our
|
||||
// unique view model members.
|
||||
@@ -92,32 +77,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else if (viewModelProperty == L"Icon")
|
||||
{
|
||||
// _DeduceCurrentIconType() ends with a "CurrentIconType" notification
|
||||
// so we don't need to call _UpdateIconPreview() here
|
||||
_DeduceCurrentIconType();
|
||||
// The icon changed; let's re-evaluate it with its new context.
|
||||
_appSettings.ResolveMediaResources();
|
||||
}
|
||||
else if (viewModelProperty == L"CurrentIconType")
|
||||
{
|
||||
// "Using*" handles the visibility of the IconType-related UI.
|
||||
// The others propagate the rendered icon into a preview (i.e. nav view, container item)
|
||||
_NotifyChanges(L"UsingNoIcon",
|
||||
L"UsingBuiltInIcon",
|
||||
L"UsingEmojiIcon",
|
||||
L"UsingImageIcon",
|
||||
L"LocalizedIcon",
|
||||
|
||||
// Propagate the rendered icon into a preview (i.e. nav view, container item)
|
||||
_NotifyChanges(L"LocalizedIcon",
|
||||
L"IconPreview",
|
||||
L"IconPath",
|
||||
L"EvaluatedIcon");
|
||||
}
|
||||
else if (viewModelProperty == L"CurrentBuiltInIcon")
|
||||
{
|
||||
IconPath(unbox_value<hstring>(_CurrentBuiltInIcon.EnumValue()));
|
||||
}
|
||||
else if (viewModelProperty == L"CurrentEmojiIcon")
|
||||
{
|
||||
IconPath(CurrentEmojiIcon());
|
||||
L"EvaluatedIcon",
|
||||
L"UsingNoIcon");
|
||||
}
|
||||
else if (viewModelProperty == L"CurrentBellSounds")
|
||||
{
|
||||
@@ -190,61 +158,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_defaultAppearanceViewModel.IsDefault(true);
|
||||
}
|
||||
|
||||
void ProfileViewModel::_UpdateBuiltInIcons()
|
||||
{
|
||||
std::vector<Editor::EnumEntry> builtInIcons;
|
||||
for (auto& [val, name] : s_SegoeFluentIcons)
|
||||
{
|
||||
builtInIcons.emplace_back(make<EnumEntry>(hstring{ name }, box_value(val)));
|
||||
}
|
||||
_BuiltInIcons = single_threaded_observable_vector<Editor::EnumEntry>(std::move(builtInIcons));
|
||||
}
|
||||
|
||||
void ProfileViewModel::_DeduceCurrentIconType()
|
||||
{
|
||||
const auto profileIcon = IconPath();
|
||||
if (profileIcon == HideIconValue)
|
||||
{
|
||||
_currentIconType = _IconTypes.GetAt(0);
|
||||
}
|
||||
else if (profileIcon.size() == 1 && (L'\uE700' <= til::at(profileIcon, 0) && til::at(profileIcon, 0) <= L'\uF8B3'))
|
||||
{
|
||||
_currentIconType = _IconTypes.GetAt(1);
|
||||
_DeduceCurrentBuiltInIcon();
|
||||
}
|
||||
else if (::Microsoft::Console::Utils::IsLikelyToBeEmojiOrSymbolIcon(profileIcon))
|
||||
{
|
||||
// We already did a range check for MDL2 Assets in the previous one,
|
||||
// so if we're out of that range but still short, assume we're an emoji
|
||||
_currentIconType = _IconTypes.GetAt(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentIconType = _IconTypes.GetAt(3);
|
||||
}
|
||||
_NotifyChanges(L"CurrentIconType");
|
||||
}
|
||||
|
||||
void ProfileViewModel::_DeduceCurrentBuiltInIcon()
|
||||
{
|
||||
if (!_BuiltInIcons)
|
||||
{
|
||||
_UpdateBuiltInIcons();
|
||||
}
|
||||
const auto profileIcon = IconPath();
|
||||
for (uint32_t i = 0; i < _BuiltInIcons.Size(); i++)
|
||||
{
|
||||
const auto& builtIn = _BuiltInIcons.GetAt(i);
|
||||
if (profileIcon == unbox_value<hstring>(builtIn.EnumValue()))
|
||||
{
|
||||
_CurrentBuiltInIcon = builtIn;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_CurrentBuiltInIcon = _BuiltInIcons.GetAt(0);
|
||||
_NotifyChanges(L"CurrentBuiltInIcon");
|
||||
}
|
||||
|
||||
void ProfileViewModel::LeftPadding(double value) noexcept
|
||||
{
|
||||
if (std::abs(_parsedPadding.Left - value) >= .0001)
|
||||
@@ -636,9 +549,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
winrt::hstring ProfileViewModel::LocalizedIcon() const
|
||||
{
|
||||
if (_currentIconType && unbox_value<IconType>(_currentIconType.as<Editor::EnumEntry>().EnumValue()) == IconType::None)
|
||||
if (UsingNoIcon())
|
||||
{
|
||||
return RS_(L"Profile_IconTypeNone");
|
||||
return RS_(L"IconPicker_IconTypeNone");
|
||||
}
|
||||
return IconPath(); // For display as a string
|
||||
}
|
||||
@@ -652,83 +565,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return icon;
|
||||
}
|
||||
|
||||
void ProfileViewModel::CurrentIconType(const Windows::Foundation::IInspectable& value)
|
||||
bool ProfileViewModel::UsingNoIcon() const noexcept
|
||||
{
|
||||
if (_currentIconType != value)
|
||||
{
|
||||
// Switching from...
|
||||
if (_currentIconType && unbox_value<IconType>(_currentIconType.as<Editor::EnumEntry>().EnumValue()) == IconType::Image)
|
||||
{
|
||||
// Stash the current value of Icon. If the user
|
||||
// switches out of then back to IconType::Image, we want
|
||||
// the path that we display in the text box to remain unchanged.
|
||||
_lastIconPath = IconPath();
|
||||
}
|
||||
|
||||
// Set the member here instead of after setting Icon() below!
|
||||
// We have an Icon property changed handler defined for when we discard changes.
|
||||
// Inadvertently, that means that we call this setter again.
|
||||
// Setting the member here means that we early exit at the beginning of the function
|
||||
// because _currentIconType == value.
|
||||
_currentIconType = value;
|
||||
|
||||
// Switched to...
|
||||
switch (unbox_value<IconType>(value.as<Editor::EnumEntry>().EnumValue()))
|
||||
{
|
||||
case IconType::None:
|
||||
{
|
||||
IconPath(winrt::hstring{ HideIconValue });
|
||||
break;
|
||||
}
|
||||
case IconType::Image:
|
||||
{
|
||||
if (!_lastIconPath.empty())
|
||||
{
|
||||
// Conversely, if we switch to Image,
|
||||
// retrieve that saved value and apply it
|
||||
IconPath(_lastIconPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IconType::FontIcon:
|
||||
{
|
||||
if (_CurrentBuiltInIcon)
|
||||
{
|
||||
IconPath(unbox_value<hstring>(_CurrentBuiltInIcon.EnumValue()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IconType::Emoji:
|
||||
{
|
||||
// Don't set Icon here!
|
||||
// Clear out the text box so we direct the user to use the emoji picker.
|
||||
CurrentEmojiIcon({});
|
||||
}
|
||||
}
|
||||
// We're not using the VM's Icon() setter above,
|
||||
// so notify HasIcon changed manually
|
||||
_NotifyChanges(L"CurrentIconType", L"HasIcon");
|
||||
}
|
||||
}
|
||||
|
||||
bool ProfileViewModel::UsingNoIcon() const
|
||||
{
|
||||
return _currentIconType == _IconTypes.GetAt(0);
|
||||
}
|
||||
|
||||
bool ProfileViewModel::UsingBuiltInIcon() const
|
||||
{
|
||||
return _currentIconType == _IconTypes.GetAt(1);
|
||||
}
|
||||
|
||||
bool ProfileViewModel::UsingEmojiIcon() const
|
||||
{
|
||||
return _currentIconType == _IconTypes.GetAt(2);
|
||||
}
|
||||
|
||||
bool ProfileViewModel::UsingImageIcon() const
|
||||
{
|
||||
return _currentIconType == _IconTypes.GetAt(3);
|
||||
const auto iconPath{ IconPath() };
|
||||
return iconPath.empty() || iconPath == HideIconValue;
|
||||
}
|
||||
|
||||
hstring ProfileViewModel::BellStylePreview() const
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
static void UpdateFontList() noexcept;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> CompleteFontList() noexcept { return _FontList; };
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> MonospaceFontList() noexcept { return _MonospaceFontList; };
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> BuiltInIcons() noexcept { return _BuiltInIcons; };
|
||||
|
||||
ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings, const Windows::UI::Core::CoreDispatcher& dispatcher);
|
||||
Control::IControlSettings TermSettings() const;
|
||||
@@ -76,23 +75,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
return _profile.Icon().Resolved();
|
||||
}
|
||||
Windows::Foundation::IInspectable CurrentIconType() const noexcept
|
||||
{
|
||||
return _currentIconType;
|
||||
}
|
||||
Windows::UI::Xaml::Controls::IconElement IconPreview() const;
|
||||
winrt::hstring LocalizedIcon() const;
|
||||
void CurrentIconType(const Windows::Foundation::IInspectable& value);
|
||||
bool UsingNoIcon() const;
|
||||
bool UsingBuiltInIcon() const;
|
||||
bool UsingEmojiIcon() const;
|
||||
bool UsingImageIcon() const;
|
||||
winrt::hstring IconPath() const { return _profile.Icon().Path(); }
|
||||
void IconPath(const winrt::hstring& path)
|
||||
{
|
||||
Icon(Model::MediaResourceHelper::FromString(path));
|
||||
_NotifyChanges(L"Icon", L"IconPath");
|
||||
}
|
||||
bool UsingNoIcon() const noexcept;
|
||||
|
||||
constexpr bool TmuxControlEnabled() noexcept
|
||||
{
|
||||
@@ -129,8 +120,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(ProfileSubPage, CurrentPage);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::BellSoundViewModel>, CurrentBellSounds);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Editor::EnumEntry, CurrentBuiltInIcon, nullptr);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, CurrentEmojiIcon);
|
||||
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, ConnectionType);
|
||||
@@ -171,7 +160,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
WINRT_PROPERTY(bool, IsBaseLayer, false);
|
||||
WINRT_PROPERTY(bool, FocusDeleteButton, false);
|
||||
WINRT_PROPERTY(hstring, ElementToFocus);
|
||||
WINRT_PROPERTY(Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable>, IconTypes);
|
||||
GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode);
|
||||
GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, CloseOnExit);
|
||||
GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, ScrollState);
|
||||
@@ -182,8 +170,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
winrt::guid _originalProfileGuid{};
|
||||
winrt::hstring _lastBgImagePath;
|
||||
winrt::hstring _lastStartingDirectoryPath;
|
||||
winrt::hstring _lastIconPath;
|
||||
Windows::Foundation::IInspectable _currentIconType{};
|
||||
Editor::AppearanceViewModel _defaultAppearanceViewModel;
|
||||
Windows::UI::Core::CoreDispatcher _dispatcher;
|
||||
|
||||
@@ -194,13 +180,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void _MarkDuplicateBellSoundDirectories();
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> _BuiltInIcons;
|
||||
|
||||
Model::CascadiaSettings _appSettings;
|
||||
Editor::AppearanceViewModel _unfocusedAppearanceViewModel;
|
||||
void _UpdateBuiltInIcons();
|
||||
void _DeduceCurrentIconType();
|
||||
void _DeduceCurrentBuiltInIcon();
|
||||
};
|
||||
|
||||
struct DeleteProfileEventArgs :
|
||||
|
||||
@@ -36,14 +36,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
Advanced = 3
|
||||
};
|
||||
|
||||
enum IconType
|
||||
{
|
||||
None = 0,
|
||||
FontIcon,
|
||||
Image,
|
||||
Emoji
|
||||
};
|
||||
|
||||
runtimeclass ProfileViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
event Windows.Foundation.TypedEventHandler<ProfileViewModel, DeleteProfileEventArgs> DeleteProfileRequested;
|
||||
@@ -101,18 +93,9 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
Windows.UI.Xaml.Controls.IconElement IconPreview { get; };
|
||||
String EvaluatedIcon { get; };
|
||||
String LocalizedIcon { get; };
|
||||
String CurrentEmojiIcon;
|
||||
IInspectable CurrentIconType;
|
||||
Windows.Foundation.Collections.IVector<IInspectable> IconTypes { get; };
|
||||
Boolean UsingNoIcon { get; };
|
||||
Boolean UsingBuiltInIcon { get; };
|
||||
Boolean UsingEmojiIcon { get; };
|
||||
Boolean UsingImageIcon { get; };
|
||||
Boolean TmuxControlEnabled { get; };
|
||||
String IconPath;
|
||||
|
||||
EnumEntry CurrentBuiltInIcon;
|
||||
Windows.Foundation.Collections.IObservableVector<EnumEntry> BuiltInIcons { get; };
|
||||
Boolean UsingNoIcon { get; };
|
||||
|
||||
String TabTitlePreview { get; };
|
||||
String AnswerbackMessagePreview { get; };
|
||||
|
||||
@@ -134,18 +134,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine Profiles_Base::Icon_Click(const IInspectable&, const RoutedEventArgs&)
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(_windowRoot.GetHostingWindow()) };
|
||||
auto file = co_await OpenImagePicker(parentHwnd);
|
||||
if (!file.empty())
|
||||
{
|
||||
_Profile.IconPath(file);
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine Profiles_Base::StartingDirectory_Click(const IInspectable&, const RoutedEventArgs&)
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
@@ -170,77 +158,4 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_Profile.StartingDirectory(folder);
|
||||
}
|
||||
}
|
||||
|
||||
IconSource Profiles_Base::BuiltInIconConverter(const IInspectable& iconVal)
|
||||
{
|
||||
return Microsoft::Terminal::UI::IconPathConverter::IconSourceWUX(unbox_value<hstring>(iconVal));
|
||||
}
|
||||
|
||||
void Profiles_Base::BuiltInIconPicker_GotFocus(const IInspectable& sender, const RoutedEventArgs& /*e*/)
|
||||
{
|
||||
_updateIconFilter({});
|
||||
sender.as<AutoSuggestBox>().IsSuggestionListOpen(true);
|
||||
}
|
||||
|
||||
void Profiles_Base::BuiltInIconPicker_QuerySubmitted(const AutoSuggestBox& /*sender*/, const AutoSuggestBoxQuerySubmittedEventArgs& e)
|
||||
{
|
||||
const auto iconEntry = unbox_value_or<EnumEntry>(e.ChosenSuggestion(), nullptr);
|
||||
if (!iconEntry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_Profile.CurrentBuiltInIcon(iconEntry);
|
||||
}
|
||||
|
||||
void Profiles_Base::BuiltInIconPicker_TextChanged(const AutoSuggestBox& sender, const AutoSuggestBoxTextChangedEventArgs& e)
|
||||
{
|
||||
if (e.Reason() != AutoSuggestionBoxTextChangeReason::UserInput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::wstring_view filter{ sender.Text() };
|
||||
filter = til::trim(filter, L' ');
|
||||
_updateIconFilter(filter);
|
||||
}
|
||||
|
||||
void Profiles_Base::_updateIconFilter(std::wstring_view filter)
|
||||
{
|
||||
if (_iconFilter != filter)
|
||||
{
|
||||
_filteredBuiltInIcons = nullptr;
|
||||
_iconFilter = filter;
|
||||
_updateFilteredIconList();
|
||||
PropertyChanged.raise(*this, PropertyChangedEventArgs{ L"FilteredBuiltInIconList" });
|
||||
}
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> Profiles_Base::FilteredBuiltInIconList()
|
||||
{
|
||||
if (!_filteredBuiltInIcons)
|
||||
{
|
||||
_updateFilteredIconList();
|
||||
}
|
||||
return _filteredBuiltInIcons;
|
||||
}
|
||||
|
||||
void Profiles_Base::_updateFilteredIconList()
|
||||
{
|
||||
_filteredBuiltInIcons = ProfileViewModel::BuiltInIcons();
|
||||
if (_iconFilter.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find matching icons and populate the filtered list
|
||||
std::vector<Editor::EnumEntry> filtered;
|
||||
filtered.reserve(_filteredBuiltInIcons.Size());
|
||||
for (const auto& icon : _filteredBuiltInIcons)
|
||||
{
|
||||
if (til::contains_linguistic_insensitive(icon.EnumName(), _iconFilter))
|
||||
{
|
||||
filtered.emplace_back(icon);
|
||||
}
|
||||
}
|
||||
_filteredBuiltInIcons = winrt::single_threaded_observable_vector(std::move(filtered));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,32 +18,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
|
||||
|
||||
safe_void_coroutine StartingDirectory_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
safe_void_coroutine Icon_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
safe_void_coroutine Commandline_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void Appearance_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void Terminal_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void Advanced_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void DeleteConfirmation_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> FilteredBuiltInIconList();
|
||||
void BuiltInIconPicker_GotFocus(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void BuiltInIconPicker_TextChanged(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxTextChangedEventArgs& e);
|
||||
void BuiltInIconPicker_QuerySubmitted(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxQuerySubmittedEventArgs& e);
|
||||
|
||||
static Windows::UI::Xaml::Controls::IconSource BuiltInIconConverter(const Windows::Foundation::IInspectable& iconVal);
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
Editor::IHostedInWindow WindowRoot() const noexcept { return _windowRoot; }
|
||||
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
|
||||
|
||||
private:
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
Editor::IHostedInWindow _windowRoot;
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::EnumEntry> _filteredBuiltInIcons;
|
||||
std::wstring _iconFilter;
|
||||
|
||||
void _updateIconFilter(std::wstring_view filter);
|
||||
void _updateFilteredIconList();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "ProfileViewModel.idl";
|
||||
import "MainPage.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
@@ -9,8 +10,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
Profiles_Base();
|
||||
ProfileViewModel Profile { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<EnumEntry> FilteredBuiltInIconList { get; };
|
||||
|
||||
static Windows.UI.Xaml.Controls.IconSource BuiltInIconConverter(IInspectable iconVal);
|
||||
IHostedInWindow WindowRoot { get; };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,82 +124,8 @@
|
||||
</Grid>
|
||||
</local:SettingContainer.CurrentValue>
|
||||
<local:SettingContainer.Content>
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Icon Type -->
|
||||
<ComboBox x:Uid="Profile_IconType"
|
||||
Grid.Column="0"
|
||||
ItemsSource="{x:Bind Profile.IconTypes}"
|
||||
SelectedItem="{x:Bind Profile.CurrentIconType, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:EnumEntry">
|
||||
<TextBlock Text="{x:Bind EnumName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<!-- Built-In Icon -->
|
||||
<AutoSuggestBox x:Uid="Profile_BuiltInIcon"
|
||||
Grid.Column="1"
|
||||
GotFocus="BuiltInIconPicker_GotFocus"
|
||||
ItemsSource="{x:Bind FilteredBuiltInIconList, Mode=OneWay}"
|
||||
QuerySubmitted="BuiltInIconPicker_QuerySubmitted"
|
||||
Text="{x:Bind Profile.CurrentBuiltInIcon.EnumName, Mode=OneWay}"
|
||||
TextBoxStyle="{StaticResource TextBoxSettingStyle}"
|
||||
TextChanged="BuiltInIconPicker_TextChanged"
|
||||
Visibility="{x:Bind Profile.UsingBuiltInIcon, Mode=OneWay}">
|
||||
<AutoSuggestBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:EnumEntry">
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<IconSourceElement Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind local:Profiles_Base.BuiltInIconConverter(EnumValue), Mode=OneTime}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind EnumName}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</AutoSuggestBox.ItemTemplate>
|
||||
</AutoSuggestBox>
|
||||
|
||||
<!-- Image (File) Icon -->
|
||||
<TextBox x:Uid="Profile_IconBox"
|
||||
Grid.Column="1"
|
||||
MaxWidth="Infinity"
|
||||
HorizontalAlignment="Stretch"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.IconPath, Mode=TwoWay}"
|
||||
Visibility="{x:Bind Profile.UsingImageIcon, Mode=OneWay}" />
|
||||
<Button x:Uid="Profile_IconBrowse"
|
||||
Grid.Column="2"
|
||||
Margin="0"
|
||||
VerticalAlignment="Top"
|
||||
Click="Icon_Click"
|
||||
Style="{StaticResource BrowseButtonStyle}"
|
||||
Visibility="{x:Bind Profile.UsingImageIcon, Mode=OneWay}" />
|
||||
|
||||
<!-- Emoji Icon -->
|
||||
<TextBox x:Uid="Profile_IconEmojiBox"
|
||||
Grid.Column="1"
|
||||
MaxWidth="Infinity"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.CurrentEmojiIcon, Mode=TwoWay}"
|
||||
Visibility="{x:Bind Profile.UsingEmojiIcon, Mode=OneWay}" />
|
||||
</Grid>
|
||||
<local:IconPicker CurrentIconPath="{x:Bind Profile.IconPath, Mode=TwoWay}"
|
||||
WindowRoot="{x:Bind WindowRoot, Mode=OneWay}" />
|
||||
</local:SettingContainer.Content>
|
||||
</local:SettingContainer>
|
||||
|
||||
|
||||
@@ -1114,11 +1114,11 @@
|
||||
<value>Icon</value>
|
||||
<comment>Header for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="IconPicker_ImagePathBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Icon</value>
|
||||
<comment>Name for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.</comment>
|
||||
<comment>Name for a control to determine what icon can be used. This is not necessarily a file path, but can be one. It's usually used for images.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconEmojiBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="IconPicker_EmojiBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Icon</value>
|
||||
<comment>Name for a control to determine what icon can be used to represent this profile.</comment>
|
||||
</data>
|
||||
@@ -1126,7 +1126,7 @@
|
||||
<value>Emoji or image file location of the icon used in the profile.</value>
|
||||
<comment>A description for what the "icon" setting does. Presented near "Profile_Icon".</comment>
|
||||
</data>
|
||||
<data name="Profile_IconBrowse.Content" xml:space="preserve">
|
||||
<data name="IconPicker_IconBrowse.Content" xml:space="preserve">
|
||||
<value>Browse...</value>
|
||||
<comment>Button label that opens a file picker in a new window. The "..." is standard to mean it will open a new window.</comment>
|
||||
</data>
|
||||
@@ -2322,31 +2322,31 @@
|
||||
<value>Use theme color</value>
|
||||
<comment>Label for a button directing the user to use the tab color defined in the terminal's current theme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
<data name="IconPicker_IconTypeNone" xml:space="preserve">
|
||||
<value>None</value>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, there will be no icon for the profile.</comment>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, there will be no icon set.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeImage" xml:space="preserve">
|
||||
<data name="IconPicker_IconTypeImage" xml:space="preserve">
|
||||
<value>File</value>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, a custom image can set for the profile's icon.</comment>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, a custom image can set as the icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeEmoji" xml:space="preserve">
|
||||
<data name="IconPicker_IconTypeEmoji" xml:space="preserve">
|
||||
<value>Emoji</value>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, an emoji can be set for the profile's icon.</comment>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, an emoji can be set as the icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeFontIcon" xml:space="preserve">
|
||||
<data name="IconPicker_IconTypeFontIcon" xml:space="preserve">
|
||||
<value>Built-in Icon</value>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, the user can choose from several preselected options to set the profile's icon.</comment>
|
||||
<comment>An option to choose from for the "icon style" dropdown. When selected, the user can choose from several preselected options to set as the icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconEmojiBox.PlaceholderText" xml:space="preserve">
|
||||
<data name="IconPicker_EmojiBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Use "Win + period" to open the emoji picker</value>
|
||||
<comment>"Win + period" refers to the OS key binding to open the emoji picker.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconType.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="IconPicker_IconType.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Icon type</value>
|
||||
<comment>Accessible name for a control allowing the user to select the type of icon they would like to use.</comment>
|
||||
</data>
|
||||
<data name="Profile_BuiltInIcon.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<data name="IconPicker_BuiltInIcon.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Icon</value>
|
||||
<comment>Accessible name for a control allowing the user to select the icon from a list of built in icons.</comment>
|
||||
</data>
|
||||
@@ -2450,6 +2450,14 @@
|
||||
<value>Folder Name</value>
|
||||
<comment>Header for a control that allows the user to modify the name of the current folder entry.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_CurrentFolderIcon.Header" xml:space="preserve">
|
||||
<value>Folder Icon</value>
|
||||
<comment>Header for a control that allows the user to modify the icon of the current folder entry.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_CurrentFolderIcon.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Folder Icon</value>
|
||||
<comment>Name for a control to that allows the user to modify the icon of the current folder entry.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_CurrentFolderInlining.Header" xml:space="preserve">
|
||||
<value>Allow inlining</value>
|
||||
<comment>Header for a control that allows the nested entries to be presented inline rather than with a folder.</comment>
|
||||
@@ -2713,4 +2721,8 @@
|
||||
<value>No results for "{}"</value>
|
||||
<comment>{Locked="{}"} Displayed when no results were found for a given query. "{}" will be replaced with the query.</comment>
|
||||
</data>
|
||||
<data name="IconPicker_BuiltInIcon.PlaceholderText" xml:space="preserve">
|
||||
<value>Type to filter icons</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
</root>
|
||||
Reference in New Issue
Block a user