mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-17 07:15:57 +01:00
input-field: add dots_text_format to support setting arbitrary chars as the input indicator (#510)
* input-field: make dots support arbitrary chars * input-field: add font_familiy for placeholder and text dots * input-field: allow dots_spacing from -1.0 to 1.0 Useful when using emojis in dots_text_format
This commit is contained in:
parent
7362ce3435
commit
71021cc3de
3 changed files with 63 additions and 20 deletions
|
@ -106,9 +106,11 @@ void CConfigManager::init() {
|
||||||
m_config.addSpecialConfigValue("input-field", "dots_spacing", Hyprlang::FLOAT{0.2});
|
m_config.addSpecialConfigValue("input-field", "dots_spacing", Hyprlang::FLOAT{0.2});
|
||||||
m_config.addSpecialConfigValue("input-field", "dots_rounding", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("input-field", "dots_rounding", Hyprlang::INT{-1});
|
||||||
m_config.addSpecialConfigValue("input-field", "dots_fade_time", Hyprlang::INT{200});
|
m_config.addSpecialConfigValue("input-field", "dots_fade_time", Hyprlang::INT{200});
|
||||||
|
m_config.addSpecialConfigValue("input-field", "dots_text_format", Hyprlang::STRING{""});
|
||||||
m_config.addSpecialConfigValue("input-field", "fade_on_empty", Hyprlang::INT{1});
|
m_config.addSpecialConfigValue("input-field", "fade_on_empty", Hyprlang::INT{1});
|
||||||
m_config.addSpecialConfigValue("input-field", "fade_timeout", Hyprlang::INT{2000});
|
m_config.addSpecialConfigValue("input-field", "fade_timeout", Hyprlang::INT{2000});
|
||||||
m_config.addSpecialConfigValue("input-field", "font_color", Hyprlang::INT{0xFF000000});
|
m_config.addSpecialConfigValue("input-field", "font_color", Hyprlang::INT{0xFF000000});
|
||||||
|
m_config.addSpecialConfigValue("input-field", "font_family", Hyprlang::STRING{"Sans"});
|
||||||
m_config.addSpecialConfigValue("input-field", "halign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("input-field", "halign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("input-field", "valign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("input-field", "valign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("input-field", "position", Hyprlang::VEC2{0, -20});
|
m_config.addSpecialConfigValue("input-field", "position", Hyprlang::VEC2{0, -20});
|
||||||
|
@ -260,9 +262,11 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||||
{"dots_center", m_config.getSpecialConfigValue("input-field", "dots_center", k.c_str())},
|
{"dots_center", m_config.getSpecialConfigValue("input-field", "dots_center", k.c_str())},
|
||||||
{"dots_rounding", m_config.getSpecialConfigValue("input-field", "dots_rounding", k.c_str())},
|
{"dots_rounding", m_config.getSpecialConfigValue("input-field", "dots_rounding", k.c_str())},
|
||||||
{"dots_fade_time", m_config.getSpecialConfigValue("input-field", "dots_fade_time", k.c_str())},
|
{"dots_fade_time", m_config.getSpecialConfigValue("input-field", "dots_fade_time", k.c_str())},
|
||||||
|
{"dots_text_format", m_config.getSpecialConfigValue("input-field", "dots_text_format", k.c_str())},
|
||||||
{"fade_on_empty", m_config.getSpecialConfigValue("input-field", "fade_on_empty", k.c_str())},
|
{"fade_on_empty", m_config.getSpecialConfigValue("input-field", "fade_on_empty", k.c_str())},
|
||||||
{"fade_timeout", m_config.getSpecialConfigValue("input-field", "fade_timeout", k.c_str())},
|
{"fade_timeout", m_config.getSpecialConfigValue("input-field", "fade_timeout", k.c_str())},
|
||||||
{"font_color", m_config.getSpecialConfigValue("input-field", "font_color", k.c_str())},
|
{"font_color", m_config.getSpecialConfigValue("input-field", "font_color", k.c_str())},
|
||||||
|
{"font_family", m_config.getSpecialConfigValue("input-field", "font_family", k.c_str())},
|
||||||
{"halign", m_config.getSpecialConfigValue("input-field", "halign", k.c_str())},
|
{"halign", m_config.getSpecialConfigValue("input-field", "halign", k.c_str())},
|
||||||
{"valign", m_config.getSpecialConfigValue("input-field", "valign", k.c_str())},
|
{"valign", m_config.getSpecialConfigValue("input-field", "valign", k.c_str())},
|
||||||
{"position", m_config.getSpecialConfigValue("input-field", "position", k.c_str())},
|
{"position", m_config.getSpecialConfigValue("input-field", "position", k.c_str())},
|
||||||
|
|
|
@ -16,6 +16,7 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
||||||
dots.center = std::any_cast<Hyprlang::INT>(props.at("dots_center"));
|
dots.center = std::any_cast<Hyprlang::INT>(props.at("dots_center"));
|
||||||
dots.rounding = std::any_cast<Hyprlang::INT>(props.at("dots_rounding"));
|
dots.rounding = std::any_cast<Hyprlang::INT>(props.at("dots_rounding"));
|
||||||
dots.fadeMs = std::any_cast<Hyprlang::INT>(props.at("dots_fade_time"));
|
dots.fadeMs = std::any_cast<Hyprlang::INT>(props.at("dots_fade_time"));
|
||||||
|
dots.textFormat = std::any_cast<Hyprlang::STRING>(props.at("dots_text_format"));
|
||||||
fadeOnEmpty = std::any_cast<Hyprlang::INT>(props.at("fade_on_empty"));
|
fadeOnEmpty = std::any_cast<Hyprlang::INT>(props.at("fade_on_empty"));
|
||||||
fadeTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fade_timeout"));
|
fadeTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fade_timeout"));
|
||||||
hiddenInputState.enabled = std::any_cast<Hyprlang::INT>(props.at("hide_input"));
|
hiddenInputState.enabled = std::any_cast<Hyprlang::INT>(props.at("hide_input"));
|
||||||
|
@ -23,6 +24,7 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
||||||
configPlaceholderText = std::any_cast<Hyprlang::STRING>(props.at("placeholder_text"));
|
configPlaceholderText = std::any_cast<Hyprlang::STRING>(props.at("placeholder_text"));
|
||||||
configFailText = std::any_cast<Hyprlang::STRING>(props.at("fail_text"));
|
configFailText = std::any_cast<Hyprlang::STRING>(props.at("fail_text"));
|
||||||
configFailTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fail_timeout"));
|
configFailTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fail_timeout"));
|
||||||
|
fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||||
colorConfig.transitionMs = std::any_cast<Hyprlang::INT>(props.at("fail_transition"));
|
colorConfig.transitionMs = std::any_cast<Hyprlang::INT>(props.at("fail_transition"));
|
||||||
colorConfig.outer = std::any_cast<Hyprlang::INT>(props.at("outer_color"));
|
colorConfig.outer = std::any_cast<Hyprlang::INT>(props.at("outer_color"));
|
||||||
colorConfig.inner = std::any_cast<Hyprlang::INT>(props.at("inner_color"));
|
colorConfig.inner = std::any_cast<Hyprlang::INT>(props.at("inner_color"));
|
||||||
|
@ -46,7 +48,7 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
||||||
|
|
||||||
pos = posFromHVAlign(viewport, size, pos, halign, valign);
|
pos = posFromHVAlign(viewport, size, pos, halign, valign);
|
||||||
dots.size = std::clamp(dots.size, 0.2f, 0.8f);
|
dots.size = std::clamp(dots.size, 0.2f, 0.8f);
|
||||||
dots.spacing = std::clamp(dots.spacing, 0.f, 1.f);
|
dots.spacing = std::clamp(dots.spacing, -1.f, 1.f);
|
||||||
colorConfig.transitionMs = std::clamp(colorConfig.transitionMs, 0, 1000);
|
colorConfig.transitionMs = std::clamp(colorConfig.transitionMs, 0, 1000);
|
||||||
|
|
||||||
colorConfig.both = colorConfig.both == -1 ? colorConfig.outer : colorConfig.both;
|
colorConfig.both = colorConfig.both == -1 ? colorConfig.outer : colorConfig.both;
|
||||||
|
@ -57,6 +59,19 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
||||||
colorState.outer = colorConfig.outer;
|
colorState.outer = colorConfig.outer;
|
||||||
colorState.font = colorConfig.font;
|
colorState.font = colorConfig.font;
|
||||||
|
|
||||||
|
if (!dots.textFormat.empty()) {
|
||||||
|
dots.textResourceID = std::format("input:{}-{}", (uintptr_t)this, dots.textFormat);
|
||||||
|
CAsyncResourceGatherer::SPreloadRequest request;
|
||||||
|
request.id = dots.textResourceID;
|
||||||
|
request.asset = dots.textFormat;
|
||||||
|
request.type = CAsyncResourceGatherer::eTargetType::TARGET_TEXT;
|
||||||
|
request.props["font_family"] = fontFamily;
|
||||||
|
request.props["color"] = colorState.font;
|
||||||
|
request.props["font_size"] = (int)(std::nearbyint(size.y * dots.size * 0.5f) * 2.f);
|
||||||
|
|
||||||
|
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||||
|
}
|
||||||
|
|
||||||
// request the inital placeholder asset
|
// request the inital placeholder asset
|
||||||
updatePlaceholder();
|
updatePlaceholder();
|
||||||
}
|
}
|
||||||
|
@ -226,27 +241,41 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
||||||
g_pRenderer->renderRect(inputFieldBox, innerCol, rounding == -1 ? inputFieldBox.h / 2.0 : rounding - outThick);
|
g_pRenderer->renderRect(inputFieldBox, innerCol, rounding == -1 ? inputFieldBox.h / 2.0 : rounding - outThick);
|
||||||
|
|
||||||
if (!hiddenInputState.enabled && !g_pHyprlock->m_bFadeStarted) {
|
if (!hiddenInputState.enabled && !g_pHyprlock->m_bFadeStarted) {
|
||||||
const int PASS_SIZE = std::nearbyint(inputFieldBox.h * dots.size * 0.5f) * 2.f;
|
const int RECTPASSSIZE = std::nearbyint(inputFieldBox.h * dots.size * 0.5f) * 2.f;
|
||||||
const int PASS_SPACING = std::floor(PASS_SIZE * dots.spacing);
|
Vector2D passSize{RECTPASSSIZE, RECTPASSSIZE};
|
||||||
const int DOT_PAD = (inputFieldBox.h - PASS_SIZE) / 2;
|
int passSpacing = std::floor(passSize.x * dots.spacing);
|
||||||
|
|
||||||
|
if (!dots.textFormat.empty()) {
|
||||||
|
if (!dots.textAsset)
|
||||||
|
dots.textAsset = g_pRenderer->asyncResourceGatherer->getAssetByID(dots.textResourceID);
|
||||||
|
|
||||||
|
if (!dots.textAsset)
|
||||||
|
forceReload = true;
|
||||||
|
else {
|
||||||
|
passSize = dots.textAsset->texture.m_vSize;
|
||||||
|
passSpacing = std::floor(passSize.x * dots.spacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int DOT_PAD = (inputFieldBox.h - passSize.y) / 2;
|
||||||
const int DOT_AREA_WIDTH = inputFieldBox.w - DOT_PAD * 2; // avail width for dots
|
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 MAX_DOTS = std::round(DOT_AREA_WIDTH * 1.0 / (passSize.x + passSpacing)); // max amount of dots that can fit in the area
|
||||||
const int DOT_FLOORED = std::floor(dots.currentAmount);
|
const int DOT_FLOORED = std::floor(dots.currentAmount);
|
||||||
const float DOT_ALPHA = fontCol.a;
|
const float DOT_ALPHA = fontCol.a;
|
||||||
|
|
||||||
// Calculate the total width required for all dots including spaces between them
|
// 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;
|
const int TOTAL_DOTS_WIDTH = (passSize.x + passSpacing) * dots.currentAmount - passSpacing;
|
||||||
|
|
||||||
// Calculate starting x-position to ensure dots stay centered within the input field
|
// 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;
|
int xstart = dots.center ? (DOT_AREA_WIDTH - TOTAL_DOTS_WIDTH) / 2 + DOT_PAD : DOT_PAD;
|
||||||
|
|
||||||
if (dots.currentAmount > MAX_DOTS)
|
if (dots.currentAmount > MAX_DOTS)
|
||||||
xstart = (inputFieldBox.w + MAX_DOTS * (PASS_SIZE + PASS_SPACING) - PASS_SPACING - 2 * TOTAL_DOTS_WIDTH) / 2;
|
xstart = (inputFieldBox.w + MAX_DOTS * (passSize.x + passSpacing) - passSpacing - 2 * TOTAL_DOTS_WIDTH) / 2;
|
||||||
|
|
||||||
if (dots.rounding == -1)
|
if (dots.rounding == -1)
|
||||||
dots.rounding = PASS_SIZE / 2.0;
|
dots.rounding = passSize.x / 2.0;
|
||||||
else if (dots.rounding == -2)
|
else if (dots.rounding == -2)
|
||||||
dots.rounding = rounding == -1 ? PASS_SIZE / 2.0 : rounding * dots.size;
|
dots.rounding = rounding == -1 ? passSize.x / 2.0 : rounding * dots.size;
|
||||||
|
|
||||||
for (int i = 0; i < dots.currentAmount; ++i) {
|
for (int i = 0; i < dots.currentAmount; ++i) {
|
||||||
if (i < DOT_FLOORED - MAX_DOTS)
|
if (i < DOT_FLOORED - MAX_DOTS)
|
||||||
|
@ -260,9 +289,16 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D dotPosition =
|
Vector2D dotPosition =
|
||||||
inputFieldBox.pos() + Vector2D{xstart + (int)inputFieldBox.w % 2 / 2.f + i * (PASS_SIZE + PASS_SPACING), inputFieldBox.h / 2.f - PASS_SIZE / 2.f};
|
inputFieldBox.pos() + Vector2D{xstart + (int)inputFieldBox.w % 2 / 2.f + i * (passSize.x + passSpacing), inputFieldBox.h / 2.f - passSize.y / 2.f};
|
||||||
CBox box{dotPosition, Vector2D{PASS_SIZE, PASS_SIZE}};
|
CBox box{dotPosition, passSize};
|
||||||
g_pRenderer->renderRect(box, fontCol, dots.rounding);
|
if (!dots.textFormat.empty()) {
|
||||||
|
if (!dots.textAsset)
|
||||||
|
break;
|
||||||
|
|
||||||
|
g_pRenderer->renderTexture(box, dots.textAsset->texture, fontCol.a, dots.rounding);
|
||||||
|
} else {
|
||||||
|
g_pRenderer->renderRect(box, fontCol, dots.rounding);
|
||||||
|
}
|
||||||
fontCol.a = DOT_ALPHA;
|
fontCol.a = DOT_ALPHA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,7 +374,7 @@ void CPasswordInputField::updatePlaceholder() {
|
||||||
request.id = placeholder.resourceID;
|
request.id = placeholder.resourceID;
|
||||||
request.asset = placeholder.currentText;
|
request.asset = placeholder.currentText;
|
||||||
request.type = CAsyncResourceGatherer::eTargetType::TARGET_TEXT;
|
request.type = CAsyncResourceGatherer::eTargetType::TARGET_TEXT;
|
||||||
request.props["font_family"] = std::string{"Sans"};
|
request.props["font_family"] = fontFamily;
|
||||||
request.props["color"] = colorState.font;
|
request.props["color"] = colorState.font;
|
||||||
request.props["font_size"] = (int)size.y / 4;
|
request.props["font_size"] = (int)size.y / 4;
|
||||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||||
|
|
|
@ -40,19 +40,22 @@ class CPasswordInputField : public IWidget {
|
||||||
Vector2D configPos;
|
Vector2D configPos;
|
||||||
Vector2D configSize;
|
Vector2D configSize;
|
||||||
|
|
||||||
std::string halign, valign, configFailText, outputStringPort, configPlaceholderText;
|
std::string halign, valign, configFailText, outputStringPort, configPlaceholderText, fontFamily;
|
||||||
uint64_t configFailTimeoutMs = 2000;
|
uint64_t configFailTimeoutMs = 2000;
|
||||||
|
|
||||||
int outThick, rounding;
|
int outThick, rounding;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
float currentAmount = 0;
|
float currentAmount = 0;
|
||||||
int fadeMs = 0;
|
int fadeMs = 0;
|
||||||
std::chrono::system_clock::time_point lastFrame;
|
std::chrono::system_clock::time_point lastFrame;
|
||||||
bool center = false;
|
bool center = false;
|
||||||
float size = 0;
|
float size = 0;
|
||||||
float spacing = 0;
|
float spacing = 0;
|
||||||
int rounding = 0;
|
int rounding = 0;
|
||||||
|
std::string textFormat = "";
|
||||||
|
SPreloadedAsset* textAsset = nullptr;
|
||||||
|
std::string textResourceID;
|
||||||
} dots;
|
} dots;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Reference in a new issue