mirror of
https://github.com/hyprwm/hyprlock.git
synced 2025-05-12 21:30:37 +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
|
$font = Monospace
|
||||||
|
|
||||||
general {
|
general {
|
||||||
hide_cursor = true
|
hide_cursor = false
|
||||||
}
|
}
|
||||||
|
|
||||||
# uncomment to enable fingerprint authentication
|
# uncomment to enable fingerprint authentication
|
||||||
|
@ -90,3 +90,14 @@ label {
|
||||||
halign = right
|
halign = right
|
||||||
valign = top
|
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_passes", Hyprlang::INT{0}); \
|
||||||
m_config.addSpecialConfigValue(name, "shadow_color", Hyprlang::INT{0xFF000000}); \
|
m_config.addSpecialConfigValue(name, "shadow_color", Hyprlang::INT{0xFF000000}); \
|
||||||
m_config.addSpecialConfigValue(name, "shadow_boost", Hyprlang::FLOAT{1.2});
|
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:text_trim", Hyprlang::INT{1});
|
||||||
m_config.addConfigValue("general:hide_cursor", Hyprlang::INT{0});
|
m_config.addConfigValue("general:hide_cursor", Hyprlang::INT{0});
|
||||||
m_config.addConfigValue("general:grace", 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", "xray", Hyprlang::INT{0});
|
||||||
m_config.addSpecialConfigValue("shape", "zindex", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("shape", "zindex", Hyprlang::INT{0});
|
||||||
SHADOWABLE("shape");
|
SHADOWABLE("shape");
|
||||||
|
CLICKABLE("shape");
|
||||||
|
|
||||||
m_config.addSpecialCategory("image", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
m_config.addSpecialCategory("image", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
m_config.addSpecialConfigValue("image", "monitor", Hyprlang::STRING{""});
|
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", "reload_cmd", Hyprlang::STRING{""});
|
||||||
m_config.addSpecialConfigValue("image", "zindex", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("image", "zindex", Hyprlang::INT{0});
|
||||||
SHADOWABLE("image");
|
SHADOWABLE("image");
|
||||||
|
CLICKABLE("image");
|
||||||
|
|
||||||
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
|
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", "text_align", Hyprlang::STRING{""});
|
||||||
m_config.addSpecialConfigValue("label", "zindex", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("label", "zindex", Hyprlang::INT{0});
|
||||||
SHADOWABLE("label");
|
SHADOWABLE("label");
|
||||||
|
CLICKABLE("label");
|
||||||
|
|
||||||
m_config.registerHandler(&::handleSource, "source", {.allowFlags = false});
|
m_config.registerHandler(&::handleSource, "source", {.allowFlags = false});
|
||||||
m_config.registerHandler(&::handleBezier, "bezier", {.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());
|
Debug::log(ERR, "Config has errors:\n{}\nProceeding ignoring faulty entries", result.getError());
|
||||||
|
|
||||||
#undef SHADOWABLE
|
#undef SHADOWABLE
|
||||||
|
#undef CLICKABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
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()) \
|
"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");
|
auto keys = m_config.listKeysForSpecialCategory("background");
|
||||||
result.reserve(keys.size());
|
result.reserve(keys.size());
|
||||||
|
@ -414,6 +423,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||||
{"xray", m_config.getSpecialConfigValue("shape", "xray", k.c_str())},
|
{"xray", m_config.getSpecialConfigValue("shape", "xray", k.c_str())},
|
||||||
{"zindex", m_config.getSpecialConfigValue("shape", "zindex", k.c_str())},
|
{"zindex", m_config.getSpecialConfigValue("shape", "zindex", k.c_str())},
|
||||||
SHADOWABLE("shape"),
|
SHADOWABLE("shape"),
|
||||||
|
CLICKABLE("shape"),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -440,6 +450,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||||
{"reload_cmd", m_config.getSpecialConfigValue("image", "reload_cmd", k.c_str())},
|
{"reload_cmd", m_config.getSpecialConfigValue("image", "reload_cmd", k.c_str())},
|
||||||
{"zindex", m_config.getSpecialConfigValue("image", "zindex", k.c_str())},
|
{"zindex", m_config.getSpecialConfigValue("image", "zindex", k.c_str())},
|
||||||
SHADOWABLE("image"),
|
SHADOWABLE("image"),
|
||||||
|
CLICKABLE("image"),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -505,6 +516,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||||
{"text_align", m_config.getSpecialConfigValue("label", "text_align", k.c_str())},
|
{"text_align", m_config.getSpecialConfigValue("label", "text_align", k.c_str())},
|
||||||
{"zindex", m_config.getSpecialConfigValue("label", "zindex", k.c_str())},
|
{"zindex", m_config.getSpecialConfigValue("label", "zindex", k.c_str())},
|
||||||
SHADOWABLE("label"),
|
SHADOWABLE("label"),
|
||||||
|
CLICKABLE("label"),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -9,12 +9,15 @@ CCursorShape::CCursorShape(SP<CCWpCursorShapeManagerV1> mgr) : mgr(mgr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCursorShape::setShape(const wpCursorShapeDeviceV1Shape shape) {
|
void CCursorShape::setShape(const wpCursorShapeDeviceV1Shape shape) {
|
||||||
if (!dev)
|
if (!g_pSeatManager->m_pPointer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
dev = makeShared<CCWpCursorShapeDeviceV1>(mgr->sendGetPointer(g_pSeatManager->m_pPointer->resource()));
|
||||||
|
|
||||||
dev->sendSetShape(lastCursorSerial, shape);
|
dev->sendSetShape(lastCursorSerial, shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCursorShape::hideCursor() {
|
void CCursorShape::hideCursor() {
|
||||||
g_pSeatManager->m_pPointer->sendSetCursor(lastCursorSerial, nullptr, 0, 0);
|
g_pSeatManager->m_pPointer->sendSetCursor(lastCursorSerial, nullptr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,3 +139,7 @@ void CSessionLockSurface::onCallback() {
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SP<CCWlSurface> CSessionLockSurface::getWlSurface() {
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
|
@ -17,15 +17,16 @@ class CSessionLockSurface {
|
||||||
CSessionLockSurface(const SP<COutput>& pOutput);
|
CSessionLockSurface(const SP<COutput>& pOutput);
|
||||||
~CSessionLockSurface();
|
~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 render();
|
||||||
void onCallback();
|
void onCallback();
|
||||||
void onScaleUpdate();
|
void onScaleUpdate();
|
||||||
|
SP<CCWlSurface> getWlSurface();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WP<COutput> m_outputRef;
|
WP<COutput> m_outputRef;
|
||||||
|
|
|
@ -26,7 +26,13 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
||||||
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
||||||
m_pPointer = makeShared<CCWlPointer>(r->sendGetPointer());
|
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) {
|
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)
|
if (std::chrono::system_clock::now() > g_pHyprlock->m_tGraceEnds)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -40,16 +46,34 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
||||||
if (!m_pCursorShape)
|
if (!m_pCursorShape)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static const auto HIDE = g_pConfigManager->getValue<Hyprlang::INT>("general:hide_cursor");
|
|
||||||
|
|
||||||
m_pCursorShape->lastCursorSerial = serial;
|
m_pCursorShape->lastCursorSerial = serial;
|
||||||
|
|
||||||
if (*HIDE)
|
if (*HIDECURSOR)
|
||||||
m_pCursorShape->hideCursor();
|
m_pCursorShape->hideCursor();
|
||||||
else
|
else
|
||||||
m_pCursorShape->setShape(wpCursorShapeDeviceV1Shape::WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
|
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)};
|
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() {
|
bool CHyprlock::acquireSessionLock() {
|
||||||
Debug::log(LOG, "Locking session");
|
Debug::log(LOG, "Locking session");
|
||||||
m_sLockState.lock = makeShared<CCExtSessionLockV1>(m_sWaylandState.sessionLock->sendLock());
|
m_sLockState.lock = makeShared<CCExtSessionLockV1>(m_sWaylandState.sessionLock->sendLock());
|
||||||
|
@ -817,19 +872,6 @@ void CHyprlock::enqueueForceUpdateTimers() {
|
||||||
nullptr, false);
|
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() {
|
SP<CCZwlrScreencopyManagerV1> CHyprlock::getScreencopy() {
|
||||||
return m_sWaylandState.screencopy;
|
return m_sWaylandState.screencopy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,9 @@ class CHyprlock {
|
||||||
bool acquireSessionLock();
|
bool acquireSessionLock();
|
||||||
void releaseSessionLock();
|
void releaseSessionLock();
|
||||||
|
|
||||||
std::string spawnSync(const std::string& cmd);
|
|
||||||
|
|
||||||
void onKey(uint32_t key, bool down);
|
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 startKeyRepeat(xkb_keysym_t sym);
|
||||||
void repeatKey(xkb_keysym_t sym);
|
void repeatKey(xkb_keysym_t sym);
|
||||||
void handleKeySym(xkb_keysym_t sym, bool compose);
|
void handleKeySym(xkb_keysym_t sym, bool compose);
|
||||||
|
@ -95,6 +95,9 @@ class CHyprlock {
|
||||||
//
|
//
|
||||||
std::chrono::system_clock::time_point m_tGraceEnds;
|
std::chrono::system_clock::time_point m_tGraceEnds;
|
||||||
Vector2D m_vLastEnterCoords = {};
|
Vector2D m_vLastEnterCoords = {};
|
||||||
|
WP<COutput> m_focusedOutput;
|
||||||
|
|
||||||
|
Vector2D m_vMouseLocation = {};
|
||||||
|
|
||||||
std::shared_ptr<CTimer> m_pKeyRepeatTimer = nullptr;
|
std::shared_ptr<CTimer> m_pKeyRepeatTimer = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
#include "MiscFunctions.hpp"
|
#include "MiscFunctions.hpp"
|
||||||
#include "Log.hpp"
|
#include "Log.hpp"
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
|
#include <hyprutils/os/Process.hpp>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
using namespace Hyprutils::String;
|
using namespace Hyprutils::String;
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
|
std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
|
||||||
std::filesystem::path path(rawpath);
|
std::filesystem::path path(rawpath);
|
||||||
|
@ -137,3 +139,22 @@ int createPoolFile(size_t size, std::string& name) {
|
||||||
|
|
||||||
return FD;
|
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&);
|
std::string absolutePath(const std::string&, const std::string&);
|
||||||
int64_t configStringToInt(const std::string& VALUE);
|
int64_t configStringToInt(const std::string& VALUE);
|
||||||
int createPoolFile(size_t size, std::string& name);
|
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;
|
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");
|
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) {
|
if (*TRIM) {
|
||||||
text.erase(0, text.find_first_not_of(" \n\r\t"));
|
text.erase(0, text.find_first_not_of(" \n\r\t"));
|
||||||
|
|
|
@ -117,6 +117,6 @@ CFramebuffer::~CFramebuffer() {
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFramebuffer::isAllocated() {
|
bool CFramebuffer::isAllocated() const {
|
||||||
return m_iFb != (GLuint)-1;
|
return m_iFb != (GLuint)-1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class CFramebuffer {
|
||||||
void bind() const;
|
void bind() const;
|
||||||
void release();
|
void release();
|
||||||
void reset();
|
void reset();
|
||||||
bool isAllocated();
|
bool isAllocated() const;
|
||||||
|
|
||||||
Vector2D m_vSize;
|
Vector2D m_vSize;
|
||||||
|
|
||||||
|
@ -21,4 +21,4 @@ class CFramebuffer {
|
||||||
GLuint m_iFb = -1;
|
GLuint m_iFb = -1;
|
||||||
|
|
||||||
CTexture* m_pStencilTex = nullptr;
|
CTexture* m_pStencilTex = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,27 +48,26 @@ class CRenderer {
|
||||||
|
|
||||||
void startFadeIn();
|
void startFadeIn();
|
||||||
void startFadeOut(bool unlock = false, bool immediate = true);
|
void startFadeOut(bool unlock = false, bool immediate = true);
|
||||||
|
std::vector<SP<IWidget>>& getOrCreateWidgetsFor(const CSessionLockSurface& surf);
|
||||||
|
|
||||||
private:
|
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;
|
Mat3x3 projMatrix = Mat3x3::identity();
|
||||||
CShader texShader;
|
Mat3x3 projection;
|
||||||
CShader texMixShader;
|
|
||||||
CShader blurShader1;
|
|
||||||
CShader blurShader2;
|
|
||||||
CShader blurPrepareShader;
|
|
||||||
CShader blurFinishShader;
|
|
||||||
CShader borderShader;
|
|
||||||
|
|
||||||
Mat3x3 projMatrix = Mat3x3::identity();
|
PHLANIMVAR<float> opacity;
|
||||||
Mat3x3 projection;
|
|
||||||
|
|
||||||
PHLANIMVAR<float> opacity;
|
std::vector<GLint> boundFBs;
|
||||||
|
|
||||||
std::vector<GLint> boundFBs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline UP<CRenderer> g_pRenderer;
|
inline UP<CRenderer> g_pRenderer;
|
||||||
|
|
|
@ -240,7 +240,7 @@ void CBackground::onReloadTimerUpdate() {
|
||||||
// Path parsing and early returns
|
// Path parsing and early returns
|
||||||
|
|
||||||
if (!reloadCommand.empty()) {
|
if (!reloadCommand.empty()) {
|
||||||
path = g_pHyprlock->spawnSync(reloadCommand);
|
path = spawnSync(reloadCommand);
|
||||||
|
|
||||||
if (path.ends_with('\n'))
|
if (path.ends_with('\n'))
|
||||||
path.pop_back();
|
path.pop_back();
|
||||||
|
|
|
@ -266,3 +266,15 @@ IWidget::SFormatResult IWidget::formatString(std::string in) {
|
||||||
result.formatted = in;
|
result.formatted = in;
|
||||||
return result;
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "../../helpers/Math.hpp"
|
|
||||||
#include "../../defines.hpp"
|
#include "../../defines.hpp"
|
||||||
|
#include "../../helpers/Math.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <any>
|
#include <any>
|
||||||
|
@ -24,6 +24,13 @@ class IWidget {
|
||||||
static int roundingForBox(const CBox& box, int roundingConfig);
|
static int roundingForBox(const CBox& box, int roundingConfig);
|
||||||
static int roundingForBorderBox(const CBox& borderBox, int roundingConfig, int thickness);
|
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 {
|
struct SFormatResult {
|
||||||
std::string formatted;
|
std::string formatted;
|
||||||
float updateEveryMs = 0; // 0 means don't (static)
|
float updateEveryMs = 0; // 0 means don't (static)
|
||||||
|
@ -33,4 +40,10 @@ class IWidget {
|
||||||
};
|
};
|
||||||
|
|
||||||
static SFormatResult formatString(std::string in);
|
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 "../../config/ConfigDataValues.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
CImage::~CImage() {
|
CImage::~CImage() {
|
||||||
reset();
|
reset();
|
||||||
|
@ -31,7 +32,7 @@ void CImage::onTimerUpdate() {
|
||||||
const std::string OLDPATH = path;
|
const std::string OLDPATH = path;
|
||||||
|
|
||||||
if (!reloadCommand.empty()) {
|
if (!reloadCommand.empty()) {
|
||||||
path = g_pHyprlock->spawnSync(reloadCommand);
|
path = spawnSync(reloadCommand);
|
||||||
|
|
||||||
if (path.ends_with('\n'))
|
if (path.ends_with('\n'))
|
||||||
path.pop_back();
|
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);
|
shadow.configure(m_self.lock(), props, viewport);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
||||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||||
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
configPos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||||
|
|
||||||
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
||||||
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
||||||
reloadCommand = std::any_cast<Hyprlang::STRING>(props.at("reload_cmd"));
|
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) {
|
} catch (const std::bad_any_cast& e) {
|
||||||
RASSERT(false, "Failed to construct CImage: {}", e.what()); //
|
RASSERT(false, "Failed to construct CImage: {}", e.what()); //
|
||||||
} catch (const std::out_of_range& e) {
|
} catch (const std::out_of_range& e) {
|
||||||
|
@ -196,10 +198,10 @@ bool CImage::draw(const SRenderData& data) {
|
||||||
|
|
||||||
shadow.draw(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.x = pos.x;
|
||||||
texbox.y = TEXPOS.y;
|
texbox.y = pos.y;
|
||||||
|
|
||||||
texbox.round();
|
texbox.round();
|
||||||
texbox.rot = angle;
|
texbox.rot = angle;
|
||||||
|
@ -233,3 +235,23 @@ void CImage::renderUpdate() {
|
||||||
|
|
||||||
g_pHyprlock->renderOutput(stringPort);
|
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 void configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput);
|
||||||
virtual bool draw(const SRenderData& data);
|
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();
|
void reset();
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ class CImage : public IWidget {
|
||||||
double angle;
|
double angle;
|
||||||
CGradientValueData color;
|
CGradientValueData color;
|
||||||
Vector2D pos;
|
Vector2D pos;
|
||||||
|
Vector2D configPos;
|
||||||
|
|
||||||
std::string halign, valign, path;
|
std::string halign, valign, path;
|
||||||
|
|
||||||
|
@ -49,6 +53,8 @@ class CImage : public IWidget {
|
||||||
|
|
||||||
int reloadTime;
|
int reloadTime;
|
||||||
std::string reloadCommand;
|
std::string reloadCommand;
|
||||||
|
std::string onclickCommand;
|
||||||
|
|
||||||
std::filesystem::file_time_type modificationTime;
|
std::filesystem::file_time_type modificationTime;
|
||||||
std::shared_ptr<CTimer> imageTimer;
|
std::shared_ptr<CTimer> imageTimer;
|
||||||
CAsyncResourceGatherer::SPreloadRequest request;
|
CAsyncResourceGatherer::SPreloadRequest request;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../../helpers/Log.hpp"
|
#include "../../helpers/Log.hpp"
|
||||||
#include "../../core/hyprlock.hpp"
|
#include "../../core/hyprlock.hpp"
|
||||||
#include "../../helpers/Color.hpp"
|
#include "../../helpers/Color.hpp"
|
||||||
|
#include "../../helpers/MiscFunctions.hpp"
|
||||||
#include "../../config/ConfigDataValues.hpp"
|
#include "../../config/ConfigDataValues.hpp"
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
#include <stdexcept>
|
#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"));
|
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||||
angle = angle * M_PI / 180.0;
|
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 textAlign = std::any_cast<Hyprlang::STRING>(props.at("text_align"));
|
||||||
std::string fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
std::string fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||||
|
@ -172,3 +174,23 @@ void CLabel::renderUpdate() {
|
||||||
|
|
||||||
g_pHyprlock->renderOutput(outputStringPort);
|
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 void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||||
virtual bool draw(const SRenderData& data);
|
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();
|
void reset();
|
||||||
|
|
||||||
|
@ -43,6 +46,7 @@ class CLabel : public IWidget {
|
||||||
std::string resourceID;
|
std::string resourceID;
|
||||||
std::string pendingResourceID; // if dynamic label
|
std::string pendingResourceID; // if dynamic label
|
||||||
std::string halign, valign;
|
std::string halign, valign;
|
||||||
|
std::string onclickCommand;
|
||||||
SPreloadedAsset* asset = nullptr;
|
SPreloadedAsset* asset = nullptr;
|
||||||
|
|
||||||
std::string outputStringPort;
|
std::string outputStringPort;
|
||||||
|
|
|
@ -473,3 +473,14 @@ void CPasswordInputField::updateColors() {
|
||||||
|
|
||||||
colorState.font = fontTarget;
|
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 void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||||
virtual bool draw(const SRenderData& data);
|
virtual bool draw(const SRenderData& data);
|
||||||
|
virtual void onHover(const Vector2D& pos);
|
||||||
|
virtual CBox getBoundingBoxWl() const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void onFadeOutTimer();
|
void onFadeOutTimer();
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
#include "Shape.hpp"
|
#include "Shape.hpp"
|
||||||
#include "../Renderer.hpp"
|
#include "../Renderer.hpp"
|
||||||
#include "../../config/ConfigDataValues.hpp"
|
#include "../../config/ConfigDataValues.hpp"
|
||||||
|
#include "../../core/hyprlock.hpp"
|
||||||
|
#include "../../helpers/MiscFunctions.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
void CShape::registerSelf(const SP<CShape>& self) {
|
void CShape::registerSelf(const SP<CShape>& self) {
|
||||||
m_self = 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);
|
shadow.configure(m_self.lock(), props, viewport);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport);
|
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport);
|
||||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||||
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||||
xray = std::any_cast<Hyprlang::INT>(props.at("xray"));
|
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) {
|
} catch (const std::bad_any_cast& e) {
|
||||||
RASSERT(false, "Failed to construct CShape: {}", e.what()); //
|
RASSERT(false, "Failed to construct CShape: {}", e.what()); //
|
||||||
} catch (const std::out_of_range& e) {
|
} catch (const std::out_of_range& e) {
|
||||||
|
@ -100,3 +104,19 @@ bool CShape::draw(const SRenderData& data) {
|
||||||
|
|
||||||
return data.opacity < 1.0;
|
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 void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||||
virtual bool draw(const SRenderData& data);
|
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:
|
private:
|
||||||
WP<CShape> m_self;
|
WP<CShape> m_self;
|
||||||
|
@ -38,6 +41,7 @@ class CShape : public IWidget {
|
||||||
std::string halign, valign;
|
std::string halign, valign;
|
||||||
|
|
||||||
bool firstRender = true;
|
bool firstRender = true;
|
||||||
|
std::string onclickCommand;
|
||||||
|
|
||||||
Vector2D viewport;
|
Vector2D viewport;
|
||||||
CShadowable shadow;
|
CShadowable shadow;
|
||||||
|
|
Loading…
Reference in a new issue