diff --git a/include/config.h b/include/config.h index 497ab21..9d15c7f 100644 --- a/include/config.h +++ b/include/config.h @@ -46,10 +46,15 @@ #define KB_KEY_BACKSPACE 0x08 #define KB_KEY_TAB 0x09 #define KB_KEY_ESC 0x1B +#define KB_KEY_LEFT 0xB4 +#define KB_KEY_UP 0xB5 +#define KB_KEY_DOWN 0xB6 +#define KB_KEY_RIGHT 0xB7 // Notes mode / BT dump #define BT_DUMP_COUNTDOWN_S 3 #define NOTES_FILE "/notes.txt" +#define NOTES_HISTORY_LINES 100 // scrollback kept in RAM for notes mode // ESP-NOW Chat diff --git a/src/meshberry/chat.cpp b/src/meshberry/chat.cpp index b64dcfa..3cac5ed 100644 --- a/src/meshberry/chat.cpp +++ b/src/meshberry/chat.cpp @@ -4,7 +4,7 @@ // Original author : 7h30th3r0n3, https://github.com/7h30th3r0n3/Evil-M5Project // // I've tried to keep the original code as much as possible as it was -// but some ui/logic snuck in when adding the BT functonality. +// but –some- a lot ui/logic snuck in when adding the BT functonality. #include "chat.h" #include "config.h" @@ -108,13 +108,24 @@ static void chat_show_recent() { } } -// get the last few lines of the notes file. -static void notes_show_recent() { +static char notesBuf[NOTES_HISTORY_LINES][MAX_MSG_LEN]; +static int currNote = 0;// next pos +static int notesCount = 0; +static int notesScrollPos = 0; + +static void notes_to_buffer(const char* line) { + strncpy(notesBuf[currNote], line, MAX_MSG_LEN - 1); + notesBuf[currNote][MAX_MSG_LEN - 1] = '\0'; + currNote = (currNote + 1) % NOTES_HISTORY_LINES; + if (notesCount < NOTES_HISTORY_LINES) notesCount++; +} + +static void notes_load() { + notesCount = 0; currNote = 0; notesScrollPos = 0; + File f = LittleFS.open(NOTES_FILE, "r"); if (!f) return; - static char buf[MODE_HISTORY_LINES][MAX_MSG_LEN]; - int count = 0, head = 0; char line[MAX_MSG_LEN]; while (f.available()) { int n = f.readBytesUntil('\n', line, sizeof(line) - 1); @@ -122,20 +133,30 @@ static void notes_show_recent() { n--; // remove trailing /r from .println line[n] = '\0'; if (n == 0) continue; - strncpy(buf[head], line, MAX_MSG_LEN - 1); - buf[head][MAX_MSG_LEN - 1] = '\0'; - head = (head + 1) % MODE_HISTORY_LINES; - if (count < MODE_HISTORY_LINES) count++; + notes_to_buffer(line); } - f.close(); - int start = (count < MODE_HISTORY_LINES) ? 0 : head; - for (int i = 0; i < count; i++) - ui_push_message("", buf[(start + i) % MODE_HISTORY_LINES], true, false); +} + +static void notes_render() { + int visible = UI_VISIBLE_LINES; + int maxScroll = (notesCount > visible) ? (notesCount - visible) : 0; + if (notesScrollPos > maxScroll) notesScrollPos = maxScroll; + if (notesScrollPos < 0) notesScrollPos = 0; + + int windowEnd = notesCount - notesScrollPos; + int windowStart = windowEnd - visible; + if (windowStart < 0) windowStart = 0; + + int start = (notesCount < NOTES_HISTORY_LINES) ? 0 : currNote; + + ui_clear_messages(); + for (int i = windowStart; i < windowEnd; i++) + ui_push_message("", notesBuf[(start + i) % NOTES_HISTORY_LINES], true, false); } /* -Switch between chat mode (default) adn notes mode. +Switch between chat mode (default) adn notes mode. also redraw the UI somewhat */ static void switch_mode(AppMode m) { @@ -143,7 +164,8 @@ static void switch_mode(AppMode m) { ui_clear_messages(); if (m == AppMode::NOTES) { ui_set_header_mode("NOTE MODE"); - notes_show_recent(); + notes_load(); + notes_render(); } else { ui_set_header(nodesCount, currentNick); chat_show_recent(); @@ -767,6 +789,14 @@ void chat_tick(char key) { return; } + /* Scroll through notes */ + if (appMode == AppMode::NOTES && + ((uint8_t)key == KB_KEY_UP || (uint8_t)key == KB_KEY_DOWN)) { + notesScrollPos += ((uint8_t)key == KB_KEY_UP) ? 1 : -1; + notes_render(); + return; + } + if (appMode == AppMode::BT) { if((uint8_t)key == 0x80) { // FN + ESC bt_dump_start(); @@ -798,7 +828,9 @@ void chat_tick(char key) { handleCommand(inputBuffer); else if (appMode == AppMode::NOTES) { notes_append(inputBuffer); - ui_push_message("", inputBuffer, true, false); + notes_to_buffer(inputBuffer); + notesScrollPos = 0; // snap back to the latest note + notes_render(); } else if (appMode == AppMode::CHAT) { broadcastChatMessage(currentNick, inputBuffer); }