Implement the Delta E algorithm to improve color perception (#11095)

- Implements the Delta E algorithm
- Uses the Delta E algorithm to precalculate adjusted foreground values based on possible foreground/background color pairs in the color table
- Adds a setting to use the adjusted foreground values when applicable

## PR Checklist
* [x] Closes #2638
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
Before:
<img width="759" alt="color before" src="https://user-images.githubusercontent.com/26824113/131576768-b3b9eebd-5933-45de-8da8-88a985070312.png">

After (note dark blue):
<img width="760" alt="color after" src="https://user-images.githubusercontent.com/26824113/133158807-4e63198f-8a49-4d03-914e-55a5ad57d725.png">
This commit is contained in:
PankajBhojwani 2021-10-07 15:43:17 -07:00 committed by GitHub
parent bc4f410788
commit dd5dbb2a40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 453 additions and 9 deletions

View File

@ -1,3 +1,10 @@
atan
CPrime
HBar
HPrime
isnan
LPrime
LStep
powf
RSub
sqrtf

View File

@ -1,5 +1,7 @@
http
www
easyrgb
php
ecma
rapidtables
WCAG

View File

@ -252,6 +252,43 @@ DEALINGS IN THE SOFTWARE.
```
## ConEmu
**Source**: [https://github.com/Maximus5/ConEmu](https://github.com/Maximus5/ConEmu)
### License
```
BSD 3-Clause License
Copyright (c) 2009-2017, Maximus5 <ConEmu.Maximus5@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
# Microsoft Open Source
This product also incorporates source code from other Microsoft open source projects, all licensed under the MIT license.

View File

@ -188,6 +188,10 @@
],
"type": "string"
},
"adjustIndistinguishableColors": {
"description": "When set to true, we will (when necessary) adjust the foreground color to make it more visible, based on the background color.",
"type": "boolean"
},
"experimental.retroTerminalEffect": {
"description": "When set to true, enable retro terminal effects when unfocused. This is an experimental feature, and its continued existence is not guaranteed.",
"type": "boolean"
@ -1973,6 +1977,10 @@
}
]
},
"adjustIndistinguishableColors": {
"description": "When set to true, we will (when necessary) adjust the foreground color to make it more visible, based on the background color.",
"type": "boolean"
},
"scrollbarState": {
"default": "visible",
"description": "Defines the visibility of the scrollbar.",

View File

@ -0,0 +1,228 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
// A lot of code was taken from
// https://github.com/Maximus5/ConEmu/blob/master/src/ConEmu/ColorFix.cpp
// and then adjusted to fit our style guidelines
#include "pch.h"
#include <Windows.h>
#include "ColorFix.hpp"
static constexpr double gMinThreshold = 12.0;
static constexpr double gExpThreshold = 20.0;
static constexpr double gLStep = 5.0;
static constexpr double rad006 = 0.104719755119659774;
static constexpr double rad025 = 0.436332312998582394;
static constexpr double rad030 = 0.523598775598298873;
static constexpr double rad060 = 1.047197551196597746;
static constexpr double rad063 = 1.099557428756427633;
static constexpr double rad180 = 3.141592653589793238;
static constexpr double rad275 = 4.799655442984406336;
static constexpr double rad360 = 6.283185307179586476;
ColorFix::ColorFix(COLORREF color)
{
rgb = color;
_ToLab();
}
// Method Description:
// - Helper function to calculate HPrime
double ColorFix::_GetHPrimeFn(double x, double y)
{
if (x == 0 && y == 0)
{
return 0;
}
const auto hueAngle = atan2(x, y);
return hueAngle >= 0 ? hueAngle : hueAngle + rad360;
}
// Method Description:
// - Given 2 colors, computes the DeltaE value between them
// Arguments:
// - x1: the first color
// - x2: the second color
// Return Value:
// - The DeltaE value between x1 and x2
double ColorFix::_GetDeltaE(ColorFix x1, ColorFix x2)
{
constexpr double kSubL = 1;
constexpr double kSubC = 1;
constexpr double kSubH = 1;
// Delta L Prime
const double deltaLPrime = x2.L - x1.L;
// L Bar
const double lBar = (x1.L + x2.L) / 2;
// C1 & C2
const double c1 = sqrt(pow(x1.A, 2) + pow(x1.B, 2));
const double c2 = sqrt(pow(x2.A, 2) + pow(x2.B, 2));
// C Bar
const double cBar = (c1 + c2) / 2;
// A Prime 1
const double aPrime1 = x1.A + (x1.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7))));
// A Prime 2
const double aPrime2 = x2.A + (x2.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7))));
// C Prime 1
const double cPrime1 = sqrt(pow(aPrime1, 2) + pow(x1.B, 2));
// C Prime 2
const double cPrime2 = sqrt(pow(aPrime2, 2) + pow(x2.B, 2));
// C Bar Prime
const double cBarPrime = (cPrime1 + cPrime2) / 2;
// Delta C Prime
const double deltaCPrime = cPrime2 - cPrime1;
// S sub L
const double sSubL = 1 + ((0.015 * pow(lBar - 50, 2)) / sqrt(20 + pow(lBar - 50, 2)));
// S sub C
const double sSubC = 1 + 0.045 * cBarPrime;
// h Prime 1
const double hPrime1 = _GetHPrimeFn(x1.B, aPrime1);
// h Prime 2
const double hPrime2 = _GetHPrimeFn(x2.B, aPrime2);
// Delta H Prime
const double deltaHPrime = 0 == c1 || 0 == c2 ? 0 : 2 * sqrt(cPrime1 * cPrime2) * sin(abs(hPrime1 - hPrime2) <= rad180 ? hPrime2 - hPrime1 : (hPrime2 <= hPrime1 ? hPrime2 - hPrime1 + rad360 : hPrime2 - hPrime1 - rad360) / 2);
// H Bar Prime
const double hBarPrime = (abs(hPrime1 - hPrime2) > rad180) ? (hPrime1 + hPrime2 + rad360) / 2 : (hPrime1 + hPrime2) / 2;
// T
const double t = 1 - 0.17 * cos(hBarPrime - rad030) + 0.24 * cos(2 * hBarPrime) + 0.32 * cos(3 * hBarPrime + rad006) - 0.20 * cos(4 * hBarPrime - rad063);
// S sub H
const double sSubH = 1 + 0.015 * cBarPrime * t;
// R sub T
const double rSubT = -2 * sqrt(pow(cBarPrime, 7) / (pow(cBarPrime, 7) + pow(25.0, 7))) * sin(rad060 * exp(-pow((hBarPrime - rad275) / rad025, 2)));
// Put it all together!
const double lightness = deltaLPrime / (kSubL * sSubL);
const double chroma = deltaCPrime / (kSubC * sSubC);
const double hue = deltaHPrime / (kSubH * sSubH);
return sqrt(pow(lightness, 2) + pow(chroma, 2) + pow(hue, 2) + rSubT * chroma * hue);
}
// Method Description:
// - Populates our L, A, B values, based on our r, g, b values
// - Converts a color in rgb format to a color in lab format
// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1
void ColorFix::_ToLab()
{
double var_R = r / 255.0;
double var_G = g / 255.0;
double var_B = b / 255.0;
var_R = var_R > 0.04045 ? pow(((var_R + 0.055) / 1.055), 2.4) : var_R / 12.92;
var_G = var_G > 0.04045 ? pow(((var_G + 0.055) / 1.055), 2.4) : var_G / 12.92;
var_B = var_B > 0.04045 ? pow(((var_B + 0.055) / 1.055), 2.4) : var_B / 12.92;
var_R = var_R * 100.;
var_G = var_G * 100.;
var_B = var_B * 100.;
//Observer. = 2 degrees, Illuminant = D65
const double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
const double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
const double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65)
double var_Y = Y / 100.000; //ref_Y = 100.000
double var_Z = Z / 108.883; //ref_Z = 108.883
var_X = var_X > 0.008856 ? pow(var_X, (1. / 3.)) : (7.787 * var_X) + (16. / 116.);
var_Y = var_Y > 0.008856 ? pow(var_Y, (1. / 3.)) : (7.787 * var_Y) + (16. / 116.);
var_Z = var_Z > 0.008856 ? pow(var_Z, (1. / 3.)) : (7.787 * var_Z) + (16. / 116.);
L = (116. * var_Y) - 16.;
A = 500. * (var_X - var_Y);
B = 200. * (var_Y - var_Z);
}
// Method Description:
// - Populates our r, g, b values, based on our L, A, B values
// - Converts a color in lab format to a color in rgb format
// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1
void ColorFix::_ToRGB()
{
double var_Y = (L + 16.) / 116.;
double var_X = A / 500. + var_Y;
double var_Z = var_Y - B / 200.;
var_Y = (pow(var_Y, 3) > 0.008856) ? pow(var_Y, 3) : (var_Y - 16. / 116.) / 7.787;
var_X = (pow(var_X, 3) > 0.008856) ? pow(var_X, 3) : (var_X - 16. / 116.) / 7.787;
var_Z = (pow(var_Z, 3) > 0.008856) ? pow(var_Z, 3) : (var_Z - 16. / 116.) / 7.787;
double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65)
double Y = 100.000 * var_Y; //ref_Y = 100.000
double Z = 108.883 * var_Z; //ref_Z = 108.883
var_X = X / 100.; //X from 0 to 95.047 (Observer = 2 degrees, Illuminant = D65)
var_Y = Y / 100.; //Y from 0 to 100.000
var_Z = Z / 100.; //Z from 0 to 108.883
double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;
double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;
double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570;
var_R = var_R > 0.0031308 ? 1.055 * pow(var_R, (1 / 2.4)) - 0.055 : var_R = 12.92 * var_R;
var_G = var_G > 0.0031308 ? 1.055 * pow(var_G, (1 / 2.4)) - 0.055 : var_G = 12.92 * var_G;
var_B = var_B > 0.0031308 ? 1.055 * pow(var_B, (1 / 2.4)) - 0.055 : var_B = 12.92 * var_B;
r = (BYTE)std::clamp(var_R * 255., 0., 255.);
g = (BYTE)std::clamp(var_G * 255., 0., 255.);
b = (BYTE)std::clamp(var_B * 255., 0., 255.);
}
// Method Description:
// - Given foreground and background colors, change the foreground color to
// make it more perceivable if necessary
// - Arguments:
// - fg: the foreground color
// - bg: the background color
// - Return Value:
// - The foreground color after performing any necessary changes to make it more perceivable
COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg)
{
ColorFix backLab(bg);
ColorFix frontLab(fg);
const double de1 = _GetDeltaE(frontLab, backLab);
if (de1 < gMinThreshold)
{
for (int i = 0; i <= 1; i++)
{
const double step = (i == 0) ? gLStep : -gLStep;
frontLab.L += step;
while (((i == 0) && (frontLab.L <= 100)) || ((i == 1) && (frontLab.L >= 0)))
{
const double de2 = _GetDeltaE(frontLab, backLab);
if (de2 >= gExpThreshold)
{
frontLab._ToRGB();
return frontLab.rgb;
}
frontLab.L += step;
}
}
}
return frontLab.rgb;
}

