mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 23:08:11 +00:00
feat(trail): scroll-editor for add-waypoint coordinates
Replace the text keyboard for the "Add by coords" Lat/Lon fields with the shared digit-by-digit DigitEditor (the radio-frequency widget): Enter opens the editor on the magnitude (LEFT/RIGHT move the cursor, UP/DOWN change the digit), and LEFT/RIGHT on the row still toggles the hemisphere when the editor is closed. The keyboard never fit numeric entry — no minus, easy to type stray letters. Label still uses the keyboard. Docs updated. Verified: WioTrackerL1_companion_solo_dual builds clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -139,7 +139,7 @@ A waypoint is a saved spot — your car, camp, a water source — that you can n
|
||||
|
||||
**Adding by coordinates** — open **Hold Enter → Waypoints** and select the **+ Add by coords** row (always the last entry in the list). This creates a waypoint without being there — no GPS fix required (handy for a meeting point or a spot read off a map). It opens a small form with three editable rows plus **Save**:
|
||||
|
||||
- **Lat** / **Lon** — **Enter** opens the keyboard to type the value in decimal degrees (magnitude only; the keyboard has no minus sign), and **LEFT/RIGHT** toggles the hemisphere — N/S for latitude, E/W for longitude.
|
||||
- **Lat** / **Lon** — **Enter** opens the digit-by-digit scroll editor (the same widget as the radio frequency field): **LEFT/RIGHT** move the cursor between decimal places, **UP/DOWN** change the digit under it, **Enter** confirms. With the editor closed, **LEFT/RIGHT** on the row toggles the hemisphere — N/S for latitude, E/W for longitude.
|
||||
- **Label** — **Enter** to type a name (blank → auto `WP<n>`).
|
||||
- **Save** — validates the range and stores the waypoint. Missing or out-of-range values report a brief error.
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "KeyboardWidget.h"
|
||||
#include "PopupMenu.h"
|
||||
#include "NavView.h"
|
||||
#include "DigitEditor.h"
|
||||
|
||||
class WaypointsView {
|
||||
UITask* _task;
|
||||
@@ -30,14 +31,18 @@ class WaypointsView {
|
||||
int32_t _mark_lat = 0, _mark_lon = 0; // pending new-mark position
|
||||
uint32_t _mark_ts = 0;
|
||||
|
||||
// ADD form — type a waypoint by coordinates. The keyboard has no comma or
|
||||
// minus, so lat/lon are entered as magnitude + a hemisphere toggle (LEFT/RIGHT).
|
||||
char _add_lat[12] = "", _add_lon[12] = ""; // magnitude strings
|
||||
// ADD form — enter a waypoint by coordinates. Lat/Lon are numeric, so they use
|
||||
// the digit-by-digit scroll editor (same widget as the radio frequency field)
|
||||
// rather than the text keyboard: Enter opens the editor on the magnitude,
|
||||
// LEFT/RIGHT on the row toggles the hemisphere (N/S, E/W). Only the Label field
|
||||
// uses the keyboard.
|
||||
float _add_lat_mag = 0.0f, _add_lon_mag = 0.0f; // magnitude (degrees)
|
||||
char _add_label[WAYPOINT_LABEL_LEN] = "";
|
||||
bool _add_lat_neg = false; // true = S
|
||||
bool _add_lon_neg = false; // true = W
|
||||
int _add_sel = 0; // 0=Lat 1=Lon 2=Label 3=Save
|
||||
int _kb_field = -1; // which ADD field the keyboard edits (-1 = label/rename)
|
||||
int _kb_field = -1; // ADD label edit (>=0) vs mark/rename (-1)
|
||||
DigitEditor _add_editor; // active while editing a Lat/Lon magnitude
|
||||
|
||||
bool useImperial() const { return _task && _task->useImperial(); }
|
||||
bool ownPos(int32_t& lat, int32_t& lon) const { return _task->currentLocation(lat, lon); }
|
||||
@@ -53,38 +58,23 @@ class WaypointsView {
|
||||
// Add a waypoint by coordinates (no GPS fix needed). Opens the ADD form.
|
||||
void openAddForm() {
|
||||
if (_task->waypoints().full()) { _task->showAlert("Waypoints full", 1000); return; }
|
||||
_add_lat[0] = _add_lon[0] = _add_label[0] = '\0';
|
||||
_add_lat_mag = _add_lon_mag = 0.0f;
|
||||
_add_label[0] = '\0';
|
||||
_add_lat_neg = _add_lon_neg = false;
|
||||
_add_sel = 0;
|
||||
_add_editor.active = false;
|
||||
_mode = ADD;
|
||||
}
|
||||
|
||||
// Store the just-typed value into the focused ADD field.
|
||||
// Store the just-typed label (the only ADD field that still uses the keyboard).
|
||||
void applyAddField(const char* buf) {
|
||||
char* dst = (_kb_field == 0) ? _add_lat
|
||||
: (_kb_field == 1) ? _add_lon : _add_label;
|
||||
int cap = (_kb_field == 2) ? WAYPOINT_LABEL_LEN : (int)sizeof(_add_lat);
|
||||
strncpy(dst, buf, cap - 1);
|
||||
dst[cap - 1] = '\0';
|
||||
}
|
||||
|
||||
// Parse a numeric field: true only when the whole string is a number (so a
|
||||
// stray letter from the full keyboard can't silently read as 0).
|
||||
static bool parseNum(const char* s, double& out) {
|
||||
if (!s || !s[0]) return false;
|
||||
char* end = nullptr;
|
||||
out = strtod(s, &end);
|
||||
if (end == s) return false; // nothing numeric parsed
|
||||
while (*end == ' ') end++;
|
||||
return *end == '\0'; // no trailing non-numeric chars
|
||||
strncpy(_add_label, buf, sizeof(_add_label) - 1);
|
||||
_add_label[sizeof(_add_label) - 1] = '\0';
|
||||
}
|
||||
|
||||
// Validate the ADD form and save the waypoint.
|
||||
void commitAddForm() {
|
||||
double la, lo;
|
||||
if (!parseNum(_add_lat, la) || !parseNum(_add_lon, lo)) {
|
||||
_task->showAlert("Lat/Lon invalid", 1200); return;
|
||||
}
|
||||
double la = _add_lat_mag, lo = _add_lon_mag;
|
||||
if (_add_lat_neg) la = -la;
|
||||
if (_add_lon_neg) lo = -lo;
|
||||
if (la < -90.0 || la > 90.0 || lo < -180.0 || lo > 180.0) {
|
||||
@@ -134,12 +124,22 @@ class WaypointsView {
|
||||
int y = top + i * step;
|
||||
bool sel = (i == _add_sel);
|
||||
display.drawSelectionRow(0, y - 1, display.width(), step - 1, sel);
|
||||
char row[28];
|
||||
if (i == 0) snprintf(row, sizeof(row), "Lat: %c %s", _add_lat_neg ? 'S' : 'N', _add_lat[0] ? _add_lat : "--");
|
||||
else if (i == 1) snprintf(row, sizeof(row), "Lon: %c %s", _add_lon_neg ? 'W' : 'E', _add_lon[0] ? _add_lon : "--");
|
||||
else if (i == 2) snprintf(row, sizeof(row), "Label: %s", _add_label[0] ? _add_label : "(auto)");
|
||||
else snprintf(row, sizeof(row), "[Save]");
|
||||
display.setCursor(2, y); display.print(row);
|
||||
// While editing a magnitude, draw the row prefix + the digit editor so the
|
||||
// place under the cursor is highlighted; otherwise draw the plain value.
|
||||
if ((i == 0 || i == 1) && sel && _add_editor.active) {
|
||||
char prefix[10];
|
||||
if (i == 0) snprintf(prefix, sizeof(prefix), "Lat: %c ", _add_lat_neg ? 'S' : 'N');
|
||||
else snprintf(prefix, sizeof(prefix), "Lon: %c ", _add_lon_neg ? 'W' : 'E');
|
||||
display.setCursor(2, y); display.print(prefix);
|
||||
_add_editor.render(display, 2 + (int)strlen(prefix) * display.getCharWidth(), y);
|
||||
} else {
|
||||
char row[28];
|
||||
if (i == 0) snprintf(row, sizeof(row), "Lat: %c %.5f", _add_lat_neg ? 'S' : 'N', _add_lat_mag);
|
||||
else if (i == 1) snprintf(row, sizeof(row), "Lon: %c %.5f", _add_lon_neg ? 'W' : 'E', _add_lon_mag);
|
||||
else if (i == 2) snprintf(row, sizeof(row), "Label: %s", _add_label[0] ? _add_label : "(auto)");
|
||||
else snprintf(row, sizeof(row), "[Save]");
|
||||
display.setCursor(2, y); display.print(row);
|
||||
}
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
}
|
||||
@@ -288,8 +288,17 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
// ADD form: type lat/lon (magnitude) + hemisphere toggle + label.
|
||||
// ADD form: scroll-edit lat/lon (magnitude) + hemisphere toggle + label.
|
||||
if (_mode == ADD) {
|
||||
// The digit editor, while open, consumes all input (UP/DOWN change the
|
||||
// digit, LEFT/RIGHT move the cursor, Enter commits, Cancel aborts).
|
||||
if (_add_editor.active) {
|
||||
if (_add_editor.handleInput(c) == DigitEditor::DONE) {
|
||||
if (_add_sel == 0) _add_lat_mag = _add_editor.value;
|
||||
else _add_lon_mag = _add_editor.value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_CANCEL) { _mode = OFF; return true; }
|
||||
if (c == KEY_UP) { _add_sel = (_add_sel > 0) ? _add_sel - 1 : 3; return true; }
|
||||
if (c == KEY_DOWN) { _add_sel = (_add_sel < 3) ? _add_sel + 1 : 0; return true; }
|
||||
@@ -299,8 +308,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_ENTER) {
|
||||
if (_add_sel == 0) { _kb_field = 0; openKb(_add_lat, 11); }
|
||||
else if (_add_sel == 1) { _kb_field = 1; openKb(_add_lon, 11); }
|
||||
if (_add_sel == 0) _add_editor.begin(_add_lat_mag, 0.0f, 90.0f, 2, 5);
|
||||
else if (_add_sel == 1) _add_editor.begin(_add_lon_mag, 0.0f, 180.0f, 3, 5);
|
||||
else if (_add_sel == 2) { _kb_field = 2; openKb(_add_label, WAYPOINT_LABEL_LEN - 1); }
|
||||
else { commitAddForm(); }
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user