diff --git a/nix/hm-module.nix b/nix/hm-module.nix
index b8b053a..06bf45b 100644
--- a/nix/hm-module.nix
+++ b/nix/hm-module.nix
@@ -90,68 +90,67 @@ in {
backgrounds = mkOption {
description = "Background configurations";
type = listOf (submodule {
- options =
- {
- monitor = mkOption {
- description = "The monitor to apply the given wallpaper to";
- type = str;
- default = "";
- };
-
- path = mkOption {
- description = "The path to the wallpaper";
- type = str;
- default = "echo '/home/me/someImage.png'"; # only png supported for now
- };
-
- color = mkOption {
- description = "Background color";
- type = str;
- default = "rgba(25, 20, 20, 1.0)";
- };
-
- blur_size = mkOption {
- description = "Blur size";
- type = int;
- default = 8;
- };
-
- blur_passes = mkOption {
- description = "Blur passes";
- type = int;
- default = 0;
- };
-
- noise = mkOption {
- description = "Noise applied to blur";
- type = float;
- default = 0.0117;
- };
-
- contrast = mkOption {
- description = "Contrast applied to blur";
- type = float;
- default = 0.8917;
- };
-
- brightness = mkOption {
- description = "Brightness applied to blur";
- type = float;
- default = 0.8172;
- };
-
- vibrancy = mkOption {
- description = "Vibrancy applied to blur";
- type = float;
- default = 0.1686;
- };
-
- vibrancy_darkness = mkOption {
- description = "Vibrancy darkness applied to blur";
- type = float;
- default = 0.05;
- };
+ options = {
+ monitor = mkOption {
+ description = "The monitor to apply the given wallpaper to";
+ type = str;
+ default = "";
};
+
+ path = mkOption {
+ description = "The path to the wallpaper";
+ type = str;
+ default = "echo '/home/me/someImage.png'"; # only png supported for now
+ };
+
+ color = mkOption {
+ description = "Background color";
+ type = str;
+ default = "rgba(25, 20, 20, 1.0)";
+ };
+
+ blur_size = mkOption {
+ description = "Blur size";
+ type = int;
+ default = 8;
+ };
+
+ blur_passes = mkOption {
+ description = "Blur passes";
+ type = int;
+ default = 0;
+ };
+
+ noise = mkOption {
+ description = "Noise applied to blur";
+ type = float;
+ default = 0.0117;
+ };
+
+ contrast = mkOption {
+ description = "Contrast applied to blur";
+ type = float;
+ default = 0.8917;
+ };
+
+ brightness = mkOption {
+ description = "Brightness applied to blur";
+ type = float;
+ default = 0.8172;
+ };
+
+ vibrancy = mkOption {
+ description = "Vibrancy applied to blur";
+ type = float;
+ default = 0.1686;
+ };
+
+ vibrancy_darkness = mkOption {
+ description = "Vibrancy darkness applied to blur";
+ type = float;
+ default = 0.05;
+ };
+ };
});
default = [
{}
@@ -308,6 +307,30 @@ in {
type = str;
default = "center";
};
+
+ capslock_color = mkOption {
+ description = "Color of the input field when Caps Lock is active";
+ type = str;
+ default = "-1";
+ };
+
+ numlock_color = mkOption {
+ description = "Color of the input field when NumLock is active";
+ type = str;
+ default = "-1";
+ };
+
+ bothlock_color = mkOption {
+ description = "Color of the input field when both Caps Lock and NumLock are active";
+ type = str;
+ default = "-1";
+ };
+
+ invert_numlock = mkOption {
+ description = "Whether to change the color when NumLock is not active";
+ type = bool;
+ default = false;
+ };
}
// shadow;
});
@@ -437,6 +460,10 @@ in {
fail_color = ${input-field.fail_color}
fail_text = ${input-field.fail_text}
fail_transition = ${toString input-field.fail_transition}
+ capslock_color = ${input-field.capslock_color}
+ numlock_color = ${input-field.numlock_color}
+ bothlock_color = ${input-field.bothlock_color}
+ invert_numlock = ${boolToString input-field.invert_numlock}
position = ${toString input-field.position.x}, ${toString input-field.position.y}
halign = ${input-field.halign}
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 9e7d8ab..9e126ad 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -82,6 +82,10 @@ void CConfigManager::init() {
m_config.addSpecialConfigValue("input-field", "fail_color", Hyprlang::INT{0xFFCC2222});
m_config.addSpecialConfigValue("input-field", "fail_text", Hyprlang::STRING{"$FAIL"});
m_config.addSpecialConfigValue("input-field", "fail_transition", Hyprlang::INT{300});
+ m_config.addSpecialConfigValue("input-field", "capslock_color", Hyprlang::INT{-1});
+ m_config.addSpecialConfigValue("input-field", "numlock_color", Hyprlang::INT{-1});
+ m_config.addSpecialConfigValue("input-field", "bothlock_color", Hyprlang::INT{-1});
+ m_config.addSpecialConfigValue("input-field", "invert_numlock", Hyprlang::INT{0});
SHADOWABLE("input-field");
m_config.addSpecialCategory("label", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
@@ -174,6 +178,10 @@ std::vector CConfigManager::getWidgetConfigs() {
{"fail_color", m_config.getSpecialConfigValue("input-field", "fail_color", k.c_str())},
{"fail_text", m_config.getSpecialConfigValue("input-field", "fail_text", k.c_str())},
{"fail_transition", m_config.getSpecialConfigValue("input-field", "fail_transition", k.c_str())},
+ {"capslock_color", m_config.getSpecialConfigValue("input-field", "capslock_color", k.c_str())},
+ {"numlock_color", m_config.getSpecialConfigValue("input-field", "numlock_color", k.c_str())},
+ {"bothlock_color", m_config.getSpecialConfigValue("input-field", "bothlock_color", k.c_str())},
+ {"invert_numlock", m_config.getSpecialConfigValue("input-field", "invert_numlock", k.c_str())},
SHADOWABLE("input-field"),
}
});
diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp
index bbc2d66..00e2fb1 100644
--- a/src/core/hyprlock.cpp
+++ b/src/core/hyprlock.cpp
@@ -755,6 +755,9 @@ void CHyprlock::onKey(uint32_t key, bool down) {
return;
}
+ m_bCapsLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED);
+ m_bNumLock = xkb_state_mod_name_is_active(g_pHyprlock->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED);
+
if (SYM == XKB_KEY_BackSpace) {
if (m_sPasswordState.passBuffer.length() > 0)
m_sPasswordState.passBuffer = m_sPasswordState.passBuffer.substr(0, m_sPasswordState.passBuffer.length() - 1);
@@ -766,6 +769,10 @@ void CHyprlock::onKey(uint32_t key, bool down) {
Debug::log(LOG, "Clearing password buffer");
m_sPasswordState.passBuffer = "";
+ } else if (SYM == XKB_KEY_Caps_Lock) {
+ m_bCapsLock = !m_bCapsLock;
+ } else if (SYM == XKB_KEY_Num_Lock) {
+ m_bNumLock = !m_bNumLock;
} else {
char buf[16] = {0};
int len = xkb_keysym_to_utf8(SYM, buf, 16);
diff --git a/src/core/hyprlock.hpp b/src/core/hyprlock.hpp
index 9841a5c..9030e42 100644
--- a/src/core/hyprlock.hpp
+++ b/src/core/hyprlock.hpp
@@ -79,6 +79,9 @@ class CHyprlock {
bool m_bLocked = false;
+ bool m_bCapsLock = false;
+ bool m_bNumLock = false;
+
//
std::chrono::system_clock::time_point m_tGraceEnds;
Vector2D m_vLastEnterCoords = {};
diff --git a/src/renderer/widgets/PasswordInputField.cpp b/src/renderer/widgets/PasswordInputField.cpp
index 658249f..9502175 100644
--- a/src/renderer/widgets/PasswordInputField.cpp
+++ b/src/renderer/widgets/PasswordInputField.cpp
@@ -4,37 +4,47 @@
#include
CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::unordered_map& props) : shadow(this, props, viewport_) {
- size = std::any_cast(props.at("size"));
- inner = std::any_cast(props.at("inner_color"));
- outer = std::any_cast(props.at("outer_color"));
- outThick = std::any_cast(props.at("outline_thickness"));
- dots.size = std::any_cast(props.at("dots_size"));
- dots.spacing = std::any_cast(props.at("dots_spacing"));
- dots.center = std::any_cast(props.at("dots_center"));
- dots.rounding = std::any_cast(props.at("dots_rounding"));
- fadeOnEmpty = std::any_cast(props.at("fade_on_empty"));
- fadeTimeoutMs = std::any_cast(props.at("fade_timeout"));
- font = std::any_cast(props.at("font_color"));
- hiddenInputState.enabled = std::any_cast(props.at("hide_input"));
- rounding = std::any_cast(props.at("rounding"));
- placeholder.failColor = std::any_cast(props.at("fail_color"));
- placeholder.failTransitionMs = std::any_cast(props.at("fail_transition"));
- configFailText = std::any_cast(props.at("fail_text"));
- checkColor = std::any_cast(props.at("check_color"));
- viewport = viewport_;
+ size = std::any_cast(props.at("size"));
+ inner = std::any_cast(props.at("inner_color"));
+ outThick = std::any_cast(props.at("outline_thickness"));
+ dots.size = std::any_cast(props.at("dots_size"));
+ dots.spacing = std::any_cast(props.at("dots_spacing"));
+ dots.center = std::any_cast(props.at("dots_center"));
+ dots.rounding = std::any_cast(props.at("dots_rounding"));
+ fadeOnEmpty = std::any_cast(props.at("fade_on_empty"));
+ fadeTimeoutMs = std::any_cast(props.at("fade_timeout"));
+ font = std::any_cast(props.at("font_color"));
+ hiddenInputState.enabled = std::any_cast(props.at("hide_input"));
+ rounding = std::any_cast(props.at("rounding"));
+ configFailText = std::any_cast(props.at("fail_text"));
+ outerColor.transitionMs = std::any_cast(props.at("fail_transition"));
+ outerColor.main = std::any_cast(props.at("outer_color"));
+ outerColor.fail = std::any_cast(props.at("fail_color"));
+ outerColor.check = std::any_cast(props.at("check_color"));
+ outerColor.both = std::any_cast(props.at("bothlock_color"));
+ outerColor.caps = std::any_cast(props.at("capslock_color"));
+ outerColor.num = std::any_cast(props.at("numlock_color"));
+ outerColor.invertNum = std::any_cast(props.at("invert_numlock"));
+ viewport = viewport_;
- auto POS__ = std::any_cast(props.at("position"));
- pos = {POS__.x, POS__.y};
- configPos = pos;
- configSize = size;
+ auto POS__ = std::any_cast(props.at("position"));
+ pos = {POS__.x, POS__.y};
+ configPos = pos;
+ configSize = size;
halign = std::any_cast(props.at("halign"));
valign = std::any_cast(props.at("valign"));
- pos = posFromHVAlign(viewport, size, pos, halign, valign);
- dots.size = std::clamp(dots.size, 0.2f, 0.8f);
- dots.spacing = std::clamp(dots.spacing, 0.f, 1.f);
- placeholder.failTransitionMs = std::clamp(placeholder.failTransitionMs, 1, 5000);
+ pos = posFromHVAlign(viewport, size, pos, halign, valign);
+ dots.size = std::clamp(dots.size, 0.2f, 0.8f);
+ dots.spacing = std::clamp(dots.spacing, 0.f, 1.f);
+ outerColor.transitionMs = std::clamp(outerColor.transitionMs, 0, 1000);
+
+ outerColor.both = outerColor.both == -1 ? outerColor.main : outerColor.both;
+ outerColor.caps = outerColor.caps == -1 ? outerColor.main : outerColor.caps;
+ outerColor.num = outerColor.num == -1 ? outerColor.main : outerColor.num;
+
+ g_pHyprlock->m_bNumLock = outerColor.invertNum;
std::string placeholderText = std::any_cast(props.at("placeholder_text"));
if (!placeholderText.empty()) {
@@ -198,7 +208,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
float passAlpha = g_pHyprlock->passwordCheckWaiting() ? 0.5 : 1.0;
- CColor outerCol = outer;
+ CColor outerCol = outerColor.main;
outerCol.a *= fade.a * data.opacity;
CColor innerCol = inner;
innerCol.a *= fade.a * data.opacity;
@@ -291,7 +301,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
forceReload = true;
}
- return dots.currentAmount != PASSLEN || fade.animated || outerAnimated || redrawShadow || data.opacity < 1.0 || forceReload;
+ return dots.currentAmount != PASSLEN || fade.animated || outerColor.animated || redrawShadow || data.opacity < 1.0 || forceReload;
}
void CPasswordInputField::updateFailTex() {
@@ -326,7 +336,7 @@ void CPasswordInputField::updateFailTex() {
request.asset = placeholder.failText;
request.type = CAsyncResourceGatherer::eTargetType::TARGET_TEXT;
request.props["font_family"] = std::string{"Sans"};
- request.props["color"] = placeholder.failColor;
+ request.props["color"] = outerColor.fail;
request.props["font_size"] = (int)size.y / 4;
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
@@ -364,67 +374,81 @@ void CPasswordInputField::updateOuter() {
if (outThick == 0)
return;
- static auto OUTERCOL = outer, CHANGETO = OUTERCOL;
- static auto TIMER = std::chrono::system_clock::now();
- const auto WAITING = g_pHyprlock->passwordCheckWaiting();
- bool emptyFail = placeholder.failID.empty();
+ static auto OUTER = outerColor.main, TARGET = OUTER, SOURCE = OUTER;
+ static auto TIMER = std::chrono::system_clock::now();
- outerAnimated = false;
+ if (outerColor.animated) {
+ if (outerColor.stateNum != outerColor.invertNum ? !g_pHyprlock->m_bNumLock : g_pHyprlock->m_bNumLock || outerColor.stateCaps != g_pHyprlock->m_bCapsLock)
+ SOURCE = outerColor.main;
+ } else
+ SOURCE = outerColor.main;
- if (emptyFail) {
- CHANGETO = WAITING ? checkColor : OUTERCOL;
+ outerColor.animated = false;
+ outerColor.stateNum = outerColor.invertNum ? !g_pHyprlock->m_bNumLock : g_pHyprlock->m_bNumLock;
+ outerColor.stateCaps = g_pHyprlock->m_bCapsLock;
- if (outer == CHANGETO)
- return;
+ if (placeholder.failID.empty()) {
+ if (g_pHyprlock->passwordCheckWaiting())
+ TARGET = outerColor.check;
+ else if (outerColor.both != OUTER && outerColor.stateCaps && outerColor.stateNum)
+ TARGET = outerColor.both;
+ else if (outerColor.caps != OUTER && outerColor.stateCaps)
+ TARGET = outerColor.caps;
+ else if (outerColor.num != OUTER && outerColor.stateNum)
+ TARGET = outerColor.num;
+ else
+ TARGET = OUTER;
+ } else {
+ SOURCE = outerColor.check;
+ TARGET = outerColor.fail;
- if (outer == placeholder.failColor || (outer == OUTERCOL && WAITING))
- TIMER = std::chrono::system_clock::now();
- } else if (!emptyFail) {
if (fade.animated || fade.a < 1.0) {
- emptyFail = true;
- CHANGETO = OUTERCOL;
+ TARGET = OUTER;
+ SOURCE = outerColor.fail;
}
-
- if (outer == CHANGETO)
- TIMER = std::chrono::system_clock::now();
}
- const auto MULTI = std::clamp(
- std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - TIMER).count() / (double)placeholder.failTransitionMs, 0.001, 0.5);
- const auto DELTA = emptyFail ? CHANGETO - (WAITING ? OUTERCOL : placeholder.failColor) : placeholder.failColor - CHANGETO;
- const auto TARGET = emptyFail ? CHANGETO : placeholder.failColor;
- const auto SOURCE = emptyFail ? (WAITING ? OUTERCOL : placeholder.failColor) : CHANGETO;
+ if (outerColor.main == TARGET)
+ return;
- if (outer.r != TARGET.r) {
- outer.r += DELTA.r * MULTI;
- outerAnimated = true;
+ if (outerColor.main == SOURCE && !fade.animated)
+ TIMER = std::chrono::system_clock::now();
- if ((SOURCE.r < TARGET.r && outer.r > TARGET.r) || (SOURCE.r > TARGET.r && outer.r < TARGET.r))
- outer.r = TARGET.r;
+ const auto MULTI = outerColor.transitionMs == 0 ?
+ 1.0 :
+ std::clamp(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - TIMER).count() / (double)outerColor.transitionMs, 0.02, 0.5);
+ const auto DELTA = TARGET - SOURCE;
+
+ if (outerColor.main.r != TARGET.r) {
+ outerColor.main.r += DELTA.r * MULTI;
+ outerColor.animated = true;
+
+ if ((SOURCE.r < TARGET.r && outerColor.main.r > TARGET.r) || (SOURCE.r > TARGET.r && outerColor.main.r < TARGET.r))
+ outerColor.main.r = TARGET.r;
}
- if (outer.g != TARGET.g) {
- outer.g += DELTA.g * MULTI;
- outerAnimated = true;
+ if (outerColor.main.g != TARGET.g) {
+ outerColor.main.g += DELTA.g * MULTI;
+ outerColor.animated = true;
- if ((SOURCE.g < TARGET.g && outer.g > TARGET.g) || (SOURCE.g > TARGET.g && outer.g < TARGET.g))
- outer.g = TARGET.g;
+ if ((SOURCE.g < TARGET.g && outerColor.main.g > TARGET.g) || (SOURCE.g > TARGET.g && outerColor.main.g < TARGET.g))
+ outerColor.main.g = TARGET.g;
}
- if (outer.b != TARGET.b) {
- outer.b += DELTA.b * MULTI;
- outerAnimated = true;
+ if (outerColor.main.b != TARGET.b) {
+ outerColor.main.b += DELTA.b * MULTI;
+ outerColor.animated = true;
- if ((SOURCE.b < TARGET.b && outer.b > TARGET.b) || (SOURCE.b > TARGET.b && outer.b < TARGET.b))
- outer.b = TARGET.b;
+ if ((SOURCE.b < TARGET.b && outerColor.main.b > TARGET.b) || (SOURCE.b > TARGET.b && outerColor.main.b < TARGET.b))
+ outerColor.main.b = TARGET.b;
}
- if (outer.a != TARGET.a) {
- outer.a += DELTA.a * MULTI;
- outerAnimated = true;
+ if (outerColor.main.a != TARGET.a) {
+ outerColor.main.a += DELTA.a * MULTI;
+ outerColor.animated = true;
- if ((SOURCE.a < TARGET.a && outer.a > TARGET.a) || (SOURCE.a > TARGET.a && outer.a < TARGET.a))
- outer.a = TARGET.a;
+ if ((SOURCE.a < TARGET.a && outerColor.main.a > TARGET.a) || (SOURCE.a > TARGET.a && outerColor.main.a < TARGET.a))
+ outerColor.main.a = TARGET.a;
}
TIMER = std::chrono::system_clock::now();
diff --git a/src/renderer/widgets/PasswordInputField.hpp b/src/renderer/widgets/PasswordInputField.hpp
index 45d636a..f3675af 100644
--- a/src/renderer/widgets/PasswordInputField.hpp
+++ b/src/renderer/widgets/PasswordInputField.hpp
@@ -26,9 +26,8 @@ class CPasswordInputField : public IWidget {
void updateHiddenInputState();
void updateOuter();
- bool firstRender = true;
- bool redrawShadow = false;
- bool outerAnimated = false;
+ bool firstRender = true;
+ bool redrawShadow = false;
Vector2D size;
Vector2D pos;
@@ -40,7 +39,7 @@ class CPasswordInputField : public IWidget {
int outThick, rounding;
- CColor inner, outer, font, checkColor;
+ CColor inner, font;
struct {
float currentAmount = 0;
@@ -68,9 +67,7 @@ class CPasswordInputField : public IWidget {
std::string failID = "";
SPreloadedAsset* failAsset = nullptr;
bool canGetNewFail = true;
- CColor failColor;
- int failTransitionMs = 0;
- std::string failText = "";
+ std::string failText = "";
} placeholder;
struct {
@@ -80,6 +77,20 @@ class CPasswordInputField : public IWidget {
bool enabled = false;
} hiddenInputState;
+ struct {
+ CColor main;
+ CColor fail;
+ CColor check;
+ CColor caps;
+ CColor num;
+ CColor both;
+ int transitionMs = 0;
+ bool invertNum = false;
+ bool animated = false;
+ bool stateNum = false;
+ bool stateCaps = false;
+ } outerColor;
+
bool fadeOnEmpty;
uint64_t fadeTimeoutMs;