core: add custom format decoration (#142)

* added custom format option

* removed redundant switch

* made error message more specifc
This commit is contained in:
Sepandar 2025-10-17 00:01:04 +00:00 committed by GitHub
parent b3f3f230c9
commit cd7ba93fad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 69 additions and 36 deletions

View file

@ -435,32 +435,39 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
std::string previewBuffer; std::string previewBuffer;
switch (m_bSelectedOutputMode) { switch (m_bSelectedOutputMode) {
case OUTPUT_HEX: { case OUTPUT_HEX: {
previewBuffer = std::format("#{:02X}{:02X}{:02X}", currentColor.r, currentColor.g, currentColor.b); std::string rHex, gHex, bHex;
if (m_bUseLowerCase) if (m_bUseLowerCase) {
for (auto& c : previewBuffer) rHex = std::format("{:02x}", currentColor.r);
c = std::tolower(c); gHex = std::format("{:02x}", currentColor.g);
bHex = std::format("{:02x}", currentColor.b);
} else {
rHex = std::format("{:02X}", currentColor.r);
gHex = std::format("{:02X}", currentColor.g);
bHex = std::format("{:02X}", currentColor.b);
}
previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(rHex, gHex, bHex));
break; break;
}; };
case OUTPUT_RGB: { case OUTPUT_RGB: {
previewBuffer = std::format("{} {} {}", currentColor.r, currentColor.g, currentColor.b); previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(currentColor.r, currentColor.g, currentColor.b));
break; break;
}; };
case OUTPUT_HSL: { case OUTPUT_HSL: {
float h, s, l; float h, s, l;
currentColor.getHSL(h, s, l); currentColor.getHSL(h, s, l);
previewBuffer = std::format("{} {}% {}%", h, s, l); previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(h, s, l));
break; break;
}; };
case OUTPUT_HSV: { case OUTPUT_HSV: {
float h, s, v; float h, s, v;
currentColor.getHSV(h, s, v); currentColor.getHSV(h, s, v);
previewBuffer = std::format("{} {}% {}%", h, s, v); previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(h, s, v));
break; break;
}; };
case OUTPUT_CMYK: { case OUTPUT_CMYK: {
float c, m, y, k; float c, m, y, k;
currentColor.getCMYK(c, m, y, k); currentColor.getCMYK(c, m, y, k);
previewBuffer = std::format("{}% {}% {}% {}%", c, m, y, k); previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(c, m, y, k));
break; break;
}; };
}; };
@ -661,30 +668,19 @@ void CHyprpicker::initMouse() {
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
const uint8_t FG = 0.2126 * FLUMI(COL.r / 255.0f) + 0.7152 * FLUMI(COL.g / 255.0f) + 0.0722 * FLUMI(COL.b / 255.0f) > 0.17913 ? 0 : 255; const uint8_t FG = 0.2126 * FLUMI(COL.r / 255.0f) + 0.7152 * FLUMI(COL.g / 255.0f) + 0.0722 * FLUMI(COL.b / 255.0f) > 0.17913 ? 0 : 255;
auto toHex = [this](int i) -> std::string { std::string hexColor = std::format("#{0:02x}{1:02x}{2:02x}", COL.r, COL.g, COL.b);
const char* DS = m_bUseLowerCase ? "0123456789abcdef" : "0123456789ABCDEF";
std::string result = "";
result += DS[i / 16];
result += DS[i % 16];
return result;
};
std::string hexColor = std::format("#{0:02x}{1:02x}{2:02x}", COL.r, COL.g, COL.b);
switch (m_bSelectedOutputMode) { switch (m_bSelectedOutputMode) {
case OUTPUT_CMYK: { case OUTPUT_CMYK: {
float c, m, y, k; float c, m, y, k;
COL.getCMYK(c, m, y, k); COL.getCMYK(c, m, y, k);
std::string formattedColor = std::format("{}% {}% {}% {}%", c, m, y, k); std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(c, m, y, k));
if (m_bFancyOutput) if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%g%% %g%% %g%% %g%%\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, c, m, y, k); Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else else
Debug::log(NONE, "%g%% %g%% %g%% %g%%", c, m, y, k); Debug::log(NONE, formattedColor.c_str());
if (m_bAutoCopy) if (m_bAutoCopy)
NClipboard::copy(formattedColor); NClipboard::copy(formattedColor);
@ -696,11 +692,21 @@ void CHyprpicker::initMouse() {
break; break;
} }
case OUTPUT_HEX: { case OUTPUT_HEX: {
std::string rHex, gHex, bHex;
if (m_bUseLowerCase) {
rHex = std::format("{:02x}", COL.r);
gHex = std::format("{:02x}", COL.g);
bHex = std::format("{:02x}", COL.b);
} else {
rHex = std::format("{:02X}", COL.r);
gHex = std::format("{:02X}", COL.g);
bHex = std::format("{:02X}", COL.b);
}
std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(rHex, gHex, bHex));
if (m_bFancyOutput) if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im#%s%s%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, toHex(COL.r).c_str(), toHex(COL.g).c_str(), Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
toHex(COL.b).c_str());
else else
Debug::log(NONE, "#%s%s%s", toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str()); Debug::log(NONE, formattedColor.c_str());
if (m_bAutoCopy) if (m_bAutoCopy)
NClipboard::copy(hexColor); NClipboard::copy(hexColor);
@ -712,12 +718,12 @@ void CHyprpicker::initMouse() {
break; break;
} }
case OUTPUT_RGB: { case OUTPUT_RGB: {
std::string formattedColor = std::format("{} {} {}", COL.r, COL.g, COL.b); std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(COL.r, COL.g, COL.b));
if (m_bFancyOutput) if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%i %i %i\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, COL.r, COL.g, COL.b); Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else else
Debug::log(NONE, "%i %i %i", COL.r, COL.g, COL.b); Debug::log(NONE, formattedColor.c_str());
if (m_bAutoCopy) if (m_bAutoCopy)
NClipboard::copy(formattedColor); NClipboard::copy(formattedColor);
@ -736,12 +742,11 @@ void CHyprpicker::initMouse() {
else else
COL.getHSL(h, s, l_or_v); COL.getHSL(h, s, l_or_v);
std::string formattedColor = std::format("{} {}% {}%", h, s, l_or_v); std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(h, s, l_or_v));
if (m_bFancyOutput) if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%g %g%% %g%%\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, h, s, l_or_v); Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else else
Debug::log(NONE, "%g %g%% %g%%", h, s, l_or_v); Debug::log(NONE, formattedColor.c_str());
if (m_bAutoCopy) if (m_bAutoCopy)
NClipboard::copy(formattedColor); NClipboard::copy(formattedColor);

