Skip to content

Commit

Permalink
input-field: fix width animations (#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaideiaDilemma authored Dec 16, 2024
1 parent 8010b81 commit 4681f8f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 27 deletions.
73 changes: 46 additions & 27 deletions src/renderer/widgets/PasswordInputField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ void CPasswordInputField::updateDots() {
if (passwordLength == dots.currentAmount)
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) {
dots.currentAmount = std::clamp(dots.currentAmount, passwordLength - 1.f, passwordLength + 1.f);
dots.lastFrame = std::chrono::system_clock::now();
Expand Down Expand Up @@ -188,35 +194,14 @@ bool CPasswordInputField::draw(const SRenderData& data) {
updateDots();
updateColors();
updatePlaceholder();
updateWidth();
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;
shadowData.opacity *= fade.a;
shadow.draw(shadowData);

if (!dynamicWidth.animated || size.x > dynamicWidth.source)
shadow.draw(shadowData);

CGradientValueData outerGrad = colorState.outer;
for (auto& c : outerGrad.m_vColors)
Expand Down Expand Up @@ -320,7 +305,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {

currAsset = placeholder.asset;

if (currAsset) {
if (currAsset && currAsset->texture.m_vSize.x + size.y <= size.x) {
Vector2D pos = outerBox.pos() + outerBox.size() / 2.f;
pos = pos - currAsset->texture.m_vSize / 2.f;
CBox textbox{pos, currAsset->texture.m_vSize};
Expand All @@ -329,7 +314,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
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) {
Expand Down Expand Up @@ -389,6 +374,40 @@ void CPasswordInputField::updatePlaceholder() {
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() {
if (!hiddenInputState.enabled || (size_t)hiddenInputState.lastPasswordLength == passwordLength)
return;
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/widgets/PasswordInputField.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class CPasswordInputField : public IWidget {
void updateDots();
void updateFade();
void updatePlaceholder();
void updateWidth();
void updateHiddenInputState();
void updateInputState();
void updateColors();
Expand All @@ -46,6 +47,12 @@ class CPasswordInputField : public IWidget {

int outThick, rounding;

struct {
std::chrono::system_clock::time_point start;
bool animated = false;
double source = 0;
} dynamicWidth;

struct {
float currentAmount = 0;
int fadeMs = 0;
Expand Down

0 comments on commit 4681f8f

Please sign in to comment.