Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow editing font axes in the Settings UI #16104

Merged
merged 31 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5a64ea5
editing/deleting works
PankajBhojwani Oct 4, 2023
267a6c9
discard changes fixed
PankajBhojwani Oct 5, 2023
eac2fd2
spelling and format
PankajBhojwani Oct 5, 2023
4fffd25
actually fix spelling this time
PankajBhojwani Oct 5, 2023
0091390
combo box for the keys with a source of common font axis keys
PankajBhojwani Oct 5, 2023
3aaac0e
spell/format again
PankajBhojwani Oct 6, 2023
ec43d6f
Merge branch 'main' of https://github.com/microsoft/terminal into dev…
PankajBhojwani Oct 19, 2023
7ebee5d
Merge branch 'main' of https://github.com/microsoft/terminal into dev…
PankajBhojwani Jan 8, 2024
35a719c
note some todos
PankajBhojwani Jan 11, 2024
db2523e
works with some stretch goals for the future
PankajBhojwani Jan 25, 2024
f9e4254
actually use the localeindex, remove unneeded resources
PankajBhojwani Jan 25, 2024
076647b
spelling things
PankajBhojwani Jan 25, 2024
40876a1
comment and another unnecessary resources
PankajBhojwani Jan 25, 2024
1adc8e1
remove negative margins
PankajBhojwani Jan 25, 2024
1c34419
initialize name betteR
PankajBhojwani Jan 26, 2024
97dbaa0
format
PankajBhojwani Jan 26, 2024
038a5fd
logic for disabling/enabling the entire setting container and the add…
PankajBhojwani Jan 29, 2024
40996da
update comments
PankajBhojwani Jan 29, 2024
d3363e3
reset button
PankajBhojwani Jan 30, 2024
3f3885e
preview control works
PankajBhojwani Jan 30, 2024
8c035b0
comments, cleanup
PankajBhojwani Jan 30, 2024
c4f94ae
minor nit
PankajBhojwani Jan 30, 2024
ce966b8
switch to wil
PankajBhojwani Feb 1, 2024
becca2a
build std map first
PankajBhojwani Feb 1, 2024
0edfe2e
another round of nits
PankajBhojwani Feb 23, 2024
42e5341
conflict
PankajBhojwani Feb 23, 2024
a68d5a9
every time
PankajBhojwani Feb 23, 2024
4982f2c
std map first, cleanup hanging empty struct in json
PankajBhojwani Feb 28, 2024
42677ff
hstring builder
PankajBhojwani Feb 28, 2024
610ffa4
cleanup nesting
PankajBhojwani Feb 28, 2024
5f527f7
fix conflict
PankajBhojwani Feb 28, 2024
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
1 change: 1 addition & 0 deletions .github/actions/spelling/allow/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ CMMI
copyable
Counterintuitively
CtrlDToClose
CVS
cybersecurity
dalet
Dcs
Expand Down
154 changes: 154 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Appearances.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "pch.h"
#include "Appearances.h"
#include "Appearances.g.cpp"
#include "AxisKeyValuePair.g.cpp"
#include "EnumEntry.h"

#include <LibraryResources.h>
Expand Down Expand Up @@ -42,6 +43,69 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _hasPowerlineCharacters.value_or(false);
}

Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> Font::FontAxesTagsAndNames()
lhecker marked this conversation as resolved.
Show resolved Hide resolved
{
auto fontAxesTagsAndNames = winrt::single_threaded_map<winrt::hstring, winrt::hstring>();
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved

winrt::com_ptr<IDWriteFont> font;
THROW_IF_FAILED(_family->GetFont(0, font.put()));
winrt::com_ptr<IDWriteFontFace> fontFace;
THROW_IF_FAILED(font->CreateFontFace(fontFace.put()));
winrt::com_ptr<IDWriteFontFace5> fontFace5{ fontFace.as<IDWriteFontFace5>() };
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved

winrt::com_ptr<IDWriteFontResource> fontResource;
THROW_IF_FAILED(fontFace5->GetFontResource(fontResource.put()));

std::vector<DWRITE_FONT_AXIS_VALUE> axesVector;
const auto axesCount = fontFace5->GetFontAxisValueCount();
if (axesCount > 0)
{
uint32_t localeIndex;
BOOL localeExists;
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
const auto localeToTry = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) ? localeName : L"en-US";

axesVector.resize(axesCount);
fontFace5->GetFontAxisValues(axesVector.data(), axesCount);
for (uint32_t i = 0; i < axesCount; ++i)
{
const auto tagString = _axisTagToString(axesVector[i].axisTag);

winrt::com_ptr<IDWriteLocalizedStrings> names;
THROW_IF_FAILED(fontResource->GetAxisNames(i, names.put()));

if (!SUCCEEDED(names->FindLocaleName(localeToTry, &localeIndex, &localeExists)) || !localeExists)
{
// default to the first locale in the list
localeIndex = 0;
}

uint32_t length;
if (SUCCEEDED(names->GetStringLength(localeIndex, &length)))
{
wchar_t* name = new (std::nothrow) wchar_t[length + 1];
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
if (SUCCEEDED(names->GetString(localeIndex, name, length + 1)))
{
fontAxesTagsAndNames.Insert(tagString, winrt::hstring{ name });
continue;
}
}
fontAxesTagsAndNames.Insert(tagString, tagString);
}
}
return fontAxesTagsAndNames;
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
}