View file

@ -4,14 +4,17 @@
#include "helpers/LayerSurface.hpp" #include "helpers/LayerSurface.hpp"
#include "helpers/PoolBuffer.hpp" #include "helpers/PoolBuffer.hpp"
enum eOutputMode { // OUTPUT_COUNT is being used to count the number of output formats, it should always be last in the enum
enum eOutputMode : uint8_t {
OUTPUT_CMYK = 0, OUTPUT_CMYK = 0,
OUTPUT_HEX, OUTPUT_HEX,
OUTPUT_RGB, OUTPUT_RGB,
OUTPUT_HSL, OUTPUT_HSL,
OUTPUT_HSV OUTPUT_HSV,
}; };
const std::array<uint8_t, 5> numOutputValues = {4, 3, 3, 3, 3};
class CHyprpicker { class CHyprpicker {
public: public:
void init(); void init();
@ -37,6 +40,7 @@ class CHyprpicker {
xkb_state* m_pXKBState = nullptr; xkb_state* m_pXKBState = nullptr;
eOutputMode m_bSelectedOutputMode = OUTPUT_HEX; eOutputMode m_bSelectedOutputMode = OUTPUT_HEX;
std::string m_sOutputFormat = "";
bool m_bFancyOutput = true; bool m_bFancyOutput = true;

View file

@ -1,13 +1,18 @@
#include <cstdint>
#include <format>
#include <regex>
#include <strings.h> #include <strings.h>
#include <iostream> #include <iostream>
#include "hyprpicker.hpp" #include "hyprpicker.hpp"
#include "src/debug/Log.hpp"
static void help() { static void help() {
std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\n" std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\n"
<< " -a | --autocopy | Automatically copies the output to the clipboard (requires wl-clipboard)\n" << " -a | --autocopy | Automatically copies the output to the clipboard (requires wl-clipboard)\n"
<< " -f | --format=fmt | Specifies the output format (cmyk, hex, rgb, hsl, hsv)\n" << " -f | --format=fmt | Specifies the output format (cmyk, hex, rgb, hsl, hsv)\n"
<< " -o | --output-format=fmt | Specifies how the output color should be formatted e.g. rgb({0}, {1}, {2}) would output rgb(red, green, blue) if --format=rgb\n"
<< " -n | --notify | Sends a desktop notification when a color is picked (requires notify-send and a notification daemon like dunst)\n" << " -n | --notify | Sends a desktop notification when a color is picked (requires notify-send and a notification daemon like dunst)\n"
<< " -b | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" << " -b | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n"
<< " -h | --help | Show this help message\n" << " -h | --help | Show this help message\n"
@ -30,6 +35,7 @@ int main(int argc, char** argv, char** envp) {
int option_index = 0; int option_index = 0;
static struct option long_options[] = {{"autocopy", no_argument, nullptr, 'a'}, static struct option long_options[] = {{"autocopy", no_argument, nullptr, 'a'},
{"format", required_argument, nullptr, 'f'}, {"format", required_argument, nullptr, 'f'},
{"output-format", required_argument, nullptr, 'o'},
{"help", no_argument, nullptr, 'h'}, {"help", no_argument, nullptr, 'h'},
{"no-fancy", no_argument, nullptr, 'b'}, {"no-fancy", no_argument, nullptr, 'b'},
{"notify", no_argument, nullptr, 'n'}, {"notify", no_argument, nullptr, 'n'},
@ -45,7 +51,7 @@ int main(int argc, char** argv, char** envp) {
{"radius", required_argument, nullptr, 'u'}, {"radius", required_argument, nullptr, 'u'},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int c = getopt_long(argc, argv, ":f:hnbarzqvtdlVs:u:", long_options, &option_index); int c = getopt_long(argc, argv, ":f:o:hnbarzqvtdlVs:u:", long_options, &option_index);
if (c == -1) if (c == -1)
break; break;
@ -66,6 +72,7 @@ int main(int argc, char** argv, char** envp) {
exit(1); exit(1);
} }
break; break;
case 'o': g_pHyprpicker->m_sOutputFormat = optarg; break;
case 'h': help(); exit(0); case 'h': help(); exit(0);
case 'b': g_pHyprpicker->m_bFancyOutput = false; break; case 'b': g_pHyprpicker->m_bFancyOutput = false; break;
case 'n': g_pHyprpicker->m_bNotify = true; break; case 'n': g_pHyprpicker->m_bNotify = true; break;
@ -123,6 +130,23 @@ int main(int argc, char** argv, char** envp) {
if (!isatty(fileno(stdout)) || getenv("NO_COLOR")) if (!isatty(fileno(stdout)) || getenv("NO_COLOR"))
g_pHyprpicker->m_bFancyOutput = false; g_pHyprpicker->m_bFancyOutput = false;
if (g_pHyprpicker->m_sOutputFormat.empty()) {
switch (g_pHyprpicker->m_bSelectedOutputMode) {
case OUTPUT_CMYK: g_pHyprpicker->m_sOutputFormat = "{}% {}% {}% {}%"; break;
case OUTPUT_HEX: g_pHyprpicker->m_sOutputFormat = "#{}{}{}"; break;
case OUTPUT_RGB: g_pHyprpicker->m_sOutputFormat = "{} {} {}"; break;
case OUTPUT_HSL: g_pHyprpicker->m_sOutputFormat = "{} {}% {}%"; break;
case OUTPUT_HSV: g_pHyprpicker->m_sOutputFormat = "{} {}% {}%"; break;
}
}
try {
std::array<uint8_t, 4> dummy = {0, 0, 0, 0};
(void)std::vformat(g_pHyprpicker->m_sOutputFormat, std::make_format_args(dummy[0], dummy[1], dummy[2], dummy[3]));
} catch (const std::format_error& e) {
Debug::log(NONE, "Invalid --output-format: %s", e.what());
exit(1);
}
g_pHyprpicker->init(); g_pHyprpicker->init();
return 0; return 0;