View File

@ -0,0 +1,49 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- ColorFix
Abstract:
- Implementation of perceptual color nudging, which allows the Terminal
to slightly shift the foreground color to make it more perceivable on
the current background (for cases where the foreground is very close
to being imperceivable on the background).
Author(s):
- Pankaj Bhojwani - Sep 2021
--*/
#pragma once
struct ColorFix
{
public:
ColorFix(COLORREF color);
static COLORREF GetPerceivableColor(COLORREF fg, COLORREF bg);
// RGB
union
{
struct
{
BYTE r, g, b, dummy;
};
COLORREF rgb;
};
// Lab
struct
{
double L, A, B;
};
private:
static double _GetHPrimeFn(double x, double y);
static double _GetDeltaE(ColorFix x1, ColorFix x2);
void _ToLab();
void _ToRGB();
};

View File

@ -67,5 +67,6 @@ namespace Microsoft.Terminal.Core
CursorStyle CursorShape;
UInt32 CursorHeight;
Boolean IntenseIsBright;
Boolean AdjustIndistinguishableColors;
};
}

View File

@ -53,7 +53,8 @@ Terminal::Terminal() :
_taskbarState{ 0 },
_taskbarProgress{ 0 },
_trimBlockSelection{ false },
_intenseIsBright{ true }
_intenseIsBright{ true },
_adjustIndistinguishableColors{ true }
{
auto dispatch = std::make_unique<TerminalDispatch>(*this);
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
@ -175,11 +176,16 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
_defaultBg = newBackgroundColor.with_alpha(0);
_defaultFg = appearance.DefaultForeground();
_intenseIsBright = appearance.IntenseIsBright();
_adjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
for (int i = 0; i < 16; i++)
{
_colorTable.at(i) = til::color{ appearance.GetColorTableEntry(i) };
}
if (_adjustIndistinguishableColors)
{
_MakeAdjustedColorArray();
}
CursorType cursorShape = CursorType::VerticalBar;
switch (appearance.CursorShape())

View File

@ -301,6 +301,7 @@ private:
bool _bracketedPasteMode;
bool _trimBlockSelection;
bool _intenseIsBright;
bool _adjustIndistinguishableColors;
size_t _taskbarState;
size_t _taskbarProgress;
@ -401,6 +402,9 @@ private:
Microsoft::Console::VirtualTerminal::SgrStack _sgrStack;
void _MakeAdjustedColorArray();
std::array<std::array<COLORREF, 18>, 18> _adjustedForegroundColors;
#ifdef UNIT_TESTING
friend class TerminalCoreUnitTests::TerminalBufferTests;
friend class TerminalCoreUnitTests::TerminalApiTest;

View File

@ -8,6 +8,7 @@
<ClCompile Include="..\TerminalSelection.cpp" />
<ClCompile Include="..\TerminalApi.cpp" />
<ClCompile Include="..\Terminal.cpp" />
<ClCompile Include="..\ColorFix.cpp" />
<ClCompile Include="..\pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
@ -19,6 +20,7 @@
<ClInclude Include="..\ITerminalApi.hpp" />
<ClInclude Include="..\pch.h" />
<ClInclude Include="..\Terminal.hpp" />
<ClInclude Include="..\ColorFix.hpp" />
</ItemGroup>
</Project>

View File

@ -3,11 +3,16 @@
#include "pch.h"
#include "Terminal.hpp"
#include "ColorFix.hpp"
#include <DefaultSettings.h>
using namespace Microsoft::Terminal::Core;
using namespace Microsoft::Console::Types;
using namespace Microsoft::Console::Render;
static constexpr size_t DefaultBgIndex{ 16 };
static constexpr size_t DefaultFgIndex{ 17 };
Viewport Terminal::GetViewport() noexcept
{
return _GetVisibleViewport();
@ -44,14 +49,47 @@ const TextAttribute Terminal::GetDefaultBrushColors() noexcept
std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute& attr) const noexcept
{
std::pair<COLORREF, COLORREF> colors;
_blinkingState.RecordBlinkingUsage(attr);
auto colors = attr.CalculateRgbColors(
_colorTable,
_defaultFg,
_defaultBg,
_screenReversed,
_blinkingState.IsBlinkingFaint(),
_intenseIsBright);
const auto fgTextColor = attr.GetForeground();
const auto bgTextColor = attr.GetBackground();
// We want to nudge the foreground color to make it more perceivable only for the
// default color pairs within the color table
if (_adjustIndistinguishableColors &&
!(attr.IsFaint() || (attr.IsBlinking() && _blinkingState.IsBlinkingFaint())) &&
(fgTextColor.IsDefault() || fgTextColor.IsLegacy()) &&
(bgTextColor.IsDefault() || bgTextColor.IsLegacy()))
{
const auto bgIndex = bgTextColor.IsDefault() ? DefaultBgIndex : bgTextColor.GetIndex();
auto fgIndex = fgTextColor.IsDefault() ? DefaultFgIndex : fgTextColor.GetIndex();
if (fgTextColor.IsIndex16() && (fgIndex < 8) && attr.IsBold() && _intenseIsBright)
{
// There is a special case for bold here - we need to get the bright version of the foreground color
fgIndex += 8;
}
if (attr.IsReverseVideo() ^ _screenReversed)
{
colors.first = _adjustedForegroundColors[fgIndex][bgIndex];
colors.second = fgTextColor.GetColor(_colorTable, _defaultFg);
}
else
{
colors.first = _adjustedForegroundColors[bgIndex][fgIndex];
colors.second = bgTextColor.GetColor(_colorTable, _defaultBg);
}
}
else
{
colors = attr.CalculateRgbColors(_colorTable,
_defaultFg,
_defaultBg,
_screenReversed,
_blinkingState.IsBlinkingFaint(),
_intenseIsBright);
}
colors.first |= 0xff000000;
// We only care about alpha for the default BG (which enables acrylic)
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
@ -262,3 +300,34 @@ const bool Terminal::IsUiaDataInitialized() const noexcept
// UiaData are not yet initialized.
return !!_buffer;
}
// Method Description:
// - Creates the adjusted color array, which contains the possible foreground colors,
// adjusted for perceivability
// - The adjusted color array is 2-d, and effectively maps a background and foreground
// color pair to the adjusted foreground for that color pair
void Terminal::_MakeAdjustedColorArray()
{
// The color table has 16 colors, but the adjusted color table needs to be 18
// to include the default background and default foreground colors
std::array<COLORREF, 18> colorTableWithDefaults;
std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults));
colorTableWithDefaults[DefaultBgIndex] = _defaultBg;
colorTableWithDefaults[DefaultFgIndex] = _defaultFg;
for (auto fgIndex = 0; fgIndex < 18; ++fgIndex)
{
const auto fg = til::at(colorTableWithDefaults, fgIndex);
for (auto bgIndex = 0; bgIndex < 18; ++bgIndex)
{
if (fgIndex == bgIndex)
{
_adjustedForegroundColors[bgIndex][fgIndex] = fg;
}
else
{
const auto bg = til::at(colorTableWithDefaults, bgIndex);
_adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg);
}
}
}
}

