Skip to content

Commit

Permalink
Implement cell size customizations (#14255)
Browse files Browse the repository at this point in the history
Does what it says in the title. After this commit you can customize the height
and width of the terminal's cells. This commit supports parts of CSS'
`<length-percentage>` data type: Font-size relative sizes as multiples (`1.2`),
percentage (`120%`), or advance-width relative (`1.2ch`), as well as absolute
sizes in CSS pixels (`px`) or points (`pt`).

This PR is neither bug free in DxEngine, nor in AtlasEngine.
The former fails to implement glyph advance corrections (for instance #9381),
as well as disallowing glyphs to overlap rows. The latter has the same
overlap issue, but more severely as it tries to shrink glyphs to fit in.

Closes #3498
Closes #14068

## Validation Steps Performed
* Setting `height` to `1` creates 12pt tall rows ✅
* Setting `height` to `1ch` creates square cells ✅
* Setting `width` to `1` creates square cells ✅
* Setting `width` or `height` to `Npx` or `Npt` works ✅
* Trailing zeroes are trimmed properly during serialization ✅
* Patching the PR to allow >100 line heights and entering "100.123456"
  displays 6 fractional digits ✅
  • Loading branch information
lhecker authored Feb 14, 2023
1 parent e4bba3c commit b6e6dd8
Show file tree
Hide file tree
Showing 28 changed files with 348 additions and 64 deletions.
15 changes: 15 additions & 0 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
"pattern": "^(-?\\d+)?(,\\s?(-?\\d+)?)?$",
"type": "string"
},
"CSSLengthPercentage": {
"pattern": "^[+-]?\\d+(?:\\.\\d+)?(?:%|ch|pt|px)?$",
"type": [
"string",
"null"
]
},
"DynamicProfileSource": {
"enum": [
"Windows.Terminal.Wsl",
Expand Down Expand Up @@ -314,6 +321,14 @@
}
},
"additionalProperties": false
},
"cellWidth": {
"$ref": "#/$defs/CSSLengthPercentage",
"description": "Override the width of the terminal's cells. The override works similar to CSS' letter-spacing. It defaults to the natural glyph advance width of the primary font rounded to the nearest pixel."
},
"cellHeight": {
"$ref": "#/$defs/CSSLengthPercentage",
"description": "Override the height of the terminal's cells. The override works similar to CSS' line-height. Defaults to the sum of the natural glyph ascend, descend and line-gap of the primary font rounded to the nearest pixel. The default is usually quite close to setting this to 1.2."
}
},
"type": "object"
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation

auto lock = _terminal->LockForWriting();

_cellWidth = CSSLengthPercentage::FromString(_settings->CellWidth().c_str());
_cellHeight = CSSLengthPercentage::FromString(_settings->CellHeight().c_str());
_runtimeOpacity = std::nullopt;

// Manually turn off acrylic if they turn off transparency.
Expand Down Expand Up @@ -880,6 +882,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_actualFont = { fontFace, 0, fontWeight.Weight, _desiredFont.GetEngineSize(), CP_UTF8, false };
_actualFontFaceName = { fontFace };

_desiredFont.SetCellSize(_cellWidth, _cellHeight);

const auto before = _actualFont.GetSize();
_updateFont();
const auto after = _actualFont.GetSize();
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
FontInfoDesired _desiredFont;
FontInfo _actualFont;
winrt::hstring _actualFontFaceName;
CSSLengthPercentage _cellWidth;
CSSLengthPercentage _cellHeight;

// storage location for the leading surrogate of a utf-16 surrogate pair
std::optional<wchar_t> _leadingSurrogate{ std::nullopt };
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/IControlSettings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ namespace Microsoft.Terminal.Control
String Padding { get; };
Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures { get; };
Windows.Foundation.Collections.IMap<String, Single> FontAxes { get; };
String CellWidth { get; };
String CellHeight { get; };

Microsoft.Terminal.Control.IKeyBindings KeyBindings { get; };

Expand Down
84 changes: 80 additions & 4 deletions src/cascadia/TerminalSettingsEditor/Appearances.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,78 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}

