Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
38 changes: 38 additions & 0 deletions include/MenuItemInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#include "core/display.h"
#include <globals.h>

// Pixel span a menu icon covers when drawn at scale 1. Lower it to render the icons
// bigger inside the same box, raise it if the widest ones start touching their label.
#define ICON_SCALE_REFERENCE 80.0f

class MenuItemInterface {
public:
virtual ~MenuItemInterface() = default;
Expand Down Expand Up @@ -42,6 +46,40 @@ class MenuItemInterface {
drawStatusBar();
}

// Renders drawIcon() inside an arbitrary box instead of the full screen icon area,
// used by the grid main menu. The icons paint straight to `tft` using the member
// coordinates and read their colors from bruceConfig, so both are swapped for the
// call and put back afterwards.
void drawIconInBox(int centerX, int centerY, int box, uint16_t fgColor, uint16_t bgColor) {
int oldCenterX = iconCenterX, oldCenterY = iconCenterY;
int oldAreaX = iconAreaX, oldAreaY = iconAreaY;
int oldAreaW = iconAreaW, oldAreaH = iconAreaH;
uint16_t oldPriColor = bruceConfig.priColor;
uint16_t oldBgColor = bruceConfig.bgColor;

iconCenterX = centerX;
iconCenterY = centerY;
iconAreaW = box;
iconAreaH = box;
iconAreaX = centerX - box / 2;
iconAreaY = centerY - box / 2;
bruceConfig.priColor = fgColor;
bruceConfig.bgColor = bgColor;

// The widest icon spans about ICON_SCALE_REFERENCE px at scale 1, so dividing by it
// keeps every icon inside `box` and stops it bleeding into the neighbouring cells.
drawIcon((float)box / ICON_SCALE_REFERENCE);

bruceConfig.priColor = oldPriColor;
bruceConfig.bgColor = oldBgColor;
iconCenterX = oldCenterX;
iconCenterY = oldCenterY;
iconAreaX = oldAreaX;
iconAreaY = oldAreaY;
iconAreaW = oldAreaW;
iconAreaH = oldAreaH;
}

void drawArrows(float scale = 1) {
tft.fillRect(arrowAreaX, iconAreaY, arrowAreaW, iconAreaH, bruceConfig.bgColor);
tft.fillRect(
Expand Down
19 changes: 19 additions & 0 deletions src/core/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ JsonDocument BruceConfig::toJson() const {
setting["wdgwarsApiKey"] = wdgwarsApiKey;
setting["devMode"] = devMode;
setting["colorInverted"] = colorInverted;
setting["mainMenuStyle"] = mainMenuStyle;

setting["badUSBBLEKeyboardLayout"] = badUSBBLEKeyboardLayout;
setting["badUSBBLEKeyDelay"] = badUSBBLEKeyDelay;
Expand Down Expand Up @@ -386,6 +387,12 @@ void BruceConfig::fromFile(bool checkFS) {
count++;
log_e("Fail");
}
if (!setting["mainMenuStyle"].isNull()) {
mainMenuStyle = setting["mainMenuStyle"].as<int>();
} else {
count++;
log_e("Fail");
}

if (!setting["badUSBBLEKeyboardLayout"].isNull()) {
badUSBBLEKeyboardLayout = setting["badUSBBLEKeyboardLayout"].as<int>();
Expand Down Expand Up @@ -483,6 +490,7 @@ void BruceConfig::validateConfig() {
validateMifareKeysItems();
validateDevModeValue();
validateColorInverted();
validateMainMenuStyle();
validateBadUSBBLEKeyboardLayout();
validateBadUSBBLEKeyDelay();
validateEvilEndpointCreds();
Expand Down Expand Up @@ -783,6 +791,17 @@ void BruceConfig::validateColorInverted() {
if (colorInverted > 1) colorInverted = 1;
}

void BruceConfig::setMainMenuStyle(int value) {
mainMenuStyle = value;
validateMainMenuStyle();
saveFile();
}

void BruceConfig::validateMainMenuStyle() {
if (mainMenuStyle < MAIN_MENU_CAROUSEL || mainMenuStyle > MAIN_MENU_GRID)
mainMenuStyle = MAIN_MENU_CAROUSEL;
}

void BruceConfig::setBadUSBBLEKeyboardLayout(int value) {
badUSBBLEKeyboardLayout = value;
validateBadUSBBLEKeyboardLayout();
Expand Down
7 changes: 7 additions & 0 deletions src/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@

enum EvilPortalPasswordMode { FULL_PASSWORD = 0, FIRST_LAST_CHAR = 1, HIDE_PASSWORD = 2, SAVE_LENGTH = 3 };

// How the main menu presents the modules:
// CAROUSEL shows one big icon at a time, GRID exposes every module as a selectable cell
enum MainMenuStyle { MAIN_MENU_CAROUSEL = 0, MAIN_MENU_GRID = 1 };

class BruceConfig : public BruceTheme {
public:
struct WiFiCredential {
Expand Down Expand Up @@ -87,6 +91,7 @@ class BruceConfig : public BruceTheme {
String wdgwarsApiKey = "your 64-char hex key from wdgwars.pl/profile";
int devMode = 0;
int colorInverted = 1;
int mainMenuStyle = MAIN_MENU_CAROUSEL;
int badUSBBLEKeyboardLayout = 0;
uint16_t badUSBBLEKeyDelay = 10;
bool badUSBBLEShowOutput = true;
Expand Down Expand Up @@ -192,6 +197,8 @@ class BruceConfig : public BruceTheme {
void validateDevModeValue();
void setColorInverted(int value);
void validateColorInverted();
void setMainMenuStyle(int value);
void validateMainMenuStyle();
void setBadUSBBLEKeyboardLayout(int value);
void validateBadUSBBLEKeyboardLayout();
void setBadUSBBLEKeyDelay(uint16_t value);
Expand Down
29 changes: 29 additions & 0 deletions src/core/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#define MAX_MENU_SIZE (int)(tftHeight / 25)

uint8_t mainMenuGridColumns = 0;

// Send the ST7789 into or out of sleep mode
void panelSleep(bool on) {
#if defined(ST7789_2_DRIVER) || defined(ST7789_DRIVER)
Expand Down Expand Up @@ -630,6 +632,33 @@ int loopOptions(
break;
}

// Grid main menu: Up/Down jump a whole row, Prev/Next keep stepping one cell at a time.
// Consumed here so the linear handlers below don't also act on the same press.
if (menuType == MENU_TYPE_MAIN && mainMenuGridColumns > 1 &&
mainMenuGridColumns < static_cast<int>(options.size())) {
int rowStep = 0;
if (check(UpPress)) rowStep = -1;
else if (check(DownPress)) rowStep = 1;

if (rowStep != 0) {
int size = static_cast<int>(options.size());
int cols = mainMenuGridColumns;
int rows = (size + cols - 1) / cols;
int col = index % cols;
int row = index / cols + rowStep;

if (row < 0) row = rows - 1;
else if (row >= rows) row = 0;

int idx = row * cols + col;
if (idx >= size) idx = size - 1; // the last row can be shorter than the others
if (options[idx].enabled) index = idx;

devModeCounter = 0;
redraw = true;
}
}

#ifdef HAS_ENCODER
int32_t rotarySteps = drainRotarySteps();
if (rotarySteps != 0) {
Expand Down
4 changes: 4 additions & 0 deletions src/core/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#define MENU_TYPE_SUBMENU 1
#define MENU_TYPE_REGULAR 2

// Columns of the main menu grid layout, set by MainMenu::begin().
// 0 means the carousel layout is active and navigation stays linear.
extern uint8_t mainMenuGridColumns;

void panelSleep(bool on);
void turnOffDisplay();
bool wakeUpScreen();
Expand Down
Loading
Loading