Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 79 additions & 58 deletions src/core/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,34 @@ bool __attribute__((weak)) isCharging() { return false; }
***************************************************************************************/
void displayScrollingText(const String &text, Opt_Coord &coord) {
int len = text.length();
String displayText = text + " "; // Add spaces for smooth looping
int scrollLen = len + 8; // Full text plus space buffer
static String _lastText = "";
static int i = 0;
static long _lastmillis = 0;

// Reset scroll position when the selected item changes
if (text != _lastText) {
i = 0;
_lastText = text;
_lastmillis = 0;
}

tft.setTextColor(coord.fgcolor, coord.bgcolor);
if (len < coord.size) {
// Text fits within limit, no scrolling needed
return;
} else if (millis() > _lastmillis + 200) {
String scrollingPart =
displayText.substring(i, i + (coord.size - 1)); // Display charLimit characters at a time
String displayText = text + " ";
int scrollLen = len + 8;
String scrollingPart = displayText.substring(i, i + (coord.size - 1));
tft.fillRect(
coord.x,
coord.y,
coord.x, coord.y,
(coord.size - 1) * LW * tft.getTextSize(),
LH * tft.getTextSize(),
bruceConfig.bgColor
); // Clear display area
tft.setCursor(coord.x, coord.y);
);
tft.setCursor(coord.x, coord.y);
tft.print(scrollingPart);
if (i >= scrollLen - coord.size) i = -1; // Loop back
if (i >= scrollLen - coord.size) i = -1;
_lastmillis = millis();
i++;
if (i == 1) _lastmillis = millis() + 1000;
Expand Down Expand Up @@ -928,47 +934,81 @@ void drawWireguardStatus(int x, int y) {
** Description: Função para desenhar e mostrar o menu principal
***************************************************************************************/
#define MAX_ITEMS (int)(tftHeight - 20) / (LH * FM)

static bool _listFilesForceReset = true;
void resetListFilesCache() { _listFilesForceReset = true; }

// Draw one line with text+bg atomically — no flicker, no separate fillRect
static void _drawLine(int visPos, bool selected, const FileList &item, int nchars) {
uint16_t fg;
if (item.folder) fg = getColorVariation(bruceConfig.priColor);
else if (item.operation) fg = ALCOLOR;
else fg = bruceConfig.priColor;

tft.setTextColor(fg, bruceConfig.bgColor);
tft.setCursor(10, 10 + visPos * LH * FM);
String txt = selected ? ">" : " ";
txt += item.filename;
while ((int)txt.length() < nchars) txt += ' ';
tft.print(txt.substring(0, nchars));
}

Opt_Coord listFiles(int index, std::vector<FileList> fileList) {
Opt_Coord coord;
tft.drawPixel(0, 0, bruceConfig.bgColor);
if (index == 0) {
tft.fillScreen(bruceConfig.bgColor);
tft.drawRoundRect(5, 5, tftWidth - 10, tftHeight - 10, 5, bruceConfig.priColor);
}
tft.setCursor(10, 10);
tft.setTextSize(FM);
int i = 0;

int arraySize = fileList.size();
int nchars = (tftWidth - 20) / (6 * FM);

int start = 0;
if (index >= MAX_ITEMS) {
start = index - MAX_ITEMS + 1;
if (start < 0) start = 0;
}
int nchars = (tftWidth - 20) / (6 * tft.getTextSize());
String txt = ">";
while (i < arraySize) {
if (i >= start) {
tft.setCursor(10, tft.getCursorY());
if (fileList[i].folder == true)
tft.setTextColor(getColorVariation(bruceConfig.priColor), bruceConfig.bgColor);
else if (fileList[i].operation == true) tft.setTextColor(ALCOLOR, bruceConfig.bgColor);
else { tft.setTextColor(bruceConfig.priColor, bruceConfig.bgColor); }

if (index == i) {
txt = ">";
coord.x = 10 + FM * LW;
coord.y = tft.getCursorY();
coord.size = nchars;
coord.fgcolor =
fileList[i].folder ? getColorVariation(bruceConfig.priColor) : bruceConfig.priColor;
coord.bgcolor = bruceConfig.bgColor;
} else txt = " ";
txt += fileList[i].filename + " ";
tft.println(txt.substring(0, nchars));

static int _lastStart = -1;
static int _lastIndex = -1;

bool pageChanged = (_listFilesForceReset || start != _lastStart);

if (pageChanged) {
// Full redraw only when page changes or forced (folder change)
if (_listFilesForceReset) {
tft.fillScreen(bruceConfig.bgColor);
tft.drawRoundRect(5, 5, tftWidth - 10, tftHeight - 10, 5, bruceConfig.priColor);
}
i++;
if (i == (start + MAX_ITEMS) || i == arraySize) break;
for (int visPos = 0; visPos < MAX_ITEMS; visPos++) {
int i = start + visPos;
if (i >= arraySize) {
// Clear empty slot
tft.setTextColor(bruceConfig.priColor, bruceConfig.bgColor);
tft.setCursor(10, 10 + visPos * LH * FM);
String blank(nchars, ' ');
tft.print(blank);
} else {
_drawLine(visPos, i == index, fileList[i], nchars);
}
}
_listFilesForceReset = false;
} else if (index != _lastIndex) {
// Partial redraw: only the 2 lines that changed
int oldVis = _lastIndex - start;
int newVis = index - start;
if (oldVis >= 0 && oldVis < MAX_ITEMS && _lastIndex < arraySize)
_drawLine(oldVis, false, fileList[_lastIndex], nchars);
if (newVis >= 0 && newVis < MAX_ITEMS)
_drawLine(newVis, true, fileList[index], nchars);
}

_lastStart = start;
_lastIndex = index;

coord.x = 10 + FM * LW;
coord.y = 10 + (index - start) * LH * FM;
coord.size = nchars;
coord.fgcolor = fileList[index].folder ? getColorVariation(bruceConfig.priColor) : bruceConfig.priColor;
coord.bgcolor = bruceConfig.bgColor;

return coord;
}

Expand Down Expand Up @@ -1228,25 +1268,6 @@ bool showJpeg(FS &fs, String filename, int x, int y, bool center) {
return true;
}

bool showJpeg(const uint8_t *data_array, size_t data_size, int x, int y, bool center) {
bool decoded = false;
if (data_array) {
decoded = JpegDec.decodeArray(data_array, data_size);
} else {
return false;
}

if (decoded) {
if (center) {
x = x + (tftWidth - JpegDec.width) / 2;
y = y + (tftHeight - JpegDec.height) / 2;
}
jpegRender(x, y);
}

return true;
}

#if !defined(LITE_VERSION)
// ####################################################################################################
// Draw a GIF on the TFT
Expand Down
122 changes: 58 additions & 64 deletions src/core/sd_functions.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "sd_functions.h"
#include "display.h" // using displayRedStripe as error msg
#include "display.h"
extern void resetListFilesCache(); // using displayRedStripe as error msg
#include "modules/badusb_ble/ducky_typer.h"
#include "modules/bjs_interpreter/interpreter.h"
#include "modules/gps/wigle.h"
Expand Down Expand Up @@ -564,7 +565,7 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext, String rootPath) {
String Folder = rootPath;
String PreFolder = rootPath;
tft.drawPixel(0, 0, 0);
tft.fillScreen(bruceConfig.bgColor); // TODO: Does only the T-Embed CC1101 need this?
tft.fillScreen(bruceConfig.bgColor);
tft.drawRoundRect(5, 5, tftWidth - 10, tftHeight - 10, 5, bruceConfig.priColor);
if (&fs == &SD) {
if (!setupSdCard()) {
Expand All @@ -573,95 +574,91 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext, String rootPath) {
}
}
bool exit = false;
// returnToMenu=true; // make sure menu is redrawn when quitting in any point

readFs(fs, Folder, allowed_ext);

maxFiles = fileList.size() - 1; // discount the >back operator
maxFiles = fileList.size() - 1;
LongPress = false;
unsigned long LongPressTmp = millis();

while (1) {
delay(10);
// if(returnToMenu) break; // stop this loop and retur to the previous loop
if (exit) break; // stop this loop and retur to the previous loop
yield();

if (redraw) {
if (strcmp(PreFolder.c_str(), Folder.c_str()) != 0 || reload) {
index = 0;
tft.fillScreen(bruceConfig.bgColor);
tft.drawRoundRect(5, 5, tftWidth - 10, tftHeight - 10, 5, bruceConfig.priColor);
Serial.println("reload to read: " + Folder);
readFs(fs, Folder, allowed_ext);
PreFolder = Folder;
maxFiles = fileList.size() - 1;
if (strcmp(PreFolder.c_str(), Folder.c_str()) != 0 || index > maxFiles) index = 0;
reload = false;
}
if (fileList.size() < 2) readFs(fs, Folder, allowed_ext);
if (exit) break;

coord = listFiles(index, fileList);
#if defined(HAS_TOUCH)
TouchFooter();
#endif
redraw = false;
}
displayScrollingText(fileList[index].filename, coord);

// !PrevPress enables EscPress on 3Btn devices to be used in Serial Navigation
// This condition is important for StickCPlus, Core and other 3 Btn devices
if (EscPress && PrevPress) EscPress = false;
char pressed_letter;
if (check(EscPress)) goto BACK_FOLDER;

#ifdef HAS_KEYBOARD
pressed_letter = checkLetterShortcutPress();

// check letter shortcuts
if (pressed_letter > 0) {
// Serial.println(pressed_letter);
if (tolower(fileList[index].filename.c_str()[0]) == pressed_letter) {
// already selected, go to the next
index += 1;
// check if index is still valid
if (index <= maxFiles && tolower(fileList[index].filename.c_str()[0]) == pressed_letter) {
redraw = true;
continue;
{
char pressed_letter = checkLetterShortcutPress();
if (pressed_letter > 0) {
if (tolower(fileList[index].filename.c_str()[0]) == pressed_letter) {
index += 1;
if (index <= maxFiles && tolower(fileList[index].filename.c_str()[0]) == pressed_letter) {
redraw = true;
}
}
}
// else look again from the start
for (int i = 0; i < maxFiles; i++) {
if (tolower(fileList[i].filename.c_str()[0]) == pressed_letter) { // check if 1st char matches
index = i;
redraw = true;
break; // quit on 1st match
for (int i = 0; i < maxFiles; i++) {
if (tolower(fileList[i].filename.c_str()[0]) == pressed_letter) {
index = i;
redraw = true;
break;
}
}
}
}
#endif

if (check(PrevPress) || check(UpPress)) {
if (index == 0) index = maxFiles;
else if (index > 0) index--;
for (int s = 0; s < 3; s++) {
if (index == 0) index = maxFiles;
else index--;
if (s < 2 && !(check(PrevPress) || check(UpPress))) break;
}
redraw = true;
}
/* DW Btn to next item */
if (check(NextPress) || check(DownPress)) {
if (index == maxFiles) index = 0;
else index++;
for (int s = 0; s < 3; s++) {
if (index == maxFiles) index = 0;
else index++;
if (s < 2 && !(check(NextPress) || check(DownPress))) break;
}
redraw = true;
}
if (check(NextPagePress)) {
index += PAGE_JUMP_SIZE;
if (index > maxFiles) index = maxFiles - 1; // check bounds
if (index > maxFiles) index = maxFiles - 1;
redraw = true;
continue;
}
if (check(PrevPagePress)) {
index -= PAGE_JUMP_SIZE;
if (index < 0) index = 0; // check bounds
if (index < 0) index = 0;
redraw = true;
continue;
}

if (redraw) {
bool folderChanged = (strcmp(PreFolder.c_str(), Folder.c_str()) != 0);
bool forceFullRedraw = folderChanged || reload;

if (forceFullRedraw) {
index = 0;
readFs(fs, Folder, allowed_ext);
PreFolder = Folder;
maxFiles = fileList.size() - 1;
reload = false;
resetListFilesCache();
}
if (fileList.size() < 2) readFs(fs, Folder, allowed_ext);

coord = listFiles(index, fileList);
#if defined(HAS_TOUCH)
TouchFooter();
#endif
redraw = false;
}

displayScrollingText(fileList[index].filename, coord);
/* Select to install */
if (LongPress || SelPress) {
if (!LongPress) {
Expand Down Expand Up @@ -753,10 +750,7 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext, String rootPath) {
if (filepath.endsWith(".sub"))
options.insert(options.begin(), {"Subghz Tx", [&]() {
delay(200);
RfCodes data{};

if (readSubFile(&fs, filepath, data))
txSubFile(data);
txSubFile(&fs, filepath);
}});
if (filepath.endsWith(".csv")) {
options.insert(options.begin(), {"Wigle Upload", [&]() {
Expand Down Expand Up @@ -872,7 +866,7 @@ String loopSD(FS &fs, bool filePicker, String allowed_ext, String rootPath) {
redraw = true;
}
WAITING:
delay(10);
yield();
}
}
fileList.clear();
Expand Down