d4d59fa339
This commit introduces all of the Windows Terminal and Console Host source, under the MIT license.
226 lines
7.7 KiB
C++
226 lines
7.7 KiB
C++
/*++
|
|
Copyright (c) Microsoft Corporation
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
- conattrs.cpp
|
|
|
|
Abstract:
|
|
- Defines common operations on console attributes, especially in regards to
|
|
finding the nearest color from a color table.
|
|
|
|
Author(s):
|
|
- Mike Griese (migrie) 01-Sept-2017
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "..\inc\conattrs.hpp"
|
|
#include <math.h>
|
|
|
|
struct _HSL
|
|
{
|
|
double h, s, l;
|
|
|
|
// constructs an HSL color from a RGB Color.
|
|
_HSL(const COLORREF rgb)
|
|
{
|
|
const double r = (double) GetRValue(rgb);
|
|
const double g = (double) GetGValue(rgb);
|
|
const double b = (double) GetBValue(rgb);
|
|
|
|
const auto[min, max] = std::minmax({ r, g, b });
|
|
|
|
const auto diff = max - min;
|
|
const auto sum = max + min;
|
|
// Luminence
|
|
l = max / 255.0;
|
|
|
|
// Saturation
|
|
s = (max == 0) ? 0 : diff / max;
|
|
|
|
//Hue
|
|
double q = (diff == 0)? 0 : 60.0/diff;
|
|
if (max == r)
|
|
{
|
|
h = (g < b)? ((360.0 + q * (g - b))/360.0) : ((q * (g - b))/360.0);
|
|
}
|
|
else if (max == g)
|
|
{
|
|
h = (120.0 + q * (b - r))/360.0;
|
|
}
|
|
else if (max == b)
|
|
{
|
|
h = (240.0 + q * (r - g))/360.0;
|
|
}
|
|
else
|
|
{
|
|
h = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
//Routine Description:
|
|
// Finds the "distance" between a given HSL color and an RGB color, using the HSL color space.
|
|
// This function is designed such that the caller would convert one RGB color to HSL ahead of time,
|
|
// then compare many RGB colors to that first color.
|
|
//Arguments:
|
|
// - phslColorA - a pointer to the first color, as a HSL color.
|
|
// - rgbColorB - The second color to compare, in RGB color.
|
|
// Return value:
|
|
// The "distance" between the two.
|
|
static double _FindDifference(const _HSL* const phslColorA, const COLORREF rgbColorB)
|
|
{
|
|
const _HSL hslColorB = _HSL(rgbColorB);
|
|
return sqrt( pow((hslColorB.h - phslColorA->h), 2) +
|
|
pow((hslColorB.s - phslColorA->s), 2) +
|
|
pow((hslColorB.l - phslColorA->l), 2) );
|
|
}
|
|
|
|
//Routine Description:
|
|
// For a given RGB color Color, finds the nearest color from the array ColorTable, and returns the index of that match.
|
|
//Arguments:
|
|
// - Color - The RGB color to fine the nearest color to.
|
|
// - ColorTable - The array of colors to find a nearest color from.
|
|
// - cColorTable - The number of elements in ColorTable
|
|
// Return value:
|
|
// The index in ColorTable of the nearest match to Color.
|
|
WORD FindNearestTableIndex(const COLORREF Color, _In_reads_(cColorTable) const COLORREF* const ColorTable, const WORD cColorTable)
|
|
{
|
|
// Quick check for an exact match in the color table:
|
|
for (WORD i = 0; i < cColorTable; i++)
|
|
{
|
|
if (Color == ColorTable[i])
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// Did not find an exact match - do an expensive comparison to the elements
|
|
// of the table to find the nearest color.
|
|
const _HSL hslColor = _HSL(Color);
|
|
WORD closest = 0;
|
|
double minDiff = _FindDifference(&hslColor, ColorTable[0]);
|
|
for (WORD i = 1; i < cColorTable; i++)
|
|
{
|
|
double diff = _FindDifference(&hslColor, ColorTable[i]);
|
|
if (diff < minDiff)
|
|
{
|
|
minDiff = diff;
|
|
closest = i;
|
|
}
|
|
}
|
|
return closest;
|
|
}
|
|
|
|
// Function Description:
|
|
// - Converts the value of a xterm color table index to the windows color table equivalent.
|
|
// Arguments:
|
|
// - xtermTableEntry: the xterm color table index
|
|
// Return Value:
|
|
// - The windows color table equivalent.
|
|
WORD XtermToWindowsIndex(const size_t xtermTableEntry) noexcept
|
|
{
|
|
const bool fRed = WI_IsFlagSet(xtermTableEntry, XTERM_RED_ATTR);
|
|
const bool fGreen = WI_IsFlagSet(xtermTableEntry, XTERM_GREEN_ATTR);
|
|
const bool fBlue = WI_IsFlagSet(xtermTableEntry, XTERM_BLUE_ATTR);
|
|
const bool fBright = WI_IsFlagSet(xtermTableEntry, XTERM_BRIGHT_ATTR);
|
|
|
|
return (fRed ? WINDOWS_RED_ATTR : 0x0) +
|
|
(fGreen ? WINDOWS_GREEN_ATTR : 0x0) +
|
|
(fBlue ? WINDOWS_BLUE_ATTR : 0x0) +
|
|
(fBright ? WINDOWS_BRIGHT_ATTR : 0x0);
|
|
}
|
|
|
|
// Function Description:
|
|
// - Converts the value of a xterm color table index to the windows color table
|
|
// equivalent. The range of values is [0, 255], where the lowest 16 are
|
|
// mapped to the equivalent Windows index, and the rest of the values are
|
|
// passed through.
|
|
// Arguments:
|
|
// - xtermTableEntry: the xterm color table index
|
|
// Return Value:
|
|
// - The windows color table equivalent.
|
|
WORD Xterm256ToWindowsIndex(const size_t xtermTableEntry) noexcept
|
|
{
|
|
return xtermTableEntry < 16 ? XtermToWindowsIndex(xtermTableEntry) :
|
|
static_cast<WORD>(xtermTableEntry);
|
|
}
|
|
|
|
// Function Description:
|
|
// - Converts the value of a pair of xterm color table indicies to the legacy attr equivalent.
|
|
// Arguments:
|
|
// - xtermForeground: the xterm color table foreground index
|
|
// - xtermBackground: the xterm color table background index
|
|
// Return Value:
|
|
// - The legacy windows attribute equivalent.
|
|
WORD XtermToLegacy(const size_t xtermForeground, const size_t xtermBackground)
|
|
{
|
|
const WORD fgAttr = XtermToWindowsIndex(xtermForeground);
|
|
const WORD bgAttr = XtermToWindowsIndex(xtermBackground);
|
|
|
|
return (bgAttr << 4) | fgAttr;
|
|
}
|
|
|
|
//Routine Description:
|
|
// Returns the exact entry from the color table, if it's in there.
|
|
//Arguments:
|
|
// - Color - The RGB color to fine the nearest color to.
|
|
// - ColorTable - The array of colors to find a nearest color from.
|
|
// - cColorTable - The number of elements in ColorTable
|
|
// Return value:
|
|
// The index in ColorTable of the nearest match to Color.
|
|
bool FindTableIndex(const COLORREF Color,
|
|
_In_reads_(cColorTable) const COLORREF* const ColorTable,
|
|
const WORD cColorTable,
|
|
_Out_ WORD* const pFoundIndex)
|
|
{
|
|
*pFoundIndex = 0;
|
|
for (WORD i = 0; i < cColorTable; i++)
|
|
{
|
|
if (ColorTable[i] == Color)
|
|
{
|
|
*pFoundIndex = i;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Get a COLORREF for the foreground component of the given legacy attributes.
|
|
// Arguments:
|
|
// - wLegacyAttrs - The legacy attributes to get the foreground color from.
|
|
// - ColorTable - The array of colors to to get the color from.
|
|
// - cColorTable - The number of elements in ColorTable
|
|
// Return Value:
|
|
// - the COLORREF for the foreground component
|
|
COLORREF ForegroundColor(const WORD wLegacyAttrs,
|
|
_In_reads_(cColorTable) const COLORREF* const ColorTable,
|
|
const size_t cColorTable)
|
|
{
|
|
const byte iColorTableIndex = LOBYTE(wLegacyAttrs) & FG_ATTRS;
|
|
|
|
return (iColorTableIndex < cColorTable && iColorTableIndex >= 0) ?
|
|
ColorTable[iColorTableIndex] :
|
|
INVALID_COLOR;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Get a COLORREF for the background component of the given legacy attributes.
|
|
// Arguments:
|
|
// - wLegacyAttrs - The legacy attributes to get the background color from.
|
|
// - ColorTable - The array of colors to to get the color from.
|
|
// - cColorTable - The number of elements in ColorTable
|
|
// Return Value:
|
|
// - the COLORREF for the background component
|
|
COLORREF BackgroundColor(const WORD wLegacyAttrs,
|
|
_In_reads_(cColorTable) const COLORREF* const ColorTable,
|
|
const size_t cColorTable)
|
|
{
|
|
const byte iColorTableIndex = (LOBYTE(wLegacyAttrs) & BG_ATTRS) >> 4;
|
|
|
|
return (iColorTableIndex < cColorTable && iColorTableIndex >= 0) ?
|
|
ColorTable[iColorTableIndex] :
|
|
INVALID_COLOR;
|
|
}
|