9 Commits

9 changed files with 305 additions and 145 deletions

View File

@@ -0,0 +1,78 @@
# mcolor - Maxine's Mean Color Library
mcolor is a C++20 library designed to provide an efficient suite for color management. Ideal for use in games, console applications, UI, and so forth.
## Color as a Class
At its heart, mcolor defines fundamental color structures for clear and concise representation:
- `Color3`: Represents an RGB color with 8-bit unsigned integer components (uint8_t r, g, b).
- `Color4`: Extends Color3 to include an alpha channel (uint8_t r, g, b, a).
These core types are complemented by a full range of conversion structs, enabling seamless transitions between various color models:
- `HSV`, `HSVA`: Hue, Saturation, Value (with Alpha)
- `RGB`, `RGBA`: Red, Green, Blue (with Alpha) using u8 components.
- `RGBf`, `RGBAf`: Red, Green, Blue (with Alpha) using float components.
- `LCH`, `LCHA`: Lightness, Chroma, Hue (with Alpha)
- `CMYK`: Cyan, Magenta, Yellow, Key (Black)
The library also includes organized Color Palettes within dedicated namespaces:
- `Colors::Primary`, or just `Colors`,
- <span style='color: red;'>Colors::Reds</span>
- <span style='color: orange;'>Colors::Oranges</span>
- <span style='color: yellow;'>Colors::Yellows</span>
- <span style='color: green;'>Colors::Greens</span>
- <span style='color: cyan;'>Colors::Cyans</span>
- <span style='color: blue;'>Colors::Blues</span>
- <span style='color: purple;'>Colors::Purples</span>
- <span style='color: pink;'>Colors::Pinks</span>
- <span style='color: white;'>Colors::Whites</span>
- <span style='color: gray;'>Colors::Grays</span>
- <span style='color: brown;'>Colors::Browns</span>
offering a rich set of predefined swatches for immediate use.
Additionally, we have worked to implement Ansi Escape Codes, console-output utilities, and cross-platform abstraction so that it works the same on Windows and Linux.
## Usage
Integrating mcolor into your project is straightforward. Here's a quick sample:
```cpp
int main() {
#ifdef WIN32
mcolor::windowsSaneify();
#endif
mcolor::printBuiltinColorList();
mcolor::printAnsiColorTable();
mcolor::printRGBConsoleTest();
for (float i = 0; i < 360; i+=10.f)
{
HSVA hsva {i, 1.f, 1.f};
Color4 c = Color4(hsva);
std::cout << std::format("{}hue:{} rgb: {},{},{} hex: {}", c.ToEscapeCode(), i, c.r, c.g, c.b, c.ToHex()) << std::endl;
}
return 0;
}
```
## Acknowledgements
This library was created by `maxine`, and is currently maintained by Josh O'Leary.
## Contributing
Pull requests and issues are always welcome! You know what to do!
## License
This work is expressly dedicated to the Public Domain under the Unlicense.

View File

