Handle touch-down events separately from tap events in settings activities to provide immediate visual feedback when menu items are touched, before the tap is completed. This improves UI responsiveness by updating the selected index on touch-down.
137 lines
4.5 KiB
C++
137 lines
4.5 KiB
C++
#include "IntervalSelectionActivity.h"
|
|
|
|
#include <GfxRenderer.h>
|
|
#include <I18n.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
#include <utility>
|
|
|
|
#include "components/UITheme.h"
|
|
#include "fontIds.h"
|
|
|
|
int IntervalSelectionActivity::clampedValue(const int candidate) const {
|
|
return std::clamp(candidate, minValue, maxValue);
|
|
}
|
|
|
|
void IntervalSelectionActivity::onEnter() {
|
|
Activity::onEnter();
|
|
value = clampedValue(value);
|
|
requestUpdate();
|
|
}
|
|
|
|
void IntervalSelectionActivity::adjustValue(const int delta) {
|
|
value = clampedValue(value + delta);
|
|
requestUpdate();
|
|
}
|
|
|
|
bool IntervalSelectionActivity::setValueFromTouch(const int x, const int y) {
|
|
const int screenWidth = renderer.getScreenWidth();
|
|
const int barWidth = std::min(360, std::max(0, screenWidth - 40));
|
|
constexpr int barHeight = 16;
|
|
const int barX = std::max(0, (screenWidth - barWidth) / 2);
|
|
const int barY = 140;
|
|
if (y < barY - 28 || y > barY + barHeight + 36 || x < barX - 20 || x > barX + barWidth + 20) return false;
|
|
|
|
const int clampedX = std::max(barX, std::min(x, barX + barWidth));
|
|
const int range = std::max(1, maxValue - minValue);
|
|
value = clampedValue(minValue + (clampedX - barX) * range / std::max(1, barWidth));
|
|
return true;
|
|
}
|
|
|
|
void IntervalSelectionActivity::loop() {
|
|
if (ignoreConfirmRelease) {
|
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
|
ignoreConfirmRelease = false;
|
|
return;
|
|
}
|
|
if (!mappedInput.isPressed(MappedInputManager::Button::Confirm)) {
|
|
ignoreConfirmRelease = false;
|
|
}
|
|
}
|
|
|
|
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
|
ActivityResult result;
|
|
result.isCancelled = true;
|
|
setResult(std::move(result));
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
|
setResult(IntervalResult{static_cast<uint32_t>(value)});
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
switch (mappedInput.wasSwipe()) {
|
|
case MappedInputManager::SwipeDir::Left:
|
|
adjustValue(-smallStep);
|
|
return;
|
|
case MappedInputManager::SwipeDir::Right:
|
|
adjustValue(smallStep);
|
|
return;
|
|
case MappedInputManager::SwipeDir::Up:
|
|
adjustValue(largeStep);
|
|
return;
|
|
case MappedInputManager::SwipeDir::Down:
|
|
adjustValue(-largeStep);
|
|
return;
|
|
case MappedInputManager::SwipeDir::None:
|
|
break;
|
|
}
|
|
|
|
int tapX = 0;
|
|
int tapY = 0;
|
|
if (mappedInput.wasScreenTapped(tapX, tapY) && setValueFromTouch(tapX, tapY)) {
|
|
setResult(IntervalResult{static_cast<uint32_t>(value)});
|
|
finish();
|
|
return;
|
|
}
|
|
|
|
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] { adjustValue(-smallStep); });
|
|
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] { adjustValue(smallStep); });
|
|
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Up}, [this] { adjustValue(largeStep); });
|
|
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Down}, [this] { adjustValue(-largeStep); });
|
|
}
|
|
|
|
void IntervalSelectionActivity::render(RenderLock&&) {
|
|
renderer.clearScreen();
|
|
|
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, I18N.get(titleId), true, EpdFontFamily::BOLD);
|
|
|
|
char formattedValue[32];
|
|
if (maxBoundaryLabelId != StrId::STR_NONE_OPT && value == maxValue) {
|
|
snprintf(formattedValue, sizeof(formattedValue), "%s", I18N.get(maxBoundaryLabelId));
|
|
} else if (valueFormatId != StrId::STR_NONE_OPT) {
|
|
snprintf(formattedValue, sizeof(formattedValue), I18N.get(valueFormatId), static_cast<unsigned int>(value));
|
|
} else {
|
|
snprintf(formattedValue, sizeof(formattedValue), "%d", value);
|
|
}
|
|
renderer.drawCenteredText(UI_12_FONT_ID, 90, formattedValue, true, EpdFontFamily::BOLD);
|
|
|
|
const int screenWidth = renderer.getScreenWidth();
|
|
const int barWidth = std::min(360, std::max(0, screenWidth - 40));
|
|
constexpr int barHeight = 16;
|
|
const int barX = std::max(0, (screenWidth - barWidth) / 2);
|
|
const int barY = 140;
|
|
|
|
renderer.drawRect(barX, barY, barWidth, barHeight);
|
|
|
|
const int range = std::max(1, maxValue - minValue);
|
|
const int fillWidth = (barWidth - 4) * (value - minValue) / range;
|
|
if (fillWidth > 0) {
|
|
renderer.fillRect(barX + 2, barY + 2, fillWidth, barHeight - 4);
|
|
}
|
|
|
|
const int knobX = std::max(barX + 2, barX + 2 + fillWidth - 2);
|
|
renderer.fillRect(knobX, barY - 4, 4, barHeight + 8, true);
|
|
|
|
renderer.drawCenteredText(SMALL_FONT_ID, barY + 30, I18N.get(stepHintId), true);
|
|
|
|
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "-", "+");
|
|
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
|
|
|
renderer.displayBuffer();
|
|
}
|