diff --git a/hyprbars/README.md b/hyprbars/README.md index 35435b5..daee7a0 100644 --- a/hyprbars/README.md +++ b/hyprbars/README.md @@ -48,6 +48,8 @@ plugin { `bar_button_padding` -> (int) padding between the buttons (default `5`) +`icon_on_hover` -> (bool) whether the icons show on mouse hovering over the buttons (default `false`) + ## Buttons Config Use the `hyprbars-button` keyword. diff --git a/hyprbars/barDeco.cpp b/hyprbars/barDeco.cpp index 32216c6..d62f01c 100644 --- a/hyprbars/barDeco.cpp +++ b/hyprbars/barDeco.cpp @@ -113,6 +113,11 @@ void CHyprBar::onTouchDown(SCallbackInfo& info, ITouch::SDownEvent e) { } void CHyprBar::onMouseMove(Vector2D coords) { + // ensure proper redraws of button icons on hover when using hardware cursors + static auto* const PICONONHOVER = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:icon_on_hover")->getDataStaticPtr(); + if (**PICONONHOVER) + damageOnButtonHover(); + if (!m_bDragPending || m_bTouchEv || !validMapped(m_pWindow)) return; @@ -160,7 +165,8 @@ void CHyprBar::handleDownEvent(SCallbackInfo& info, std::optionalfocusWindow(PWINDOW); + if (g_pCompositor->m_pLastWindow.lock() != PWINDOW) + g_pCompositor->focusWindow(PWINDOW); if (PWINDOW->m_bIsFloating) g_pCompositor->changeWindowZOrder(PWINDOW, true); @@ -437,19 +443,30 @@ void CHyprBar::renderBarButtons(const Vector2D& bufferSize, const float scale) { } void CHyprBar::renderBarButtonsText(CBox* barBox, const float scale, const float a) { + static auto* const PHEIGHT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->getDataStaticPtr(); static auto* const PBARBUTTONPADDING = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->getDataStaticPtr(); static auto* const PBARPADDING = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->getDataStaticPtr(); static auto* const PALIGNBUTTONS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->getDataStaticPtr(); + static auto* const PICONONHOVER = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:icon_on_hover")->getDataStaticPtr(); const bool BUTTONSRIGHT = std::string{*PALIGNBUTTONS} != "left"; const auto visibleCount = getVisibleButtonCount(PBARBUTTONPADDING, PBARPADDING, Vector2D{barBox->w, barBox->h}, scale); + const auto COORDS = cursorRelativeToBar(); + + int offset = **PBARPADDING * scale; + float noScaleOffset = **PBARPADDING; - int offset = **PBARPADDING * scale; for (size_t i = 0; i < visibleCount; ++i) { auto& button = g_pGlobalState->buttons[i]; const auto scaledButtonSize = button.size * scale; const auto scaledButtonsPad = **PBARBUTTONPADDING * scale; + // check if hovering here + const auto BARBUF = Vector2D{(int)assignedBoxGlobal().w, **PHEIGHT}; + Vector2D currentPos = Vector2D{(BUTTONSRIGHT ? BARBUF.x - **PBARBUTTONPADDING - button.size - noScaleOffset : noScaleOffset), (BARBUF.y - button.size) / 2.0}.floor(); + bool hovering = VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + button.size + **PBARBUTTONPADDING, currentPos.y + button.size); + noScaleOffset += **PBARBUTTONPADDING + button.size; + if (button.iconTex->m_iTexID == 0 /* icon is not rendered */ && !button.icon.empty()) { // render icon const Vector2D BUFSIZE = {scaledButtonSize, scaledButtonSize}; @@ -464,8 +481,16 @@ void CHyprBar::renderBarButtonsText(CBox* barBox, const float scale, const float CBox pos = {barBox->x + (BUTTONSRIGHT ? barBox->width - offset - scaledButtonSize : offset), barBox->y + (barBox->height - scaledButtonSize) / 2.0, scaledButtonSize, scaledButtonSize}; - g_pHyprOpenGL->renderTexture(button.iconTex, pos, a); + if (!**PICONONHOVER || (**PICONONHOVER && m_iButtonHoverState > 0)) + g_pHyprOpenGL->renderTexture(button.iconTex, pos, a); offset += scaledButtonsPad + scaledButtonSize; + + bool currentBit = (m_iButtonHoverState & (1 << i)) != 0; + if (hovering != currentBit) { + m_iButtonHoverState ^= (1 << i); + // damage to get rid of some artifacts when icons are "hidden" + damageEntire(); + } } } @@ -675,3 +700,29 @@ void CHyprBar::applyRule(const SP& r) { else if (r->szRule.starts_with("plugin:hyprbars:title_color")) m_bForcedTitleColor = CHyprColor(configStringToInt(arg).value_or(0)); } + +void CHyprBar::damageOnButtonHover() { + static auto* const PBARPADDING = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_padding")->getDataStaticPtr(); + static auto* const PBARBUTTONPADDING = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding")->getDataStaticPtr(); + static auto* const PHEIGHT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_height")->getDataStaticPtr(); + static auto* const PALIGNBUTTONS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment")->getDataStaticPtr(); + const bool BUTTONSRIGHT = std::string{*PALIGNBUTTONS} != "left"; + + float offset = **PBARPADDING; + + const auto COORDS = cursorRelativeToBar(); + + for (auto& b : g_pGlobalState->buttons) { + const auto BARBUF = Vector2D{(int)assignedBoxGlobal().w, **PHEIGHT}; + Vector2D currentPos = Vector2D{(BUTTONSRIGHT ? BARBUF.x - **PBARBUTTONPADDING - b.size - offset : offset), (BARBUF.y - b.size) / 2.0}.floor(); + + bool hover = VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + b.size + **PBARBUTTONPADDING, currentPos.y + b.size); + + if (hover != m_bButtonHovered) { + m_bButtonHovered = hover; + damageEntire(); + } + + offset += **PBARBUTTONPADDING + b.size; + } +} diff --git a/hyprbars/barDeco.hpp b/hyprbars/barDeco.hpp index dc06ca3..04f2244 100644 --- a/hyprbars/barDeco.hpp +++ b/hyprbars/barDeco.hpp @@ -59,6 +59,7 @@ class CHyprBar : public IHyprWindowDecoration { bool m_bWindowSizeChanged = false; bool m_bHidden = false; bool m_bTitleColorChanged = false; + bool m_bButtonHovered = false; std::optional m_bForcedBarColor; std::optional m_bForcedTitleColor; @@ -71,6 +72,7 @@ class CHyprBar : public IHyprWindowDecoration { void renderText(SP out, const std::string& text, const CHyprColor& color, const Vector2D& bufferSize, const float scale, const int fontSize); void renderBarButtons(const Vector2D& bufferSize, const float scale); void renderBarButtonsText(CBox* barBox, const float scale, const float a); + void damageOnButtonHover(); bool inputIsValid(); void onMouseButton(SCallbackInfo& info, IPointer::SButtonEvent e); @@ -99,6 +101,9 @@ class CHyprBar : public IHyprWindowDecoration { bool m_bDragPending = false; bool m_bCancelledDown = false; + // store hover state for buttons as a bitfield + unsigned int m_iButtonHoverState = 0; + // for dynamic updates int m_iLastHeight = 0; diff --git a/hyprbars/main.cpp b/hyprbars/main.cpp index 04ec92d..ee2d9bc 100644 --- a/hyprbars/main.cpp +++ b/hyprbars/main.cpp @@ -140,6 +140,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_buttons_alignment", Hyprlang::STRING{"right"}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_padding", Hyprlang::INT{7}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:bar_button_padding", Hyprlang::INT{5}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprbars:icon_on_hover", Hyprlang::INT{0}); HyprlandAPI::addConfigKeyword(PHANDLE, "hyprbars-button", onNewButton, Hyprlang::SHandlerOptions{}); static auto P4 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "preConfigReload", [&](void* self, SCallbackInfo& info, std::any data) { onPreConfigReload(); });