double AppearanceViewModel::LineHeight() const noexcept
{
const auto fontInfo = _appearance.SourceProfile().FontInfo();
const auto cellHeight = fontInfo.CellHeight();
const auto str = cellHeight.c_str();

auto& errnoRef = errno; // Nonzero cost, pay it once.
errnoRef = 0;

wchar_t* end;
const auto value = std::wcstod(str, &end);

return str == end || errnoRef == ERANGE ? NAN : value;
}

void AppearanceViewModel::LineHeight(const double value)
{
std::wstring str;

if (value >= 0.1 && value <= 10.0)
{
str = fmt::format(FMT_STRING(L"{:.6g}"), value);
}

const auto fontInfo = _appearance.SourceProfile().FontInfo();

if (fontInfo.CellHeight() != str)
{
if (str.empty())
{
fontInfo.ClearCellHeight();
}
else
{
fontInfo.CellHeight(str);
}
_NotifyChanges(L"HasLineHeight", L"LineHeight");
}
}

bool AppearanceViewModel::HasLineHeight() const
{
const auto fontInfo = _appearance.SourceProfile().FontInfo();
return fontInfo.HasCellHeight();
}

void AppearanceViewModel::ClearLineHeight()
{
LineHeight(NAN);
}

Model::FontConfig AppearanceViewModel::LineHeightOverrideSource() const
{
const auto fontInfo = _appearance.SourceProfile().FontInfo();
return fontInfo.CellHeightOverrideSource();
}

void AppearanceViewModel::SetFontWeightFromDouble(double fontWeight)
{
FontWeight(Converters::DoubleToFontWeight(fontWeight));
}

void AppearanceViewModel::SetBackgroundImageOpacityFromPercentageValue(double percentageValue)
{
BackgroundImageOpacity(Converters::PercentageValueToPercentage(percentageValue));
}

void AppearanceViewModel::SetBackgroundImagePath(winrt::hstring path)
{
BackgroundImagePath(path);
}

bool AppearanceViewModel::UseDesktopBGImage()
{
return BackgroundImagePath() == L"desktopWallpaper";
Expand Down Expand Up @@ -123,10 +195,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// > .NET rounds to 12 significant digits when displaying doubles, so we will [...]
// ...obviously not do that, because this is an UI element for humans. This prevents
// issues when displaying 32-bit floats, because WinUI is unaware about their existence.
SignificantDigitsNumberRounder rounder;
rounder.SignificantDigits(6);
// BODGY: Depends on WinUI internals.
_fontSizeBox().NumberFormatter().as<DecimalFormatter>().NumberRounder(rounder);
IncrementNumberRounder rounder;
rounder.Increment(1e-6);

for (const auto& box : { _fontSizeBox(), _lineHeightBox() })
{
// BODGY: Depends on WinUI internals.
box.NumberFormatter().as<DecimalFormatter>().NumberRounder(rounder);
}
}

INITIALIZE_BINDABLE_ENUM_SETTING(CursorShape, CursorStyle, winrt::Microsoft::Terminal::Core::CursorStyle, L"Profile_CursorShape", L"Content");
Expand Down
21 changes: 9 additions & 12 deletions src/cascadia/TerminalSettingsEditor/Appearances.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
public:
AppearanceViewModel(const Model::AppearanceConfig& appearance);

void SetFontWeightFromDouble(double fontWeight)
{
FontWeight(winrt::Microsoft::Terminal::Settings::Editor::Converters::DoubleToFontWeight(fontWeight));
}
void SetBackgroundImageOpacityFromPercentageValue(double percentageValue)
{
BackgroundImageOpacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(percentageValue));
}
void SetBackgroundImagePath(winrt::hstring path)
{
BackgroundImagePath(path);
}
double LineHeight() const noexcept;
void LineHeight(const double value);
bool HasLineHeight() const;
void ClearLineHeight();
Model::FontConfig LineHeightOverrideSource() const;
void SetFontWeightFromDouble(double fontWeight);
void SetBackgroundImageOpacityFromPercentageValue(double percentageValue);
void SetBackgroundImagePath(winrt::hstring path);

