mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
fix: e-ink portrait/landscape layout — separators, battery, keyboard, screens
- DisplayDriver: add sepH() (2px landscape, 1px OLED); fix transliterateCodepoint fallback '?' (was '\xDB' which broke UTF-8 word-wrap and rendered tiny block char) - GxEPDDisplay: drawRect draws double border on landscape for visible 2px weight - UITask: navigation dots scale with lh; content_y saves 16px by using dots_y+6; battery iconW=lh*2, fill margin bm scales with orientation; indicator spacing fixed; clock separator uses sepH(); alert popup tight and vertically centred - KeyboardWidget: compact cell height (no stretch), multi-line preview, cursor always on last visible line - BotScreen / NearbyScreen detail: use lineStep() as natural item height, shrink only when items don't fit (fixes portrait stretch) - QuickMsgScreen: send button pinned to display bottom (height-lh-2), not floating - SettingsScreen: AUTO_OFF guarded with #if AUTO_OFF_MILLIS>0; default sel=AUTO_LOCK - All screens: separators updated to sepH() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@ public:
|
||||
int tip_y = bar_y + bar_h + 4;
|
||||
|
||||
display.drawTextCentered(display.width() / 2, 0, "AUTO-ADVERT");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
display.setCursor(2, label_y);
|
||||
display.print("Interval:");
|
||||
|
||||
@@ -55,12 +55,14 @@ public:
|
||||
return _kb.render(display);
|
||||
}
|
||||
|
||||
int avail_h = display.height() - display.listStart();
|
||||
int item_h = display.lineStep();
|
||||
if (item_h * ITEM_COUNT > avail_h) item_h = avail_h / ITEM_COUNT;
|
||||
int start_y = display.listStart();
|
||||
int val_x = display.valCol();
|
||||
|
||||
display.drawTextCentered(display.width() / 2, 0, "AUTO-REPLY BOT");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
static const char* labels[] = { "Enable", "Channel", "Trigger", "Reply DM", "Reply Ch" };
|
||||
for (int i = 0; i < ITEM_COUNT; i++) {
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
int val_x = display.valCol();
|
||||
|
||||
display.drawTextCentered(display.width() / 2, 0, "CLOCK FIELDS");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
static const char* labels[] = { "Field 1", "Field 2", "Field 3" };
|
||||
for (int i = 0; i < FIELD_SLOTS; i++) {
|
||||
|
||||
@@ -61,22 +61,39 @@ struct KeyboardWidget {
|
||||
const int lh = display.getLineHeight();
|
||||
const int cw = display.getCharWidth();
|
||||
const int cell_w = display.width() / KB_COLS_CHAR;
|
||||
const int sep_y = lh; // tight separator: preview row height only
|
||||
// compact: don't stretch cells beyond lh; freed vertical space goes to preview lines
|
||||
const int kb_h = (KB_ROWS_CHAR + 1) * lh;
|
||||
const int preview_h = display.height() - kb_h - 1;
|
||||
const int prev_lines = (preview_h / lh) > 1 ? (preview_h / lh) : 1;
|
||||
const int sep_y = prev_lines * lh;
|
||||
const int chars_y = sep_y + 1;
|
||||
const int cell_h = (display.height() - chars_y) / (KB_ROWS_CHAR + 1);
|
||||
const int spec_y = chars_y + KB_ROWS_CHAR * cell_h;
|
||||
const int spec_w = display.width() / KB_SPECIAL;
|
||||
|
||||
// text preview: last N chars + cursor (fit within screen width)
|
||||
int max_preview = display.width() / cw - 1;
|
||||
if (max_preview > 30) max_preview = 30;
|
||||
const char* disp_start = buf;
|
||||
int disp_len = len;
|
||||
if (disp_len > max_preview) { disp_start = buf + (disp_len - max_preview); disp_len = max_preview; }
|
||||
char preview[32];
|
||||
snprintf(preview, sizeof(preview), "%.*s_", disp_len, disp_start);
|
||||
display.setCursor(0, 0);
|
||||
display.print(preview);
|
||||
// multi-line text preview: cursor always on last preview line
|
||||
int cpl = display.width() / cw; // chars per preview line
|
||||
if (cpl < 1) cpl = 1;
|
||||
int cursor_line = len / cpl;
|
||||
int first_line = (cursor_line >= prev_lines) ? (cursor_line - prev_lines + 1) : 0;
|
||||
int start = first_line * cpl;
|
||||
for (int pl = 0; pl < prev_lines; pl++) {
|
||||
int ps = start + pl * cpl;
|
||||
int pe = ps + cpl;
|
||||
bool cursor_here = (ps <= len && (len < pe || pl == prev_lines - 1));
|
||||
char linebuf[32];
|
||||
if (cursor_here) {
|
||||
int nc = len - ps; if (nc < 0) nc = 0; if (nc > cpl - 1) nc = cpl - 1;
|
||||
snprintf(linebuf, sizeof(linebuf), "%.*s_", nc, buf + ps);
|
||||
} else if (len > ps) {
|
||||
int nc = (len < pe) ? (len - ps) : cpl;
|
||||
snprintf(linebuf, sizeof(linebuf), "%.*s", nc, buf + ps);
|
||||
} else {
|
||||
linebuf[0] = '\0';
|
||||
}
|
||||
display.setCursor(0, pl * lh);
|
||||
display.print(linebuf);
|
||||
}
|
||||
display.fillRect(0, sep_y, display.width(), 1);
|
||||
|
||||
// character grid
|
||||
|
||||
@@ -234,8 +234,9 @@ class NearbyScreen : public UIScreen {
|
||||
display.print(b64_line);
|
||||
}
|
||||
|
||||
// distribute 4 remaining lines across available height below b64
|
||||
int step = (display.height() - hdr) / 5;
|
||||
// distribute 4 remaining lines below b64 — compact step, shrink only if needed
|
||||
int step = display.lineStep();
|
||||
if (step * 5 > display.height() - hdr) step = (display.height() - hdr) / 5;
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "RSSI: %d dBm", (int)r.rssi);
|
||||
display.setCursor(2, hdr + step); display.print(buf);
|
||||
@@ -419,8 +420,9 @@ public:
|
||||
display.drawTextEllipsized(2, 1, display.width() - 4, filtered);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
|
||||
// 5 lines: lat, lon, dist+bearing, type, seen — distributed across available height
|
||||
int step = (display.height() - hdr) / 5;
|
||||
// 5 lines: lat, lon, dist+bearing, type, seen — compact step, shrink only if needed
|
||||
int step = display.lineStep();
|
||||
if (step * 5 > display.height() - hdr) step = (display.height() - hdr) / 5;
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "Lat: %.5f", e.lat_e6 / 1e6);
|
||||
display.setCursor(2, hdr); display.print(buf);
|
||||
@@ -459,7 +461,7 @@ public:
|
||||
char title[22];
|
||||
snprintf(title, sizeof(title), "NEARBY[%s]", FILTER_LABELS[_filter]);
|
||||
display.drawTextCentered(display.width() / 2, 0, title);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
if (_count == 0) {
|
||||
display.drawTextCentered(display.width() / 2, display.height() / 2 - display.lineStep() / 2, "No contacts found");
|
||||
|
||||
@@ -468,7 +468,7 @@ public:
|
||||
|
||||
if (_phase == MODE_SELECT) {
|
||||
display.drawTextCentered(display.width()/2, 0, "MESSAGE");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
const char* opts[] = { "Direct message", "Channels", "Room Servers" };
|
||||
int badges[3] = {
|
||||
getDMUnreadTotal(),
|
||||
@@ -501,7 +501,7 @@ public:
|
||||
|
||||
} else if (_phase == CONTACT_PICK) {
|
||||
display.drawTextCentered(display.width()/2, 0, _room_mode ? "SELECT ROOM" : "SELECT CONTACT");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
if (_num_contacts == 0) {
|
||||
display.drawTextCentered(display.width()/2, display.height()/2, _room_mode ? "No room servers" : "No favourites");
|
||||
@@ -551,7 +551,7 @@ public:
|
||||
|
||||
} else if (_phase == CHANNEL_PICK) {
|
||||
display.drawTextCentered(display.width()/2, 0, "SELECT CHANNEL");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
if (_num_channels == 0) {
|
||||
display.drawTextCentered(display.width()/2, display.height()/2, "No channels");
|
||||
@@ -618,15 +618,16 @@ public:
|
||||
int hist_box_h = 2 * lh + 3;
|
||||
int hist_item_h = hist_box_h + 2;
|
||||
int hist_start_y = display.headerH();
|
||||
_hist_visible = (display.height() - hist_start_y) / hist_item_h;
|
||||
int btn_h = lh + 4;
|
||||
_hist_visible = (display.height() - hist_start_y - btn_h) / hist_item_h;
|
||||
if (_hist_visible < 1) _hist_visible = 1;
|
||||
int cby = hist_start_y + _hist_visible * hist_item_h + 2;
|
||||
int cby = display.height() - lh - 2;
|
||||
|
||||
char title[24];
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
snprintf(title, sizeof(title), "%.23s", filtered_name);
|
||||
display.drawTextCentered(display.width()/2, 0, title);
|
||||
display.fillRect(0, lh + 1, display.width(), 1);
|
||||
display.fillRect(0, lh + 1, display.width(), display.sepH());
|
||||
|
||||
int dm_count = dmHistCountForContact(_sel_contact.id.pub_key);
|
||||
|
||||
@@ -720,16 +721,17 @@ public:
|
||||
int hist_box_h = 2 * lh + 3;
|
||||
int hist_item_h = hist_box_h + 2;
|
||||
int hist_start_y = display.headerH();
|
||||
_hist_visible = (display.height() - hist_start_y) / hist_item_h;
|
||||
int btn_h = lh + 4;
|
||||
_hist_visible = (display.height() - hist_start_y - btn_h) / hist_item_h;
|
||||
if (_hist_visible < 1) _hist_visible = 1;
|
||||
int cby = hist_start_y + _hist_visible * hist_item_h + 2;
|
||||
int cby = display.height() - lh - 2;
|
||||
|
||||
ChannelDetails ch;
|
||||
the_mesh.getChannel(_sel_channel_idx, ch);
|
||||
char title[24];
|
||||
snprintf(title, sizeof(title), "%.23s", ch.name);
|
||||
display.drawTextCentered(display.width()/2, 0, title);
|
||||
display.fillRect(0, lh + 1, display.width(), 1);
|
||||
display.fillRect(0, lh + 1, display.width(), display.sepH());
|
||||
|
||||
int ch_hist_count = histCountForChannel(_sel_channel_idx);
|
||||
|
||||
@@ -832,7 +834,7 @@ public:
|
||||
snprintf(title, sizeof(title), "TO:%.14s", _sel_contact.name);
|
||||
}
|
||||
display.drawTextCentered(display.width()/2, 0, title);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
int total_msg_items = 1 + _active_msg_count;
|
||||
for (int i = 0; i < _visible && (_msg_scroll+i) < total_msg_items; i++) {
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
snprintf(hdr, sizeof(hdr), "M%d BPM:%u %d/%d", _slot + 1, BPM_OPTS[_bpm_idx], _len, MAX_NOTES);
|
||||
display.setCursor(0, 0);
|
||||
display.print(hdr);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
for (int i = 0; i < _visible_notes; i++) {
|
||||
int ni = _scroll + i;
|
||||
|
||||
@@ -11,7 +11,9 @@ class SettingsScreen : public UIScreen {
|
||||
#if !defined(EINK_DISPLAY_MODEL)
|
||||
BRIGHTNESS,
|
||||
#endif
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
AUTO_OFF,
|
||||
#endif
|
||||
AUTO_LOCK,
|
||||
BATT_DISPLAY,
|
||||
#if !defined(EINK_DISPLAY_MODEL)
|
||||
@@ -64,9 +66,11 @@ class SettingsScreen : public UIScreen {
|
||||
int _visible; // items fitting on screen; updated each render, used by handleInput
|
||||
bool _dirty;
|
||||
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
static const uint16_t AUTO_OFF_OPTS[5];
|
||||
static const char* AUTO_OFF_LABELS[5];
|
||||
static const int AUTO_OFF_COUNT = 5;
|
||||
#endif
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
static const uint32_t GPS_INTERVAL_OPTS[6];
|
||||
static const char* GPS_INTERVAL_LABELS[6];
|
||||
@@ -101,6 +105,7 @@ class SettingsScreen : public UIScreen {
|
||||
}
|
||||
}
|
||||
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
int autoOffIndex() {
|
||||
NodePrefs* p = _task->getNodePrefs();
|
||||
if (!p) return 1;
|
||||
@@ -108,6 +113,7 @@ class SettingsScreen : public UIScreen {
|
||||
if (AUTO_OFF_OPTS[i] == p->auto_off_secs) return i;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
int gpsIntervalIndex() {
|
||||
@@ -289,10 +295,12 @@ class SettingsScreen : public UIScreen {
|
||||
sprintf(buf, "%ddBm", p ? p->tx_power_dbm : 0);
|
||||
display.setCursor(display.valCol(), y);
|
||||
display.print(buf);
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
} else if (item == AUTO_OFF) {
|
||||
display.print("AutoOff");
|
||||
display.setCursor(display.valCol(), y);
|
||||
display.print(AUTO_OFF_LABELS[autoOffIndex()]);
|
||||
#endif
|
||||
} else if (item == AUTO_LOCK) {
|
||||
display.print("AutoLock");
|
||||
display.setCursor(display.valCol(), y);
|
||||
@@ -367,7 +375,7 @@ class SettingsScreen : public UIScreen {
|
||||
|
||||
public:
|
||||
SettingsScreen(UITask* task)
|
||||
: _task(task), _selected(AUTO_OFF), _scroll(0), _visible(4), _dirty(false), _edit_slot(-1) {}
|
||||
: _task(task), _selected(AUTO_LOCK), _scroll(0), _visible(4), _dirty(false), _edit_slot(-1) {}
|
||||
|
||||
|
||||
void markClean() { _dirty = false; }
|
||||
@@ -385,7 +393,7 @@ public:
|
||||
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.drawTextCentered(display.width() / 2, 0, "SETTINGS");
|
||||
display.fillRect(0, display.headerH() - 2, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - display.sepH(), display.width(), display.sepH());
|
||||
|
||||
for (int i = 0; i < _visible && (_scroll + i) < SettingItem::Count; i++) {
|
||||
renderItem(display, _scroll + i, start_y + i * item_h);
|
||||
@@ -489,12 +497,14 @@ public:
|
||||
if (right && p->tx_power_dbm < 22) { p->tx_power_dbm++; _task->applyTxPower(); _dirty = true; return true; }
|
||||
if (left && p->tx_power_dbm > 2) { p->tx_power_dbm--; _task->applyTxPower(); _dirty = true; return true; }
|
||||
}
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
if (_selected == AUTO_OFF && p) {
|
||||
int idx = autoOffIndex();
|
||||
if (right) idx = (idx + 1) % AUTO_OFF_COUNT;
|
||||
if (left) idx = (idx + AUTO_OFF_COUNT - 1) % AUTO_OFF_COUNT;
|
||||
if (left || right) { p->auto_off_secs = AUTO_OFF_OPTS[idx]; _dirty = true; return true; }
|
||||
}
|
||||
#endif
|
||||
if (_selected == AUTO_LOCK && p && (left || right || enter)) {
|
||||
p->auto_lock ^= 1;
|
||||
_dirty = true;
|
||||
@@ -576,8 +586,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
const uint16_t SettingsScreen::AUTO_OFF_OPTS[5] = { 5, 15, 30, 60, 0 };
|
||||
const char* SettingsScreen::AUTO_OFF_LABELS[5] = { "5s", "15s", "30s", "60s", "never" };
|
||||
#endif
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
const uint32_t SettingsScreen::GPS_INTERVAL_OPTS[6] = { 0, 30, 60, 300, 900, 1800 };
|
||||
const char* SettingsScreen::GPS_INTERVAL_LABELS[6] = { "off", "30s", "1min", "5min", "15min", "30min" };
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
display.setTextSize(1);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.drawTextCentered(display.width() / 2, 0, "TOOLS");
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), 1);
|
||||
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
||||
|
||||
int item_h = display.lineStep();
|
||||
int start_y = display.listStart();
|
||||
|
||||
@@ -240,9 +240,10 @@ class HomeScreen : public UIScreen {
|
||||
display.setTextSize(1);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
|
||||
const int lh = display.getLineHeight();
|
||||
const int cw = display.getCharWidth();
|
||||
const int ind = cw + 2; // single-char indicator width
|
||||
const int lh = display.getLineHeight();
|
||||
const int cw = display.getCharWidth();
|
||||
const int ind = cw + 2; // single-char indicator width
|
||||
const int ind_gap = (lh >= 16) ? 3 : 1; // gap between indicator boxes
|
||||
|
||||
int battLeftX;
|
||||
if (mode == 1) { // percent
|
||||
@@ -259,18 +260,19 @@ class HomeScreen : public UIScreen {
|
||||
display.print(buf);
|
||||
} else { // icon — scales with lh
|
||||
const int iconH = lh;
|
||||
const int iconW = iconH * 3;
|
||||
const int iconW = lh * 2;
|
||||
const int bm = (lh >= 16) ? 3 : 2; // inner margin: 3px on landscape (2px border), 2px on OLED
|
||||
battLeftX = display.width() - iconW - 3;
|
||||
display.drawRect(battLeftX, 0, iconW, iconH);
|
||||
display.fillRect(battLeftX + iconW, iconH / 4, 2, iconH / 2);
|
||||
int fillW = (pct * (iconW - 4)) / 100;
|
||||
display.fillRect(battLeftX + 2, 2, fillW, iconH - 4);
|
||||
int fillW = (pct * (iconW - 2 * bm)) / 100;
|
||||
display.fillRect(battLeftX + bm, bm, fillW, iconH - 2 * bm);
|
||||
}
|
||||
|
||||
#ifdef PIN_BUZZER
|
||||
if (_task->isBuzzerQuiet()) {
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
int mx = battLeftX - ind - 1;
|
||||
int mx = battLeftX - ind - ind_gap;
|
||||
display.fillRect(mx, 0, ind, lh);
|
||||
display.setColor(DisplayDriver::DARK);
|
||||
display.setCursor(mx + 1, 0);
|
||||
@@ -283,7 +285,7 @@ class HomeScreen : public UIScreen {
|
||||
// BT connection indicator (left of muted/battery icons)
|
||||
int leftmostX = battLeftX;
|
||||
if (_task->isSerialEnabled()) {
|
||||
int btX = battLeftX - ind - 1;
|
||||
int btX = battLeftX - ind - ind_gap;
|
||||
if (_task->hasConnection()) {
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.fillRect(btX, 0, ind, lh);
|
||||
@@ -295,7 +297,7 @@ class HomeScreen : public UIScreen {
|
||||
display.setCursor(btX + 1, 0);
|
||||
display.print("b");
|
||||
}
|
||||
leftmostX = btX - 1;
|
||||
leftmostX = btX - ind_gap;
|
||||
|
||||
// "A" indicator — left of BT, blinks 50% duty at 4s period
|
||||
if (_node_prefs && _node_prefs->advert_auto_interval_sec > 0) {
|
||||
@@ -358,7 +360,7 @@ public:
|
||||
const int lh = display.getLineHeight(); // line height at sz1
|
||||
const int step = display.lineStep(); // lh + 2
|
||||
const int dots_y = lh + 4; // page-dot row: just below header
|
||||
const int content_y = dots_y + step; // first content row
|
||||
const int content_y = dots_y + 6; // first content row (6px gap keeps dots visible)
|
||||
|
||||
// node name + battery — hidden on CLOCK page (full screen used for dashboard)
|
||||
if (_page != CLOCK) {
|
||||
@@ -385,8 +387,9 @@ public:
|
||||
int vi = 0;
|
||||
for (int i = 0; i < (int)Count; i++) {
|
||||
if (!isPageVisible(i)) continue;
|
||||
if (vi == curr_vis) display.fillRect(x-1, dots_y-1, 3, 3);
|
||||
else display.fillRect(x, dots_y, 1, 1);
|
||||
int ds = (lh >= 16) ? 2 : 1;
|
||||
if (vi == curr_vis) display.fillRect(x-ds, dots_y-ds, 2*ds+1, 2*ds+1);
|
||||
else display.fillRect(x-ds+1, dots_y-ds+1, 2*ds-1, 2*ds-1);
|
||||
x += 10; vi++;
|
||||
}
|
||||
}
|
||||
@@ -431,8 +434,8 @@ public:
|
||||
display.drawTextCentered(display.width() / 2, date_y, buf);
|
||||
|
||||
int sep_y = date_y + lh + 1;
|
||||
int dash0 = sep_y + 3;
|
||||
display.fillRect(0, sep_y, display.width(), 1);
|
||||
int dash0 = sep_y + display.sepH() + 2;
|
||||
display.fillRect(0, sep_y, display.width(), display.sepH());
|
||||
|
||||
// dashboard data fields
|
||||
if (_node_prefs) {
|
||||
@@ -1448,13 +1451,17 @@ void UITask::loop() {
|
||||
int delay_millis = curr->render(*_display);
|
||||
if (millis() < _alert_expiry && curr == home) { // render alert only on home screen
|
||||
_display->setTextSize(1);
|
||||
int y = _display->height() / 3;
|
||||
int p = _display->height() / 32;
|
||||
int lh = _display->getLineHeight();
|
||||
int pad = 3;
|
||||
int box_h = lh + pad * 2;
|
||||
int box_w = _display->width() - 8;
|
||||
int box_x = 4;
|
||||
int box_y = (_display->height() - box_h) / 2;
|
||||
_display->setColor(DisplayDriver::DARK);
|
||||
_display->fillRect(p, y, _display->width() - p*2, y);
|
||||
_display->setColor(DisplayDriver::LIGHT); // draw box border
|
||||
_display->drawRect(p, y, _display->width() - p*2, y);
|
||||
_display->drawTextCentered(_display->width() / 2, y + p*3, _alert);
|
||||
_display->fillRect(box_x, box_y, box_w, box_h);
|
||||
_display->setColor(DisplayDriver::LIGHT);
|
||||
_display->drawRect(box_x, box_y, box_w, box_h);
|
||||
_display->drawTextCentered(_display->width() / 2, box_y + pad, _alert);
|
||||
_next_refresh = _alert_expiry; // will need refresh when alert is dismissed
|
||||
} else {
|
||||
_next_refresh = millis() + delay_millis;
|
||||
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
int listVisible() const { return listVisible(lineStep()); }
|
||||
// x where a right-side value column starts (leaves ~8 chars for the value)
|
||||
int valCol() const { return width() - getCharWidth() * 8; }
|
||||
// separator line thickness: 2px on landscape e-ink, 1px on OLED
|
||||
int sepH() const { return (width() >= height()) ? 2 : 1; }
|
||||
virtual void drawTextCentered(int mid_x, int y, const char* str) { // helper method (override to optimise)
|
||||
int w = getTextWidth(str);
|
||||
setCursor(mid_x - w/2, y);
|
||||
@@ -135,7 +137,7 @@ public:
|
||||
case 0x00E7: return 'c'; case 0x00C7: return 'C'; // ç Ç
|
||||
case 0x00F1: return 'n'; case 0x00D1: return 'N'; // ñ Ñ
|
||||
case 0x00FD: return 'y'; case 0x00DD: return 'Y'; // ý Ý
|
||||
default: return '\xDB'; // CP437 full block █
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,8 @@ void GxEPDDisplay::drawRect(int x, int y, int w, int h) {
|
||||
display_crc.update<int>(w);
|
||||
display_crc.update<int>(h);
|
||||
display.drawRect(x, y, w, h, _curr_color);
|
||||
if (width() >= height() && w > 2 && h > 2)
|
||||
display.drawRect(x + 1, y + 1, w - 2, h - 2, _curr_color);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
|
||||
|
||||
Reference in New Issue
Block a user