input-field: fix width animations (#582)

This commit is contained in:
Maximilian Seidler 2024-12-16 00:00:41 +00:00 committed by GitHub
parent 8010b81e7b
commit 4681f8f7f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 53 additions and 27 deletions

View file

@ -146,6 +146,12 @@ void CPasswordInputField::updateDots() {
if (passwordLength == dots.currentAmount) if (passwordLength == dots.currentAmount)
return; return;
// Fully fading the dots to 0 currently does not look good
if (passwordLength == 0 && dots.currentAmount > 2) {
dots.currentAmount = 0;
return;
}
if (std::abs(passwordLength - dots.currentAmount) > 1) { if (std::abs(passwordLength - dots.currentAmount) > 1) {
dots.currentAmount = std::clamp(dots.currentAmount, passwordLength - 1.f, passwordLength + 1.f); dots.currentAmount = std::clamp(dots.currentAmount, passwordLength - 1.f, passwordLength + 1.f);
dots.lastFrame = std::chrono::system_clock::now(); dots.lastFrame = std::chrono::system_clock::now();
@ -188,34 +194,13 @@ bool CPasswordInputField::draw(const SRenderData& data) {
updateDots(); updateDots();
updateColors(); updateColors();
updatePlaceholder(); updatePlaceholder();
updateWidth();
updateHiddenInputState(); updateHiddenInputState();
static auto TIMER = std::chrono::system_clock::now();
if (placeholder.asset) {
const auto TARGETSIZEX = placeholder.asset->texture.m_vSize.x + inputFieldBox.h;
if (size.x < TARGETSIZEX) {
const auto DELTA = std::clamp((int)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - TIMER).count(), 8000, 20000);
TIMER = std::chrono::system_clock::now();
forceReload = true;
size.x += std::clamp((TARGETSIZEX - size.x) * DELTA / 100000.0, 1.0, 1000.0);
if (size.x > TARGETSIZEX) {
size.x = TARGETSIZEX;
redrawShadow = true;
}
}
pos = posFromHVAlign(viewport, size, configPos, halign, valign);
} else if (size.x != configSize.x) {
size.x = configSize.x;
pos = posFromHVAlign(viewport, size, configPos, halign, valign);
}
SRenderData shadowData = data; SRenderData shadowData = data;
shadowData.opacity *= fade.a; shadowData.opacity *= fade.a;
if (!dynamicWidth.animated || size.x > dynamicWidth.source)
shadow.draw(shadowData); shadow.draw(shadowData);
CGradientValueData outerGrad = colorState.outer; CGradientValueData outerGrad = colorState.outer;
@ -320,7 +305,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
currAsset = placeholder.asset; currAsset = placeholder.asset;
if (currAsset) { if (currAsset && currAsset->texture.m_vSize.x + size.y <= size.x) {
Vector2D pos = outerBox.pos() + outerBox.size() / 2.f; Vector2D pos = outerBox.pos() + outerBox.size() / 2.f;
pos = pos - currAsset->texture.m_vSize / 2.f; pos = pos - currAsset->texture.m_vSize / 2.f;
CBox textbox{pos, currAsset->texture.m_vSize}; CBox textbox{pos, currAsset->texture.m_vSize};
@ -329,7 +314,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
forceReload = true; forceReload = true;
} }
return dots.currentAmount != passwordLength || fade.animated || colorState.animated || redrawShadow || data.opacity < 1.0 || forceReload; return dots.currentAmount != passwordLength || fade.animated || colorState.animated || redrawShadow || data.opacity < 1.0 || dynamicWidth.animated || forceReload;
} }
static void failTimeoutCallback(std::shared_ptr<CTimer> self, void* data) { static void failTimeoutCallback(std::shared_ptr<CTimer> self, void* data) {
@ -389,6 +374,40 @@ void CPasswordInputField::updatePlaceholder() {
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
} }
void CPasswordInputField::updateWidth() {
const auto NOW = std::chrono::system_clock::now();
double targetSizeX = configSize.x;
if (placeholder.asset)
targetSizeX = placeholder.asset->texture.m_vSize.x + size.y;
if (targetSizeX < configSize.x)
targetSizeX = configSize.x;
if (size.x != targetSizeX) {
if (!dynamicWidth.animated) {
dynamicWidth.source = size.x;
dynamicWidth.start = NOW;
dynamicWidth.animated = true;
}
const auto TIMEDELTA = std::clamp((int)std::chrono::duration_cast<std::chrono::microseconds>(NOW - dynamicWidth.start).count(), 1000, 100000);
const auto INCR = std::clamp(std::abs(targetSizeX - dynamicWidth.source) * TIMEDELTA / 1000000.0, 1.0, 1000.0);
if (size.x > targetSizeX)
size.x -= INCR;
else
size.x += INCR;
if ((dynamicWidth.source < targetSizeX && size.x > targetSizeX) || (dynamicWidth.source > targetSizeX && size.x < targetSizeX)) {
size.x = targetSizeX;
redrawShadow = true;
dynamicWidth.animated = false;
}
}
pos = posFromHVAlign(viewport, size, configPos, halign, valign);
}
void CPasswordInputField::updateHiddenInputState() { void CPasswordInputField::updateHiddenInputState() {
if (!hiddenInputState.enabled || (size_t)hiddenInputState.lastPasswordLength == passwordLength) if (!hiddenInputState.enabled || (size_t)hiddenInputState.lastPasswordLength == passwordLength)
return; return;

View file

@ -24,6 +24,7 @@ class CPasswordInputField : public IWidget {
void updateDots(); void updateDots();
void updateFade(); void updateFade();
void updatePlaceholder(); void updatePlaceholder();
void updateWidth();
void updateHiddenInputState(); void updateHiddenInputState();
void updateInputState(); void updateInputState();
void updateColors(); void updateColors();
@ -46,6 +47,12 @@ class CPasswordInputField : public IWidget {
int outThick, rounding; int outThick, rounding;
struct {
std::chrono::system_clock::time_point start;
bool animated = false;
double source = 0;
} dynamicWidth;
struct { struct {
float currentAmount = 0; float currentAmount = 0;
int fadeMs = 0; int fadeMs = 0;