// background image
bool UseDesktopBGImage();
Expand Down Expand Up @@ -100,6 +96,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
private:
Model::AppearanceConfig _appearance;
winrt::hstring _lastBgImagePath;
float _cachedLineHeight = 0;
};

struct Appearances : AppearancesT<Appearances>
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsEditor/Appearances.idl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace Microsoft.Terminal.Settings.Editor

OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, LineHeight);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight);

OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, DarkColorSchemeName);
Expand Down
17 changes: 16 additions & 1 deletion src/cascadia/TerminalSettingsEditor/Appearances.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
<muxc:NumberBox x:Name="_fontSizeBox"
x:Uid="Profile_FontSizeBox"
AcceptsExpression="False"
LargeChange="10"
Maximum="128"
Minimum="1"
Expand All @@ -228,6 +227,22 @@
Value="{x:Bind Appearance.FontSize, Mode=TwoWay}" />
</local:SettingContainer>

<!-- Line Height -->
<local:SettingContainer x:Uid="Profile_LineHeight"
ClearSettingValue="{x:Bind Appearance.ClearLineHeight}"
HasSettingValue="{x:Bind Appearance.HasLineHeight, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.LineHeightOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
<muxc:NumberBox x:Name="_lineHeightBox"
x:Uid="Profile_LineHeightBox"
LargeChange="0.1"
Maximum="10"
Minimum="0.1"
SmallChange="0.1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind Appearance.LineHeight, Mode=TwoWay}" />
</local:SettingContainer>

<!-- Font Weight -->
<local:SettingContainer x:Name="FontWeightContainer"
x:Uid="Profile_FontWeight"
Expand Down
16 changes: 16 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,22 @@
<value>Size of the font in points.</value>
<comment>A description for what the "font size" setting does. Presented near "Profile_FontSize".</comment>
</data>
<data name="Profile_LineHeight.Header" xml:space="preserve">
<value>Line height</value>
<comment>Header for a control that sets the text line height.</comment>
</data>
<data name="Profile_LineHeightBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Line height</value>
<comment>Header for a control that sets the text line height.</comment>
</data>
<data name="Profile_LineHeight.HelpText" xml:space="preserve">
<value>Sets the height of each line in the terminal as a multiple of the font size. The default depends on your font and is usually around 1.2.</value>
<comment>A description for what the "line height" setting does. Presented near "Profile_LineHeight".</comment>
</data>
<data name="Profile_LineHeightBox.PlaceholderText" xml:space="preserve">
<value>1.2</value>
<comment>"1.2" is a decimal number.</comment>
</data>
<data name="Profile_FontWeightComboBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Font weight</value>
<comment>Name for a control to select the weight (i.e. bold, thin, etc.) of the text in the app.</comment>
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source)
MTSM_PROFILE_SETTINGS(DUPLICATE_PROFILE_SETTINGS)
#undef DUPLICATE_PROFILE_SETTINGS

// These two aren't in MTSM_PROFILE_SETTINGS because they're special
// These aren't in MTSM_PROFILE_SETTINGS because they're special
DUPLICATE_SETTING_MACRO(TabColor);
DUPLICATE_SETTING_MACRO(Padding);

Expand Down
5 changes: 0 additions & 5 deletions src/cascadia/TerminalSettingsModel/FontConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ void FontConfig::LayerJson(const Json::Value& json)
}
}

bool FontConfig::HasAnyOptionSet() const
{
return HasFontFace() || HasFontSize() || HasFontWeight();
}

winrt::Microsoft::Terminal::Settings::Model::Profile FontConfig::SourceProfile()
{
return _sourceProfile.get();
Expand Down
1 change: 0 additions & 1 deletion src/cascadia/TerminalSettingsModel/FontConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static winrt::com_ptr<FontConfig> CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile);
Json::Value ToJson() const;
void LayerJson(const Json::Value& json);
bool HasAnyOptionSet() const;

