From bfe23c6ee77f284dde5070f790904cd233f73e86 Mon Sep 17 00:00:00 2001 From: Felix Salcher Date: Tue, 24 Jun 2025 02:18:46 +0200 Subject: [PATCH] directly query the length of the password and change it accordingly --- src/renderer/AsyncResourceGatherer.cpp | 69 +++++++++++++++++++++ src/renderer/AsyncResourceGatherer.hpp | 9 +-- src/renderer/widgets/PasswordInputField.cpp | 57 ++++++++++------- src/renderer/widgets/PasswordInputField.hpp | 1 - 4 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/renderer/AsyncResourceGatherer.cpp b/src/renderer/AsyncResourceGatherer.cpp index b1a52de..c6b5fd2 100644 --- a/src/renderer/AsyncResourceGatherer.cpp +++ b/src/renderer/AsyncResourceGatherer.cpp @@ -206,6 +206,75 @@ void CAsyncResourceGatherer::renderImage(const SPreloadRequest& rq) { preloadTargets.push_back(target); } +Vector2D CAsyncResourceGatherer::getTextAssetSize(const SPreloadRequest& rq) { + SPreloadTarget target; + target.type = TARGET_IMAGE; /* text is just an image lol */ + target.id = rq.id; + + const int FONTSIZE = rq.props.contains("font_size") ? std::any_cast(rq.props.at("font_size")) : 16; + const std::string FONTFAMILY = rq.props.contains("font_family") ? std::any_cast(rq.props.at("font_family")) : "Sans"; + const bool ISCMD = rq.props.contains("cmd") ? std::any_cast(rq.props.at("cmd")) : false; + + static const auto TRIM = g_pConfigManager->getValue("general:text_trim"); + std::string text = ISCMD ? spawnSync(rq.asset) : rq.asset; + + if (*TRIM) { + text.erase(0, text.find_first_not_of(" \n\r\t")); + text.erase(text.find_last_not_of(" \n\r\t") + 1); + } + + auto CAIROSURFACE = makeShared(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* dummy value */)); + auto CAIRO = cairo_create(CAIROSURFACE->cairo()); + + // draw title using Pango + PangoLayout* layout = pango_cairo_create_layout(CAIRO); + + PangoFontDescription* fontDesc = pango_font_description_from_string(FONTFAMILY.c_str()); + pango_font_description_set_size(fontDesc, FONTSIZE * PANGO_SCALE); + pango_layout_set_font_description(layout, fontDesc); + pango_font_description_free(fontDesc); + + if (rq.props.contains("text_align")) { + const std::string TEXTALIGN = std::any_cast(rq.props.at("text_align")); + PangoAlignment align = PANGO_ALIGN_LEFT; + if (TEXTALIGN == "center") + align = PANGO_ALIGN_CENTER; + else if (TEXTALIGN == "right") + align = PANGO_ALIGN_RIGHT; + + pango_layout_set_alignment(layout, align); + } + + PangoAttrList* attrList = nullptr; + GError* gError = nullptr; + char* buf = nullptr; + if (pango_parse_markup(text.c_str(), -1, 0, &attrList, &buf, nullptr, &gError)) + pango_layout_set_text(layout, buf, -1); + else { + Debug::log(ERR, "Pango markup parsing for {} failed: {}", text, gError->message); + g_error_free(gError); + pango_layout_set_text(layout, text.c_str(), -1); + } + + if (!attrList) + attrList = pango_attr_list_new(); + + if (buf) + free(buf); + + pango_attr_list_insert(attrList, pango_attr_scale_new(1)); + pango_layout_set_attributes(layout, attrList); + pango_attr_list_unref(attrList); + + int layoutWidth, layoutHeight; + pango_layout_get_size(layout, &layoutWidth, &layoutHeight); + + // TODO: avoid this? + cairo_destroy(CAIRO); + + return Vector2D{layoutWidth / PANGO_SCALE, layoutHeight / PANGO_SCALE}; +} + void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) { SPreloadTarget target; target.type = TARGET_IMAGE; /* text is just an image lol */ diff --git a/src/renderer/AsyncResourceGatherer.hpp b/src/renderer/AsyncResourceGatherer.hpp index 24aedd6..db2e4e8 100644 --- a/src/renderer/AsyncResourceGatherer.hpp +++ b/src/renderer/AsyncResourceGatherer.hpp @@ -40,10 +40,11 @@ class CAsyncResourceGatherer { std::function callback = nullptr; }; - void requestAsyncAssetPreload(const SPreloadRequest& request); - void unloadAsset(SPreloadedAsset* asset); - void notify(); - void await(); + Vector2D getTextAssetSize(const SPreloadRequest& request); + void requestAsyncAssetPreload(const SPreloadRequest& request); + void unloadAsset(SPreloadedAsset* asset); + void notify(); + void await(); private: std::thread asyncLoopThread; diff --git a/src/renderer/widgets/PasswordInputField.cpp b/src/renderer/widgets/PasswordInputField.cpp index 9485a54..717a6b7 100644 --- a/src/renderer/widgets/PasswordInputField.cpp +++ b/src/renderer/widgets/PasswordInputField.cpp @@ -1,5 +1,6 @@ #include "PasswordInputField.hpp" #include "../Renderer.hpp" +#include "../AsyncResourceGatherer.hpp" #include "../../core/hyprlock.hpp" #include "../../auth/Auth.hpp" #include "../../config/ConfigDataValues.hpp" @@ -195,25 +196,40 @@ void CPasswordInputField::updatePassword() { password.trim -= 1; } - password.content = passwordContent; - std::string trimmedContent = passwordContent; + password.content = passwordContent; - if (password.trim) { - trimmedContent.erase(0, password.trim); - password.trimmed = true; - } - - std::string textResourceID = std::format("password:{}-{}", (uintptr_t)this, trimmedContent); CAsyncResourceGatherer::SPreloadRequest request; - request.id = textResourceID; - request.asset = trimmedContent; - request.type = CAsyncResourceGatherer::eTargetType::TARGET_TEXT; - request.props["font_family"] = fontFamily; - request.props["color"] = colorConfig.font; - request.props["font_size"] = (int)(std::nearbyint(configSize.y * password.size * 0.5f) * 2.f); - request.callback = [REF = m_self]() { assetReadyCallback(REF); }; + Vector2D assetSize; + double offset; + CBox inputFieldBox = {pos, size->value()}; - password.pendingResourceID = textResourceID; + while (true) { + std::string trimmedContent = passwordContent; + + if (password.trim) { + trimmedContent.erase(0, password.trim); + } + + std::string textResourceID = std::format("password:{}-{}", (uintptr_t)this, trimmedContent); + request.id = textResourceID; + request.asset = trimmedContent; + request.type = CAsyncResourceGatherer::eTargetType::TARGET_TEXT; + request.props["font_family"] = fontFamily; + request.props["color"] = colorConfig.font; + request.props["font_size"] = (int)(std::nearbyint(configSize.y * password.size * 0.5f) * 2.f); + request.callback = [REF = m_self]() { assetReadyCallback(REF); }; + + password.pendingResourceID = textResourceID; + + assetSize = g_pRenderer->asyncResourceGatherer->getTextAssetSize(request); + offset = (inputFieldBox.h - assetSize.y) / 2.0; + + if (assetSize.x <= (inputFieldBox.w - offset * 2)) { + break; + } + + password.trim += 1; + } g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); } @@ -368,13 +384,8 @@ bool CPasswordInputField::draw(const SRenderData& data) { password.asset = g_pRenderer->asyncResourceGatherer->getAssetByID(password.resourceID); if (password.asset) { - auto size = password.asset->texture.m_vSize; - double offset = (inputFieldBox.h - size.y) / 2.0; - - if (size.x > inputFieldBox.w - offset * 2 && password.trimmed == true) { - password.trim += 1; - password.trimmed = false; - } + auto size = password.asset->texture.m_vSize; + double offset = (inputFieldBox.h - size.y) / 2.0; double xstart = password.center ? inputFieldBox.w / 2.0 - size.x / 2.0 : offset; diff --git a/src/renderer/widgets/PasswordInputField.hpp b/src/renderer/widgets/PasswordInputField.hpp index b449d1e..c83bdc0 100644 --- a/src/renderer/widgets/PasswordInputField.hpp +++ b/src/renderer/widgets/PasswordInputField.hpp @@ -81,7 +81,6 @@ class CPasswordInputField : public IWidget { SPreloadedAsset* asset = nullptr; SPreloadedAsset* previousAsset = nullptr; int trim = 0; - bool trimmed = true; } password; struct {