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:
parent
bc4f410788
commit
dd5dbb2a40
|
@ -1,3 +1,10 @@
|
|||
atan
|
||||
CPrime
|
||||
HBar
|
||||
HPrime
|
||||
isnan
|
||||
LPrime
|
||||
LStep
|
||||
powf
|
||||
RSub
|
||||
sqrtf
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
http
|
||||
www
|
||||
easyrgb
|
||||
php
|
||||
ecma
|
||||
rapidtables
|
||||
WCAG
|
||||
|
|
37
NOTICE.md
37
NOTICE.md
|
@ -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.
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -67,5 +67,6 @@ namespace Microsoft.Terminal.Core
|
|||
CursorStyle CursorShape;
|
||||
UInt32 CursorHeight;
|
||||
Boolean IntenseIsBright;
|
||||
Boolean AdjustIndistinguishableColors;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 -->
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>{});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -74,6 +74,7 @@ namespace TerminalCoreUnitTests
|
|||
void DetectURLs(bool) {}
|
||||
|
||||
WINRT_PROPERTY(bool, IntenseIsBright, true);
|
||||
WINRT_PROPERTY(bool, AdjustIndistinguishableColors, true);
|
||||
|
||||
private:
|
||||
int32_t _historySize;
|
||||
|
|
Loading…
Reference in New Issue