winrt::hstring Font::_axisTagToString(DWRITE_FONT_AXIS_TAG tag)
{
std::wstring result;
for (int i = 0; i < 4; ++i)
{
result.push_back((tag >> (i * 8)) & 0xFF);
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
}
return winrt::hstring{ result };
}

AppearanceViewModel::AppearanceViewModel(const Model::AppearanceConfig& appearance) :
_appearance{ appearance }
{
Expand All @@ -62,6 +126,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
});

InitializeFontAxesVector();

// Cache the original BG image path. If the user clicks "Use desktop
// wallpaper", then un-checks it, this is the string we'll restore to
// them.
Expand Down Expand Up @@ -205,6 +271,65 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
LightColorSchemeName(val.Name());
}

void AppearanceViewModel::AddNewAxisKeyValuePair()
{
if (!_appearance.SourceProfile().FontInfo().FontAxes())
{
_appearance.SourceProfile().FontInfo().FontAxes(winrt::single_threaded_map<winrt::hstring, float>());
}
auto fontAxesMap = _appearance.SourceProfile().FontInfo().FontAxes();

// find one axis that does not already exist, and add that
// if there are no more possible axes to add, don't do anything
// (maybe in the future we could popup a message to let the user know there are no more valid axes)
const auto possibleAxesTagsAndNames = ProfileViewModel::FindFontWithLocalizedName(FontFace()).FontAxesTagsAndNames();
for (const auto tagAndName : possibleAxesTagsAndNames)
{
if (!fontAxesMap.HasKey(tagAndName.Key()))
{
fontAxesMap.Insert(tagAndName.Key(), gsl::narrow<float>(0));
FontAxesVector().Append(winrt::make<winrt::Microsoft::Terminal::Settings::Editor::implementation::AxisKeyValuePair>(tagAndName.Key(), gsl::narrow<float>(0), fontAxesMap, possibleAxesTagsAndNames));
break;
}
}
}

void AppearanceViewModel::DeleteAxisKeyValuePair(winrt::hstring key)
{
for (uint32_t i = 0; i < _FontAxesVector.Size(); i++)
{
if (_FontAxesVector.GetAt(i).AxisKey() == key)
{
FontAxesVector().RemoveAt(i);
_appearance.SourceProfile().FontInfo().FontAxes().Remove(key);
break;
}
}
}

void AppearanceViewModel::InitializeFontAxesVector()
{
if (!_FontAxesVector)
{
_FontAxesVector = winrt::single_threaded_observable_vector<Editor::AxisKeyValuePair>();
}
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved

_FontAxesVector.Clear();
if (const auto fontAxesMap = _appearance.SourceProfile().FontInfo().FontAxes())
{
const auto fontAxesTagToNameMap = ProfileViewModel::FindFontWithLocalizedName(FontFace()).FontAxesTagsAndNames();
for (const auto axis : fontAxesMap)
{
// only show the axes that the font supports
// any axes that the font doesn't support continue to be stored in the json, we just don't show them in the UI
if (fontAxesTagToNameMap.HasKey(axis.Key()))
{
_FontAxesVector.Append(winrt::make<winrt::Microsoft::Terminal::Settings::Editor::implementation::AxisKeyValuePair>(axis.Key(), axis.Value(), fontAxesMap, fontAxesTagToNameMap));
}
}
}
}

