From 6d2e0f17b94b7dfa9a249226bb99287d0d2a2c70 Mon Sep 17 00:00:00 2001 From: Rennan Cockles Date: Fri, 20 Dec 2024 15:47:20 -0300 Subject: [PATCH 1/6] refactor scrollable area and add device info screen --- src/core/menu_items/ConfigMenu.cpp | 2 + src/core/scrollableTextArea.cpp | 126 +++++++++++++++++++---------- src/core/scrollableTextArea.h | 21 +++-- src/core/utils.cpp | 30 ++++++- src/core/utils.h | 4 +- 5 files changed, 133 insertions(+), 50 deletions(-) diff --git a/src/core/menu_items/ConfigMenu.cpp b/src/core/menu_items/ConfigMenu.cpp index d698b24a..c4895438 100644 --- a/src/core/menu_items/ConfigMenu.cpp +++ b/src/core/menu_items/ConfigMenu.cpp @@ -3,6 +3,7 @@ #include "core/settings.h" #include "core/i2c_finder.h" #include "core/wifi_common.h" +#include "core/utils.h" void ConfigMenu::optionsMenu() { options = { @@ -31,6 +32,7 @@ void ConfigMenu::optionsMenu() { void ConfigMenu::devMenu(){ options = { + {"Device Info", [=]() { showDeviceInfo(); }}, {"MAC Address", [=]() { checkMAC(); }}, {"I2C Finder", [=]() { find_i2c_addresses(); }}, {"Back", [=]() { optionsMenu(); }}, diff --git a/src/core/scrollableTextArea.cpp b/src/core/scrollableTextArea.cpp index b8bae5d8..b63402f8 100644 --- a/src/core/scrollableTextArea.cpp +++ b/src/core/scrollableTextArea.cpp @@ -1,58 +1,98 @@ #include "scrollableTextArea.h" -// god, it's ugly -ScrollableTextArea::ScrollableTextArea(uint8_t fontSize, - int16_t startX, - int16_t startY, - int32_t width, - int32_t height) - : _startLine{0}, - _redraw{true}, - _fontSize(fontSize), - _startX(startX), - _startY(startY), - _width(width), - _height(height) - #if defined(HAS_SCREEN) - ,_scrollBuffer(&tft) - #endif +ScrollableTextArea::ScrollableTextArea(const String& title) : + _startLine{0}, + _redraw{true}, + _title(title), + _fontSize(FP), + _startX(BORDER_PAD_X), + _startY(BORDER_PAD_Y), + _width(WIDTH - 2*BORDER_PAD_X), + _height(HEIGHT - BORDER_PAD_X - BORDER_PAD_Y) +#ifdef HAS_SCREEN + ,_scrollBuffer(&tft) +#endif { - #if defined(HAS_SCREEN) - _scrollBuffer.createSprite(_width, _height); - _scrollBuffer.setTextColor(bruceConfig.priColor); - _scrollBuffer.setTextSize(_fontSize); - _scrollBuffer.fillSprite(TFT_BLACK); - - _maxCharsInLine = floor(width / _scrollBuffer.textWidth("w", _fontSize)); - _pxlsPerLine = _scrollBuffer.fontHeight() + 2; - _maxLinesInArea = floor(_height / _pxlsPerLine); - #endif + drawMainBorder(); + + if (!_title.isEmpty()) { + printTitle(_title); + _startY = tft.getCursorY(); + _height -= (_startY - BORDER_PAD_Y); + } + + setup(); +} + +ScrollableTextArea::ScrollableTextArea( + uint8_t fontSize, int16_t startX, int16_t startY, int32_t width, int32_t height +) : _startLine{0}, + _redraw{true}, + _title(""), + _fontSize(fontSize), + _startX(startX), + _startY(startY), + _width(width), + _height(height) +#ifdef HAS_SCREEN + ,_scrollBuffer(&tft) +#endif +{ + setup(); +} + +ScrollableTextArea::~ScrollableTextArea() { +#ifdef HAS_SCREEN + _scrollBuffer.deleteSprite(); +#endif } -ScrollableTextArea::~ScrollableTextArea(){ - #if defined(HAS_SCREEN) - _scrollBuffer.deleteSprite(); - #endif +void ScrollableTextArea::setup() { +#ifdef HAS_SCREEN + _scrollBuffer.createSprite(_width, _height); + _scrollBuffer.setTextColor(bruceConfig.priColor); + _scrollBuffer.setTextSize(_fontSize); + _scrollBuffer.fillSprite(bruceConfig.bgColor); + + _maxCharsInLine = floor(_width / _scrollBuffer.textWidth("w", _fontSize)); + _pxlsPerLine = _scrollBuffer.fontHeight() + 2; + _maxLinesInArea = floor(_height / _pxlsPerLine); +#endif } void ScrollableTextArea::scrollUp() { - if( _startLine ){ - --_startLine; + if (_startLine) { + _startLine--; _redraw = true; } } void ScrollableTextArea::scrollDown() { if (_startLine + _maxLinesInArea < _lines.size()) { - ++_startLine; + _startLine++; _redraw = true; } } +void ScrollableTextArea::show(bool force) { + while(checkSelPress()) { update(); yield(); } + while(!checkSelPress()) { update(); yield(); } +} + +void ScrollableTextArea::update() { + if (checkPrevPress()) scrollUp(); + else if (checkNextPress()) scrollDown(); + + draw(); +} + // for devices it will act as a scrollable text area -#if defined(HAS_SCREEN) +#ifdef HAS_SCREEN void ScrollableTextArea::addLine(const String& text) { - if( text.isEmpty() ) return; + if (text.isEmpty()) { + _lines.emplace_back(""); + return; + } String buff; size_t start{0}; @@ -67,34 +107,34 @@ void ScrollableTextArea::addLine(const String& text) { } void ScrollableTextArea::draw(bool force) { - if( !_redraw && !force ) return; + if (!_redraw && !force) return; - _scrollBuffer.fillSprite(TFT_BLACK); + _scrollBuffer.fillSprite(bruceConfig.bgColor); uint16_t yOffset = 0; uint16_t lines = 0; // if there is text above - if( _startLine ){ + if (_startLine) { _scrollBuffer.drawString("...", 0, yOffset); yOffset += _pxlsPerLine; - ++lines; + lines++; } int32_t tmpHeight = _height; // if there is text below - if( _lines.size() - _startLine > _maxLinesInArea ){ + if (_lines.size() - _startLine > _maxLinesInArea) { _scrollBuffer.drawString("...", 0, _height - _pxlsPerLine); tmpHeight -= _pxlsPerLine; - ++lines; + lines++; } size_t idx{_startLine}; while( yOffset < tmpHeight && lines < _maxLinesInArea && idx < _lines.size() ){ _scrollBuffer.drawString(_lines[idx], 0, yOffset); yOffset += _pxlsPerLine; - ++lines; - ++idx; + lines++; + idx++; } _scrollBuffer.pushSprite(_startX, _startY); diff --git a/src/core/scrollableTextArea.h b/src/core/scrollableTextArea.h index 4e971a18..af4f4aa2 100644 --- a/src/core/scrollableTextArea.h +++ b/src/core/scrollableTextArea.h @@ -2,12 +2,15 @@ class ScrollableTextArea { public: + ScrollableTextArea(const String& title = ""); + ScrollableTextArea( - uint8_t fontSize, - int16_t startX, - int16_t startY, - int32_t width, - int32_t height); + uint8_t fontSize, + int16_t startX, + int16_t startY, + int32_t width, + int32_t height + ); ~ScrollableTextArea(); @@ -18,7 +21,11 @@ class ScrollableTextArea { void addLine(const String& text); void draw(bool force = false); + + void show(bool force = false); + private: + String _title; uint16_t _startLine; bool _redraw; uint8_t _fontSize; @@ -35,4 +42,8 @@ class ScrollableTextArea { SerialDisplayClass& _scrollBuffer = tft; #endif + void setup(); + + void update(); + }; \ No newline at end of file diff --git a/src/core/utils.cpp b/src/core/utils.cpp index 55255ba3..225fe68d 100644 --- a/src/core/utils.cpp +++ b/src/core/utils.cpp @@ -1,5 +1,6 @@ #include "utils.h" #include "globals.h" +#include "scrollableTextArea.h" void updateClockTimezone(){ timeClient.begin(); @@ -14,4 +15,31 @@ void updateClockTimezone(){ updateTimeStr(rtc.getTimeStruct()); clock_set = true; #endif -} \ No newline at end of file +} + + +void showDeviceInfo() { + ScrollableTextArea area = ScrollableTextArea("DEVICE INFO"); + + area.addLine("Bruce Version: " + String(BRUCE_VERSION)); + area.addLine("EEPROM size: " + String(EEPROMSIZE)); + area.addLine(""); + +#ifdef HAS_SCREEN + area.addLine("[SCREEN]"); + area.addLine("Rotation: " + String(ROTATION)); + area.addLine("Width: " + String(WIDTH) + "px"); + area.addLine("Height: " + String(HEIGHT) + "px"); + area.addLine(""); +#endif + + area.addLine("[GPIO]"); + area.addLine("GROVE_SDA: " + String(GROVE_SDA)); + area.addLine("GROVE_SCL: " + String(GROVE_SCL)); + area.addLine("SPI_SCK_PIN: " + String(SPI_SCK_PIN)); + area.addLine("SPI_MOSI_PIN: " + String(SPI_MOSI_PIN)); + area.addLine("SPI_MISO_PIN: " + String(SPI_MISO_PIN)); + area.addLine("SPI_SS_PIN: " + String(SPI_SS_PIN)); + + area.show(); +} diff --git a/src/core/utils.h b/src/core/utils.h index 8b4fddfc..8ae3cd2d 100644 --- a/src/core/utils.h +++ b/src/core/utils.h @@ -1 +1,3 @@ -void updateClockTimezone(); \ No newline at end of file +void updateClockTimezone(); + +void showDeviceInfo(); From 45a5ce9ec9f6f5aca401bbd6907d365fb3d8dea3 Mon Sep 17 00:00:00 2001 From: Rennan Cockles Date: Fri, 20 Dec 2024 23:10:49 -0300 Subject: [PATCH 2/6] fix scrollable area not showing last line --- src/core/scrollableTextArea.cpp | 17 ++++++---- src/core/scrollableTextArea.h | 2 +- src/modules/wifi/ap_info.cpp | 56 ++++++++++++--------------------- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/src/core/scrollableTextArea.cpp b/src/core/scrollableTextArea.cpp index b63402f8..b9e6c22f 100644 --- a/src/core/scrollableTextArea.cpp +++ b/src/core/scrollableTextArea.cpp @@ -68,22 +68,27 @@ void ScrollableTextArea::scrollUp() { } void ScrollableTextArea::scrollDown() { - if (_startLine + _maxLinesInArea < _lines.size()) { + if (_startLine + _maxLinesInArea <= _lines.size()) { + if (_startLine == 0) _startLine++; _startLine++; _redraw = true; } } void ScrollableTextArea::show(bool force) { - while(checkSelPress()) { update(); yield(); } - while(!checkSelPress()) { update(); yield(); } + draw(force); + + delay(100); + + while(checkSelPress()) { update(force); yield(); } + while(!checkSelPress()) { update(force); yield(); } } -void ScrollableTextArea::update() { +void ScrollableTextArea::update(bool force) { if (checkPrevPress()) scrollUp(); else if (checkNextPress()) scrollDown(); - draw(); + draw(force); } // for devices it will act as a scrollable text area @@ -123,7 +128,7 @@ void ScrollableTextArea::draw(bool force) { int32_t tmpHeight = _height; // if there is text below - if (_lines.size() - _startLine > _maxLinesInArea) { + if (_lines.size() - _startLine >= _maxLinesInArea) { _scrollBuffer.drawString("...", 0, _height - _pxlsPerLine); tmpHeight -= _pxlsPerLine; lines++; diff --git a/src/core/scrollableTextArea.h b/src/core/scrollableTextArea.h index af4f4aa2..0f658516 100644 --- a/src/core/scrollableTextArea.h +++ b/src/core/scrollableTextArea.h @@ -44,6 +44,6 @@ class ScrollableTextArea { void setup(); - void update(); + void update(bool force = false); }; \ No newline at end of file diff --git a/src/modules/wifi/ap_info.cpp b/src/modules/wifi/ap_info.cpp index 13249d24..bd2a20fd 100644 --- a/src/modules/wifi/ap_info.cpp +++ b/src/modules/wifi/ap_info.cpp @@ -104,24 +104,23 @@ void fillInfo(ScrollableTextArea& area){ wifi_ap_record_t ap_info; err_t res; if( (res = esp_wifi_sta_get_ap_info(&ap_info)) != ESP_OK ){ - String err; - switch (res) - { - case ESP_ERR_WIFI_CONN: - err = "iface is not initialized"; - break; - case ESP_ERR_WIFI_NOT_CONNECT: - err = "station disconnected"; - break; - default: - err = "failed with" + String(res); - break; - } - - tft.print(err); - - while(checkSelPress()) yield(); - while(!checkSelPress()) yield(); + String err; + switch (res) { + case ESP_ERR_WIFI_CONN: + err = "iface is not initialized"; + break; + case ESP_ERR_WIFI_NOT_CONNECT: + err = "station disconnected"; + break; + default: + err = "failed with" + String(res); + break; + } + + tft.print(err); + + while(checkSelPress()) yield(); + while(!checkSelPress()) yield(); } const auto mac = MAC(ap_info.bssid); @@ -145,23 +144,8 @@ void fillInfo(ScrollableTextArea& area){ area.addLine("Antenna: " + String(ap_info.ant)); } -void update(ScrollableTextArea& area){ - if( checkPrevPress() ){ - area.scrollUp(); - } else if( checkNextPress() ){ - area.scrollDown(); - } - area.draw(); -} - void displayAPInfo(){ - drawMainBorder(); - - // offset header and border - ScrollableTextArea area(FP, 10, 30, WIDTH - 20, HEIGHT - 40); - + ScrollableTextArea area = ScrollableTextArea("AP INFO"); fillInfo(area); - - while(checkSelPress()){ update(area); yield();} - while(!checkSelPress()){ update(area); yield();} -} \ No newline at end of file + area.show(); +} From 4c0c2454c93416afb5d31365ec6eae3b65acb164 Mon Sep 17 00:00:00 2001 From: Rennan Cockles Date: Sat, 21 Dec 2024 12:47:10 -0300 Subject: [PATCH 3/6] refactor viewFile to use scrollable area --- src/core/scrollableTextArea.cpp | 23 +++++++ src/core/scrollableTextArea.h | 4 ++ src/core/sd_functions.cpp | 115 ++------------------------------ src/core/sd_functions.h | 2 - 4 files changed, 34 insertions(+), 110 deletions(-) diff --git a/src/core/scrollableTextArea.cpp b/src/core/scrollableTextArea.cpp index b9e6c22f..ee0475b8 100644 --- a/src/core/scrollableTextArea.cpp +++ b/src/core/scrollableTextArea.cpp @@ -38,6 +38,7 @@ ScrollableTextArea::ScrollableTextArea( ,_scrollBuffer(&tft) #endif { + drawMainBorder(); setup(); } @@ -91,6 +92,28 @@ void ScrollableTextArea::update(bool force) { draw(force); } +void ScrollableTextArea::fromFile(File file) { + while (file.available()) addLine(file.readStringUntil('\n')); + + draw(true); + delay(100); + draw(true); +} + +void ScrollableTextArea::fromString(const String& text) { + int startIdx = 0; + int endIdx = 0; + + while (endIdx < text.length()) { + if (text[endIdx] == '\n') { + addLine(text.substring(startIdx, endIdx)); + startIdx = endIdx + 1; + } + + endIdx++; + } +} + // for devices it will act as a scrollable text area #ifdef HAS_SCREEN void ScrollableTextArea::addLine(const String& text) { diff --git a/src/core/scrollableTextArea.h b/src/core/scrollableTextArea.h index 0f658516..78776041 100644 --- a/src/core/scrollableTextArea.h +++ b/src/core/scrollableTextArea.h @@ -20,6 +20,10 @@ class ScrollableTextArea { void addLine(const String& text); + void fromString(const String& text); + + void fromFile(File file); + void draw(bool force = false); void show(bool force = false); diff --git a/src/core/sd_functions.cpp b/src/core/sd_functions.cpp index 03a16928..f10d2a60 100644 --- a/src/core/sd_functions.cpp +++ b/src/core/sd_functions.cpp @@ -4,6 +4,7 @@ #include "mykeyboard.h" // using keyboard when calling rename #include "display.h" // using displayRedStripe as error msg #include "passwords.h" +#include "scrollableTextArea.h" #include "modules/others/audio.h" #include "modules/rf/rf.h" #include "modules/ir/TV-B-Gone.h" @@ -17,20 +18,10 @@ #include // for CRC32 #include // for std::sort -struct FilePage { - int pageIndex; - int startIdx; - int endIdx; -}; - - //SPIClass sdcardSPI; String fileToCopy; std::vector fileList; -FilePage filePages[100]; // Maximum of 100 pages - - /*************************************************************************************** ** Function name: setupSdCard @@ -761,115 +752,22 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext) { } -/********************************************************************* -** Function: createFilePages -** Create a list of file pages to be displayed -**********************************************************************/ -int createFilePages(String fileContent) { - const int8_t MAX_LINES = 16; - const int8_t MAX_LINE_CHARS = 41; - - int currentPage = 0; - int lineStartIdx = 0; - int pageStartIdx = 0; - int pageEndIdx = 0; - int totalPageLines = 0; - - while (pageEndIdx < fileContent.length()) { - // Check end of line - if (fileContent[pageEndIdx] == '\n' || (pageEndIdx-lineStartIdx) == MAX_LINE_CHARS) { - totalPageLines++; - lineStartIdx = pageEndIdx + 1; - } - - // Check end of page - if (totalPageLines == MAX_LINES) { - filePages[currentPage].pageIndex = currentPage; - filePages[currentPage].startIdx = pageStartIdx; - filePages[currentPage].endIdx = pageEndIdx; - - currentPage++; - pageStartIdx = pageEndIdx + 1; - totalPageLines = 0; - } - - pageEndIdx++; - } - - if (totalPageLines > 0) { - filePages[currentPage].pageIndex = currentPage; - filePages[currentPage].startIdx = pageStartIdx; - filePages[currentPage].endIdx = pageEndIdx; - } - - return currentPage; -} - /********************************************************************* ** Function: viewFile ** Display file content **********************************************************************/ void viewFile(FS fs, String filepath) { - tft.fillScreen(bruceConfig.bgColor); - String fileContent = ""; - File file; - String displayText; - int totalPages; - int currentPage = 0; - bool updateContent = true; - - file = fs.open(filepath, FILE_READ); + File file = fs.open(filepath, FILE_READ); if (!file) return; - // TODO: detect binary file, switch to hex view - // String header=file.read(100); file.rewind(); - // if(isValidAscii(header)) ... + ScrollableTextArea area = ScrollableTextArea(file.name()); + area.fromFile(file); - while (file.available()) { - fileContent = file.readString(); - } file.close(); - delay(100); - - totalPages = createFilePages(fileContent); - - while(1) { - if(updateContent) { - tft.fillScreen(bruceConfig.bgColor); - tft.setCursor(0,4); - tft.setTextSize(FP); - - displayText = fileContent.substring( - filePages[currentPage].startIdx, - filePages[currentPage].endIdx - ); - tft.print(displayText); - - delay(150); - updateContent = false; - } - - if(checkEscPress()) break; - - if(checkPrevPress()) { - if (currentPage > 0) { - currentPage--; - updateContent = true; - } - } - - if(checkNextPress()) { - if (currentPage < totalPages) { - currentPage++; - updateContent = true; - } - } - delay(100); - } - - return; + area.show(); } + /********************************************************************* ** Function: checkLittleFsSize ** Check if there are more then 4096 bytes available for storage @@ -880,6 +778,7 @@ bool checkLittleFsSize() { return false; } else return true; } + /********************************************************************* ** Function: checkLittleFsSize ** Check if there are more then 4096 bytes available for storage diff --git a/src/core/sd_functions.h b/src/core/sd_functions.h index 062871d1..8a34b337 100644 --- a/src/core/sd_functions.h +++ b/src/core/sd_functions.h @@ -46,8 +46,6 @@ String loopSD(FS &fs, bool filePicker = false, String allowed_ext = "*"); void viewFile(FS fs, String filepath); -int createFilePages(String fileContent); - bool checkLittleFsSize(); bool checkLittleFsSizeNM(); //Don't display msg From b014634624f35d5de144082883a7608dee9fb2cc Mon Sep 17 00:00:00 2001 From: Rennan Cockles Date: Sat, 21 Dec 2024 13:11:32 -0300 Subject: [PATCH 4/6] refactor fileInfo to use main border --- src/core/sd_functions.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/core/sd_functions.cpp b/src/core/sd_functions.cpp index f10d2a60..24dba2a5 100644 --- a/src/core/sd_functions.cpp +++ b/src/core/sd_functions.cpp @@ -805,11 +805,6 @@ bool getFsStorage(FS *&fs) { ** Display file info **********************************************************************/ void fileInfo(FS fs, String filepath) { - tft.fillScreen(bruceConfig.bgColor); - tft.setCursor(0,0); - tft.setTextColor(bruceConfig.priColor, bruceConfig.bgColor); - tft.setTextSize(FP); - File file = fs.open(filepath, FILE_READ); if (!file) return; @@ -827,9 +822,8 @@ void fileInfo(FS fs, String filepath) { unit = "kB"; } + drawMainBorderWithTitle(file.name()); padprintln(""); - tft.drawCentreString("-"+String(file.name()), WIDTH/2, tft.getCursorY(), 1); - padprintln("\n"); padprintln("Path: " + filepath); padprintln(""); padprintf("Bytes: %d\n", bytesize); @@ -841,10 +835,7 @@ void fileInfo(FS fs, String filepath) { file.close(); delay(100); - while(1) { - if(checkEscPress() || checkSelPress()) break; - delay(100); - } + while(!checkEscPress() && !checkSelPress()) { delay(100); } return; } From fe73cb354d46e00069d8d3c8aa31d7133b1c140a Mon Sep 17 00:00:00 2001 From: Rennan Cockles Date: Sat, 21 Dec 2024 14:24:16 -0300 Subject: [PATCH 5/6] fix scroll speed too fast --- src/core/scrollableTextArea.cpp | 1 + src/core/sd_functions.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/scrollableTextArea.cpp b/src/core/scrollableTextArea.cpp index ee0475b8..d3ea89a6 100644 --- a/src/core/scrollableTextArea.cpp +++ b/src/core/scrollableTextArea.cpp @@ -90,6 +90,7 @@ void ScrollableTextArea::update(bool force) { else if (checkNextPress()) scrollDown(); draw(force); + delay(100); } void ScrollableTextArea::fromFile(File file) { diff --git a/src/core/sd_functions.cpp b/src/core/sd_functions.cpp index 24dba2a5..9cd065ef 100644 --- a/src/core/sd_functions.cpp +++ b/src/core/sd_functions.cpp @@ -760,7 +760,7 @@ void viewFile(FS fs, String filepath) { File file = fs.open(filepath, FILE_READ); if (!file) return; - ScrollableTextArea area = ScrollableTextArea(file.name()); + ScrollableTextArea area = ScrollableTextArea("VIEW FILE"); area.fromFile(file); file.close(); @@ -822,7 +822,7 @@ void fileInfo(FS fs, String filepath) { unit = "kB"; } - drawMainBorderWithTitle(file.name()); + drawMainBorderWithTitle("FILE INFO"); padprintln(""); padprintln("Path: " + filepath); padprintln(""); From 709f833b3dac7fc4182bc14df61a1ea6357a2d5d Mon Sep 17 00:00:00 2001 From: Rennan Cockles Date: Sat, 21 Dec 2024 20:54:10 -0300 Subject: [PATCH 6/6] fix padprintln to print inside border --- src/core/display.cpp | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/core/display.cpp b/src/core/display.cpp index 9d7913f7..c795512b 100644 --- a/src/core/display.cpp +++ b/src/core/display.cpp @@ -234,12 +234,40 @@ void padprint(double n, int digits, int16_t padx) { } void padprintln(const String &s, int16_t padx) { - tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); - tft.println(s); + if (s.isEmpty()) { + tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); + tft.println(s); + return; + } + + String buff; + size_t start = 0; + int _maxCharsInLine = (WIDTH - (padx+1) * BORDER_PAD_X) / (FP*LW); + + // automatically split into multiple lines + while( !(buff = s.substring(start, start + _maxCharsInLine)).isEmpty() ){ + tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); + tft.println(buff); + start += buff.length(); + } } void padprintln(const char str[], int16_t padx) { - tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); - tft.println(str); + if (str == "") { + tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); + tft.println(str); + return; + } + + String buff; + size_t start = 0; + int _maxCharsInLine = (WIDTH - (padx+1) * BORDER_PAD_X) / (FP*LW); + + // automatically split into multiple lines + while( !(buff = String(str).substring(start, start + _maxCharsInLine)).isEmpty() ){ + tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); + tft.println(buff); + start += buff.length(); + } } void padprintln(char c, int16_t padx) { tft.setCursor(padx * BORDER_PAD_X, tft.getCursorY()); @@ -407,7 +435,7 @@ Opt_Coord drawOptions(int index,std::vector