mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-18 09:21:43 +10:00
emdashes begone (#10847)
This commit is contained in:
+11
-11
@@ -2,9 +2,9 @@
|
||||
BaseUI
|
||||
|
||||
Developed and Maintained By:
|
||||
- Ronald Garcia (HarukiToreda) – Lead development and implementation.
|
||||
- JasonP (Xaositek) – Screen layout and icon design, UI improvements and testing.
|
||||
- TonyG (Tropho) – Project management, structural planning, and testing
|
||||
- Ronald Garcia (HarukiToreda) - Lead development and implementation.
|
||||
- JasonP (Xaositek) - Screen layout and icon design, UI improvements and testing.
|
||||
- TonyG (Tropho) - Project management, structural planning, and testing
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -126,7 +126,7 @@ static inline void prepareFrameColorRegions()
|
||||
// "LOCKED" plus battery so the operator can see the device is alive and
|
||||
// charged without leaking any node/channel/message/position content.
|
||||
// Draw the LOCKED frame into the host-side framebuffer. Does NOT commit
|
||||
// to the panel — the caller is responsible for calling display->display()
|
||||
// to the panel - the caller is responsible for calling display->display()
|
||||
// once it has composited any overlays on top. Committing here would cause
|
||||
// visible flicker between "just LOCKED" and "LOCKED + banner overlay" when
|
||||
// the pairing-PIN special-case in updateUiFrame paints the overlay after
|
||||
@@ -166,8 +166,8 @@ static inline void updateUiFrame(OLEDDisplayUi *ui)
|
||||
if (meshtastic_security::shouldRedactDisplay() && screen != nullptr) {
|
||||
OLEDDisplay *display = screen->getDisplayDevice();
|
||||
// Paint LOCKED into the framebuffer WITHOUT committing. We commit
|
||||
// exactly once at the bottom — after any overlay has been composed
|
||||
// on top — so the panel never visibly transitions from "just LOCKED"
|
||||
// exactly once at the bottom - after any overlay has been composed
|
||||
// on top - so the panel never visibly transitions from "just LOCKED"
|
||||
// to "LOCKED + overlay" mid-frame. Committing twice per cycle was
|
||||
// the source of the H13 flicker.
|
||||
drawLockdownLockScreenIntoBuffer(display);
|
||||
@@ -663,7 +663,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
// 16-50 ms before the next ui->update() lands. Painting the
|
||||
// LOCKED frame now ensures the only thing the operator (or
|
||||
// someone over their shoulder) can see on wake is the redacted
|
||||
// view. Gated on lockdown — non-lockdown builds keep the
|
||||
// view. Gated on lockdown - non-lockdown builds keep the
|
||||
// previous frame as a UX cue that the display is just dimmed.
|
||||
// dispdev is dereferenced unguarded throughout this file (incl.
|
||||
// displayOff() just below), so no null check here.
|
||||
@@ -793,7 +793,7 @@ void Screen::setup()
|
||||
// M20: e-ink panels physically retain the last-rendered image without
|
||||
// power, so a power-cycled lockdown handheld would keep showing
|
||||
// operator-identifying content (position, messages, node info) until
|
||||
// the firmware's first natural refresh — which on e-ink can be seconds
|
||||
// the firmware's first natural refresh - which on e-ink can be seconds
|
||||
// into boot. Force a full refresh to the LOCKED frame here, immediately
|
||||
// after the display is initialised and before any other rendering, so
|
||||
// the persistent pixels are wiped to the redacted view before an
|
||||
@@ -1035,7 +1035,7 @@ int32_t Screen::runOnce()
|
||||
bool suppressRegionOnboard = false;
|
||||
#ifdef MESHTASTIC_LOCKDOWN
|
||||
// While lockdown is active and storage is still locked, config.lora.region
|
||||
// is a deliberate UNSET placeholder — the real region lives in encrypted
|
||||
// is a deliberate UNSET placeholder - the real region lives in encrypted
|
||||
// storage and is restored on unlock (see NodeDB's locked-boot path). Don't
|
||||
// pop the region picker over the lock screen: it would trap input, and the
|
||||
// operator can't set a region until they unlock anyway.
|
||||
@@ -1473,7 +1473,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
break;
|
||||
|
||||
case FOCUS_PRESERVE:
|
||||
// No more adjustment — force stay on same index
|
||||
// No more adjustment - force stay on same index
|
||||
if (previousFrameCount > fsi.frameCount) {
|
||||
ui->switchToFrame(originalPosition - 1);
|
||||
} else if (previousFrameCount < fsi.frameCount) {
|
||||
@@ -1828,7 +1828,7 @@ void Screen::handleOnPress()
|
||||
void Screen::logFrameChange(const char *reason, uint8_t targetIdx)
|
||||
{
|
||||
// Reverse-map an index to a stable name string keyed off FramePositions
|
||||
// field names — so the pytest harness can assert `name=nodelist_nodes`
|
||||
// field names - so the pytest harness can assert `name=nodelist_nodes`
|
||||
// without caring about how the positions were ordered this boot.
|
||||
const auto &p = framesetInfo.positions;
|
||||
const char *name = "unknown";
|
||||
|
||||
@@ -693,7 +693,7 @@ class Screen : public concurrency::OSThread
|
||||
// so the chatty log doesn't ship in release builds. Enabled via
|
||||
// build_testing_profile(enable_ui_log=True) in mcp-server/userprefs.py.
|
||||
// Member function (not free) because FramesetInfo is a private nested
|
||||
// type — only methods of Screen can reach it.
|
||||
// type - only methods of Screen can reach it.
|
||||
void logFrameChange(const char *reason, uint8_t targetIdx);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -536,7 +536,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.memory_width = 240;
|
||||
cfg.memory_height = 320;
|
||||
cfg.offset_x = 0;
|
||||
cfg.offset_y = 0; // No vertical shift needed — panel is top-aligned
|
||||
cfg.offset_y = 0; // No vertical shift needed - panel is top-aligned
|
||||
cfg.offset_rotation = 2; // Rotate 180° to correct upside-down layout
|
||||
#else
|
||||
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
@@ -1144,8 +1144,8 @@ static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(VARIANT_DISPLAY_DRIVER)
|
||||
// Board-specific framebuffer backends (class LGFX) can livee in the
|
||||
// variant files — variant_display.h (declaration) and
|
||||
// variant_display.cpp (bodies) — so this shared
|
||||
// variant files - variant_display.h (declaration) and
|
||||
// variant_display.cpp (bodies) - so this shared
|
||||
// file isn't inflated for a single board. It exposes the same surface TFTDisplay
|
||||
// drives, so the generic `tft = new LGFX;` in connect() works.
|
||||
#include "variant_display.h"
|
||||
|
||||
@@ -482,9 +482,9 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
// Weighting for nonlinear segments
|
||||
float milestone1 = 25;
|
||||
float milestone2 = 40;
|
||||
float weight1 = 0.45; // Weight for 0–25%
|
||||
float weight2 = 0.35; // Weight for 25–40%
|
||||
float weight3 = 0.20; // Weight for 40–100%
|
||||
float weight1 = 0.45; // Weight for 0-25%
|
||||
float weight2 = 0.35; // Weight for 25-40%
|
||||
float weight3 = 0.20; // Weight for 40-100%
|
||||
float totalWeight = weight1 + weight2 + weight3;
|
||||
|
||||
int seg1 = chutil_bar_max_fill * (weight1 / totalWeight);
|
||||
|
||||
@@ -182,7 +182,7 @@ static void applyLoraRegion(meshtastic_Config_LoRaConfig_RegionCode region, bool
|
||||
|
||||
// Reconcile the preset with the explicitly chosen region: a preset locked to another
|
||||
// region would leave config.lora invalid until applyModemConfig() repairs it with
|
||||
// error/critical-error side effects — or, for the swappable EU trio, the clamp would
|
||||
// error/critical-error side effects - or, for the swappable EU trio, the clamp would
|
||||
// flip the region right back. The user picked the region, so the preset follows it.
|
||||
const RegionInfo *newRegion = getRegion(region);
|
||||
if (config.lora.use_preset && !newRegion->supportsPreset(config.lora.modem_preset)) {
|
||||
@@ -282,7 +282,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
|
||||
// Guard: without a reboot, reconfigure() applies the region directly, so reject
|
||||
// regions this node can't use up front: unrecognized codes, licensed-only regions,
|
||||
// and radio hardware mismatches (2.4 GHz vs sub-GHz) — the same checks the admin
|
||||
// and radio hardware mismatches (2.4 GHz vs sub-GHz) - the same checks the admin
|
||||
// set-config path applies, but side-effect-free: ignoring a menu selection should
|
||||
// not record a critical error or notify clients. getRadio() used to catch hardware
|
||||
// mismatches post-reboot only.
|
||||
@@ -468,7 +468,7 @@ static constexpr int MAX_PRESET_OPTIONS = 16;
|
||||
|
||||
static BannerOverlayOptions buildRegionPresetBanner()
|
||||
{
|
||||
// Static storage reused each call — safe because the banner is shown immediately after.
|
||||
// Static storage reused each call - safe because the banner is shown immediately after.
|
||||
static const char *optionsArray[MAX_PRESET_OPTIONS];
|
||||
static int optionsEnumArray[MAX_PRESET_OPTIONS];
|
||||
static char presetLabelBuf[MAX_PRESET_OPTIONS][12]; // scratch space for name copies
|
||||
|
||||
@@ -261,7 +261,7 @@ void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayU
|
||||
case notificationTypeEnum::text_banner:
|
||||
case notificationTypeEnum::selection_picker:
|
||||
case notificationTypeEnum::pairing_pin:
|
||||
// pairing_pin is rendered the same as text_banner — it's just a
|
||||
// pairing_pin is rendered the same as text_banner - it's just a
|
||||
// text banner. The split type exists only so the lockdown UI
|
||||
// short-circuit in Screen.cpp can recognise the BLE pair-PIN
|
||||
// banner as the one safe banner to composite over the LOCKED
|
||||
|
||||
@@ -134,7 +134,7 @@ class SafeFastEPD : public FASTEPD
|
||||
|
||||
void ED047TC1::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst)
|
||||
{
|
||||
// Parallel display — SPI parameters are not used
|
||||
// Parallel display - SPI parameters are not used
|
||||
(void)spi;
|
||||
(void)pin_dc;
|
||||
(void)pin_cs;
|
||||
@@ -159,7 +159,7 @@ void ED047TC1::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_
|
||||
// so variant touch-control polling can read the key reliably.
|
||||
epaper->ioPinMode(10, INPUT);
|
||||
#else
|
||||
#error "ED047TC1 driver: unsupported variant — define T5_S3_EPAPER_PRO_V1 or T5_S3_EPAPER_PRO_V2"
|
||||
#error "ED047TC1 driver: unsupported variant - define T5_S3_EPAPER_PRO_V1 or T5_S3_EPAPER_PRO_V2"
|
||||
#endif
|
||||
|
||||
if (initRc != BBEP_SUCCESS) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
Unlike the other NicheGraphics EInk drivers, this one drives a parallel e-paper
|
||||
panel via the FastEPD library. SPI parameters passed to begin() are ignored.
|
||||
|
||||
The ED047TC1 panel has an inactive pixel border on all four edges (~4–8 physical
|
||||
The ED047TC1 panel has an inactive pixel border on all four edges (~4-8 physical
|
||||
pixels). DISPLAY_WIDTH / DISPLAY_HEIGHT expose a reduced "safe area" to InkHUD so
|
||||
that content is never drawn into this dead zone. The update() method copies the
|
||||
InkHUD frame buffer into the centre of the larger physical 960×540 buffer, using
|
||||
@@ -18,9 +18,9 @@
|
||||
V_OFFSET_TOP and V_OFFSET_BOTTOM (vertical, pixel rows) to position it.
|
||||
|
||||
Changing these constants shifts content inward from each physical edge:
|
||||
H_OFFSET_BYTES = 2 → 16px left margin, 16px right margin (960 – 16 – 16 = 928)
|
||||
H_OFFSET_BYTES = 2 → 16px left margin, 16px right margin (960 - 16 - 16 = 928)
|
||||
V_OFFSET_TOP = 16 → 16px top margin
|
||||
V_OFFSET_BOTTOM = 16 → 16px bottom margin (540 – 16 – 16 = 508)
|
||||
V_OFFSET_BOTTOM = 16 → 16px bottom margin (540 - 16 - 16 = 508)
|
||||
|
||||
*/
|
||||
|
||||
@@ -74,7 +74,7 @@ class ED047TC1 : public EInk
|
||||
public:
|
||||
ED047TC1() : EInk(DISPLAY_WIDTH, DISPLAY_HEIGHT, supported) {}
|
||||
|
||||
// EInk interface — SPI params are not used for this parallel display
|
||||
// EInk interface - SPI params are not used for this parallel display
|
||||
void begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst = 0xFF) override;
|
||||
void update(uint8_t *imageData, UpdateTypes type) override;
|
||||
|
||||
|
||||
@@ -275,11 +275,11 @@ void InkHUD::MapApplet::drawMapTileBackground(int zoom)
|
||||
|
||||
void InkHUD::MapApplet::onRender(bool full)
|
||||
{
|
||||
// Map center is always the node centroid — tiles are background only.
|
||||
// Map center is always the node centroid - tiles are background only.
|
||||
getMapCenter(&latCenter, &lngCenter);
|
||||
calculateAllMarkers();
|
||||
|
||||
// Show placeholder only if we have no position at all — no tiles, no own node
|
||||
// Show placeholder only if we have no position at all - no tiles, no own node
|
||||
if (!enoughMarkers() && !centerIsOurNode) {
|
||||
printAt(X(0.5), Y(0.5) - (getFont().lineHeight() / 2), "Node positions", CENTER, MIDDLE);
|
||||
printAt(X(0.5), Y(0.5) + (getFont().lineHeight() / 2), "will appear here", CENTER, MIDDLE);
|
||||
@@ -324,7 +324,7 @@ void InkHUD::MapApplet::onRender(bool full)
|
||||
float chosenMetersToPx = metersToPxFit; // fallback: fit-scale (may downsample)
|
||||
|
||||
if (s_zoomLocked && s_lockedZoom >= 0) {
|
||||
// Use locked zoom at native 1:1 scale — never zoom out for new nodes
|
||||
// Use locked zoom at native 1:1 scale - never zoom out for new nodes
|
||||
chosenZoom = s_lockedZoom;
|
||||
float mpp = (2.0f * M_PI * R / (256.0f * (float)(1 << chosenZoom))) * cosf(latRad);
|
||||
chosenMetersToPx = 1.0f / mpp;
|
||||
@@ -338,7 +338,7 @@ void InkHUD::MapApplet::onRender(bool full)
|
||||
float mpp = (2.0f * M_PI * R / (256.0f * (float)(1 << zooms[zi]))) * cosf(latRad);
|
||||
float nativeMetersToPx = 1.0f / mpp;
|
||||
if (nativeMetersToPx <= metersToPxFit) {
|
||||
// This zoom at native scale shows all nodes — use it (highest detail that fits)
|
||||
// This zoom at native scale shows all nodes - use it (highest detail that fits)
|
||||
chosenZoom = zooms[zi];
|
||||
chosenMetersToPx = nativeMetersToPx;
|
||||
break;
|
||||
@@ -628,7 +628,7 @@ void InkHUD::MapApplet::getMapCenter(float *lat, float *lng)
|
||||
// When zoom is locked, keep center exactly on own node / zero-hop centroid.
|
||||
// Skip bounding-box shift so new distant nodes don't move the zoomed view.
|
||||
if (s_zoomLocked) {
|
||||
// Own node has no position — re-center on zero-hop centroid instead.
|
||||
// Own node has no position - re-center on zero-hop centroid instead.
|
||||
if (!centerIsOurNode) {
|
||||
uint32_t count = 0;
|
||||
float xAvg = 0, yAvg = 0, zAvg = 0;
|
||||
@@ -878,7 +878,7 @@ void InkHUD::MapApplet::calculateAllMarkers()
|
||||
if (node->num == nodeDB->getNodeNum())
|
||||
continue;
|
||||
|
||||
// Skip nodes with unknown hop count — partial info, not useful to plot
|
||||
// Skip nodes with unknown hop count - partial info, not useful to plot
|
||||
if (!node->has_hops_away)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class MapApplet : public Applet
|
||||
|
||||
MapApplet *asMapApplet() override { return this; } // Identify as MapApplet without RTTI
|
||||
|
||||
// Zoom lock — shared across all MapApplet instances (static)
|
||||
// Zoom lock - shared across all MapApplet instances (static)
|
||||
static constexpr int ZOOM_MAX_NO_TILES = 16;
|
||||
|
||||
void zoomIn();
|
||||
|
||||
@@ -260,7 +260,7 @@ int32_t InkHUD::MenuApplet::runOnce()
|
||||
return OSThread::disable();
|
||||
}
|
||||
|
||||
// Storage for the dynamically-built region preset list — populated in showPage(NODE_CONFIG_PRESET)
|
||||
// Storage for the dynamically-built region preset list - populated in showPage(NODE_CONFIG_PRESET)
|
||||
static constexpr uint8_t MAX_REGION_PRESETS = 16;
|
||||
static meshtastic_Config_LoRaConfig_ModemPreset regionPresets[MAX_REGION_PRESETS];
|
||||
static uint8_t regionPresetCount = 0;
|
||||
@@ -1069,7 +1069,7 @@ void InkHUD::MenuApplet::showPage(MenuPage page)
|
||||
|
||||
items.push_back(MenuItem("Send", MenuPage::SEND));
|
||||
|
||||
// Map zoom controls — only when viewing a map applet
|
||||
// Map zoom controls - only when viewing a map applet
|
||||
{
|
||||
MapApplet *mapApplet = borrowedTileOwner ? borrowedTileOwner->asMapApplet() : nullptr;
|
||||
if (mapApplet) {
|
||||
|
||||
@@ -190,7 +190,7 @@ ProcessMessage InkHUD::ThreadedMessageApplet::handleReceived(const meshtastic_Me
|
||||
if (mp.to != NODENUM_BROADCAST)
|
||||
return ProcessMessage::CONTINUE;
|
||||
|
||||
// Store in the global messageStore — this handles sender, timestamp, channel, text, and ack status
|
||||
// Store in the global messageStore - this handles sender, timestamp, channel, text, and ack status
|
||||
messageStore.addFromPacket(mp);
|
||||
|
||||
// If this was an incoming message, suggest that our applet becomes foreground, if permitted
|
||||
|
||||
@@ -260,7 +260,7 @@ If you need to create several similar applets, it might make sense to create a r
|
||||
|
||||
##### Map Tiles
|
||||
|
||||
Map tiles are stored in `MapTile.h` (`src/graphics/niche/InkHUD/Applets/Bases/Map/MapTile.h`). The file committed to the repository contains no tile data by default — the map applets work without tiles, falling back to the original marker-only display.
|
||||
Map tiles are stored in `MapTile.h` (`src/graphics/niche/InkHUD/Applets/Bases/Map/MapTile.h`). The file committed to the repository contains no tile data by default - the map applets work without tiles, falling back to the original marker-only display.
|
||||
|
||||
Tiles are 256×256 pixels, 1-bit (column-major bit packing), compressed per tile with LZ4 to keep flash usage low.
|
||||
|
||||
@@ -489,8 +489,8 @@ We keep this separate latest-message cache for this purpose, because:
|
||||
|
||||
Broadcasts and DMs take different paths into `messageStore`:
|
||||
|
||||
- **Broadcasts** — `ThreadedMessageApplet::handleReceived()` calls `messageStore.addFromPacket()`. `Events::onReceiveTextMessage()` then updates `latestMessage.broadcast` separately for fast access by `AllMessageApplet` and `NotificationApplet`.
|
||||
- **DMs** — `ThreadedMessageApplet` skips DMs entirely. `Events::onReceiveTextMessage()` calls `messageStore.addFromPacket()` directly and stores the result in `latestMessage.dm`.
|
||||
- **Broadcasts** - `ThreadedMessageApplet::handleReceived()` calls `messageStore.addFromPacket()`. `Events::onReceiveTextMessage()` then updates `latestMessage.broadcast` separately for fast access by `AllMessageApplet` and `NotificationApplet`.
|
||||
- **DMs** - `ThreadedMessageApplet` skips DMs entirely. `Events::onReceiveTextMessage()` calls `messageStore.addFromPacket()` directly and stores the result in `latestMessage.dm`.
|
||||
|
||||
#### Saving / Loading
|
||||
|
||||
|
||||
Reference in New Issue
Block a user