mirror of
https://github.com/hyprwm/hyprlock.git
synced 2025-05-12 13:20:36 +01:00
widgets: add onclick feature (#736)
Some checks are pending
Build / nix (push) Waiting to run
Some checks are pending
Build / nix (push) Waiting to run
* widget: add click handling and point containment methods to IWidget interface * core: add onClick method to handle mouse click events - renderer: move getOrCreateWidgetsFor method declaration to public section * core: update mouse event handling to track mouse location and button clicks * widget: add onclick command handling and point containment to CLabel - config: add onclick special config value to label * assets: add label configuration for keyboard layout switching * config: add onclick configuration for label widgets - add CLICKABLE macro for onclick configuration - replace direct onclick assignment with CLICKABLE macro * core: fix cursor shape initialization and pointer handling - ensure pointer is available before setting cursor shape - initialize cursor shape device if not already done * core: add hover handling and cursor shape updates - implement onHover method to manage widget hover states - update cursor shape based on hover status - ensure all outputs are redrawn after state changes * widgets: add hover state management and bounding box calculations - add setHover and isHovered methods to manage hover state - implement containsPoint method for hit testing - override getBoundingBox in CLabel for accurate positioning - add onHover method in CLabel to change cursor shape * core: add hover handling in pointer motion - invoke onHover method with current mouse location * widgets: add hover handling and bounding box for password input field - add getBoundingBox method to calculate the widget's bounding box - implement onHover method to update cursor shape on hover * widgets: update hover behavior for label widget - modify cursor shape setting to only apply when onclickCommand is not empty * core: optimize hover handling and rendering for lock surfaces - Improve hover state tracking for widgets - reduce unnecessary redraw calls by tracking hover changes - remove redundant renderAllOutputs() call * widgets: add onclick and hover to shape and image * core: trigger hover and onclick only for the currently focused surface * core: handle fractionalScale in onclick and hover * core: don't trigger onclick or hover when hide_cursor is set * misc: remove braces * core: run onclick commands asnychronously --------- Co-authored-by: Memoraike <memoraike@gmail.com>
This commit is contained in:
parent
6c64630df8
commit
e3bd47e177
25 changed files with 312 additions and 74 deletions
|
@ -9,7 +9,7 @@
|
|||
$font = Monospace
|
||||
|
||||
general {
|
||||
hide_cursor = true
|
||||
hide_cursor = false
|
||||
}
|
||||
|
||||
# uncomment to enable fingerprint authentication
|
||||
|
@ -90,3 +90,14 @@ label {
|
|||
halign = right
|
||||
valign = top
|
||||
}
|
||||
|
||||
label {
|
||||
monitor =
|
||||
text = $LAYOUT[en,ru]
|
||||
font_size = 24
|
||||
onclick = hyprctl switchxkblayout all next
|
||||
|
||||
position = 250, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
|
|
@ -209,6 +209,9 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue(name, "shadow_passes", Hyprlang::INT{0}); \
|
||||
m_config.addSpecialConfigValue(name, "shadow_color", Hyprlang::INT{0xFF000000}); \
|
||||
m_config.addSpecialConfigValue(name, "shadow_boost", Hyprlang::FLOAT{1.2});
|
||||
|
||||
#define CLICKABLE(name) m_config.addSpecialConfigValue(name, "onclick", Hyprlang::STRING{""});
|
||||
|
||||
m_config.addConfigValue("general:text_trim", Hyprlang::INT{1});
|
||||
m_config.addConfigValue("general:hide_cursor", Hyprlang::INT{0});
|
||||
m_config.addConfigValue("general:grace", Hyprlang::INT{0});
|
||||
|
@ -257,6 +260,7 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("shape", "xray", Hyprlang::INT{0});
|
||||
m_config.addSpecialConfigValue("shape", "zindex", Hyprlang::INT{0});
|
||||
SHADOWABLE("shape");
|
||||
CLICKABLE("shape");
|
||||
|
||||
m_config.addSpecialCategory("image", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||
m_config.addSpecialConfigValue("image", "monitor", Hyprlang::STRING{""});
|
||||
|
@ -273,6 +277,7 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("image", "reload_cmd", Hyprlang::STRING{""});
|
||||
m_config.addSpecialConfigValue("image", "zindex", Hyprlang::INT{0});
|
||||
SHADOWABLE("image");
|
||||
CLICKABLE("image");
|
||||
|
||||
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
|
||||
|
@ -320,6 +325,7 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("label", "text_align", Hyprlang::STRING{""});
|
||||
m_config.addSpecialConfigValue("label", "zindex", Hyprlang::INT{0});
|
||||
SHADOWABLE("label");
|
||||
CLICKABLE("label");
|
||||
|
||||
m_config.registerHandler(&::handleSource, "source", {.allowFlags = false});
|
||||
m_config.registerHandler(&::handleBezier, "bezier", {.allowFlags = false});
|
||||
|
@ -356,6 +362,7 @@ void CConfigManager::init() {
|
|||
Debug::log(ERR, "Config has errors:\n{}\nProceeding ignoring faulty entries", result.getError());
|
||||
|
||||
#undef SHADOWABLE
|
||||
#undef CLICKABLE
|
||||
}
|
||||
|
||||
std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||
|
@ -367,6 +374,8 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
"shadow_boost", m_config.getSpecialConfigValue(name, "shadow_boost", k.c_str()) \
|
||||
}
|
||||
|
||||
#define CLICKABLE(name) {"onclick", m_config.getSpecialConfigValue(name, "onclick", k.c_str())}
|
||||
|
||||
//
|
||||
auto keys = m_config.listKeysForSpecialCategory("background");
|
||||
result.reserve(keys.size());
|
||||
|
@ -414,6 +423,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"xray", m_config.getSpecialConfigValue("shape", "xray", k.c_str())},
|
||||
{"zindex", m_config.getSpecialConfigValue("shape", "zindex", k.c_str())},
|
||||
SHADOWABLE("shape"),
|
||||
CLICKABLE("shape"),
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
|
@ -440,6 +450,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"reload_cmd", m_config.getSpecialConfigValue("image", "reload_cmd", k.c_str())},
|
||||
{"zindex", m_config.getSpecialConfigValue("image", "zindex", k.c_str())},
|
||||
SHADOWABLE("image"),
|
||||
CLICKABLE("image"),
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
|
@ -505,6 +516,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"text_align", m_config.getSpecialConfigValue("label", "text_align", k.c_str())},
|
||||
{"zindex", m_config.getSpecialConfigValue("label", "zindex", k.c_str())},
|
||||
SHADOWABLE("label"),
|
||||
CLICKABLE("label"),
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
|
|
|
@ -9,12 +9,15 @@ CCursorShape::CCursorShape(SP<CCWpCursorShapeManagerV1> mgr) : mgr(mgr) {
|
|||
}
|
||||
|
||||
void CCursorShape::setShape(const wpCursorShapeDeviceV1Shape shape) {
|
||||
if (!dev)
|
||||
if (!g_pSeatManager->m_pPointer)
|
||||
return;
|
||||
|
||||
if (!dev)
|
||||
dev = makeShared<CCWpCursorShapeDeviceV1>(mgr->sendGetPointer(g_pSeatManager->m_pPointer->resource()));
|
||||
|
||||
dev->sendSetShape(lastCursorSerial, shape);
|
||||
}
|
||||
|
||||
void CCursorShape::hideCursor() {
|
||||
g_pSeatManager->m_pPointer->sendSetCursor(lastCursorSerial, nullptr, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,3 +139,7 @@ void CSessionLockSurface::onCallback() {
|
|||
render();
|
||||
}
|
||||
}
|
||||
|
||||
SP<CCWlSurface> CSessionLockSurface::getWlSurface() {
|
||||
return surface;
|
||||
}
|
||||
|
|
|
@ -17,15 +17,16 @@ class CSessionLockSurface {
|
|||
CSessionLockSurface(const SP<COutput>& pOutput);
|
||||
~CSessionLockSurface();
|
||||
|
||||
void configure(const Vector2D& size, uint32_t serial);
|
||||
void configure(const Vector2D& size, uint32_t serial);
|
||||
|
||||
bool readyForFrame = false;
|
||||
bool readyForFrame = false;
|
||||
|
||||
float fractionalScale = 1.0;
|
||||
float fractionalScale = 1.0;
|
||||
|
||||
void render();
|
||||
void onCallback();
|
||||
void onScaleUpdate();
|
||||
void render();
|
||||
void onCallback();
|
||||
void onScaleUpdate();
|
||||
SP<CCWlSurface> getWlSurface();
|
||||
|
||||
private:
|
||||
WP<COutput> m_outputRef;
|
||||
|
|
|
@ -26,7 +26,13 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
|||
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
||||
m_pPointer = makeShared<CCWlPointer>(r->sendGetPointer());
|
||||
|
||||
static const auto HIDECURSOR = g_pConfigManager->getValue<Hyprlang::INT>("general:hide_cursor");
|
||||
m_pPointer->setMotion([](CCWlPointer* r, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
g_pHyprlock->m_vMouseLocation = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)};
|
||||
|
||||
if (!*HIDECURSOR)
|
||||
g_pHyprlock->onHover(g_pHyprlock->m_vMouseLocation);
|
||||
|
||||
if (std::chrono::system_clock::now() > g_pHyprlock->m_tGraceEnds)
|
||||
return;
|
||||
|
||||
|
@ -40,16 +46,34 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
|||
if (!m_pCursorShape)
|
||||
return;
|
||||
|
||||
static const auto HIDE = g_pConfigManager->getValue<Hyprlang::INT>("general:hide_cursor");
|
||||
|
||||
m_pCursorShape->lastCursorSerial = serial;
|
||||
|
||||
if (*HIDE)
|
||||
if (*HIDECURSOR)
|
||||
m_pCursorShape->hideCursor();
|
||||
else
|
||||
m_pCursorShape->setShape(wpCursorShapeDeviceV1Shape::WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
|
||||
|
||||
g_pHyprlock->m_vLastEnterCoords = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)};
|
||||
|
||||
if (*HIDECURSOR)
|
||||
return;
|
||||
|
||||
for (const auto& POUTPUT : g_pHyprlock->m_vOutputs) {
|
||||
if (!POUTPUT->m_sessionLockSurface)
|
||||
continue;
|
||||
|
||||
const auto& PWLSURFACE = POUTPUT->m_sessionLockSurface->getWlSurface();
|
||||
if (PWLSURFACE->resource() == surf)
|
||||
g_pHyprlock->m_focusedOutput = POUTPUT;
|
||||
}
|
||||
});
|
||||
|
||||
m_pPointer->setLeave([](CCWlPointer* r, uint32_t serial, wl_proxy* surf) { g_pHyprlock->m_focusedOutput.reset(); });
|
||||
|
||||
m_pPointer->setButton([](CCWlPointer* r, uint32_t serial, uint32_t time, uint32_t button, wl_pointer_button_state state) {
|
||||
if (*HIDECURSOR)
|
||||
return;
|
||||
g_pHyprlock->onClick(button, state == WL_POINTER_BUTTON_STATE_PRESSED, g_pHyprlock->m_vMouseLocation);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -669,6 +669,61 @@ void CHyprlock::handleKeySym(xkb_keysym_t sym, bool composed) {
|
|||
}
|
||||
}
|
||||
|
||||
void CHyprlock::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (!m_focusedOutput.lock())
|
||||
return;
|
||||
|
||||
// TODO: add the UNLIKELY marco from Hyprland
|
||||
if (!m_focusedOutput->m_sessionLockSurface)
|
||||
return;
|
||||
|
||||
const auto SCALEDPOS = pos * m_focusedOutput->m_sessionLockSurface->fractionalScale;
|
||||
const auto widgets = g_pRenderer->getOrCreateWidgetsFor(*m_focusedOutput->m_sessionLockSurface);
|
||||
for (const auto& widget : widgets) {
|
||||
if (widget->containsPoint(SCALEDPOS))
|
||||
widget->onClick(button, down, pos);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprlock::onHover(const Vector2D& pos) {
|
||||
if (!m_focusedOutput.lock())
|
||||
return;
|
||||
|
||||
if (!m_focusedOutput->m_sessionLockSurface)
|
||||
return;
|
||||
|
||||
bool outputNeedsRedraw = false;
|
||||
bool cursorChanged = false;
|
||||
|
||||
const auto SCALEDPOS = pos * m_focusedOutput->m_sessionLockSurface->fractionalScale;
|
||||
const auto widgets = g_pRenderer->getOrCreateWidgetsFor(*m_focusedOutput->m_sessionLockSurface);
|
||||
for (const auto& widget : widgets) {
|
||||
const bool CONTAINSPOINT = widget->containsPoint(SCALEDPOS);
|
||||
const bool HOVERED = widget->isHovered();
|
||||
|
||||
if (CONTAINSPOINT) {
|
||||
if (!HOVERED) {
|
||||
widget->setHover(true);
|
||||
widget->onHover(pos);
|
||||
outputNeedsRedraw = true;
|
||||
}
|
||||
|
||||
if (!cursorChanged)
|
||||
cursorChanged = true;
|
||||
|
||||
} else if (HOVERED) {
|
||||
widget->setHover(false);
|
||||
outputNeedsRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cursorChanged)
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
|
||||
|
||||
if (outputNeedsRedraw)
|
||||
m_focusedOutput->m_sessionLockSurface->render();
|
||||
}
|
||||
|
||||
bool CHyprlock::acquireSessionLock() {
|
||||
Debug::log(LOG, "Locking session");
|
||||
m_sLockState.lock = makeShared<CCExtSessionLockV1>(m_sWaylandState.sessionLock->sendLock());
|
||||
|
@ -817,19 +872,6 @@ void CHyprlock::enqueueForceUpdateTimers() {
|
|||
nullptr, false);
|
||||
}
|
||||
|
||||
std::string CHyprlock::spawnSync(const std::string& cmd) {
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
if (!proc.runSync()) {
|
||||
Debug::log(ERR, "Failed to run \"{}\"", cmd);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!proc.stdErr().empty())
|
||||
Debug::log(ERR, "Shell command \"{}\" STDERR:\n{}", cmd, proc.stdErr());
|
||||
|
||||
return proc.stdOut();
|
||||
}
|
||||
|
||||
SP<CCZwlrScreencopyManagerV1> CHyprlock::getScreencopy() {
|
||||
return m_sWaylandState.screencopy;
|
||||
}
|
||||
|
|
|
@ -48,9 +48,9 @@ class CHyprlock {
|
|||
bool acquireSessionLock();
|
||||
void releaseSessionLock();
|
||||
|
||||
std::string spawnSync(const std::string& cmd);
|
||||
|
||||
void onKey(uint32_t key, bool down);
|
||||
void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
void onHover(const Vector2D& pos);
|
||||
void startKeyRepeat(xkb_keysym_t sym);
|
||||
void repeatKey(xkb_keysym_t sym);
|
||||
void handleKeySym(xkb_keysym_t sym, bool compose);
|
||||
|
@ -95,6 +95,9 @@ class CHyprlock {
|
|||
//
|
||||
std::chrono::system_clock::time_point m_tGraceEnds;
|
||||
Vector2D m_vLastEnterCoords = {};
|
||||
WP<COutput> m_focusedOutput;
|
||||
|
||||
Vector2D m_vMouseLocation = {};
|
||||
|
||||
std::shared_ptr<CTimer> m_pKeyRepeatTimer = nullptr;
|
||||
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#include "MiscFunctions.hpp"
|
||||
#include "Log.hpp"
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
|
||||
std::filesystem::path path(rawpath);
|
||||
|
@ -137,3 +139,22 @@ int createPoolFile(size_t size, std::string& name) {
|
|||
|
||||
return FD;
|
||||
}
|
||||
|
||||
std::string spawnSync(const std::string& cmd) {
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
if (!proc.runSync()) {
|
||||
Debug::log(ERR, "Failed to run \"{}\"", cmd);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!proc.stdErr().empty())
|
||||
Debug::log(ERR, "Shell command \"{}\" STDERR:\n{}", cmd, proc.stdErr());
|
||||
|
||||
return proc.stdOut();
|
||||
}
|
||||
|
||||
void spawnAsync(const std::string& cmd) {
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
if (!proc.runAsync())
|
||||
Debug::log(ERR, "Failed to start \"{}\"", cmd);
|
||||
}
|
||||
|
|
|
@ -7,3 +7,5 @@
|
|||
std::string absolutePath(const std::string&, const std::string&);
|
||||
int64_t configStringToInt(const std::string& VALUE);
|
||||
int createPoolFile(size_t size, std::string& name);
|
||||
std::string spawnSync(const std::string& cmd);
|
||||
void spawnAsync(const std::string& cmd);
|
||||
|
|
|
@ -218,7 +218,7 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) {
|
|||
const bool ISCMD = rq.props.contains("cmd") ? std::any_cast<bool>(rq.props.at("cmd")) : false;
|
||||
|
||||
static const auto TRIM = g_pConfigManager->getValue<Hyprlang::INT>("general:text_trim");
|
||||
std::string text = ISCMD ? g_pHyprlock->spawnSync(rq.asset) : rq.asset;
|
||||
std::string text = ISCMD ? spawnSync(rq.asset) : rq.asset;
|
||||
|
||||
if (*TRIM) {
|
||||
text.erase(0, text.find_first_not_of(" \n\r\t"));
|
||||
|
|
|
@ -117,6 +117,6 @@ CFramebuffer::~CFramebuffer() {
|
|||
release();
|
||||
}
|
||||
|
||||
bool CFramebuffer::isAllocated() {
|
||||
bool CFramebuffer::isAllocated() const {
|
||||
return m_iFb != (GLuint)-1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ class CFramebuffer {
|
|||
void bind() const;
|
||||
void release();
|
||||
void reset();
|
||||
bool isAllocated();
|
||||
bool isAllocated() const;
|
||||
|
||||
Vector2D m_vSize;
|
||||
|
||||
|
@ -21,4 +21,4 @@ class CFramebuffer {
|
|||
GLuint m_iFb = -1;
|
||||
|
||||
CTexture* m_pStencilTex = nullptr;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -48,27 +48,26 @@ class CRenderer {
|
|||
|
||||
void startFadeIn();
|
||||
void startFadeOut(bool unlock = false, bool immediate = true);
|
||||
std::vector<SP<IWidget>>& getOrCreateWidgetsFor(const CSessionLockSurface& surf);
|
||||
|
||||
private:
|
||||
widgetMap_t widgets;
|
||||
widgetMap_t widgets;
|
||||
|
||||
std::vector<SP<IWidget>>& getOrCreateWidgetsFor(const CSessionLockSurface& surf);
|
||||
CShader rectShader;
|
||||
CShader texShader;
|
||||
CShader texMixShader;
|
||||
CShader blurShader1;
|
||||
CShader blurShader2;
|
||||
CShader blurPrepareShader;
|
||||
CShader blurFinishShader;
|
||||
CShader borderShader;
|
||||
|
||||
CShader rectShader;
|
||||
CShader texShader;
|
||||
CShader texMixShader;
|
||||
CShader blurShader1;
|
||||
CShader blurShader2;
|
||||
CShader blurPrepareShader;
|
||||
CShader blurFinishShader;
|
||||
CShader borderShader;
|
||||
Mat3x3 projMatrix = Mat3x3::identity();
|
||||
Mat3x3 projection;
|
||||
|
||||
Mat3x3 projMatrix = Mat3x3::identity();
|
||||
Mat3x3 projection;
|
||||
PHLANIMVAR<float> opacity;
|
||||
|
||||
PHLANIMVAR<float> opacity;
|
||||
|
||||
std::vector<GLint> boundFBs;
|
||||
std::vector<GLint> boundFBs;
|
||||
};
|
||||
|
||||
inline UP<CRenderer> g_pRenderer;
|
||||
|
|
|
@ -240,7 +240,7 @@ void CBackground::onReloadTimerUpdate() {
|
|||
// Path parsing and early returns
|
||||
|
||||
if (!reloadCommand.empty()) {
|
||||
path = g_pHyprlock->spawnSync(reloadCommand);
|
||||
path = spawnSync(reloadCommand);
|
||||
|
||||
if (path.ends_with('\n'))
|
||||
path.pop_back();
|
||||
|
|
|
@ -266,3 +266,15 @@ IWidget::SFormatResult IWidget::formatString(std::string in) {
|
|||
result.formatted = in;
|
||||
return result;
|
||||
}
|
||||
|
||||
void IWidget::setHover(bool hover) {
|
||||
hovered = hover;
|
||||
}
|
||||
|
||||
bool IWidget::isHovered() const {
|
||||
return hovered;
|
||||
}
|
||||
|
||||
bool IWidget::containsPoint(const Vector2D& pos) const {
|
||||
return getBoundingBoxWl().containsPoint(pos);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../helpers/Math.hpp"
|
||||
#include "../../defines.hpp"
|
||||
#include "../../helpers/Math.hpp"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <any>
|
||||
|
@ -24,6 +24,13 @@ class IWidget {
|
|||
static int roundingForBox(const CBox& box, int roundingConfig);
|
||||
static int roundingForBorderBox(const CBox& borderBox, int roundingConfig, int thickness);
|
||||
|
||||
virtual CBox getBoundingBoxWl() const {
|
||||
return CBox();
|
||||
};
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos) {}
|
||||
virtual void onHover(const Vector2D& pos) {}
|
||||
bool containsPoint(const Vector2D& pos) const;
|
||||
|
||||
struct SFormatResult {
|
||||
std::string formatted;
|
||||
float updateEveryMs = 0; // 0 means don't (static)
|
||||
|
@ -33,4 +40,10 @@ class IWidget {
|
|||
};
|
||||
|
||||
static SFormatResult formatString(std::string in);
|
||||
|
||||
void setHover(bool hover);
|
||||
bool isHovered() const;
|
||||
|
||||
private:
|
||||
bool hovered = false;
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include <cmath>
|
||||
#include <hyprlang.hpp>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
|
||||
CImage::~CImage() {
|
||||
reset();
|
||||
|
@ -31,7 +32,7 @@ void CImage::onTimerUpdate() {
|
|||
const std::string OLDPATH = path;
|
||||
|
||||
if (!reloadCommand.empty()) {
|
||||
path = g_pHyprlock->spawnSync(reloadCommand);
|
||||
path = spawnSync(reloadCommand);
|
||||
|
||||
if (path.ends_with('\n'))
|
||||
path.pop_back();
|
||||
|
@ -84,18 +85,19 @@ void CImage::configure(const std::unordered_map<std::string, std::any>& props, c
|
|||
shadow.configure(m_self.lock(), props, viewport);
|
||||
|
||||
try {
|
||||
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
configPos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
|
||||
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
||||
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
||||
reloadCommand = std::any_cast<Hyprlang::STRING>(props.at("reload_cmd"));
|
||||
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
||||
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
||||
reloadCommand = std::any_cast<Hyprlang::STRING>(props.at("reload_cmd"));
|
||||
onclickCommand = std::any_cast<Hyprlang::STRING>(props.at("onclick"));
|
||||
} catch (const std::bad_any_cast& e) {
|
||||
RASSERT(false, "Failed to construct CImage: {}", e.what()); //
|
||||
} catch (const std::out_of_range& e) {
|
||||
|
@ -196,10 +198,10 @@ bool CImage::draw(const SRenderData& data) {
|
|||
|
||||
shadow.draw(data);
|
||||
|
||||
const auto TEXPOS = posFromHVAlign(viewport, tex->m_vSize, pos, halign, valign, angle);
|
||||
pos = posFromHVAlign(viewport, tex->m_vSize, configPos, halign, valign, angle);
|
||||
|
||||
texbox.x = TEXPOS.x;
|
||||
texbox.y = TEXPOS.y;
|
||||
texbox.x = pos.x;
|
||||
texbox.y = pos.y;
|
||||
|
||||
texbox.round();
|
||||
texbox.rot = angle;
|
||||
|
@ -233,3 +235,23 @@ void CImage::renderUpdate() {
|
|||
|
||||
g_pHyprlock->renderOutput(stringPort);
|
||||
}
|
||||
|
||||
CBox CImage::getBoundingBoxWl() const {
|
||||
if (!imageFB.isAllocated())
|
||||
return CBox{};
|
||||
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - imageFB.m_cTex.m_vSize.y},
|
||||
imageFB.m_cTex.m_vSize,
|
||||
};
|
||||
}
|
||||
|
||||
void CImage::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (down && !onclickCommand.empty())
|
||||
spawnAsync(onclickCommand);
|
||||
}
|
||||
|
||||
void CImage::onHover(const Vector2D& pos) {
|
||||
if (!onclickCommand.empty())
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ class CImage : public IWidget {
|
|||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
|
||||
void reset();
|
||||
|
||||
|
@ -42,6 +45,7 @@ class CImage : public IWidget {
|
|||
double angle;
|
||||
CGradientValueData color;
|
||||
Vector2D pos;
|
||||
Vector2D configPos;
|
||||
|
||||
std::string halign, valign, path;
|
||||
|
||||
|
@ -49,6 +53,8 @@ class CImage : public IWidget {
|
|||
|
||||
int reloadTime;
|
||||
std::string reloadCommand;
|
||||
std::string onclickCommand;
|
||||
|
||||
std::filesystem::file_time_type modificationTime;
|
||||
std::shared_ptr<CTimer> imageTimer;
|
||||
CAsyncResourceGatherer::SPreloadRequest request;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "../../helpers/Log.hpp"
|
||||
#include "../../core/hyprlock.hpp"
|
||||
#include "../../helpers/Color.hpp"
|
||||
#include "../../helpers/MiscFunctions.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include <hyprlang.hpp>
|
||||
#include <stdexcept>
|
||||
|
@ -79,6 +80,7 @@ void CLabel::configure(const std::unordered_map<std::string, std::any>& props, c
|
|||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
angle = angle * M_PI / 180.0;
|
||||
onclickCommand = std::any_cast<Hyprlang::STRING>(props.at("onclick"));
|
||||
|
||||
std::string textAlign = std::any_cast<Hyprlang::STRING>(props.at("text_align"));
|
||||
std::string fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||
|
@ -172,3 +174,23 @@ void CLabel::renderUpdate() {
|
|||
|
||||
g_pHyprlock->renderOutput(outputStringPort);
|
||||
}
|
||||
|
||||
CBox CLabel::getBoundingBoxWl() const {
|
||||
if (!asset)
|
||||
return CBox{};
|
||||
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - asset->texture.m_vSize.y},
|
||||
asset->texture.m_vSize,
|
||||
};
|
||||
}
|
||||
|
||||
void CLabel::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (down && !onclickCommand.empty())
|
||||
spawnAsync(onclickCommand);
|
||||
}
|
||||
|
||||
void CLabel::onHover(const Vector2D& pos) {
|
||||
if (!onclickCommand.empty())
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ class CLabel : public IWidget {
|
|||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
|
||||
void reset();
|
||||
|
||||
|
@ -43,6 +46,7 @@ class CLabel : public IWidget {
|
|||
std::string resourceID;
|
||||
std::string pendingResourceID; // if dynamic label
|
||||
std::string halign, valign;
|
||||
std::string onclickCommand;
|
||||
SPreloadedAsset* asset = nullptr;
|
||||
|
||||
std::string outputStringPort;
|
||||
|
|
|
@ -473,3 +473,14 @@ void CPasswordInputField::updateColors() {
|
|||
|
||||
colorState.font = fontTarget;
|
||||
}
|
||||
|
||||
CBox CPasswordInputField::getBoundingBoxWl() const {
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - size->value().y},
|
||||
size->value(),
|
||||
};
|
||||
}
|
||||
|
||||
void CPasswordInputField::onHover(const Vector2D& pos) {
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ class CPasswordInputField : public IWidget {
|
|||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
|
||||
void reset();
|
||||
void onFadeOutTimer();
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include "Shape.hpp"
|
||||
#include "../Renderer.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include "../../core/hyprlock.hpp"
|
||||
#include "../../helpers/MiscFunctions.hpp"
|
||||
#include <cmath>
|
||||
#include <hyprlang.hpp>
|
||||
#include <sys/types.h>
|
||||
|
||||
void CShape::registerSelf(const SP<CShape>& self) {
|
||||
m_self = self;
|
||||
|
@ -14,16 +17,17 @@ void CShape::configure(const std::unordered_map<std::string, std::any>& props, c
|
|||
shadow.configure(m_self.lock(), props, viewport);
|
||||
|
||||
try {
|
||||
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport);
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
xray = std::any_cast<Hyprlang::INT>(props.at("xray"));
|
||||
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport);
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
xray = std::any_cast<Hyprlang::INT>(props.at("xray"));
|
||||
onclickCommand = std::any_cast<Hyprlang::STRING>(props.at("onclick"));
|
||||
} catch (const std::bad_any_cast& e) {
|
||||
RASSERT(false, "Failed to construct CShape: {}", e.what()); //
|
||||
} catch (const std::out_of_range& e) {
|
||||
|
@ -100,3 +104,19 @@ bool CShape::draw(const SRenderData& data) {
|
|||
|
||||
return data.opacity < 1.0;
|
||||
}
|
||||
CBox CShape::getBoundingBoxWl() const {
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - size.y},
|
||||
size,
|
||||
};
|
||||
}
|
||||
|
||||
void CShape::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (down && !onclickCommand.empty())
|
||||
spawnAsync(onclickCommand);
|
||||
}
|
||||
|
||||
void CShape::onHover(const Vector2D& pos) {
|
||||
if (!onclickCommand.empty())
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ class CShape : public IWidget {
|
|||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
|
||||
private:
|
||||
WP<CShape> m_self;
|
||||
|
@ -38,6 +41,7 @@ class CShape : public IWidget {
|
|||
std::string halign, valign;
|
||||
|
||||
bool firstRender = true;
|
||||
std::string onclickCommand;
|
||||
|
||||
Vector2D viewport;
|
||||
CShadowable shadow;
|
||||
|
|
Loading…
Reference in a new issue