mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-16 23:05:58 +01:00
input-field: various fixes (#198)
* input-field: some fixes * simplify; correctly check passlen(utf8) in draw return * correctly erase utf-8 on backspace * render on up events too * omglul me dumb * revert fade speed change
This commit is contained in:
parent
3e38762e84
commit
23224d40e4
3 changed files with 88 additions and 79 deletions
|
@ -773,9 +773,6 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
|||
else
|
||||
std::erase(m_vPressedKeys, key);
|
||||
|
||||
if (!down) // we dont care about up events
|
||||
return;
|
||||
|
||||
if (m_sPasswordState.result) {
|
||||
for (auto& o : m_vOutputs) {
|
||||
o->sessionLockSurface->render();
|
||||
|
@ -783,30 +780,36 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto SYM = xkb_state_key_get_one_sym(m_pXKBState, key + 8);
|
||||
if (down) {
|
||||
const auto SYM = xkb_state_key_get_one_sym(m_pXKBState, key + 8);
|
||||
|
||||
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);
|
||||
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);
|
||||
} else if (SYM == XKB_KEY_Return || SYM == XKB_KEY_KP_Enter) {
|
||||
Debug::log(LOG, "Authenticating");
|
||||
m_sPasswordState.result = g_pPassword->verify(m_sPasswordState.passBuffer);
|
||||
} else if (SYM == XKB_KEY_Escape) {
|
||||
Debug::log(LOG, "Clearing password buffer");
|
||||
if (SYM == XKB_KEY_BackSpace) {
|
||||
if (m_sPasswordState.passBuffer.length() > 0) {
|
||||
// handle utf-8
|
||||
while ((m_sPasswordState.passBuffer.back() & 0xc0) == 0x80)
|
||||
m_sPasswordState.passBuffer.pop_back();
|
||||
m_sPasswordState.passBuffer = m_sPasswordState.passBuffer.substr(0, m_sPasswordState.passBuffer.length() - 1);
|
||||
}
|
||||
} else if (SYM == XKB_KEY_Return || SYM == XKB_KEY_KP_Enter) {
|
||||
Debug::log(LOG, "Authenticating");
|
||||
m_sPasswordState.result = g_pPassword->verify(m_sPasswordState.passBuffer);
|
||||
} else if (SYM == XKB_KEY_Escape) {
|
||||
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);
|
||||
if (len > 1)
|
||||
m_sPasswordState.passBuffer += std::string{buf, len - 1};
|
||||
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);
|
||||
if (len > 1)
|
||||
m_sPasswordState.passBuffer += std::string{buf, len - 1};
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& o : m_vOutputs) {
|
||||
|
|
|
@ -89,22 +89,20 @@ void CPasswordInputField::onFadeOutTimer() {
|
|||
}
|
||||
|
||||
void CPasswordInputField::updateFade() {
|
||||
const auto PASSLEN = g_pHyprlock->getPasswordBufferLen();
|
||||
|
||||
if (!fadeOnEmpty) {
|
||||
fade.a = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (PASSLEN > 0 && fade.allowFadeOut)
|
||||
if (passwordLength > 0 && fade.allowFadeOut)
|
||||
fade.allowFadeOut = false;
|
||||
|
||||
if (PASSLEN > 0 && fade.fadeOutTimer.get()) {
|
||||
if (passwordLength > 0 && fade.fadeOutTimer.get()) {
|
||||
fade.fadeOutTimer->cancel();
|
||||
fade.fadeOutTimer.reset();
|
||||
}
|
||||
|
||||
if (PASSLEN == 0 && fade.a != 0.0 && (!fade.animated || fade.appearing)) {
|
||||
if (passwordLength == 0 && fade.a != 0.0 && (!fade.animated || fade.appearing)) {
|
||||
if (fade.allowFadeOut || fadeTimeoutMs == 0) {
|
||||
fade.a = 1.0;
|
||||
fade.animated = true;
|
||||
|
@ -115,7 +113,7 @@ void CPasswordInputField::updateFade() {
|
|||
fade.fadeOutTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(fadeTimeoutMs), fadeOutCallback, this);
|
||||
}
|
||||
|
||||
if (PASSLEN > 0 && fade.a != 1.0 && (!fade.animated || !fade.appearing)) {
|
||||
if (passwordLength > 0 && fade.a != 1.0 && (!fade.animated || !fade.appearing)) {
|
||||
fade.a = 0.0;
|
||||
fade.animated = true;
|
||||
fade.appearing = true;
|
||||
|
@ -136,13 +134,11 @@ void CPasswordInputField::updateFade() {
|
|||
}
|
||||
|
||||
void CPasswordInputField::updateDots() {
|
||||
const auto PASSLEN = g_pHyprlock->getPasswordBufferDisplayLen();
|
||||
|
||||
if (PASSLEN == dots.currentAmount)
|
||||
if (passwordLength == dots.currentAmount)
|
||||
return;
|
||||
|
||||
if (std::abs(PASSLEN - dots.currentAmount) > 1) {
|
||||
dots.currentAmount = std::clamp(dots.currentAmount, PASSLEN - 1.f, PASSLEN + 1.f);
|
||||
if (std::abs(passwordLength - dots.currentAmount) > 1) {
|
||||
dots.currentAmount = std::clamp(dots.currentAmount, passwordLength - 1.f, passwordLength + 1.f);
|
||||
dots.lastFrame = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
|
@ -150,14 +146,14 @@ void CPasswordInputField::updateDots() {
|
|||
|
||||
const float TOADD = DELTA / 1000000.0 * dots.speedPerSecond;
|
||||
|
||||
if (PASSLEN > dots.currentAmount) {
|
||||
if (passwordLength > dots.currentAmount) {
|
||||
dots.currentAmount += TOADD;
|
||||
if (dots.currentAmount > PASSLEN)
|
||||
dots.currentAmount = PASSLEN;
|
||||
} else if (PASSLEN < dots.currentAmount) {
|
||||
if (dots.currentAmount > passwordLength)
|
||||
dots.currentAmount = passwordLength;
|
||||
} else if (passwordLength < dots.currentAmount) {
|
||||
dots.currentAmount -= TOADD;
|
||||
if (dots.currentAmount < PASSLEN)
|
||||
dots.currentAmount = PASSLEN;
|
||||
if (dots.currentAmount < passwordLength)
|
||||
dots.currentAmount = passwordLength;
|
||||
}
|
||||
|
||||
dots.lastFrame = std::chrono::system_clock::now();
|
||||
|
@ -175,6 +171,9 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
|
||||
bool forceReload = false;
|
||||
|
||||
passwordLength = g_pHyprlock->getPasswordBufferDisplayLen();
|
||||
checkWaiting = g_pHyprlock->passwordCheckWaiting();
|
||||
|
||||
updateFade();
|
||||
updateDots();
|
||||
updateFailTex();
|
||||
|
@ -209,7 +208,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
shadowData.opacity *= fade.a;
|
||||
shadow.draw(shadowData);
|
||||
|
||||
float passAlpha = g_pHyprlock->passwordCheckWaiting() ? 0.5 : 1.0;
|
||||
float passAlpha = checkWaiting ? 0.5 : 1.0;
|
||||
|
||||
CColor outerCol = outerColor.main;
|
||||
outerCol.a *= fade.a * data.opacity;
|
||||
|
@ -218,38 +217,39 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
CColor fontCol = font;
|
||||
fontCol.a *= fade.a * data.opacity * passAlpha;
|
||||
|
||||
g_pRenderer->renderRect(outerBox, outerCol, rounding == -1 ? outerBox.h / 2.0 : rounding);
|
||||
if (outThick > 0) {
|
||||
g_pRenderer->renderRect(outerBox, outerCol, rounding == -1 ? outerBox.h / 2.0 : rounding);
|
||||
|
||||
const auto PASSLEN = g_pHyprlock->getPasswordBufferLen();
|
||||
|
||||
if (PASSLEN != 0 && hiddenInputState.enabled) {
|
||||
CBox outerBoxScaled = outerBox;
|
||||
Vector2D p = outerBox.pos();
|
||||
outerBoxScaled.translate(-p).scale(0.5).translate(p);
|
||||
if (hiddenInputState.lastQuadrant > 1)
|
||||
outerBoxScaled.y += outerBoxScaled.h;
|
||||
if (hiddenInputState.lastQuadrant % 2 == 1)
|
||||
outerBoxScaled.x += outerBoxScaled.w;
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(outerBoxScaled.x, outerBoxScaled.y, outerBoxScaled.w, outerBoxScaled.h);
|
||||
g_pRenderer->renderRect(outerBox, hiddenInputState.lastColor, rounding == -1 ? outerBox.h / 2.0 : rounding);
|
||||
glScissor(0, 0, viewport.x, viewport.y);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (passwordLength != 0 && hiddenInputState.enabled && !fade.animated && data.opacity == 1.0) {
|
||||
CBox outerBoxScaled = outerBox;
|
||||
Vector2D p = outerBox.pos();
|
||||
outerBoxScaled.translate(-p).scale(0.5).translate(p);
|
||||
if (hiddenInputState.lastQuadrant > 1)
|
||||
outerBoxScaled.y += outerBoxScaled.h;
|
||||
if (hiddenInputState.lastQuadrant % 2 == 1)
|
||||
outerBoxScaled.x += outerBoxScaled.w;
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(outerBoxScaled.x, outerBoxScaled.y, outerBoxScaled.w, outerBoxScaled.h);
|
||||
g_pRenderer->renderRect(outerBox, hiddenInputState.lastColor, rounding == -1 ? outerBox.h / 2.0 : rounding);
|
||||
glScissor(0, 0, viewport.x, viewport.y);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
g_pRenderer->renderRect(inputFieldBox, innerCol, rounding == -1 ? inputFieldBox.h / 2.0 : rounding - outThick);
|
||||
|
||||
const int PASS_SIZE = std::nearbyint(inputFieldBox.h * dots.size * 0.5f) * 2.f;
|
||||
const int PASS_SPACING = std::floor(PASS_SIZE * dots.spacing);
|
||||
const int DOT_PAD = (inputFieldBox.h - PASS_SIZE) / 2;
|
||||
const int DOT_AREA_WIDTH = inputFieldBox.w - DOT_PAD * 2; // avail width for dots
|
||||
const int MAX_DOTS = std::round(DOT_AREA_WIDTH * 1.0 / (PASS_SIZE + PASS_SPACING)); // max amount of dots that can fit in the area
|
||||
const int DOT_FLOORED = std::floor(dots.currentAmount);
|
||||
const float DOT_ALPHA = fontCol.a;
|
||||
// Calculate the total width required for all dots including spaces between them
|
||||
const int TOTAL_DOTS_WIDTH = (PASS_SIZE + PASS_SPACING) * dots.currentAmount - PASS_SPACING;
|
||||
if (!hiddenInputState.enabled && !g_pHyprlock->m_bFadeStarted) {
|
||||
const int PASS_SIZE = std::nearbyint(inputFieldBox.h * dots.size * 0.5f) * 2.f;
|
||||
const int PASS_SPACING = std::floor(PASS_SIZE * dots.spacing);
|
||||
const int DOT_PAD = (inputFieldBox.h - PASS_SIZE) / 2;
|
||||
const int DOT_AREA_WIDTH = inputFieldBox.w - DOT_PAD * 2; // avail width for dots
|
||||
const int MAX_DOTS = std::round(DOT_AREA_WIDTH * 1.0 / (PASS_SIZE + PASS_SPACING)); // max amount of dots that can fit in the area
|
||||
const int DOT_FLOORED = std::floor(dots.currentAmount);
|
||||
const float DOT_ALPHA = fontCol.a;
|
||||
|
||||
// Calculate the total width required for all dots including spaces between them
|
||||
const int TOTAL_DOTS_WIDTH = (PASS_SIZE + PASS_SPACING) * dots.currentAmount - PASS_SPACING;
|
||||
|
||||
if (!hiddenInputState.enabled) {
|
||||
// Calculate starting x-position to ensure dots stay centered within the input field
|
||||
int xstart = dots.center ? (DOT_AREA_WIDTH - TOTAL_DOTS_WIDTH) / 2 + DOT_PAD : DOT_PAD;
|
||||
|
||||
|
@ -280,7 +280,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
}
|
||||
}
|
||||
|
||||
if (PASSLEN == 0 && !placeholder.resourceID.empty()) {
|
||||
if (passwordLength == 0 && !placeholder.resourceID.empty()) {
|
||||
SPreloadedAsset* currAsset = nullptr;
|
||||
|
||||
if (!placeholder.failID.empty()) {
|
||||
|
@ -304,18 +304,16 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
forceReload = true;
|
||||
}
|
||||
|
||||
return dots.currentAmount != PASSLEN || fade.animated || outerColor.animated || redrawShadow || data.opacity < 1.0 || forceReload;
|
||||
return dots.currentAmount != passwordLength || fade.animated || outerColor.animated || redrawShadow || data.opacity < 1.0 || forceReload;
|
||||
}
|
||||
|
||||
void CPasswordInputField::updateFailTex() {
|
||||
const auto FAIL = g_pHyprlock->passwordLastFailReason();
|
||||
const auto WAITING = g_pHyprlock->passwordCheckWaiting();
|
||||
const auto PASSLEN = g_pHyprlock->getPasswordBufferLen();
|
||||
const auto FAIL = g_pHyprlock->passwordLastFailReason();
|
||||
|
||||
if (WAITING)
|
||||
if (checkWaiting)
|
||||
placeholder.canGetNewFail = true;
|
||||
|
||||
if (PASSLEN != 0 || (WAITING && PASSLEN == 0)) {
|
||||
if (passwordLength != 0 || (checkWaiting && passwordLength == 0)) {
|
||||
if (placeholder.failAsset) {
|
||||
g_pRenderer->asyncResourceGatherer->unloadAsset(placeholder.failAsset);
|
||||
placeholder.failAsset = nullptr;
|
||||
|
@ -347,11 +345,11 @@ void CPasswordInputField::updateFailTex() {
|
|||
}
|
||||
|
||||
void CPasswordInputField::updateHiddenInputState() {
|
||||
if (!hiddenInputState.enabled || (size_t)hiddenInputState.lastPasswordLength == g_pHyprlock->getPasswordBufferDisplayLen())
|
||||
if (!hiddenInputState.enabled || (size_t)hiddenInputState.lastPasswordLength == passwordLength)
|
||||
return;
|
||||
|
||||
// randomize new thang
|
||||
hiddenInputState.lastPasswordLength = g_pHyprlock->getPasswordBufferDisplayLen();
|
||||
hiddenInputState.lastPasswordLength = passwordLength;
|
||||
|
||||
srand(std::chrono::system_clock::now().time_since_epoch().count());
|
||||
float r1 = (rand() % 100) / 255.0;
|
||||
|
@ -381,7 +379,7 @@ void CPasswordInputField::updateOuter() {
|
|||
static auto TIMER = std::chrono::system_clock::now();
|
||||
|
||||
if (outerColor.animated) {
|
||||
if (outerColor.stateNum != outerColor.invertNum ? !g_pHyprlock->m_bNumLock : g_pHyprlock->m_bNumLock || outerColor.stateCaps != g_pHyprlock->m_bCapsLock)
|
||||
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;
|
||||
|
@ -391,7 +389,12 @@ void CPasswordInputField::updateOuter() {
|
|||
outerColor.stateCaps = g_pHyprlock->m_bCapsLock;
|
||||
|
||||
if (placeholder.failID.empty()) {
|
||||
if (g_pHyprlock->passwordCheckWaiting())
|
||||
if (g_pHyprlock->m_bFadeStarted) {
|
||||
if (TARGET == outerColor.check)
|
||||
SOURCE = outerColor.main;
|
||||
outerColor.transitionMs = 100;
|
||||
TARGET = OUTER;
|
||||
} else if (checkWaiting)
|
||||
TARGET = outerColor.check;
|
||||
else if (outerColor.both != OUTER && outerColor.stateCaps && outerColor.stateNum)
|
||||
TARGET = outerColor.both;
|
||||
|
|
|
@ -28,6 +28,9 @@ class CPasswordInputField : public IWidget {
|
|||
|
||||
bool firstRender = true;
|
||||
bool redrawShadow = false;
|
||||
bool checkWaiting = false;
|
||||
|
||||
size_t passwordLength = 0;
|
||||
|
||||
Vector2D size;
|
||||
Vector2D pos;
|
||||
|
|
Loading…
Reference in a new issue