DependencyProperty Appearances::_AppearanceProperty{ nullptr };

Appearances::Appearances() :
Expand Down Expand Up @@ -271,6 +396,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
const auto backgroundImgCheckboxTooltip{ ToolTipService::GetToolTip(UseDesktopImageCheckBox()) };
Automation::AutomationProperties::SetFullDescription(UseDesktopImageCheckBox(), unbox_value<hstring>(backgroundImgCheckboxTooltip));

_FontAxesNames = winrt::single_threaded_observable_vector<winrt::hstring>();
FontAxesNamesCVS().Source(_FontAxesNames);

INITIALIZE_BINDABLE_ENUM_SETTING(IntenseTextStyle, IntenseTextStyle, winrt::Microsoft::Terminal::Settings::Model::IntenseStyle, L"Appearance_IntenseTextStyle", L"Content");
}

Expand Down Expand Up @@ -330,6 +458,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
ShowProportionalFontWarning(false);
}

_FontAxesNames.Clear();
const auto axesTagsAndNames = newFontFace.FontAxesTagsAndNames();
for (const auto tagAndName : axesTagsAndNames)
{
_FontAxesNames.Append(tagAndName.Value());
}
Appearance().InitializeFontAxesVector();
}

void Appearances::_ViewModelChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*args*/)
Expand All @@ -348,6 +484,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
biButton.IsChecked(biButton.Tag().as<int32_t>() == biAlignmentVal);
}

FontAxesCVS().Source(Appearance().FontAxesVector());

_ViewModelChangedRevoker = Appearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
const auto settingName{ args.PropertyName() };
if (settingName == L"CursorShape")
Expand Down Expand Up @@ -470,6 +608,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}

void Appearances::DeleteAxisKeyValuePair_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
{
if (const auto& button{ sender.try_as<Controls::Button>() })
{
if (const auto& tag{ button.Tag().try_as<winrt::hstring>() })
{
Appearance().DeleteAxisKeyValuePair(tag.value());
}
}
}

void Appearances::AddNewAxisKeyValuePair_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*e*/)
{
Appearance().AddNewAxisKeyValuePair();
}

bool Appearances::IsVintageCursor() const
{
return Appearance().CursorShape() == Core::CursorStyle::Vintage;
Expand Down
86 changes: 86 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Appearances.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Author(s):
#pragma once

#include "Font.g.h"
#include "AxisKeyValuePair.g.h"
#include "Appearances.g.h"
#include "AppearanceViewModel.g.h"
#include "Utils.h"
Expand Down Expand Up @@ -45,13 +46,88 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

hstring ToString() { return _LocalizedName; }
bool HasPowerlineCharacters();
Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> FontAxesTagsAndNames();

WINRT_PROPERTY(hstring, Name);
WINRT_PROPERTY(hstring, LocalizedName);

private:
winrt::com_ptr<IDWriteFontFamily> _family;
std::optional<bool> _hasPowerlineCharacters;
winrt::hstring _axisTagToString(DWRITE_FONT_AXIS_TAG tag);
};

struct AxisKeyValuePair : AxisKeyValuePairT<AxisKeyValuePair>
{
AxisKeyValuePair(winrt::hstring axisKey, float axisValue, const Windows::Foundation::Collections::IMap<winrt::hstring, float>& baseMap, const Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring>& tagToNameMap) :
_AxisKey{ axisKey },
_AxisValue{ axisValue },
_baseMap{ baseMap },
_tagToNameMap{ tagToNameMap }
{
if (_tagToNameMap.HasKey(_AxisKey))
{
int32_t i{ 0 };
// this loop assumes that every time we iterate through the map
// we get the same ordering - is this true?
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
for (const auto tagAndName : _tagToNameMap)
{
if (tagAndName.Key() == _AxisKey)
{
_AxisIndex = i;
break;
}
++i;
}
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
}
}

winrt::hstring AxisKey() { return _AxisKey; }
float AxisValue() { return _AxisValue; }
int32_t AxisIndex() { return _AxisIndex; }

void AxisValue(float axisValue)
{
// todo: this probably causes an issue if there are 2 pairs with the same key...
// we should probably ensure that keys can't be repeated
_baseMap.Remove(_AxisKey);
_AxisValue = axisValue;
_baseMap.Insert(_AxisKey, _AxisValue);
}

void AxisKey(winrt::hstring axisKey)
{
// todo: this probably causes an issue if there are 2 pairs with the same key...
// we should probably ensure that keys can't be repeated
_baseMap.Remove(_AxisKey);
_AxisKey = axisKey;
_baseMap.Insert(_AxisKey, _AxisValue);
}

void AxisIndex(int32_t axisIndex)
{
_AxisIndex = axisIndex;

int32_t i{ 0 };
// same as in the constructor, this assumes that iterating through the map
// gives us the same order every time
for (const auto tagAndName : _tagToNameMap)
{
if (i == _AxisIndex)
{
AxisKey(tagAndName.Key());
break;
}
++i;
}
}

private:
winrt::hstring _AxisKey;
float _AxisValue;
int32_t _AxisIndex;
Windows::Foundation::Collections::IMap<winrt::hstring, float> _baseMap{ nullptr };
Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> _tagToNameMap{ nullptr };
};