@@ -54,177 +54,148 @@ namespace mcolor
BG_BRIGHT_WHITE = 107, BG_BRIGHT_WHITE = 107,
}; };
// TODO: Refactor to constexpr string literals static const std::string AnsiEscapePrefix = "\033[";
constexpr std::string AnsiEscapePrefix = "\033[";
namespace AnsiEscapeCodes { namespace AnsiEscapeCodes {
#pragma region General #pragma region General
constexpr std::string Bell = "\a"; static const std::string Bell = "\a";
constexpr std::string Backspace = "\b"; static const std::string Backspace = "\b";
constexpr std::string Tab = "\t"; static const std::string Tab = "\t";
constexpr std::string Newline = "\n"; static const std::string Newline = "\n";
constexpr std::string VerticalTab = "\v"; static const std::string VerticalTab = "\v";
constexpr std::string Newpage = "\f"; static const std::string Newpage = "\f";
constexpr std::string Return = "\r"; static const std::string Return = "\r";
constexpr std::string Escape = "\033"; static const std::string Escape = "\033";
#pragma endregion #pragma endregion
#pragma region Cursor Controls #pragma region Cursor Controls
/// Moves cursor to home position {0, 0}. /// Moves cursor to home position {0, 0}.
constexpr std::string CursorHome = AnsiEscapePrefix + "H"; static const std::string CursorHome = AnsiEscapePrefix + "H";
/// Moves cursor to line Y, column X. /// Moves cursor to line Y, column X.
constexpr std::string CursorTo(int line, int column) { static std::string CursorTo(int line, int column);
return AnsiEscapePrefix + std::format("{};{}H", line, column);
}
/// Moves the cursor up # lines. /// Moves the cursor up # lines.
constexpr std::string CursorUp(int lines) { static std::string CursorUp(int lines);
return AnsiEscapePrefix + std::format("{}A", lines);
}
/// Moves the cursor down # lines. /// Moves the cursor down # lines.
constexpr std::string CursorDown(int lines) { static std::string CursorDown(int lines);
return AnsiEscapePrefix + std::format("{}B", lines);
}
/// Moves the cursor right # lines. /// Moves the cursor right # lines.
constexpr std::string CursorRight(int lines) { static std::string CursorRight(int lines);
return AnsiEscapePrefix + std::format("{}D", lines);
}
/// Moves the cursor left # lines. /// Moves the cursor left # lines.
constexpr std::string CursorLeft(int lines) { static std::string CursorLeft(int lines);
return AnsiEscapePrefix + std::format("{}D", lines);
}
/// Moves cursor to the beginning of line, # lines down from the current line. /// Moves cursor to the beginning of line, # lines down from the current line.
constexpr std::string CursorNextLineStart(int lines) { static std::string CursorNextLineStart(int lines);
return AnsiEscapePrefix + std::format("{}D", lines);
}
/// Moves cursor to the beginning of line, # lines up from the current line. /// Moves cursor to the beginning of line, # lines up from the current line.
constexpr std::string CursorPrevLineStart(int lines) { static std::string CursorPrevLineStart(int lines);
return AnsiEscapePrefix + std::format("{}D", lines);
}
/// Moves cursor to column #. /// Moves cursor to column #.
constexpr std::string CursorColumn(int column) { static std::string CursorColumn(int column);
return AnsiEscapePrefix + std::format("{}G", column);
}
/// Save current cursor position. /// Save current cursor position.
constexpr std::string CursorSave = AnsiEscapePrefix + "7"; static const std::string CursorSave = AnsiEscapePrefix + "7";
/// Restore cursor to last saved position. /// Restore cursor to last saved position.
constexpr std::string CursorRestore = AnsiEscapePrefix + "8"; static const std::string CursorRestore = AnsiEscapePrefix + "8";
#pragma endregion #pragma endregion
#pragma region Erase Functions #pragma region Erase Functions
constexpr std::string EraseInDisplay = AnsiEscapePrefix + "J"; static const std::string EraseInDisplay = AnsiEscapePrefix + "J";
/// Erase from cursor until end of screen. /// Erase from cursor until end of screen.
constexpr std::string EraseAfterCursor = AnsiEscapePrefix + "0J"; static const std::string EraseAfterCursor = AnsiEscapePrefix + "0J";
/// Erase from cursor to beginning of screen. /// Erase from cursor to beginning of screen.
constexpr std::string EraseBeforeCursor = AnsiEscapePrefix + "1J"; static const std::string EraseBeforeCursor = AnsiEscapePrefix + "1J";
constexpr std::string EraseEntireScreen = AnsiEscapePrefix + "2J"; static const std::string EraseEntireScreen = AnsiEscapePrefix + "2J";
constexpr std::string EraseSavedLines = AnsiEscapePrefix + "3J"; static const std::string EraseSavedLines = AnsiEscapePrefix + "3J";
constexpr std::string EraseInLine = AnsiEscapePrefix + "K"; static const std::string EraseInLine = AnsiEscapePrefix + "K";
constexpr std::string EraseLineAfterCursor = AnsiEscapePrefix + "0K"; static const std::string EraseLineAfterCursor = AnsiEscapePrefix + "0K";
constexpr std::string EraseLineBeforeCursor = AnsiEscapePrefix + "1K"; static const std::string EraseLineBeforeCursor = AnsiEscapePrefix + "1K";
#pragma endregion #pragma endregion
#pragma region Graphics Sequences #pragma region Graphics Sequences
constexpr std::string ResetAll = AnsiEscapePrefix + "0m"; static const std::string ResetAll = AnsiEscapePrefix + "0m";
constexpr std::string Bold = AnsiEscapePrefix + "1m"; static const std::string Bold = AnsiEscapePrefix + "1m";
constexpr std::string Dim = AnsiEscapePrefix + "2m"; static const std::string Dim = AnsiEscapePrefix + "2m";
constexpr std::string Italic = AnsiEscapePrefix + "3m"; static const std::string Italic = AnsiEscapePrefix + "3m";
constexpr std::string Underline = AnsiEscapePrefix + "4m"; static const std::string Underline = AnsiEscapePrefix + "4m";
constexpr std::string Blinking = AnsiEscapePrefix + "5m"; static const std::string Blinking = AnsiEscapePrefix + "5m";
constexpr std::string Inverse = AnsiEscapePrefix + "6m"; static const std::string Inverse = AnsiEscapePrefix + "6m";
constexpr std::string Hidden = AnsiEscapePrefix + "7m"; static const std::string Hidden = AnsiEscapePrefix + "7m";
constexpr std::string Strikethrough = AnsiEscapePrefix + "8m"; static const std::string Strikethrough = AnsiEscapePrefix + "8m";
#pragma endregion #pragma endregion
#pragma region Color Sequences #pragma region Color Sequences
constexpr std::string FgBlack = AnsiEscapePrefix + "30"; static const std::string FgBlack = AnsiEscapePrefix + "30";
constexpr std::string BgBlack = AnsiEscapePrefix + "40"; static const std::string BgBlack = AnsiEscapePrefix + "40";
constexpr std::string FgRed = AnsiEscapePrefix + "31"; static const std::string FgRed = AnsiEscapePrefix + "31";
constexpr std::string BgRed = AnsiEscapePrefix + "41"; static const std::string BgRed = AnsiEscapePrefix + "41";
constexpr std::string FgGreen = AnsiEscapePrefix + "32"; static const std::string FgGreen = AnsiEscapePrefix + "32";
constexpr std::string BgGreen = AnsiEscapePrefix + "42"; static const std::string BgGreen = AnsiEscapePrefix + "42";
constexpr std::string FgYellow = AnsiEscapePrefix + "33"; static const std::string FgYellow = AnsiEscapePrefix + "33";
constexpr std::string BgYellow = AnsiEscapePrefix + "43"; static const std::string BgYellow = AnsiEscapePrefix + "43";
constexpr std::string FgBlue = AnsiEscapePrefix + "34"; static const std::string FgBlue = AnsiEscapePrefix + "34";
constexpr std::string BgBlue = AnsiEscapePrefix + "44"; static const std::string BgBlue = AnsiEscapePrefix + "44";
constexpr std::string FgMagenta = AnsiEscapePrefix + "35"; static const std::string FgMagenta = AnsiEscapePrefix + "35";
constexpr std::string BgMagenta = AnsiEscapePrefix + "45"; static const std::string BgMagenta = AnsiEscapePrefix + "45";
constexpr std::string FgCyan = AnsiEscapePrefix + "36"; static const std::string FgCyan = AnsiEscapePrefix + "36";
constexpr std::string BgCyan = AnsiEscapePrefix + "46"; static const std::string BgCyan = AnsiEscapePrefix + "46";
constexpr std::string FgWhite = AnsiEscapePrefix + "37"; static const std::string FgWhite = AnsiEscapePrefix + "37";
constexpr std::string BgWhite = AnsiEscapePrefix + "47"; static const std::string BgWhite = AnsiEscapePrefix + "47";
constexpr std::string FgDefault = AnsiEscapePrefix + "38"; static const std::string FgDefault = AnsiEscapePrefix + "38";
constexpr std::string BgDefault = AnsiEscapePrefix + "48"; static const std::string BgDefault = AnsiEscapePrefix + "48";
constexpr std::string FgBrightBlack = AnsiEscapePrefix + "90"; static const std::string FgBrightBlack = AnsiEscapePrefix + "90";
constexpr std::string BgBrightBlack = AnsiEscapePrefix + "100"; static const std::string BgBrightBlack = AnsiEscapePrefix + "100";
constexpr std::string FgBrightRed = AnsiEscapePrefix + "91"; static const std::string FgBrightRed = AnsiEscapePrefix + "91";
constexpr std::string BgBrightRed = AnsiEscapePrefix + "101"; static const std::string BgBrightRed = AnsiEscapePrefix + "101";
constexpr std::string FgBrightGreen = AnsiEscapePrefix + "92"; static const std::string FgBrightGreen = AnsiEscapePrefix + "92";
constexpr std::string BgBrightGreen = AnsiEscapePrefix + "102"; static const std::string BgBrightGreen = AnsiEscapePrefix + "102";
constexpr std::string FgBrightYellow = AnsiEscapePrefix + "93"; static const std::string FgBrightYellow = AnsiEscapePrefix + "93";
constexpr std::string BgBrightYellow = AnsiEscapePrefix + "103"; static const std::string BgBrightYellow = AnsiEscapePrefix + "103";
constexpr std::string FgBrightBlue = AnsiEscapePrefix + "94"; static const std::string FgBrightBlue = AnsiEscapePrefix + "94";
constexpr std::string BgBrightBlue = AnsiEscapePrefix + "104"; static const std::string BgBrightBlue = AnsiEscapePrefix + "104";
constexpr std::string FgBrightMagenta = AnsiEscapePrefix + "95"; static const std::string FgBrightMagenta = AnsiEscapePrefix + "95";
constexpr std::string BgBrightMagenta = AnsiEscapePrefix + "105"; static const std::string BgBrightMagenta = AnsiEscapePrefix + "105";
constexpr std::string FgBrightCyan = AnsiEscapePrefix + "96"; static const std::string FgBrightCyan = AnsiEscapePrefix + "96";
constexpr std::string BgBrightCyan = AnsiEscapePrefix + "106"; static const std::string BgBrightCyan = AnsiEscapePrefix + "106";
constexpr std::string FgBrightWhite = AnsiEscapePrefix + "97"; static const std::string FgBrightWhite = AnsiEscapePrefix + "97";
constexpr std::string BgBrightWhite = AnsiEscapePrefix + "107"; static const std::string BgBrightWhite = AnsiEscapePrefix + "107";
constexpr std::string FgTrueColor(int r, int g, int b) { static std::string FgTrueColor(int r, int g, int b);
return AnsiEscapePrefix + std::format("38;2;{};{};{}m", r, g, b);
}
constexpr std::string FgTrueColor(const Color4& c) { static std::string FgTrueColor(const Color4& c);
return FgTrueColor(c.r, c.g, c.b);
}
constexpr std::string BgTrueColor(int r, int g, int b) { static std::string BgTrueColor(int r, int g, int b);
return AnsiEscapePrefix + std::format("48;2;{};{};{}m", r, g, b);
}
constexpr std::string BgTrueColor(const Color4& c) { static std::string BgTrueColor(const Color4& c);
return BgTrueColor(c.r, c.g, c.b);
}
#pragma endregion #pragma endregion
#pragma region Private Modes #pragma region Private Modes
constexpr std::string CursorInvisible = AnsiEscapePrefix + "?25l"; inline static const std::string CursorInvisible = AnsiEscapePrefix + "?25l";
constexpr std::string CursorVisible = AnsiEscapePrefix + "?25h"; static const std::string CursorVisible = AnsiEscapePrefix + "?25h";
constexpr std::string RestoreScreen = AnsiEscapePrefix + "?47l"; static const std::string RestoreScreen = AnsiEscapePrefix + "?47l";
constexpr std::string SaveScreen = AnsiEscapePrefix + "?47h"; static const std::string SaveScreen = AnsiEscapePrefix + "?47h";
constexpr std::string EnableAltBuffer = AnsiEscapePrefix + "?1049h"; static const std::string EnableAltBuffer = AnsiEscapePrefix + "?1049h";
constexpr std::string DisableAltBuffer = AnsiEscapePrefix + "?1049l"; static const std::string DisableAltBuffer = AnsiEscapePrefix + "?1049l";
#pragma endregion #pragma endregion
}
}
} }