Model::Profile SourceProfile();

Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalSettingsModel/FontConfig.idl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_FONT_SETTING(String, FontFace);
INHERITABLE_FONT_SETTING(Single, FontSize);
INHERITABLE_FONT_SETTING(Windows.UI.Text.FontWeight, FontWeight);

INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA UInt32>, FontFeatures);
INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA Single>, FontAxes);
INHERITABLE_FONT_SETTING(String, CellWidth);
INHERITABLE_FONT_SETTING(String, CellHeight);
}
}
4 changes: 3 additions & 1 deletion src/cascadia/TerminalSettingsModel/MTSMSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ Author(s):
X(float, FontSize, "size", DEFAULT_FONT_SIZE) \
X(winrt::Windows::UI::Text::FontWeight, FontWeight, "weight", DEFAULT_FONT_WEIGHT) \
X(IFontAxesMap, FontAxes, "axes") \
X(IFontFeatureMap, FontFeatures, "features")
X(IFontFeatureMap, FontFeatures, "features") \
X(winrt::hstring, CellWidth, "cellWidth") \
X(winrt::hstring, CellHeight, "cellHeight")

#define MTSM_APPEARANCE_SETTINGS(X) \
X(Core::CursorStyle, CursorShape, "cursorShape", Core::CursorStyle::Bar) \
Expand Down
6 changes: 2 additions & 4 deletions src/cascadia/TerminalSettingsModel/Profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,9 @@ Json::Value Profile::ToJson() const
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_TO_JSON)
#undef PROFILE_SETTINGS_TO_JSON

// Font settings
const auto fontInfoImpl = winrt::get_self<FontConfig>(_FontInfo);
if (fontInfoImpl->HasAnyOptionSet())
if (auto fontJSON = winrt::get_self<FontConfig>(_FontInfo)->ToJson(); !fontJSON.empty())
{
json[JsonKey(FontInfoKey)] = winrt::get_self<FontConfig>(_FontInfo)->ToJson();
json[JsonKey(FontInfoKey)] = std::move(fontJSON);
}

if (_UnfocusedAppearance)
Expand Down
13 changes: 8 additions & 5 deletions src/cascadia/TerminalSettingsModel/TerminalSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_ProfileSource = profile.Source();
_UseAcrylic = profile.UseAcrylic();

_FontFace = profile.FontInfo().FontFace();
_FontSize = profile.FontInfo().FontSize();
_FontWeight = profile.FontInfo().FontWeight();
_FontFeatures = profile.FontInfo().FontFeatures();
_FontAxes = profile.FontInfo().FontAxes();
const auto fontInfo = profile.FontInfo();
_FontFace = fontInfo.FontFace();
_FontSize = fontInfo.FontSize();
_FontWeight = fontInfo.FontWeight();
_FontFeatures = fontInfo.FontFeatures();
_FontAxes = fontInfo.FontAxes();
_CellWidth = fontInfo.CellWidth();
_CellHeight = fontInfo.CellHeight();
_Padding = profile.Padding();

_Commandline = profile.Commandline();
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalSettingsModel/TerminalSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, winrt::Windows::UI::Text::FontWeight, FontWeight);
INHERITABLE_SETTING(Model::TerminalSettings, IFontAxesMap, FontAxes);
INHERITABLE_SETTING(Model::TerminalSettings, IFontFeatureMap, FontFeatures);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, CellWidth);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, CellHeight);

INHERITABLE_SETTING(Model::TerminalSettings, Model::ColorScheme, AppliedColorScheme);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, BackgroundImage);
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/inc/ControlProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
X(winrt::Windows::UI::Text::FontWeight, FontWeight) \
X(IFontFeatureMap, FontFeatures) \
X(IFontAxesMap, FontAxes) \
X(winrt::hstring, CellWidth) \
X(winrt::hstring, CellHeight) \
X(winrt::Microsoft::Terminal::Control::IKeyBindings, KeyBindings, nullptr) \
X(winrt::hstring, Commandline) \
X(winrt::hstring, StartingDirectory) \
Expand Down
Loading

0 comments on commit b6e6dd8

Please sign in to comment.