struct AppearanceViewModel : AppearanceViewModelT<AppearanceViewModel>, ViewModelHelper<AppearanceViewModel>
Expand All @@ -77,6 +153,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Editor::ColorSchemeViewModel CurrentColorScheme();
void CurrentColorScheme(const Editor::ColorSchemeViewModel& val);

void AddNewAxisKeyValuePair();
void DeleteAxisKeyValuePair(winrt::hstring key);
void InitializeFontAxesVector();

WINRT_PROPERTY(bool, IsDefault, false);

// These settings are not defined in AppearanceConfig, so we grab them
Expand All @@ -100,6 +180,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle);
OBSERVABLE_PROJECTED_SETTING(_appearance, AdjustIndistinguishableColors);
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel>, SchemesList, _propertyChangedHandlers, nullptr);
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::AxisKeyValuePair>, FontAxesVector, _propertyChangedHandlers, nullptr);

private:
Model::AppearanceConfig _appearance;
Expand All @@ -124,6 +205,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
fire_and_forget BackgroundImage_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
void BIAlignment_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
void FontFace_SelectionChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e);
void DeleteAxisKeyValuePair_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
void AddNewAxisKeyValuePair_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);

// manually bind FontWeight
Windows::Foundation::IInspectable CurrentFontWeight() const;
Expand Down Expand Up @@ -151,6 +234,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Windows::Foundation::Collections::IMap<uint16_t, Microsoft::Terminal::Settings::Editor::EnumEntry> _FontWeightMap;
Editor::EnumEntry _CustomFontWeight{ nullptr };

Windows::Foundation::Collections::IObservableVector<winrt::hstring> _FontAxesNames;

Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
static void _ViewModelChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
void _UpdateWithNewViewModel();
Expand All @@ -160,4 +245,5 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Appearances);
BASIC_FACTORY(AxisKeyValuePair);
}
18 changes: 18 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Appearances.idl
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,26 @@ import "ColorSchemesPageViewModel.idl";
OBSERVABLE_PROJECTED_SETTING(Type, Name); \
Object Name##OverrideSource { get; }

#define COMMA ,

namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass Font : Windows.Foundation.IStringable
{
String Name { get; };
String LocalizedName { get; };
Boolean HasPowerlineCharacters { get; };
Windows.Foundation.Collections.IMap<String, String> FontAxesTagsAndNames { get; };
}

// We have to make this because we cannot bind an IObservableMap to a ListView in XAML (in c++)
// So instead we make an IObservableVector of these AxisKeyValuePair objects
runtimeclass AxisKeyValuePair
{
AxisKeyValuePair(String axisKey, Single axisValue, Windows.Foundation.Collections.IMap<String COMMA Single> baseMap, Windows.Foundation.Collections.IMap<String COMMA String> tagToNameMap);
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
String AxisKey;
Single AxisValue;
Int32 AxisIndex;
}

runtimeclass AppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
Expand All @@ -37,6 +50,11 @@ namespace Microsoft.Terminal.Settings.Editor
ColorSchemeViewModel CurrentColorScheme;
Windows.Foundation.Collections.IObservableVector<ColorSchemeViewModel> SchemesList;

void AddNewAxisKeyValuePair();
void DeleteAxisKeyValuePair(String key);
void InitializeFontAxesVector();
Windows.Foundation.Collections.IObservableVector<AxisKeyValuePair> FontAxesVector;

OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, LineHeight);
Expand Down
Loading
Loading