View File

@ -1,4 +1,4 @@
/*++
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
@ -93,6 +93,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode);
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment);
OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle);
OBSERVABLE_PROJECTED_SETTING(_appearance, AdjustIndistinguishableColors);
private:
Model::AppearanceConfig _appearance;

View File

@ -46,6 +46,7 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.IntenseStyle, IntenseTextStyle);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, AdjustIndistinguishableColors);
}
[default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged

View File

@ -153,6 +153,14 @@
SettingOverrideSource="{x:Bind Appearance.RetroTerminalEffectOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Appearance.RetroTerminalEffect, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Adjust Indistinguishable Colors -->
<local:SettingContainer x:Uid="Profile_AdjustIndistinguishableColors"
ClearSettingValue="{x:Bind Appearance.ClearAdjustIndistinguishableColors}"
HasSettingValue="{x:Bind Appearance.HasAdjustIndistinguishableColors, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.AdjustIndistinguishableColorsOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Appearance.AdjustIndistinguishableColors, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Cursor -->

View File

@ -799,6 +799,14 @@
<value>When enabled, enables retro terminal effects such as glowing text and scan lines.</value>
<comment>A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect".</comment>
</data>
<data name="Profile_AdjustIndistinguishableColors.Header" xml:space="preserve">
<value>Automatically adjust lightness of indistinguishable text</value>
<comment>Header for a control to toggle if we should adjust the foreground color's lightness to make it more visible when necessary, based on the background color.</comment>
</data>
<data name="Profile_AdjustIndistinguishableColors.HelpText" xml:space="preserve">
<value>When enabled, enables automatic adjustment of indistinguishable colors, which will, only when necessary, adjust the foreground color's lightness to make it more visible (based on the background color).</value>
<comment>A description for what the "adjust indistinguishable colors" setting does. Presented near "Profile_AdjustIndistinguishableColors".</comment>
</data>
<data name="Profile_ScrollbarVisibility.Header" xml:space="preserve">
<value>Scrollbar visibility</value>
<comment>Header for a control to select the visibility of the scrollbar in a session.</comment>

View File

@ -26,6 +26,7 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA
static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" };
static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" };
static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" };
static constexpr std::string_view AdjustIndistinguishableColorsKey{ "adjustIndistinguishableColors" };
static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" };
static constexpr std::string_view OpacityKey{ "opacity" };
@ -52,6 +53,7 @@ winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const Appearan
appearance->_PixelShaderPath = source->_PixelShaderPath;
appearance->_IntenseTextStyle = source->_IntenseTextStyle;
appearance->_Opacity = source->_Opacity;
appearance->_AdjustIndistinguishableColors = source->_AdjustIndistinguishableColors;
return appearance;
}
@ -73,6 +75,7 @@ Json::Value AppearanceConfig::ToJson() const
JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath);
JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle);
JsonUtils::SetValueForKey(json, AdjustIndistinguishableColorsKey, _AdjustIndistinguishableColors);
JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{});
return json;
@ -105,6 +108,7 @@ void AppearanceConfig::LayerJson(const Json::Value& json)
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath);
JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle);
JsonUtils::GetValueForKey(json, AdjustIndistinguishableColorsKey, _AdjustIndistinguishableColors);
JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity);
JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{});
}

View File

@ -54,6 +54,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright);
INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0);
INHERITABLE_SETTING(Model::IAppearanceConfig, bool, AdjustIndistinguishableColors, true);
private:
winrt::weak_ref<Profile> _sourceProfile;
};

View File

@ -318,6 +318,7 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source)
DUPLICATE_SETTING_MACRO_SUB(appearance, target, RetroTerminalEffect);
DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorShape);
DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorHeight);
DUPLICATE_SETTING_MACRO_SUB(appearance, target, AdjustIndistinguishableColors);
DUPLICATE_SETTING_MACRO_SUB(appearance, target, Opacity);
}

View File

@ -51,6 +51,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect);
INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath);
INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle);
INHERITABLE_APPEARANCE_SETTING(Boolean, AdjustIndistinguishableColors);
INHERITABLE_APPEARANCE_SETTING(Double, Opacity);
};
}

View File

@ -202,6 +202,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold);
_IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright);
_AdjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
_Opacity = appearance.Opacity();
}

View File

@ -114,6 +114,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, bool, IntenseIsBright);
INHERITABLE_SETTING(Model::TerminalSettings, bool, AdjustIndistinguishableColors);
// ------------------------ End of Core Settings -----------------------
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);

View File

@ -47,6 +47,7 @@ namespace ControlUnitTests
WINRT_PROPERTY(bool, TrimBlockSelection, false);
WINRT_PROPERTY(bool, DetectURLs, true);
WINRT_PROPERTY(bool, IntenseIsBright, true);
WINRT_PROPERTY(bool, AdjustIndistinguishableColors, true);
// ------------------------ End of Core Settings -----------------------
WINRT_PROPERTY(winrt::hstring, ProfileName);

View File

@ -74,6 +74,7 @@ namespace TerminalCoreUnitTests
void DetectURLs(bool) {}
WINRT_PROPERTY(bool, IntenseIsBright, true);
WINRT_PROPERTY(bool, AdjustIndistinguishableColors, true);
private:
int32_t _historySize;