From e6c9a516f8ea6f673565829a82ee220fc0a2c3d0 Mon Sep 17 00:00:00 2001 From: Sepandar Date: Wed, 12 Feb 2025 23:05:16 -0800 Subject: [PATCH 1/7] fixed description in CMakeLists.txt and fixed negative hsv --- CMakeLists.txt | 2 +- src/hyprpicker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f54d6a6..1455860 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ string(STRIP ${VER_RAW} VERSION) project( hyprpicker - DESCRIPTION "A blazing fast wayland wallpaper utility" + DESCRIPTION "A wlroots-compatible Wayland color picker that does not suck" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 650204a..d24a1f0 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -721,7 +721,7 @@ void CHyprpicker::initMouse() { l_or_v = std::round(v * 100); } - h = std::round(h); + h = std::round(h<0?h+360:h); s = std::round(s * 100); if (m_bFancyOutput) From 0c1113aef454c59a640739ed5d74cba02ec23475 Mon Sep 17 00:00:00 2001 From: Sepandar Date: Fri, 14 Feb 2025 11:33:33 -0800 Subject: [PATCH 2/7] ran clang-format --- src/hyprpicker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index d24a1f0..8cc6a47 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -721,7 +721,7 @@ void CHyprpicker::initMouse() { l_or_v = std::round(v * 100); } - h = std::round(h<0?h+360:h); + h = std::round(h < 0 ? h + 360 : h); s = std::round(s * 100); if (m_bFancyOutput) From 381f438873486b09ebed7b34dc9d520c74f80bc9 Mon Sep 17 00:00:00 2001 From: Sepandar <116840915+flashrun24@users.noreply.github.com> Date: Wed, 19 Feb 2025 22:00:09 +0000 Subject: [PATCH 3/7] updated action versions to latest --- .github/workflows/nix-build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nix-build.yaml b/.github/workflows/nix-build.yaml index e0a0d3d..3157198 100644 --- a/.github/workflows/nix-build.yaml +++ b/.github/workflows/nix-build.yaml @@ -7,11 +7,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive - name: Install nix - uses: cachix/install-nix-action@v20 + uses: cachix/install-nix-action@v27 with: install_url: https://nixos.org/nix/install extra_nix_config: | From 2db91c145a427a4e8d95df7d90faa7b5d2bfdd59 Mon Sep 17 00:00:00 2001 From: Sepandar Date: Wed, 19 Feb 2025 14:04:33 -0800 Subject: [PATCH 4/7] updated flake lock --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index f14cabb..a5f9209 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1737632363, - "narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=", + "lastModified": 1739891528, + "narHash": "sha256-h8HOCZ/rw2Buzku+GKF77VXxrGjCSOQkLhptiEKMYg0=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "006620eb29d54ea9086538891404c78563d1bae1", + "rev": "61a5382f4b1ab578064d470b1b3d3f0df396b8ba", "type": "github" }, "original": { @@ -33,11 +33,11 @@ ] }, "locked": { - "lastModified": 1735493474, - "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", + "lastModified": 1739870480, + "narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", + "rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b", "type": "github" }, "original": { @@ -48,11 +48,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737469691, - "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", + "lastModified": 1739866667, + "narHash": "sha256-EO1ygNKZlsAC9avfcwHkKGMsmipUk1Uc0TbrEZpkn64=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", + "rev": "73cf49b8ad837ade2de76f87eb53fc85ed5d4680", "type": "github" }, "original": { From d82346e4fa8263c6bb094121244e83ef3a91739c Mon Sep 17 00:00:00 2001 From: Sepandar Date: Wed, 19 Feb 2025 21:13:35 -0800 Subject: [PATCH 5/7] Updated color preview and did some refactoring Moved the lowercase hex from a bool to a output format and also made the preview match the output format, still need to make it fit in the box --- CMakeLists.txt | 1 + src/hyprpicker.cpp | 82 ++++++++++++++++++++++++++++++++++++++++------ src/hyprpicker.hpp | 4 +-- src/main.cpp | 15 ++++----- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1455860..487d4d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ project( VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) add_compile_definitions(HYPRPICKER_VERSION="${VERSION}") diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 8cc6a47..0b76e56 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -425,17 +425,78 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_clip(PCAIRO); cairo_paint(PCAIRO); - if (!m_bDisableHexPreview) { + if (!m_bDisablePreview) { const auto currentColor = getColorFromPixel(pSurface, CLICKPOS); - std::string hexBuffer; - if (m_bUseLowerCase) - hexBuffer = std::format("#{:02x}{:02x}{:02x}", currentColor.r, currentColor.g, currentColor.b); - else - hexBuffer = std::format("#{:02X}{:02X}{:02X}", currentColor.r, currentColor.g, currentColor.b); + std::string previewBuffer; + auto fmax3 = [](float a, float b, float c) -> float { return (a > b && a > c) ? a : (b > c) ? b : c; }; + auto fmin3 = [](float a, float b, float c) -> float { return (a < b && a < c) ? a : (b < c) ? b : c; }; + switch(m_bSelectedOutputMode) { + case OUTPUT_CMYK: { + float r = 1 - currentColor.r / 255.0f, g = 1 - currentColor.g / 255.0f, b = 1 - currentColor.b / 255.0f; + float k = fmin3(r, g, b), K = (k == 1) ? 1 : 1 - k; + float c = (r - k) / K, m = (g - k) / K, y = (b - k) / K; + + c = std::round(c * 100); + m = std::round(m * 100); + y = std::round(y * 100); + k = std::round(k * 100); + previewBuffer = std::format("{}% {}% {}% {}%", c, m, y, k); + break; + } + case OUTPUT_HEX: { + previewBuffer = std::format("#{:02X}{:02X}{:02X}", currentColor.r, currentColor.g, currentColor.b); + break; + } + case OUTPUT_LHEX: { + previewBuffer = std::format("#{:02x}{:02x}{:02x}", currentColor.r, currentColor.g, currentColor.b); + break; + } + case OUTPUT_HSL: + case OUTPUT_HSV: { + auto floatEq = [](float a, float b) -> bool { + return std::nextafter(a, std::numeric_limits::lowest()) <= b && std::nextafter(a, std::numeric_limits::max()) >= b; + }; + + float h, s, l, v; + float r = currentColor.r / 255.0f, g = currentColor.g / 255.0f, b = currentColor.b / 255.0f; + float max = fmax3(r, g, b), min = fmin3(r, g, b); + float c = max - min; + + v = max; + if (c == 0) + h = 0; + else if (v == r) + h = 60 * (0 + (g - b) / c); + else if (v == g) + h = 60 * (2 + (b - r) / c); + else /* v == b */ + h = 60 * (4 + (r - g) / c); + + float l_or_v; + if (m_bSelectedOutputMode == OUTPUT_HSL) { + l = (max + min) / 2; + s = (floatEq(l, 0.0f) || floatEq(l, 1.0f)) ? 0 : (v - l) / std::min(l, 1 - l); + l_or_v = std::round(l * 100); + } else { + v = max; + s = floatEq(v, 0.0f) ? 0 : c / v; + l_or_v = std::round(v * 100); + } + + h = std::round(h < 0 ? h + 360 : h); + s = std::round(s * 100); + previewBuffer = std::format("{} {}% {}%", h, s, l_or_v); + break; + } + case OUTPUT_RGB: { + previewBuffer = std::format("{} {} {}", currentColor.r, currentColor.g, currentColor.b); + break; + } + } cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.5); - double x, y, width = 85, height = 28, radius = 6; + double x, y, width = 15+(10*previewBuffer.length()), height = 28, radius = 6; if (CLICKPOS.y > (PBUFFER->pixelSize.y - 50) && CLICKPOS.x > (PBUFFER->pixelSize.x - 100)) { x = CLICKPOS.x - 80; @@ -476,7 +537,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { else cairo_move_to(PCAIRO, textX, CLICKPOS.y + 40); - cairo_show_text(PCAIRO, hexBuffer.c_str()); + cairo_show_text(PCAIRO, previewBuffer.c_str()); cairo_surface_flush(PBUFFER->surface); } @@ -650,9 +711,10 @@ void CHyprpicker::initMouse() { finish(); break; } - case OUTPUT_HEX: { + case OUTPUT_HEX: + case OUTPUT_LHEX: { auto toHex = [this](int i) -> std::string { - const char* DS = m_bUseLowerCase ? "0123456789abcdef" : "0123456789ABCDEF"; + const char* DS = m_bSelectedOutputMode == OUTPUT_LHEX ? "0123456789abcdef" : "0123456789ABCDEF"; std::string result = ""; diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 8890019..f0d3a1d 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -7,6 +7,7 @@ enum eOutputMode { OUTPUT_CMYK = 0, OUTPUT_HEX, + OUTPUT_LHEX, OUTPUT_RGB, OUTPUT_HSL, OUTPUT_HSV @@ -44,8 +45,7 @@ class CHyprpicker { bool m_bRenderInactive = false; bool m_bNoZoom = false; bool m_bNoFractional = false; - bool m_bDisableHexPreview = false; - bool m_bUseLowerCase = false; + bool m_bDisablePreview = false; bool m_bRunning = true; diff --git a/src/main.cpp b/src/main.cpp index 5ccb341..573ae83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ static void help(void) { 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" + << " -f | --format=fmt | Specifies the output format (cmyk, lhex, hex, rgb, hsl, hsv)\n" << " -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" << " -h | --help | Show this help message\n" << " -r | --render-inactive | Render (freeze) inactive displays\n" @@ -15,8 +15,7 @@ static void help(void) { << " -q | --quiet | Disable most logs (leaves errors)\n" << " -v | --verbose | Enable more logs\n" << " -t | --no-fractional | Disable fractional scaling support\n" - << " -d | --disable-hex-preview | Disable live preview of Hex code\n" - << " -l | --lowercase-hex | Outputs the hexcode in lowercase\n" + << " -d | --disable-preview | Disable live preview of color\n" << " -V | --version | Print version info\n"; } @@ -34,12 +33,11 @@ int main(int argc, char** argv, char** envp) { {"no-fractional", no_argument, NULL, 't'}, {"quiet", no_argument, NULL, 'q'}, {"verbose", no_argument, NULL, 'v'}, - {"disable-hex-preview", no_argument, NULL, 'd'}, - {"lowercase-hex", no_argument, NULL, 'l'}, + {"disable-preview", no_argument, NULL, 'd'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0}}; - int c = getopt_long(argc, argv, ":f:hnarzqvtdlV", long_options, &option_index); + int c = getopt_long(argc, argv, ":f:hnarzqvtdV", long_options, &option_index); if (c == -1) break; @@ -49,6 +47,8 @@ int main(int argc, char** argv, char** envp) { g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_CMYK; else if (strcasecmp(optarg, "hex") == 0) g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_HEX; + else if (strcasecmp(optarg, "lhex") == 0) + g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_LHEX; else if (strcasecmp(optarg, "rgb") == 0) g_pHyprpicker->m_bSelectedOutputMode = OUTPUT_RGB; else if (strcasecmp(optarg, "hsl") == 0) @@ -68,8 +68,7 @@ int main(int argc, char** argv, char** envp) { case 't': g_pHyprpicker->m_bNoFractional = true; break; case 'q': Debug::quiet = true; break; case 'v': Debug::verbose = true; break; - case 'd': g_pHyprpicker->m_bDisableHexPreview = true; break; - case 'l': g_pHyprpicker->m_bUseLowerCase = true; break; + case 'd': g_pHyprpicker->m_bDisablePreview = true; break; case 'V': { std::cout << "hyprpicker v" << HYPRPICKER_VERSION << "\n"; exit(0); From 1992282b973b7a777ccbff40d3c2138e5eff3325 Mon Sep 17 00:00:00 2001 From: Sepandar Date: Wed, 19 Feb 2025 21:25:25 -0800 Subject: [PATCH 6/7] Centered the preview so there is enough room --- src/hyprpicker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 0b76e56..992386d 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -496,7 +496,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.5); - double x, y, width = 15+(10*previewBuffer.length()), height = 28, radius = 6; + double x, y, width = 8+(11*previewBuffer.length()), height = 28, radius = 6; if (CLICKPOS.y > (PBUFFER->pixelSize.y - 50) && CLICKPOS.x > (PBUFFER->pixelSize.x - 100)) { x = CLICKPOS.x - 80; @@ -511,7 +511,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { x = CLICKPOS.x; y = CLICKPOS.y + 20; } - + x-=5.5*previewBuffer.length(); cairo_move_to(PCAIRO, x + radius, y); cairo_arc(PCAIRO, x + width - radius, y + radius, radius, -M_PI_2, 0); cairo_arc(PCAIRO, x + width - radius, y + height - radius, radius, 0, M_PI_2); From 210b00cf8db3cdafbbe203cd5eec18d1d0cc9c34 Mon Sep 17 00:00:00 2001 From: Sepandar Date: Wed, 19 Feb 2025 21:35:18 -0800 Subject: [PATCH 7/7] Ran clang format --- src/hyprpicker.cpp | 124 +++++++++++++++++++++++---------------------- src/hyprpicker.hpp | 8 +-- 2 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 992386d..d9c22e5 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -428,75 +428,79 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { if (!m_bDisablePreview) { const auto currentColor = getColorFromPixel(pSurface, CLICKPOS); std::string previewBuffer; - auto fmax3 = [](float a, float b, float c) -> float { return (a > b && a > c) ? a : (b > c) ? b : c; }; - auto fmin3 = [](float a, float b, float c) -> float { return (a < b && a < c) ? a : (b < c) ? b : c; }; - switch(m_bSelectedOutputMode) { + + auto fmax3 = [](float a, float b, float c) -> float { return (a > b && a > c) ? a : (b > c) ? b : c; }; + auto fmin3 = [](float a, float b, float c) -> float { return (a < b && a < c) ? a : (b < c) ? b : c; }; + + switch (m_bSelectedOutputMode) { case OUTPUT_CMYK: { float r = 1 - currentColor.r / 255.0f, g = 1 - currentColor.g / 255.0f, b = 1 - currentColor.b / 255.0f; - float k = fmin3(r, g, b), K = (k == 1) ? 1 : 1 - k; - float c = (r - k) / K, m = (g - k) / K, y = (b - k) / K; + float k = fmin3(r, g, b), K = (k == 1) ? 1 : 1 - k; + float c = (r - k) / K, m = (g - k) / K, y = (b - k) / K; + + c = std::round(c * 100); + m = std::round(m * 100); + y = std::round(y * 100); + k = std::round(k * 100); - c = std::round(c * 100); - m = std::round(m * 100); - y = std::round(y * 100); - k = std::round(k * 100); previewBuffer = std::format("{}% {}% {}% {}%", c, m, y, k); - break; - } - case OUTPUT_HEX: { + break; + } + case OUTPUT_HEX: { previewBuffer = std::format("#{:02X}{:02X}{:02X}", currentColor.r, currentColor.g, currentColor.b); - break; - } - case OUTPUT_LHEX: { + break; + } + case OUTPUT_LHEX: { previewBuffer = std::format("#{:02x}{:02x}{:02x}", currentColor.r, currentColor.g, currentColor.b); - break; - } - case OUTPUT_HSL: - case OUTPUT_HSV: { + break; + } + case OUTPUT_HSL: + case OUTPUT_HSV: { auto floatEq = [](float a, float b) -> bool { - return std::nextafter(a, std::numeric_limits::lowest()) <= b && std::nextafter(a, std::numeric_limits::max()) >= b; - }; - - float h, s, l, v; - float r = currentColor.r / 255.0f, g = currentColor.g / 255.0f, b = currentColor.b / 255.0f; - float max = fmax3(r, g, b), min = fmin3(r, g, b); - float c = max - min; - - v = max; - if (c == 0) - h = 0; - else if (v == r) - h = 60 * (0 + (g - b) / c); - else if (v == g) - h = 60 * (2 + (b - r) / c); - else /* v == b */ - h = 60 * (4 + (r - g) / c); - - float l_or_v; - if (m_bSelectedOutputMode == OUTPUT_HSL) { - l = (max + min) / 2; - s = (floatEq(l, 0.0f) || floatEq(l, 1.0f)) ? 0 : (v - l) / std::min(l, 1 - l); - l_or_v = std::round(l * 100); - } else { - v = max; - s = floatEq(v, 0.0f) ? 0 : c / v; - l_or_v = std::round(v * 100); - } - - h = std::round(h < 0 ? h + 360 : h); - s = std::round(s * 100); - previewBuffer = std::format("{} {}% {}%", h, s, l_or_v); - break; - } - case OUTPUT_RGB: { - previewBuffer = std::format("{} {} {}", currentColor.r, currentColor.g, currentColor.b); - break; - } - } + return std::nextafter(a, std::numeric_limits::lowest()) <= b && std::nextafter(a, std::numeric_limits::max()) >= b; + }; + + float h, s, l, v; + float r = currentColor.r / 255.0f, g = currentColor.g / 255.0f, b = currentColor.b / 255.0f; + float max = fmax3(r, g, b), min = fmin3(r, g, b); + float c = max - min; + + v = max; + if (c == 0) + h = 0; + else if (v == r) + h = 60 * (0 + (g - b) / c); + else if (v == g) + h = 60 * (2 + (b - r) / c); + else /* v == b */ + h = 60 * (4 + (r - g) / c); + + float l_or_v; + if (m_bSelectedOutputMode == OUTPUT_HSL) { + l = (max + min) / 2; + s = (floatEq(l, 0.0f) || floatEq(l, 1.0f)) ? 0 : (v - l) / std::min(l, 1 - l); + l_or_v = std::round(l * 100); + } else { + v = max; + s = floatEq(v, 0.0f) ? 0 : c / v; + l_or_v = std::round(v * 100); + } + + h = std::round(h < 0 ? h + 360 : h); + s = std::round(s * 100); + + previewBuffer = std::format("{} {}% {}%", h, s, l_or_v); + break; + } + case OUTPUT_RGB: { + previewBuffer = std::format("{} {} {}", currentColor.r, currentColor.g, currentColor.b); + break; + } + } cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.5); - double x, y, width = 8+(11*previewBuffer.length()), height = 28, radius = 6; + double x, y, width = 8 + (11 * previewBuffer.length()), height = 28, radius = 6; if (CLICKPOS.y > (PBUFFER->pixelSize.y - 50) && CLICKPOS.x > (PBUFFER->pixelSize.x - 100)) { x = CLICKPOS.x - 80; @@ -511,7 +515,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { x = CLICKPOS.x; y = CLICKPOS.y + 20; } - x-=5.5*previewBuffer.length(); + x -= 5.5 * previewBuffer.length(); cairo_move_to(PCAIRO, x + radius, y); cairo_arc(PCAIRO, x + width - radius, y + radius, radius, -M_PI_2, 0); cairo_arc(PCAIRO, x + width - radius, y + height - radius, radius, 0, M_PI_2); diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index f0d3a1d..be1702e 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -41,10 +41,10 @@ class CHyprpicker { bool m_bFancyOutput = true; - bool m_bAutoCopy = false; - bool m_bRenderInactive = false; - bool m_bNoZoom = false; - bool m_bNoFractional = false; + bool m_bAutoCopy = false; + bool m_bRenderInactive = false; + bool m_bNoZoom = false; + bool m_bNoFractional = false; bool m_bDisablePreview = false; bool m_bRunning = true;