View File

@@ -18,12 +18,17 @@ class Color4;
std::string toEscapeCode(Color4 c, bool bg=false); std::string toEscapeCode(Color4 c, bool bg=false);
void print_builtin_color_list(); namespace mcolor
{
void printBuiltinColorList();
}
/// A type representing a color with alpha. /// A type representing a color with alpha.
/// Our default format is RGBA with 8 bits-per-channel. /// Our default format is RGBA with 8 bits-per-channel.
/// Conversions to other color formats are provided. /// Conversions to other color formats are provided.
class Color4 { class Color4
{
public: public:
u8 r; u8 r;
u8 g; u8 g;
@@ -83,6 +88,7 @@ public:
static Color4 FromLCH(float l, float c, float h, float alpha = 1.f); static Color4 FromLCH(float l, float c, float h, float alpha = 1.f);
public: public:
/// Performs the interpolation in normalized color space (0-1) and converts it back.
[[nodiscard]] Color4 Lerp(const Color4& rhs, float t) const; [[nodiscard]] Color4 Lerp(const Color4& rhs, float t) const;
static Color4 Lerp(const Color4& lhs, const Color4& rhs, float t); static Color4 Lerp(const Color4& lhs, const Color4& rhs, float t);
@@ -130,10 +136,21 @@ public:
LCH ToLCH() const; LCH ToLCH() const;
// TODO: Disparate with mcolor::toEscapeCode, resolve. // TODO: Disparate with mcolor::toEscapeCode, resolve.
[[nodiscard]] std::string EscapeCode(bool bg = false, bool bold = false); [[nodiscard]] std::string EscapeCode(bool bg = false, bool bold = false) const;
[[nodiscard]] std::string FGEscapeCode(bool bold = false); [[nodiscard]] std::string FGEscapeCode(bool bold = false) const;
[[nodiscard]] std::string BGEscapeCode(bool bold = false); [[nodiscard]] std::string BGEscapeCode(bool bold = false) const;
}; bool operator==(const Color4& rhs) const;
bool operator!=(const Color4& rhs) const;
std::string ToEscapeCode(bool bg = false) const;
};
inline std::ostream& operator << (std::ostream& os, const Color4& c) {
os << "Color4(" << c.r << "," << c.g << "," << c.b << "," << c.a << ") AKA " << c.ToHex();
return os;
}

