CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
SliderView.cpp
Go to the documentation of this file.
1
6
10#include "cdc_ui/ViewStack.h"
11#include "cdc_ui/I18n.h"
12#include "cdc_hal/IDisplay.h"
13#include "cdc_hal/IKeypad.h"
14#include "cdc_log.h"
15#include <goodisplay/gdey029T94.h>
16#include <cstdio>
17#include <algorithm>
18
19static constexpr uint32_t REPEAT_INITIAL_MS = 350;
20static constexpr uint32_t REPEAT_PERIOD_MS = 80;
21
22static const char* TAG = "SliderView";
23
27static constexpr int TITLE_Y = 20;
28static constexpr int VALUE_Y = 55;
29static constexpr int BAR_Y = 85;
30static constexpr int BAR_HEIGHT = 20;
31static constexpr int BAR_MARGIN = 20;
32
33namespace cdc::ui {
34
45void SliderView::init(const char* title, uint16_t minVal, uint16_t maxVal,
46 uint16_t initial, uint16_t step, const char* unit) {
47 title_ = title;
48 minValue_ = minVal;
49 maxValue_ = maxVal;
50 value_ = std::clamp(initial, minVal, maxVal);
51 step_ = step > 0 ? step : 1;
52 unit_ = unit;
53 displayOffset_ = 0;
54 zeroLabel_ = nullptr;
55 onCancel_ = nullptr;
56 dirty_ = true;
57}
58
64void SliderView::setValue(uint16_t value) {
65 value = std::clamp(value, minValue_, maxValue_);
66 if (value_ != value) {
67 value_ = value;
68 dirty_ = true;
69 }
70}
71
77void SliderView::adjust(bool increase) {
78 uint16_t newValue = value_;
79
80 // Get step size (dynamic or fixed)
81 uint16_t currentStep = stepCallback_ ? stepCallback_(value_, increase) : step_;
82
83 if (increase) {
84 uint16_t next = value_ + currentStep;
85 newValue = (next > maxValue_) ? maxValue_ : next;
86 } else {
87 newValue = (value_ > currentStep) ? value_ - currentStep : minValue_;
88 }
89
90 if (newValue != value_) {
91 value_ = newValue;
92 dirty_ = true;
93 LOG_D(TAG, "Slider adjusted to %d (step=%d)", value_, currentStep);
94
95 // Call change callback for real-time updates (e.g., brightness preview)
96 if (onChange_) {
97 onChange_(value_);
98 }
99 }
100}
101
108 switch (key) {
109 case '6': // Right = Increase
110 adjust(true);
111 repeatStartMs_ = 0;
113
114 case '4': // Left = Decrease
115 adjust(false);
116 repeatStartMs_ = 0;
118
119 case KEY_YES: // Save
121 if (onSave_) {
122 onSave_(value_);
123 }
125
126 case KEY_NO: // Cancel
128 if (onCancel_) {
129 onCancel_();
130 }
132
133 default:
135 }
136}
137
138void SliderView::onTick(uint32_t nowMs) {
139 auto* kp = cdc::hal::getKeypadInstance();
140 if (!kp) return;
141
142 bool keyLeft = kp->isKeyPressed(cdc::hal::Key::KEY_4);
143 bool keyRight = kp->isKeyPressed(cdc::hal::Key::KEY_6);
144
145 if (!keyLeft && !keyRight) {
146 repeatStartMs_ = 0;
147 return;
148 }
149
150 if (repeatStartMs_ == 0) {
151 repeatStartMs_ = nowMs;
152 lastRepeatMs_ = nowMs;
153 return;
154 }
155
156 if (nowMs - repeatStartMs_ < REPEAT_INITIAL_MS) return;
157 if (nowMs - lastRepeatMs_ < REPEAT_PERIOD_MS) return;
158
159 lastRepeatMs_ = nowMs;
160 adjust(keyRight);
161}
162
167const char* SliderView::getFooterHint() const {
168 return ui::tr("core.hint_brightness");
169}
170
176void SliderView::render(bool partial) {
178 if (!display) return;
179
180 auto* gfx = static_cast<Gdey029T94*>(display->getNativeHandle());
181 if (!gfx) return;
182
183 const uint16_t width = display->getWidth();
184 const uint16_t height = display->getHeight();
185
186 if (!partial) {
187 gfx->fillScreen(EPD_WHITE);
188 }
189
190 gfx->setTextColor(EPD_BLACK);
191
192 // Title (centered)
193 if (title_) {
194 gfx->setTextSize(1);
195 render::drawHeaderCentered(gfx, title_, TITLE_Y, width);
196 }
197
198 // Value display (centered, larger)
199 char valueStr[32];
200 int16_t displayValue = static_cast<int16_t>(value_) + displayOffset_;
201
202 if (value_ == 0 && zeroLabel_) {
203 // Special label for zero
204 snprintf(valueStr, sizeof(valueStr), "%s", zeroLabel_);
205 } else if (unit_) {
206 snprintf(valueStr, sizeof(valueStr), "%d %s", displayValue, unit_);
207 } else {
208 snprintf(valueStr, sizeof(valueStr), "%d", displayValue);
209 }
210
211 gfx->setTextSize(2);
212 int16_t x1, y1;
213 uint16_t w, h;
214 gfx->getTextBounds(valueStr, 0, 0, &x1, &y1, &w, &h);
215 gfx->fillRect(0, VALUE_Y - 5, width, h + 10, EPD_WHITE);
216 gfx->setCursor((width - w) / 2, VALUE_Y);
217 gfx->print(valueStr);
218
219 int barWidth = width - 2 * BAR_MARGIN;
220 gfx->drawRect(BAR_MARGIN, BAR_Y, barWidth, BAR_HEIGHT, EPD_BLACK);
221
222 int fillWidth = 0;
223 if (maxValue_ > minValue_) {
224 fillWidth = (value_ - minValue_) * (barWidth - 4) / (maxValue_ - minValue_);
225 }
226 gfx->fillRect(BAR_MARGIN + 2, BAR_Y + 2, fillWidth, BAR_HEIGHT - 4, EPD_BLACK);
227
228 // Draw horizontal arrow indicators [4] < ... > [6]
229 gfx->setTextSize(1);
230
231 // Left arrow and [4] label
232 int arrowY = BAR_Y + BAR_HEIGHT / 2;
233 gfx->fillTriangle(
234 BAR_MARGIN - 15, arrowY,
235 BAR_MARGIN - 5, arrowY - 5,
236 BAR_MARGIN - 5, arrowY + 5,
237 EPD_BLACK
238 );
239 gfx->setCursor(BAR_MARGIN - 17, BAR_Y + BAR_HEIGHT + 8);
240 gfx->print("[4]");
241
242 // Right arrow and [6] label
243 int barRight = BAR_MARGIN + barWidth;
244 gfx->fillTriangle(
245 barRight + 15, arrowY,
246 barRight + 5, arrowY - 5,
247 barRight + 5, arrowY + 5,
248 EPD_BLACK
249 );
250 gfx->setCursor(barRight + 5, BAR_Y + BAR_HEIGHT + 8);
251 gfx->print("[6]");
252
253 const char* hint = getFooterHint();
254 render::drawFooterBar(gfx, width, height, nullptr, hint, false);
255
256 dirty_ = false;
257}
258
262
264
277SliderView* showSlider(const char* title, uint16_t minVal, uint16_t maxVal,
278 uint16_t initial, uint16_t step, const char* unit,
281 s_sharedSlider.init(title, minVal, maxVal, initial, step, unit);
282 s_sharedSlider.setOnSave(onSave);
283 if (onChange) {
284 s_sharedSlider.setOnChange(onChange);
285 }
287 return &s_sharedSlider;
288}
289
290} // namespace cdc::ui
static const char * TAG
static constexpr uint32_t REPEAT_PERIOD_MS
static constexpr uint32_t REPEAT_INITIAL_MS
Internationalization with English fallbacks in code and overlay translations loaded at runtime from a...
static constexpr int TITLE_Y
Display layout constants.
static constexpr int VALUE_Y
static constexpr int BAR_HEIGHT
static constexpr int BAR_Y
static constexpr int BAR_MARGIN
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_D(tag, fmt,...)
Definition cdc_log.h:148
const char * getFooterHint() const override
Returns localized footer hint text.
InputResult onKey(char key) override
Handles key input for slider adjustment and confirmation.
void onTick(uint32_t nowMs) override
void setValue(uint16_t value)
Sets slider value with range clamping.
void(*)(uint16_t value) ChangeCallback
Definition SliderView.h:32
void init(const char *title, uint16_t minVal, uint16_t maxVal, uint16_t initial, uint16_t step, const char *unit=nullptr)
Initializes slider bounds, value, and display options.
void render(bool partial) override
Renders slider title, value text, progress bar, and footer.
void(*)(uint16_t value) SaveCallback
Definition SliderView.h:26
static ViewStack & instance()
Returns singleton view-stack instance.
Definition ViewStack.cpp:34
void push(IView *view, void *context=nullptr)
IDisplay * getDisplayInstance()
Returns lazily created singleton display instance.
IKeypad * getKeypadInstance()
Returns the singleton keypad service instance.
void drawFooterBar(Gdey029T94 *gfx, uint16_t width, uint16_t height, const char *prefix, const char *hint, bool force=false)
Draws footer bar with optional prefix and hint text.
void drawHeaderCentered(Gdey029T94 *gfx, const char *title, int y, uint16_t width)
Draws a centered header title.
Centralized key-code constants for cdc_views.
Definition IModule.h:8
const char * tr(const char *key)
Look up a translation by string key.
Definition I18n.h:208
Gdey029T94 * display
InputResult
Definition IView.h:10
static constexpr char KEY_NO
Cancel / Back / Backspace.
Definition KeyCodes.h:44
static constexpr int TITLE_Y
Layout constants mirror the ones used by T9InputView.
static SliderView s_sharedSlider
Convenience factory/helper function.
SliderView * showSlider(const char *title, uint16_t minVal, uint16_t maxVal, uint16_t initial, uint16_t step, const char *unit, SliderView::SaveCallback onSave, SliderView::ChangeCallback onChange=nullptr)
Shows a shared slider view instance.
static constexpr char KEY_YES
Confirm / OK / Save.
Definition KeyCodes.h:41