fix for notification renderer

This commit is contained in:
HarukiToreda 2025-10-10 11:25:09 -04:00
parent 784e71f2fa
commit 163d8e0540

View File

@ -461,9 +461,9 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[], void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplayUiState *state, const char *lines[],
uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth) uint16_t totalLines, uint8_t firstOptionToShow, uint16_t maxWidth)
{ {
bool is_picker = false; bool is_picker = false;
uint16_t lineCount = 0; uint16_t lineCount = 0;
// Layout Configuration // Layout Configuration
constexpr uint16_t hPadding = 5; constexpr uint16_t hPadding = 5;
constexpr uint16_t vPadding = 2; constexpr uint16_t vPadding = 2;
@ -478,25 +478,26 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
// Measure all lines and calculate widest width // Track widest line INCLUDING bars (but don't change per-line widths)
uint16_t widestLineWithBars = 0; uint16_t widestLineWithBars = 0;
while (lines[lineCount] != nullptr) { while (lines[lineCount] != nullptr) {
auto newlinePointer = strchr(lines[lineCount], '\n'); auto newlinePointer = strchr(lines[lineCount], '\n');
if (newlinePointer) if (newlinePointer)
lineLengths[lineCount] = (newlinePointer - lines[lineCount]); // Check for newlines first lineLengths[lineCount] = (newlinePointer - lines[lineCount]); // Check for newlines first
else else // if the newline wasn't found, then pull string length from strlen
lineLengths[lineCount] = strlen(lines[lineCount]); // Fallback to strlen if no newline lineLengths[lineCount] = strlen(lines[lineCount]);
lineWidths[lineCount] = display->getStringWidth(lines[lineCount], lineLengths[lineCount], true); lineWidths[lineCount] = display->getStringWidth(lines[lineCount], lineLengths[lineCount], true);
// Calculate potential width including signal bars (without altering per-line widths) // Consider extra width for signal bars on lines that contain "Signal:"
uint16_t potentialWidth = lineWidths[lineCount]; uint16_t potentialWidth = lineWidths[lineCount];
if (bannerSignalBars >= 0 && strstr(lines[lineCount], "Signal:") != nullptr) { if (graphics::bannerSignalBars >= 0 && strstr(lines[lineCount], "Signal:") != nullptr) {
const int totalBars = 5; const int totalBars = 5;
const int barWidth = 3; const int barWidth = 3;
const int barSpacing = 2; const int barSpacing = 2;
int barsWidth = totalBars * barWidth + (totalBars - 1) * barSpacing + 6; const int gap = 6; // space between text and bars
int barsWidth = totalBars * barWidth + (totalBars - 1) * barSpacing + gap;
potentialWidth += barsWidth; potentialWidth += barsWidth;
} }
@ -510,8 +511,9 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
} }
lineCount++; lineCount++;
} }
// count lines
// Use widestLineWithBars to size the box if signal bars exist // Ensure box accounts for signal bars if present
if (widestLineWithBars > maxWidth) if (widestLineWithBars > maxWidth)
maxWidth = widestLineWithBars; maxWidth = widestLineWithBars;
@ -567,48 +569,111 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
// Draw Content // Draw Content
int16_t lineY = boxTop + vPadding; int16_t lineY = boxTop + vPadding;
int swingRange = 8;
static int swingOffset = 0;
static bool swingRight = true;
static unsigned long lastSwingTime = 0;
unsigned long now = millis();
int swingSpeedMs = 10 / (swingRange * 2);
if (now - lastSwingTime >= (unsigned long)swingSpeedMs) {
lastSwingTime = now;
if (swingRight) {
swingOffset++;
if (swingOffset >= swingRange)
swingRight = false;
} else {
swingOffset--;
if (swingOffset <= 0)
swingRight = true;
}
}
for (int i = 0; i < lineCount; i++) { for (int i = 0; i < lineCount; i++) {
bool isTitle = (i == 0);
int globalOptionIndex = (i - 1) + firstOptionToShow;
bool isSelectedOption = (!isTitle && globalOptionIndex >= 0 && globalOptionIndex == curSelected);
uint16_t visibleWidth = 64 - hPadding * 2;
if (totalLines > visibleTotalLines)
visibleWidth -= 6;
char lineBuffer[lineLengths[i] + 1]; char lineBuffer[lineLengths[i] + 1];
strncpy(lineBuffer, lines[i], lineLengths[i]); strncpy(lineBuffer, lines[i], lineLengths[i]);
lineBuffer[lineLengths[i]] = '\0'; lineBuffer[lineLengths[i]] = '\0';
bool isSignalLine = (bannerSignalBars >= 0 && strstr(lineBuffer, "Signal:") != nullptr); if (isTitle) {
if (visibleTotalLines == 1) {
if (isSignalLine) { display->setColor(BLACK);
// Center text + signal bars as a single group display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
const int totalBars = 5; display->setColor(WHITE);
const int barWidth = 3; display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
const int barSpacing = 2; } else {
const int barHeightStep = 2; display->setColor(WHITE);
display->fillRect(boxLeft, boxTop, boxWidth, effectiveLineHeight);
int textWidth = display->getStringWidth(lineBuffer, strlen(lineBuffer), true); display->setColor(BLACK);
int barsWidth = totalBars * barWidth + (totalBars - 1) * barSpacing + 6; display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, boxTop, lineBuffer);
int totalWidth = textWidth + barsWidth; display->setColor(WHITE);
if (needs_bell) {
int groupStartX = boxLeft + (boxWidth - totalWidth) / 2; int bellY = boxTop + (FONT_HEIGHT_SMALL - 8) / 2;
display->drawXbm(boxLeft + (boxWidth - lineWidths[i]) / 2 - 10, bellY, 8, 8, bell_alert);
display->drawString(groupStartX, lineY, lineBuffer); display->drawXbm(boxLeft + (boxWidth + lineWidths[i]) / 2 + 2, bellY, 8, 8, bell_alert);
int baseX = groupStartX + textWidth + 6;
int baseY = lineY + effectiveLineHeight - 1;
for (int b = 0; b < totalBars; b++) {
int barHeight = (b + 1) * barHeightStep;
int x = baseX + b * (barWidth + barSpacing);
int y = baseY - barHeight;
if (b < bannerSignalBars) {
display->fillRect(x, y, barWidth, barHeight);
} else {
display->drawRect(x, y, barWidth, barHeight);
} }
} }
lineY = boxTop + effectiveLineHeight + 1;
} else if (isSelectedOption) {
display->setColor(WHITE);
display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
display->setColor(BLACK);
if (lineLengths[i] > 15 && lineWidths[i] > visibleWidth) {
int textX = boxLeft + hPadding + swingOffset;
display->drawString(textX, lineY - 1, lineBuffer);
} else {
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY - 1, lineBuffer);
}
display->setColor(WHITE);
lineY += effectiveLineHeight;
} else { } else {
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2; // Draw non-selected, non-title lines
display->drawString(textX, lineY, lineBuffer); display->setColor(BLACK);
} display->fillRect(boxLeft, lineY, boxWidth, effectiveLineHeight);
display->setColor(WHITE);
lineY += effectiveLineHeight; // If this is the Signal line, center text + bars as one group
bool isSignalLine = (graphics::bannerSignalBars >= 0 && strstr(lineBuffer, "Signal:") != nullptr);
if (isSignalLine) {
const int totalBars = 5;
const int barWidth = 3;
const int barSpacing = 2;
const int barHeightStep = 2;
const int gap = 6;
int textWidth = display->getStringWidth(lineBuffer, strlen(lineBuffer), true);
int barsWidth = totalBars * barWidth + (totalBars - 1) * barSpacing + gap;
int totalWidth = textWidth + barsWidth;
int groupStartX = boxLeft + (boxWidth - totalWidth) / 2;
// Draw the "Signal: ..." text
display->drawString(groupStartX, lineY, lineBuffer);
// Draw the bars
int baseX = groupStartX + textWidth + gap;
int baseY = lineY + effectiveLineHeight - 1;
for (int b = 0; b < totalBars; b++) {
int barHeight = (b + 1) * barHeightStep;
int x = baseX + b * (barWidth + barSpacing);
int y = baseY - barHeight;
if (b < graphics::bannerSignalBars) {
display->fillRect(x, y, barWidth, barHeight);
} else {
display->drawRect(x, y, barWidth, barHeight);
}
}
} else {
// Normal centered line
display->drawString(boxLeft + (boxWidth - lineWidths[i]) / 2, lineY, lineBuffer);
}
lineY += effectiveLineHeight;
}
} }
// Scroll Bar (Thicker, inside box, not over title) // Scroll Bar (Thicker, inside box, not over title)
@ -671,47 +736,66 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
// Draw Content // Draw Content
int16_t lineY = boxTop + vPadding; int16_t lineY = boxTop + vPadding;
for (int i = 0; i < lineCount; i++) { for (int i = 0; i < lineCount; i++) {
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
if (needs_bell && i == 0) {
int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2;
display->drawXbm(textX - 10, bellY, 8, 8, bell_alert);
display->drawXbm(textX + lineWidths[i] + 2, bellY, 8, 8, bell_alert);
}
char lineBuffer[lineLengths[i] + 1]; char lineBuffer[lineLengths[i] + 1];
strncpy(lineBuffer, lines[i], lineLengths[i]); strncpy(lineBuffer, lines[i], lineLengths[i]);
lineBuffer[lineLengths[i]] = '\0'; lineBuffer[lineLengths[i]] = '\0';
// Determine if this is a pop-up or a pick list
bool isSignalLine = (bannerSignalBars >= 0 && strstr(lineBuffer, "Signal:") != nullptr); if (alertBannerOptions > 0 && i == 0) {
// Pick List
if (isSignalLine) { display->setColor(WHITE);
// Center text + signal bars as a single group int background_yOffset = 1;
const int totalBars = 5; // Determine if we have low hanging characters
const int barWidth = 3; if (strchr(lineBuffer, 'p') || strchr(lineBuffer, 'g') || strchr(lineBuffer, 'y') || strchr(lineBuffer, 'j')) {
const int barSpacing = 2; background_yOffset = -1;
const int barHeightStep = 2;
int textWidth = display->getStringWidth(lineBuffer, strlen(lineBuffer), true);
int barsWidth = totalBars * barWidth + (totalBars - 1) * barSpacing + 6;
int totalWidth = textWidth + barsWidth;
int groupStartX = boxLeft + (boxWidth - totalWidth) / 2;
display->drawString(groupStartX, lineY, lineBuffer);
int baseX = groupStartX + textWidth + 6;
int baseY = lineY + effectiveLineHeight - 1;
for (int b = 0; b < totalBars; b++) {
int barHeight = (b + 1) * barHeightStep;
int x = baseX + b * (barWidth + barSpacing);
int y = baseY - barHeight;
if (b < bannerSignalBars) {
display->fillRect(x, y, barWidth, barHeight);
} else {
display->drawRect(x, y, barWidth, barHeight);
}
} }
display->fillRect(boxLeft, boxTop + 1, boxWidth, effectiveLineHeight - background_yOffset);
display->setColor(BLACK);
int yOffset = 3;
display->drawString(textX, lineY - yOffset, lineBuffer);
display->setColor(WHITE);
lineY += (effectiveLineHeight - 2 - background_yOffset);
} else { } else {
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2; // Pop-up
display->drawString(textX, lineY, lineBuffer); // If this is the Signal line, center text + bars as one group
} bool isSignalLine = (graphics::bannerSignalBars >= 0 && strstr(lineBuffer, "Signal:") != nullptr);
if (isSignalLine) {
const int totalBars = 5;
const int barWidth = 3;
const int barSpacing = 2;
const int barHeightStep = 2;
const int gap = 6;
lineY += effectiveLineHeight; int textWidth = display->getStringWidth(lineBuffer, strlen(lineBuffer), true);
int barsWidth = totalBars * barWidth + (totalBars - 1) * barSpacing + gap;
int totalWidth = textWidth + barsWidth;
int groupStartX = boxLeft + (boxWidth - totalWidth) / 2;
display->drawString(groupStartX, lineY, lineBuffer);
int baseX = groupStartX + textWidth + gap;
int baseY = lineY + effectiveLineHeight - 1;
for (int b = 0; b < totalBars; b++) {
int barHeight = (b + 1) * barHeightStep;
int x = baseX + b * (barWidth + barSpacing);
int y = baseY - barHeight;
if (b < graphics::bannerSignalBars) {
display->fillRect(x, y, barWidth, barHeight);
} else {
display->drawRect(x, y, barWidth, barHeight);
}
}
} else {
display->drawString(textX, lineY, lineBuffer);
}
lineY += (effectiveLineHeight);
}
} }
// Scroll Bar (Thicker, inside box, not over title) // Scroll Bar (Thicker, inside box, not over title)