CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
MessageBox.cpp
Go to the documentation of this file.
1
7
11#include "cdc_ui/ViewStack.h"
12#include "cdc_hal/IDisplay.h"
13#include "cdc_log.h"
14#include <goodisplay/gdey029T94.h>
15#include <cstring>
16
17static const char* TAG = "MessageBox";
18
22static constexpr int BOX_PADDING = 12;
23static constexpr int ICON_SIZE = 16;
24static constexpr int ICON_MARGIN = 8;
25static constexpr int MIN_BOX_WIDTH = 120;
26static constexpr int MAX_BOX_WIDTH = 260;
27
28namespace cdc::ui {
29
37void MessageBox::init(const char* message, MessageIcon icon, uint32_t timeoutMs) {
38 message_ = message;
39 icon_ = icon;
40 timeoutMs_ = timeoutMs;
41 startTimeMs_ = 0; // Will be set on first tick
42 onClose_ = nullptr;
43 dirty_ = true;
44
45 LOG_D(TAG, "init: msg='%s', icon=%d, timeout=%lu",
46 message ? message : "(null)", static_cast<int>(icon), timeoutMs);
47}
48
54void MessageBox::onTick(uint32_t nowMs) {
55 // Initialize start time on first tick
56 if (startTimeMs_ == 0) {
57 startTimeMs_ = nowMs;
58 }
59
60 // Check timeout
61 if (timeoutMs_ > 0 && (nowMs - startTimeMs_) >= timeoutMs_) {
62 LOG_D(TAG, "Timeout reached, hiding");
63 if (onClose_) {
64 onClose_();
65 }
67 }
68}
69
76 // Any key dismisses (Y or N)
77 if (key == KEY_YES || key == KEY_NO) {
78 LOG_D(TAG, "Key '%c' pressed, hiding", key);
79 if (onClose_) {
80 onClose_();
81 }
84 }
86}
87
93void MessageBox::render(bool partial) {
95 if (!display) return;
96
97 auto* gfx = static_cast<Gdey029T94*>(display->getNativeHandle());
98 if (!gfx) return;
99
100 const uint16_t screenWidth = display->getWidth();
101 const uint16_t screenHeight = display->getHeight();
102
103 // Calculate text dimensions
104 int16_t x1, y1;
105 uint16_t textWidth, textHeight;
106 gfx->setTextSize(1);
107
108 if (message_) {
109 gfx->getTextBounds(message_, 0, 0, &x1, &y1, &textWidth, &textHeight);
110 } else {
111 textWidth = 0;
112 textHeight = 12;
113 }
114
115 // Calculate box dimensions
116 uint16_t contentWidth = textWidth;
117 if (icon_ != MessageIcon::NONE) {
118 contentWidth += ICON_SIZE + ICON_MARGIN;
119 }
120
121 uint16_t boxWidth = contentWidth + BOX_PADDING * 2;
122 if (boxWidth < MIN_BOX_WIDTH) boxWidth = MIN_BOX_WIDTH;
123 if (boxWidth > MAX_BOX_WIDTH) boxWidth = MAX_BOX_WIDTH;
124
125 uint16_t boxHeight = textHeight + BOX_PADDING * 2;
126 if (boxHeight < 40) boxHeight = 40;
127
128 // Center the box
129 int boxX = (screenWidth - boxWidth) / 2;
130 int boxY = (screenHeight - boxHeight) / 2;
131
132 // Draw box background (white with black border)
133 render::drawDialogFrame(gfx, boxX, boxY, boxWidth, boxHeight);
134
135 // Calculate content position
136 int contentX = boxX + BOX_PADDING;
137 int contentY = boxY + (boxHeight - textHeight) / 2;
138
139 // Draw icon if present
140 if (icon_ != MessageIcon::NONE) {
141 int iconX = contentX;
142 int iconY = boxY + (boxHeight - ICON_SIZE) / 2;
143
144 switch (icon_) {
146 // Checkmark
147 gfx->drawLine(iconX + 2, iconY + 8, iconX + 6, iconY + 12, EPD_BLACK);
148 gfx->drawLine(iconX + 6, iconY + 12, iconX + 14, iconY + 4, EPD_BLACK);
149 gfx->drawLine(iconX + 2, iconY + 9, iconX + 6, iconY + 13, EPD_BLACK);
150 gfx->drawLine(iconX + 6, iconY + 13, iconX + 14, iconY + 5, EPD_BLACK);
151 break;
152
154 // X mark
155 gfx->drawLine(iconX + 2, iconY + 2, iconX + 14, iconY + 14, EPD_BLACK);
156 gfx->drawLine(iconX + 14, iconY + 2, iconX + 2, iconY + 14, EPD_BLACK);
157 gfx->drawLine(iconX + 3, iconY + 2, iconX + 14, iconY + 13, EPD_BLACK);
158 gfx->drawLine(iconX + 13, iconY + 2, iconX + 2, iconY + 13, EPD_BLACK);
159 break;
160
162 // Circle with "i"
163 gfx->drawCircle(iconX + 8, iconY + 8, 7, EPD_BLACK);
164 gfx->fillRect(iconX + 7, iconY + 4, 2, 2, EPD_BLACK); // Dot
165 gfx->fillRect(iconX + 7, iconY + 7, 2, 5, EPD_BLACK); // Line
166 break;
167
169 // Triangle with "!"
170 gfx->drawTriangle(
171 iconX + 8, iconY + 1,
172 iconX + 1, iconY + 14,
173 iconX + 15, iconY + 14,
174 EPD_BLACK
175 );
176 gfx->fillRect(iconX + 7, iconY + 5, 2, 5, EPD_BLACK); // Line
177 gfx->fillRect(iconX + 7, iconY + 11, 2, 2, EPD_BLACK); // Dot
178 break;
179
180 default:
181 break;
182 }
183
184 contentX += ICON_SIZE + ICON_MARGIN;
185 }
186
187 // Draw message text
188 gfx->setTextColor(EPD_BLACK);
189 gfx->setCursor(contentX, contentY);
190 if (message_) {
191 render::printText(gfx, message_);
192 }
193
194 dirty_ = false;
195}
196
200
202
211void showMessage(const char* message, MessageIcon icon,
212 uint32_t timeoutMs, MessageBox::CloseCallback onClose) {
213 s_sharedMessageBox.init(message, icon, timeoutMs);
214 s_sharedMessageBox.setOnClose(onClose);
216}
217
225
226} // namespace cdc::ui
static const char * TAG
static constexpr int MIN_BOX_WIDTH
static constexpr int MAX_BOX_WIDTH
static constexpr int BOX_PADDING
Layout constants.
static constexpr int ICON_MARGIN
static constexpr int ICON_SIZE
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_D(tag, fmt,...)
Definition cdc_log.h:148
void render(bool partial) override
Renders the modal message box.
void onTick(uint32_t nowMs) override
Updates timeout-based auto-dismiss behavior.
InputResult onKey(char key) override
Handles key input for manual dismissal.
void(*)() CloseCallback
Definition MessageBox.h:33
void init(const char *message, MessageIcon icon=MessageIcon::NONE, uint32_t timeoutMs=0)
Initializes message box state.
static ViewStack & instance()
Returns singleton view-stack instance.
Definition ViewStack.cpp:34
void showModal(IView *modal)
IDisplay * getDisplayInstance()
Returns lazily created singleton display instance.
void drawDialogFrame(Gdey029T94 *gfx, int x, int y, int w, int h)
Draws a framed dialog box with double border.
void printText(Gdey029T94 *gfx, const char *text)
Draws CP437 text with the built-in 6x8 glyph font, byte-for-byte.
Centralized key-code constants for cdc_views.
Definition IModule.h:8
static MessageBox s_sharedMessageBox
Convenience helper functions.
void hideMessage()
Hides the currently shown modal message box.
Gdey029T94 * display
InputResult
Definition IView.h:10
static constexpr char KEY_NO
Cancel / Back / Backspace.
Definition KeyCodes.h:44
static const char * TAG
static constexpr char KEY_YES
Confirm / OK / Save.
Definition KeyCodes.h:41
void showMessage(const char *message, MessageIcon icon=MessageIcon::NONE, uint32_t timeoutMs=0, MessageBox::CloseCallback onClose=nullptr)
Shows the shared modal message box.