diff --git a/README.md b/README.md index 100bca8..d66aef8 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,15 @@ plugin { #background color of the label box. alpha is respected bgcolor=rgba(000000ff) + #enable blur. The bgcolor alpha must be at least semi-transparent. + blur=0 + + #Set blur alpha value. Blur must be enabled (float value) + blurA=1.0 + + #Set xray. Blur must be enabled + xray=0 + #font to use for the label. This is passed directly to the pango font description textfont=Sans @@ -85,7 +94,7 @@ wayland.windowManager.hyprland = { }; ``` # TODO -- [ ] Blur? +- [x] Blur? - [ ] Allow multi-letter labels? - [ ] Fixed/static label box sizing - [ ] Location of label in window (edges etc) diff --git a/easymotionDeco.cpp b/easymotionDeco.cpp index 941de87..9f92489 100644 --- a/easymotionDeco.cpp +++ b/easymotionDeco.cpp @@ -2,6 +2,10 @@ #include #include +#include +#include +#include +#include #include #include #include @@ -26,16 +30,21 @@ CHyprEasyLabel::CHyprEasyLabel(PHLWINDOW pWindow, SMotionActionDesc *actionDesc) m_iRounding = actionDesc->rounding; m_iBorderSize = actionDesc->borderSize; m_cBorderGradient = actionDesc->borderColor; + m_iBlur = actionDesc->blur; + m_iBlurA = actionDesc->blurA; + m_iXray = actionDesc->xray; } CHyprEasyLabel::~CHyprEasyLabel() { damageEntire(); - std::erase(g_pGlobalState->motionLabels, this); + std::erase(g_pGlobalState->motionLabels, m_self); } SDecorationPositioningInfo CHyprEasyLabel::getPositioningInfo() { SDecorationPositioningInfo info; info.policy = DECORATION_POSITION_ABSOLUTE; + info.edges = DECORATION_EDGE_BOTTOM; + info.priority = 10000; return info; } @@ -90,9 +99,10 @@ void CHyprEasyLabel::renderMotionString(Vector2D& bufferSize, const float scale) cairo_surface_flush(CAIROSURFACE); const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); m_tTextTex->allocate(); + m_tTextTex->m_vSize = {bufferSize.x, bufferSize.y}; glBindTexture(GL_TEXTURE_2D, m_tTextTex->m_iTexID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); @@ -105,22 +115,23 @@ void CHyprEasyLabel::renderMotionString(Vector2D& bufferSize, const float scale) cairo_destroy(LAYOUTCAIRO); cairo_destroy(CAIRO); cairo_surface_destroy(CAIROSURFACE); + + //renderText doesn't use ink_rect, but logical_rect. Makes the rectangle too tall + //m_tTextTex = g_pHyprOpenGL->renderText(m_szLabel, m_cTextColor, textSize, false, m_szTextFont, bufferSize.x-2); } void CHyprEasyLabel::draw(PHLMONITOR pMonitor, float const &a) { if (!validMapped(m_pWindow)) return; + + const auto PWINDOW = m_pWindow.lock(); - if (!m_pWindow->m_sWindowData.decorate.valueOrDefault()) + if (!PWINDOW->m_sWindowData.decorate.valueOrDefault()) return; - const auto PWORKSPACE = m_pWindow->m_pWorkspace; - const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); - - const auto ROUNDING = m_iRounding; - - const auto scaledRounding = ROUNDING > 0 ? ROUNDING * pMonitor->scale : 0; + const auto PWORKSPACE = PWINDOW->m_pWorkspace; + const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); const auto DECOBOX = assignedBoxGlobal(); @@ -128,32 +139,59 @@ void CHyprEasyLabel::draw(PHLMONITOR pMonitor, float const &a) { //CBox motionBox = {DECOBOX.x - pMonitor->vecPosition.x, DECOBOX.y - pMonitor->vecPosition.y, DECOBOX.w, - auto TEXTBUF = DECOBOX.size() * pMonitor->scale; + auto TEXTBUF = DECOBOX.size(); if (!m_tTextTex.get()) { renderMotionString(TEXTBUF, pMonitor->scale); } - CBox motionBox = {DECOBOX.x, DECOBOX.y, static_cast(layoutWidth), static_cast(layoutHeight)}; + + CBox motionBox = {DECOBOX.x, DECOBOX.y, m_tTextTex->m_vSize.x, m_tTextTex->m_vSize.y}; motionBox.translate(pMonitor->vecPosition*-1).scale(pMonitor->scale).round(); if (motionBox.w < 1 || motionBox.h < 1) + { return; - g_pHyprOpenGL->scissor(motionBox); - g_pHyprOpenGL->renderRect(motionBox, m_cBackgroundColor, scaledRounding); + } + + CRectPassElement::SRectData rectData; + rectData.color = m_cBackgroundColor; + rectData.box = motionBox; + rectData.clipBox = motionBox; + rectData.blur = m_iBlur; + if (m_iBlur) { + rectData.blurA = m_iBlurA; + rectData.xray = m_iXray; + } + + rectData.round = m_iRounding != 0; + rectData.roundingPower = m_iRounding ; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectData)); + if (m_iBorderSize) { CBox borderBox = {DECOBOX.x, DECOBOX.y, static_cast(layoutWidth), static_cast(layoutHeight)}; borderBox.translate(pMonitor->vecPosition*-1).scale(pMonitor->scale).round(); if (borderBox.w >= 1 && borderBox.h >= 1) { - g_pHyprOpenGL->renderBorder(borderBox, m_cBorderGradient, scaledRounding, m_iBorderSize * pMonitor->scale, a); + CBorderPassElement::SBorderData borderData; + borderData.box = borderBox; + borderData.grad1 = m_cBorderGradient; + borderData.round = m_iRounding != 0; + borderData.roundingPower = m_iRounding; + borderData.borderSize = m_iBorderSize; + borderData.a = a; + g_pHyprRenderer->m_sRenderPass.add(makeShared(borderData)); + //g_pHyprOpenGL->renderBorder(borderBox, m_cBorderGradient, scaledRounding, m_iBorderSize * pMonitor->scale, a); } } - - - g_pHyprOpenGL->renderTexture(m_tTextTex, motionBox, a); - - g_pHyprOpenGL->scissor(nullptr); + + CTexPassElement::SRenderData texData; + motionBox.round(); + texData.tex = m_tTextTex; + texData.box = motionBox; + g_pHyprRenderer->m_sRenderPass.add(makeShared(texData)); + + } eDecorationType CHyprEasyLabel::getDecorationType() { @@ -165,34 +203,37 @@ void CHyprEasyLabel::updateWindow(PHLWINDOW pWindow) { } void CHyprEasyLabel::damageEntire() { - ; // ignored + auto box = assignedBoxGlobal(); + box.translate(m_pWindow->m_vFloatingOffset); + g_pHyprRenderer->damageBox(box); } eDecorationLayer CHyprEasyLabel::getDecorationLayer() { - return DECORATION_LAYER_OVERLAY; + return DECORATION_LAYER_OVER; } uint64_t CHyprEasyLabel::getDecorationFlags() { - return DECORATION_PART_OF_MAIN_WINDOW; + return DECORATION_PART_OF_MAIN_WINDOW; } CBox CHyprEasyLabel::assignedBoxGlobal() { + const auto PWINDOW = m_pWindow.lock(); double boxHeight, boxWidth; double boxSize; - boxHeight = m_pWindow->m_vRealSize->value().y * 0.10; - boxWidth = m_pWindow->m_vRealSize->value().x * 0.10; + boxHeight = PWINDOW->m_vRealSize->value().y * 0.10; + boxWidth = PWINDOW->m_vRealSize->value().x * 0.10; boxSize = std::min(boxHeight, boxWidth); - double boxX = m_pWindow->m_vRealPosition->value().x + (m_pWindow->m_vRealSize->value().x-boxSize)/2; - double boxY = m_pWindow->m_vRealPosition->value().y + (m_pWindow->m_vRealSize->value().y-boxSize)/2; + double boxX = PWINDOW->m_vRealPosition->value().x + (PWINDOW->m_vRealSize->value().x-boxSize)/2; + double boxY = PWINDOW->m_vRealPosition->value().y + (PWINDOW->m_vRealSize->value().y-boxSize)/2; CBox box = {boxX, boxY, boxSize, boxSize}; - const auto PWORKSPACE = m_pWindow->m_pWorkspace; - const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); + const auto PWORKSPACE = PWINDOW->m_pWorkspace; + const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); return box.translate(WORKSPACEOFFSET); } PHLWINDOW CHyprEasyLabel::getOwner() { - return m_pWindow; + return m_pWindow.lock(); } diff --git a/easymotionDeco.hpp b/easymotionDeco.hpp index 322e292..1a68aa7 100644 --- a/easymotionDeco.hpp +++ b/easymotionDeco.hpp @@ -45,11 +45,15 @@ class CHyprEasyLabel : public IHyprWindowDecoration { int m_iPaddingLeft; int m_iPaddingRight; int m_iRounding; + int m_iBlur; + int m_iXray; + float m_iBlurA; CHyprColor m_cTextColor; CHyprColor m_cBackgroundColor; int m_iBorderSize; CGradientValueData m_cBorderGradient; + WP m_self; @@ -60,7 +64,7 @@ class CHyprEasyLabel : public IHyprWindowDecoration { int layoutHeight; SBoxExtents m_seExtents; - PHLWINDOW m_pWindow; + PHLWINDOWREF m_pWindow; SP m_tTextTex; diff --git a/globals.hpp b/globals.hpp index 8370926..9a9ceda 100644 --- a/globals.hpp +++ b/globals.hpp @@ -8,7 +8,7 @@ inline HANDLE PHANDLE = nullptr; class CHyprEasyLabel; struct SGlobalState { - std::vector motionLabels; + std::vector> motionLabels; }; struct SMotionActionDesc { @@ -21,8 +21,11 @@ struct SMotionActionDesc { int borderSize = 0; CGradientValueData borderColor = CGradientValueData(); int rounding = 0; + int blur = 0; + int xray = 0; + float blurA = 1.0f; std::string motionKeys = "abcdefghijklmnopqrstuvwxyz1234567890"; }; -inline std::unique_ptr g_pGlobalState; +inline UP g_pGlobalState; diff --git a/main.cpp b/main.cpp index 65db3a5..423ec74 100644 --- a/main.cpp +++ b/main.cpp @@ -20,11 +20,10 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() { SDispatchResult easymotionExitDispatch(std::string args) { for (auto &ml : g_pGlobalState->motionLabels | std::ranges::views::reverse) { - ml->getOwner()->removeWindowDeco(ml); + ml->getOwner()->removeWindowDeco(ml.get()); } HyprlandAPI::invokeHyprctlCommand("dispatch", "submap reset"); g_pEventManager->postEvent(SHyprIPCEvent{"easymotionexit", ""}); - return {}; } @@ -47,7 +46,6 @@ void addEasyMotionKeybinds() { g_pKeybindManager->addKeybind(SKeybind{"escape", {}, 0, 0, 0, {}, "easymotionexit", "", 0, "__easymotionsubmap__", "", 0, 0, 0, 0, 0, 0, 0, 0}); - //catchall g_pKeybindManager->addKeybind(SKeybind{"", {}, 0, 1, 0, {}, "", "", 0, "__easymotionsubmap__", "", 0, 0, 0, 0, 0, 0, 0, 0}); @@ -57,8 +55,9 @@ void addEasyMotionKeybinds() void addLabelToWindow(PHLWINDOW window, SMotionActionDesc *actionDesc, std::string &label) { UP motionlabel = makeUnique(window, actionDesc); - motionlabel.get()->m_szLabel = label; - g_pGlobalState->motionLabels.push_back(motionlabel.get()); + motionlabel->m_szLabel = label; + g_pGlobalState->motionLabels.emplace_back(motionlabel); + motionlabel->m_self = motionlabel; HyprlandAPI::addWindowDecoration(PHANDLE, window, std::move(motionlabel)); } @@ -101,6 +100,7 @@ static bool parseBorderGradient(std::string VALUE, CGradientValueData *DATA) { DATA->m_vColors.push_back(0); // transparent } + DATA->updateColorsOk(); return true; } @@ -115,8 +115,12 @@ SDispatchResult easymotionDispatch(std::string args) static auto *const BORDERSIZE = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:bordersize")->getDataStaticPtr(); static auto *const BORDERCOLOR = (Hyprlang::STRING const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:bordercolor")->getDataStaticPtr(); static auto *const ROUNDING = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:rounding")->getDataStaticPtr(); + static auto *const BLUR = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:blur")->getDataStaticPtr(); + static auto *const XRAY = (Hyprlang::INT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:xray")->getDataStaticPtr(); + static auto *const BLURA = (Hyprlang::FLOAT* const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:blurA")->getDataStaticPtr(); static auto *const MOTIONKEYS = (Hyprlang::STRING const *)HyprlandAPI::getConfigValue(PHANDLE, "plugin:easymotion:motionkeys")->getDataStaticPtr(); + CVarList emargs(args, 0, ','); SMotionActionDesc actionDesc; @@ -133,6 +137,9 @@ SDispatchResult easymotionDispatch(std::string args) actionDesc.borderColor.m_fAngle = 0; } actionDesc.motionKeys = *MOTIONKEYS; + actionDesc.blur = **BLUR; + actionDesc.xray = **XRAY; + actionDesc.blurA = **BLURA; for(size_t i = 0; i < emargs.size(); i++) @@ -236,10 +243,13 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:bordersize", Hyprlang::INT{0}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:bordercolor", Hyprlang::STRING{"rgba(ffffffff)"}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:rounding", Hyprlang::INT{0}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:blur", Hyprlang::INT{0}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:blurA", Hyprlang::FLOAT{1.0f}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:xray", Hyprlang::INT{0}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:easymotion:motionkeys", Hyprlang::STRING{"abcdefghijklmnopqrstuvwxyz1234567890"}); - g_pGlobalState = std::make_unique(); + g_pGlobalState = makeUnique(); HyprlandAPI::addDispatcherV2(PHANDLE, "easymotion", easymotionDispatch); HyprlandAPI::addDispatcherV2(PHANDLE, "easymotionaction", easymotionActionDispatch); HyprlandAPI::addDispatcherV2(PHANDLE, "easymotionexit", easymotionExitDispatch);