View File

@@ -7,7 +7,9 @@
#include <cstdint> #include <cstdint>
#include <format> #include <format>
#include <vector> #include <vector>
#include "Color3.hpp"
#include "Color4.hpp" #include "Color4.hpp"
#include "Colors.hpp"
#include "AnsiEscapeCodes.hpp" #include "AnsiEscapeCodes.hpp"
namespace mcolor { namespace mcolor {
@@ -15,9 +17,11 @@ namespace mcolor {
std::string toEscapeCode(AnsiColor c); std::string toEscapeCode(AnsiColor c);
#ifdef WIN32
/// Performs a hack that allows the windows console to interpret ANSI codes.
/// @note This only works on Windows 10 version 1511 and newer.
void windowsSaneify(); void windowsSaneify();
#endif
void printAnsiColorTable(); void printAnsiColorTable();

View File

@@ -5,11 +5,15 @@
#include <Color4.hpp> #include <Color4.hpp>
#include <Colors.hpp> #include <Colors.hpp>
std::string fmt_color(const Color4& c)
{
return std::format("{}hue:{} rgb: {},{},{} hex: {}", c.ToEscapeCode(), c.ToHSV().h, c.r, c.g, c.b, c.ToHex());
}
int main() int main()
{ {
#ifdef WIN32 mcolor::windowsSaneify();
mcolor::windowsSaneify();
#endif
// TODO: Demo Color Space Math Operations // TODO: Demo Color Space Math Operations
@@ -17,10 +21,15 @@ int main()
// TODO: Demo Color output in console. // TODO: Demo Color output in console.
print_builtin_color_list(); mcolor::printBuiltinColorList();
mcolor::printAnsiColorTable(); mcolor::printAnsiColorTable();
mcolor::printRGBConsoleTest(); mcolor::printRGBConsoleTest();
std::cout << "Color construction from hex codes:" << std::endl;
std::cout << fmt_color(Color4::FromHex("#FFFFFF")) << std::endl;
std::cout << fmt_color(Color4::FromHex("#F0F0F0")) << std::endl;
std::cout << fmt_color(Color4::FromHex("#0F0F0F")) << std::endl;
std::cout << fmt_color(Color4::FromHex("#00AAFF")) << std::endl;
for (float i = 0; i < 360; i+=10.f) for (float i = 0; i < 360; i+=10.f)
{ {
@@ -28,7 +37,7 @@ int main()
Color4 c = Color4(hsva); Color4 c = Color4(hsva);
std::cout << std::format("{}hue:{} rgb: {},{},{}", toEscapeCode(c), i, c.r, c.g, c.b) << std::endl; std::cout << std::format("{}hue:{} rgb: {},{},{} hex: {}", c.ToEscapeCode(), i, c.r, c.g, c.b, c.ToHex()) << std::endl;
} }
return 0; return 0;

View File

@@ -1 +1,49 @@
#include <AnsiEscapeCodes.hpp> #include <AnsiEscapeCodes.hpp>
std::string mcolor::AnsiEscapeCodes::CursorTo(int line, int column) {
return AnsiEscapePrefix + std::format("{};{}H", line, column);
}
std::string mcolor::AnsiEscapeCodes::CursorUp(int lines) {
return AnsiEscapePrefix + std::format("{}A", lines);
}
std::string mcolor::AnsiEscapeCodes::CursorDown(int lines) {
return AnsiEscapePrefix + std::format("{}B", lines);
}
std::string mcolor::AnsiEscapeCodes::CursorRight(int lines) {
return AnsiEscapePrefix + std::format("{}D", lines);
}
std::string mcolor::AnsiEscapeCodes::CursorLeft(int lines) {
return AnsiEscapePrefix + std::format("{}D", lines);
}
std::string mcolor::AnsiEscapeCodes::CursorNextLineStart(int lines) {
return AnsiEscapePrefix + std::format("{}D", lines);
}
std::string mcolor::AnsiEscapeCodes::CursorPrevLineStart(int lines) {
return AnsiEscapePrefix + std::format("{}D", lines);
}
std::string mcolor::AnsiEscapeCodes::CursorColumn(int column) {
return AnsiEscapePrefix + std::format("{}G", column);
}
std::string mcolor::AnsiEscapeCodes::FgTrueColor(int r, int g, int b) {
return AnsiEscapePrefix + std::format("38;2;{};{};{}m", r, g, b);
}
std::string mcolor::AnsiEscapeCodes::FgTrueColor(const Color4 &c) {
return FgTrueColor(c.r, c.g, c.b);
}
std::string mcolor::AnsiEscapeCodes::BgTrueColor(int r, int g, int b) {
return AnsiEscapePrefix + std::format("48;2;{};{};{}m", r, g, b);
}
std::string mcolor::AnsiEscapeCodes::BgTrueColor(const Color4 &c) {
return BgTrueColor(c.r, c.g, c.b);
}

View File

@@ -20,7 +20,7 @@ Color3 Color3::FromHex(const std::string &hexCode) {
// TODO: Support 9-character hex codes (with alpha), but raise a warning that suggests using Color4 instead. // TODO: Support 9-character hex codes (with alpha), but raise a warning that suggests using Color4 instead.
if (hexCode.length() == 7) { if (hexCode.length() == 7) {
u8 r, g, b; u8 r, g, b;
std::sscanf(hexCode.c_str(), "#%02x%02x%02x", &r, &g, &b); std::sscanf(hexCode.c_str(), "#%02hhx%02hhx%02hhx", &r, &g, &b);
return {r, g, b}; return {r, g, b};
} }

View File

@@ -14,7 +14,7 @@ std::string toEscapeCode(Color4 c, bool bg){
return std::format("\033[38;2;{};{};{}m", c.r, c.g, c.b); return std::format("\033[38;2;{};{};{}m", c.r, c.g, c.b);
} }
void print_builtin_color_list() { void mcolor::printBuiltinColorList() {
#if !defined(WIN32) #if !defined(WIN32)
int i = 0; int i = 0;
for (const Color4& color : list) { for (const Color4& color : list) {
@@ -114,13 +114,13 @@ Color4 Color4::FromHex(const std::string &hexCode, u8 alpha) {
// TODO: Support 9-character hex codes (with alpha), but raise a warning that suggests using FromHexA explicitly instead. // TODO: Support 9-character hex codes (with alpha), but raise a warning that suggests using FromHexA explicitly instead.
if (hexCode.length() == 7) { if (hexCode.length() == 7) {
u8 r, g, b; u8 r, g, b;
std::sscanf(hexCode.c_str(), "#%02x%02x%02x", &r, &g, &b); std::sscanf(hexCode.c_str(), "#%02hhx%02hhx%02hhx", &r, &g, &b);
return {r, g, b, alpha}; return {r, g, b, alpha};
} }
if (hexCode.length() == 9) { if (hexCode.length() == 9) {
u8 r, g, b, a; u8 r, g, b, a;
std::sscanf(hexCode.c_str(), "#%02x%02x%02x%02x", &r, &g, &b, &a); std::sscanf(hexCode.c_str(), "#%02hhx%02hhx%02hhx%02hhx", &r, &g, &b, &a);
return {r, g, b, a}; return {r, g, b, a};
} }
@@ -130,7 +130,7 @@ Color4 Color4::FromHex(const std::string &hexCode, u8 alpha) {
Color4 Color4::FromHexA(const std::string &hexACode) { Color4 Color4::FromHexA(const std::string &hexACode) {
if (hexACode.length() == 9) { if (hexACode.length() == 9) {
u8 r, g, b, a; u8 r, g, b, a;
std::sscanf(hexACode.c_str(), "#%02x%02x%02x%02x", &r, &g, &b, &a); std::sscanf(hexACode.c_str(), "#%02hhx%02hhx%02hhx%02hhx", &r, &g, &b, &a);
return {r, g, b, a}; return {r, g, b, a};
} }
@@ -182,7 +182,7 @@ Color4 Color4::FromNormalized(float red, float green, float blue, float alpha) {
Color4 Color4::Lerp(const Color4 &rhs, float t) const { Color4 Color4::Lerp(const Color4 &rhs, float t) const {
/// Performs the interpolation in normalized color space (0-1) and converts it back.
@@ -327,24 +327,44 @@ LCH Color4::ToLCH() const {
return {}; return {};
} }
std::string Color4::EscapeCode(bool bg, bool bold) { std::string Color4::EscapeCode(bool bg, bool bold) const {
if (bg) if (bg)
return std::format("\033[48;2;{};{};{}m", r, g, b); return std::format("\033[48;2;{};{};{}m", r, g, b);
return std::format("\033[38;2;{};{};{}m", r, g, b); return std::format("\033[38;2;{};{};{}m", r, g, b);
} }
std::string Color4::FGEscapeCode(bool bold) { std::string Color4::FGEscapeCode(bool bold) const {
return EscapeCode(false, bold); return EscapeCode(false, bold);
} }
std::string Color4::BGEscapeCode(bool bold) { std::string Color4::BGEscapeCode(bool bold) const {
return EscapeCode(true, bold); return EscapeCode(true, bold);
} }
static std::string decimal_to_hex(int dec) bool Color4::operator==(const Color4& rhs) const
{ {
if (dec < 1) return "00"; return r == rhs.r
&& g == rhs.g
&& b == rhs.b
&& a == rhs.a;
}
bool Color4::operator!=(const Color4& rhs) const
{
return !(*this == rhs);
}
std::string Color4::ToEscapeCode(bool bg) const {
if (bg)
return std::format("\033[48;2;{};{};{}m", r, g, b);
return std::format("\033[38;2;{};{};{}m", r, g, b);
}
static std::string decimal_to_hex(int dec, int digits = 0)
{
if (dec < 1) return std::string(digits, '0');
int hex = dec; int hex = dec;
std::string hexStr = ""; std::string hexStr = "";
@@ -359,22 +379,33 @@ static std::string decimal_to_hex(int dec)
dec /= 16; dec /= 16;
} }
if (digits > 0)
{
while (hexStr.length() < digits)
{
hexStr = "0" + hexStr;
digits--;
}
}
return hexStr; return hexStr;
} }
std::string Color4::ToHex() const { std::string Color4::ToHex() const {
std::string rs = decimal_to_hex(r); std::string rs = decimal_to_hex(r, 2);
std::string gs = decimal_to_hex(g); std::string gs = decimal_to_hex(g, 2);
std::string bs = decimal_to_hex(b); std::string bs = decimal_to_hex(b, 2);
return "#" + rs + gs + bs; return "#" + rs + gs + bs;
} }
std::string Color4::ToHexAlpha() const { std::string Color4::ToHexAlpha() const {
std::string rs = decimal_to_hex(r); std::string rs = decimal_to_hex(r, 2);
std::string gs = decimal_to_hex(g); std::string gs = decimal_to_hex(g, 2);
std::string bs = decimal_to_hex(b); std::string bs = decimal_to_hex(b, 2);
std::string as = decimal_to_hex(a); std::string as = decimal_to_hex(a, 2);
return "#" + rs + gs + bs + as; return "#" + rs + gs + bs + as;
} }

View File

@@ -26,7 +26,7 @@ namespace mcolor
return std::format("\033[{}m", static_cast<typename std::underlying_type<AnsiColor>::type>(c)); return std::format("\033[{}m", static_cast<typename std::underlying_type<AnsiColor>::type>(c));
} }
#ifdef WIN32
/* /*
* Beat Windows into submission and make it interpret ansi codes. * Beat Windows into submission and make it interpret ansi codes.
* Fuck you Microsoft we're doing this the right way. * Fuck you Microsoft we're doing this the right way.
@@ -37,6 +37,7 @@ namespace mcolor
* along with any code that is printing the escape codes to a terminal. * along with any code that is printing the escape codes to a terminal.
*/ */
void windowsSaneify() { void windowsSaneify() {
#ifdef WIN32
HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD consoleMode; DWORD consoleMode;
GetConsoleMode( handleOut, &consoleMode); GetConsoleMode( handleOut, &consoleMode);
@@ -44,8 +45,9 @@ namespace mcolor
consoleMode |= DISABLE_NEWLINE_AUTO_RETURN; consoleMode |= DISABLE_NEWLINE_AUTO_RETURN;
SetConsoleMode( handleOut , consoleMode ); SetConsoleMode( handleOut , consoleMode );
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
}
#endif #endif
}
void printAnsiColorTable() { void printAnsiColorTable() {
std::vector<AnsiColor> ansifg = { std::vector<AnsiColor> ansifg = {