diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 9669003..995dfd9 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -435,32 +435,39 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { std::string previewBuffer; switch (m_bSelectedOutputMode) { case OUTPUT_HEX: { - previewBuffer = std::format("#{:02X}{:02X}{:02X}", currentColor.r, currentColor.g, currentColor.b); - if (m_bUseLowerCase) - for (auto& c : previewBuffer) - c = std::tolower(c); + std::string rHex, gHex, bHex; + if (m_bUseLowerCase) { + rHex = std::format("{:02x}", currentColor.r); + 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; }; 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; }; case OUTPUT_HSL: { float 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; }; case OUTPUT_HSV: { float 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; }; case OUTPUT_CMYK: { float 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; }; }; @@ -661,30 +668,19 @@ void CHyprpicker::initMouse() { // 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; - auto toHex = [this](int i) -> std::string { - 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); + std::string hexColor = std::format("#{0:02x}{1:02x}{2:02x}", COL.r, COL.g, COL.b); switch (m_bSelectedOutputMode) { case OUTPUT_CMYK: { float 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) - 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 - Debug::log(NONE, "%g%% %g%% %g%% %g%%", c, m, y, k); + Debug::log(NONE, formattedColor.c_str()); if (m_bAutoCopy) NClipboard::copy(formattedColor); @@ -696,11 +692,21 @@ void CHyprpicker::initMouse() { break; } 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) - 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(), - toHex(COL.b).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()); 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) NClipboard::copy(hexColor); @@ -712,12 +718,12 @@ void CHyprpicker::initMouse() { break; } 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) - 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 - Debug::log(NONE, "%i %i %i", COL.r, COL.g, COL.b); + Debug::log(NONE, formattedColor.c_str()); if (m_bAutoCopy) NClipboard::copy(formattedColor); @@ -736,12 +742,11 @@ void CHyprpicker::initMouse() { else 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) - 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 - Debug::log(NONE, "%g %g%% %g%%", h, s, l_or_v); + Debug::log(NONE, formattedColor.c_str()); if (m_bAutoCopy) NClipboard::copy(formattedColor); diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 3353871..15e29c2 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -4,14 +4,17 @@ #include "helpers/LayerSurface.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_HEX, OUTPUT_RGB, OUTPUT_HSL, - OUTPUT_HSV + OUTPUT_HSV, }; +const std::array numOutputValues = {4, 3, 3, 3, 3}; + class CHyprpicker { public: void init(); @@ -37,6 +40,7 @@ class CHyprpicker { xkb_state* m_pXKBState = nullptr; eOutputMode m_bSelectedOutputMode = OUTPUT_HEX; + std::string m_sOutputFormat = ""; bool m_bFancyOutput = true; diff --git a/src/main.cpp b/src/main.cpp index 3d7f92f..4a7f472 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,18 @@ +#include +#include +#include #include #include #include "hyprpicker.hpp" +#include "src/debug/Log.hpp" static void help() { std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\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" + << " -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" << " -b | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" << " -h | --help | Show this help message\n" @@ -30,6 +35,7 @@ int main(int argc, char** argv, char** envp) { int option_index = 0; static struct option long_options[] = {{"autocopy", no_argument, nullptr, 'a'}, {"format", required_argument, nullptr, 'f'}, + {"output-format", required_argument, nullptr, 'o'}, {"help", no_argument, nullptr, 'h'}, {"no-fancy", no_argument, nullptr, 'b'}, {"notify", no_argument, nullptr, 'n'}, @@ -45,7 +51,7 @@ int main(int argc, char** argv, char** envp) { {"radius", required_argument, nullptr, 'u'}, {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) break; @@ -66,6 +72,7 @@ int main(int argc, char** argv, char** envp) { exit(1); } break; + case 'o': g_pHyprpicker->m_sOutputFormat = optarg; break; case 'h': help(); exit(0); case 'b': g_pHyprpicker->m_bFancyOutput = false; 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")) 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 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(); return 0;