refactor: move TileLayoutHelper from DisplayManager.h to Style.h
- Pure static helper class moved from DisplayManager.h to Style.h - Drivers now use TileLayoutHelper::calculateLayouts() directly - Remove extern DisplayManager references from display drivers - Drop LGFX_USE_V1 build flag (no longer needed) - Add delay(LOOP_YIELD_MS) in S3 loop to prevent watchdog
This commit is contained in:
@@ -3,8 +3,7 @@
|
||||
#include <Arduino.h>
|
||||
#include <KlubhausCore.h>
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
extern DisplayManager display;
|
||||
#include <Style.h>
|
||||
|
||||
// ── Fonts ───────────────────────────────────────────────────
|
||||
// TFT_eSPI built-in fonts for 320x480 display (scaled from 800x480)
|
||||
@@ -257,10 +256,11 @@ void DisplayDriverTFT::drawDashboard(const ScreenState& st) {
|
||||
_tft.setCursor(dispW - wifiW - 10, 20);
|
||||
_tft.print(wifiText);
|
||||
|
||||
// Get tile layouts from library helper
|
||||
int tileCount = display.calculateDashboardLayouts(STYLE_HEADER_HEIGHT, STYLE_TILE_GAP);
|
||||
display.setHeaderHeight(STYLE_HEADER_HEIGHT);
|
||||
const TileLayout* layouts = display.getTileLayouts();
|
||||
// Calculate tile layouts using TileLayoutHelper
|
||||
TileLayout layouts[DASHBOARD_TILE_COUNT];
|
||||
int gridCols, gridRows;
|
||||
int tileCount = TileLayoutHelper::calculateLayouts(
|
||||
dispW, dispH, STYLE_HEADER_HEIGHT, STYLE_TILE_GAP, layouts, &gridCols, &gridRows);
|
||||
|
||||
const char* tileLabels[] = { "Alert", "Silent", "Status", "Reboot" };
|
||||
const uint16_t tileColors[] = { 0x0280, 0x0400, 0x0440, 0x0100 };
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <KlubhausCore.h>
|
||||
#include <Style.h>
|
||||
|
||||
// ── Globals ──
|
||||
static LGFX* _gfx = nullptr;
|
||||
extern DisplayManager display;
|
||||
|
||||
// ── Forward declarations ──
|
||||
static void initDisplay();
|
||||
@@ -443,10 +443,11 @@ void DisplayDriverGFX::drawDashboard(const ScreenState& state) {
|
||||
},
|
||||
safeWifi.w);
|
||||
|
||||
// Get tile layouts from library helper
|
||||
int tileCount = display.calculateDashboardLayouts(STYLE_HEADER_HEIGHT, STYLE_TILE_GAP);
|
||||
display.setHeaderHeight(STYLE_HEADER_HEIGHT);
|
||||
const TileLayout* layouts = display.getTileLayouts();
|
||||
// Calculate tile layouts using TileLayoutHelper
|
||||
TileLayout layouts[DASHBOARD_TILE_COUNT];
|
||||
int gridCols, gridRows;
|
||||
int tileCount = TileLayoutHelper::calculateLayouts(
|
||||
DISP_W, DISP_H, STYLE_HEADER_HEIGHT, STYLE_TILE_GAP, layouts, &gridCols, &gridRows);
|
||||
|
||||
const char* tileLabels[] = { "Alert", "Silent", "Status", "Reboot" };
|
||||
const uint16_t tileColors[] = { 0x0280, 0x0400, 0x0440, 0x0100 };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FQBN="esp32:esp32:waveshare_esp32_s3_touch_lcd_43:PSRAM=enabled,FlashSize=16M,USBMode=hwcdc,PartitionScheme=app3M_fat9M_16MB"
|
||||
PORT="/dev/ttyUSB0"
|
||||
LIBS="--library ./vendor/esp32-s3-lcd-43/LovyanGFX"
|
||||
OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM -DLGFX_USE_V1 -DLOCAL_SECRETS"
|
||||
OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM -DLOCAL_SECRETS"
|
||||
|
||||
@@ -38,4 +38,7 @@ void loop() {
|
||||
|
||||
// Serial console
|
||||
logic.processSerial();
|
||||
|
||||
// Yield to WiFi/BT stack
|
||||
delay(LOOP_YIELD_MS);
|
||||
}
|
||||
|
||||
@@ -4,125 +4,6 @@
|
||||
#include "ScreenState.h"
|
||||
#include "Style.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
/// Layout helper for dashboard tiles - computes positions based on constraints
|
||||
class TileLayoutHelper {
|
||||
public:
|
||||
/// Calculate tile layouts for the given display dimensions
|
||||
/// Returns array of TileLayout (must have capacity for DASHBOARD_TILE_COUNT)
|
||||
/// Returns the number of columns and rows used
|
||||
static int calculateLayouts(int displayW, int displayH, int headerH, int margin,
|
||||
TileLayout* outLayouts, int* outCols, int* outRows) {
|
||||
int contentH = displayH - headerH;
|
||||
int tileCount = DASHBOARD_TILE_COUNT;
|
||||
|
||||
// Determine base grid based on display aspect ratio
|
||||
int cols, rows;
|
||||
calculateGrid(tileCount, displayW, contentH, &cols, &rows);
|
||||
|
||||
// Calculate base cell sizes
|
||||
int cellW = displayW / cols;
|
||||
int cellH = contentH / rows;
|
||||
|
||||
// Simple first-fit: place tiles in order, respecting min sizes
|
||||
// For more complex layouts, tiles could specify preferred positions
|
||||
for(int i = 0; i < tileCount; i++) {
|
||||
const DashboardTile& tile = DASHBOARD_TILES[i];
|
||||
int tileCols = tile.constraint.minCols;
|
||||
int tileRows = tile.constraint.minRows;
|
||||
|
||||
// Find next available position
|
||||
int col = 0, row = 0;
|
||||
findNextPosition(outLayouts, i, cols, rows, &col, &row);
|
||||
|
||||
// Ensure tile fits within grid
|
||||
if(col + tileCols > cols)
|
||||
tileCols = cols - col;
|
||||
if(row + tileRows > rows)
|
||||
tileRows = rows - row;
|
||||
|
||||
// Calculate pixel position
|
||||
int x = col * cellW + margin;
|
||||
int y = headerH + row * cellH + margin;
|
||||
int w = tileCols * cellW - 2 * margin;
|
||||
int h = tileRows * cellH - 2 * margin;
|
||||
|
||||
outLayouts[i] = { x, y, w, h, col, row, tileCols, tileRows };
|
||||
}
|
||||
|
||||
*outCols = cols;
|
||||
*outRows = rows;
|
||||
return tileCount;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Calculate optimal grid dimensions based on display and tile constraints
|
||||
static void calculateGrid(
|
||||
int tileCount, int displayW, int contentH, int* outCols, int* outRows) {
|
||||
// Use 2x2 grid for 4 tiles regardless of aspect ratio
|
||||
// This provides better visual balance than a single row
|
||||
if(tileCount == 4) {
|
||||
*outCols = 2;
|
||||
*outRows = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate aspect ratio to determine preferred layout
|
||||
float aspectRatio = (float)displayW / contentH;
|
||||
|
||||
// Start with simple square-ish grid
|
||||
int cols = (int)std::sqrt(tileCount * aspectRatio);
|
||||
if(cols < 1)
|
||||
cols = 1;
|
||||
if(cols > tileCount)
|
||||
cols = tileCount;
|
||||
|
||||
int rows = (tileCount + cols - 1) / cols;
|
||||
|
||||
// For wide displays (landscape), prefer more columns
|
||||
if(aspectRatio > 1.5f && tileCount <= 6) {
|
||||
cols = tileCount;
|
||||
rows = 1;
|
||||
}
|
||||
// For tall displays (portrait), prefer more rows
|
||||
else if(aspectRatio < 0.8f && tileCount <= 6) {
|
||||
rows = tileCount;
|
||||
cols = 1;
|
||||
}
|
||||
|
||||
*outCols = cols;
|
||||
*outRows = rows;
|
||||
}
|
||||
|
||||
/// Find next available grid position
|
||||
static void findNextPosition(const TileLayout* layouts, int count, int gridCols, int gridRows,
|
||||
int* outCol, int* outRow) {
|
||||
// Simple: find first empty cell
|
||||
// Could be enhanced to pack tightly based on tile sizes
|
||||
for(int r = 0; r < gridRows; r++) {
|
||||
for(int c = 0; c < gridCols; c++) {
|
||||
bool occupied = false;
|
||||
for(int i = 0; i < count; i++) {
|
||||
if(layouts[i].col <= c && c < layouts[i].col + layouts[i].cols
|
||||
&& layouts[i].row <= r && r < layouts[i].row + layouts[i].rows) {
|
||||
occupied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!occupied) {
|
||||
*outCol = c;
|
||||
*outRow = r;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: just use count position
|
||||
*outCol = count % gridCols;
|
||||
*outRow = count / gridCols;
|
||||
}
|
||||
};
|
||||
|
||||
class DisplayManager {
|
||||
public:
|
||||
DisplayManager(IDisplayDriver* drv)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
|
||||
struct Layout {
|
||||
uint16_t x, y, w, h;
|
||||
@@ -227,3 +228,120 @@ public:
|
||||
|
||||
static Rect icon(int16_t x, int16_t y, int16_t size) { return Rect(x, y, size, size); }
|
||||
};
|
||||
|
||||
/// Layout helper for dashboard tiles - computes positions based on constraints
|
||||
class TileLayoutHelper {
|
||||
public:
|
||||
/// Calculate tile layouts for the given display dimensions
|
||||
/// Returns array of TileLayout (must have capacity for DASHBOARD_TILE_COUNT)
|
||||
/// Returns the number of columns and rows used
|
||||
static int calculateLayouts(int displayW, int displayH, int headerH, int margin,
|
||||
TileLayout* outLayouts, int* outCols, int* outRows) {
|
||||
int contentH = displayH - headerH;
|
||||
int tileCount = DASHBOARD_TILE_COUNT;
|
||||
|
||||
// Determine base grid based on display aspect ratio
|
||||
int cols, rows;
|
||||
calculateGrid(tileCount, displayW, contentH, &cols, &rows);
|
||||
|
||||
// Calculate base cell sizes
|
||||
int cellW = displayW / cols;
|
||||
int cellH = contentH / rows;
|
||||
|
||||
// Simple first-fit: place tiles in order, respecting min sizes
|
||||
// For more complex layouts, tiles could specify preferred positions
|
||||
for(int i = 0; i < tileCount; i++) {
|
||||
const DashboardTile& tile = DASHBOARD_TILES[i];
|
||||
int tileCols = tile.constraint.minCols;
|
||||
int tileRows = tile.constraint.minRows;
|
||||
|
||||
// Find next available position
|
||||
int col = 0, row = 0;
|
||||
findNextPosition(outLayouts, i, cols, rows, &col, &row);
|
||||
|
||||
// Ensure tile fits within grid
|
||||
if(col + tileCols > cols)
|
||||
tileCols = cols - col;
|
||||
if(row + tileRows > rows)
|
||||
tileRows = rows - row;
|
||||
|
||||
// Calculate pixel position
|
||||
int x = col * cellW + margin;
|
||||
int y = headerH + row * cellH + margin;
|
||||
int w = tileCols * cellW - 2 * margin;
|
||||
int h = tileRows * cellH - 2 * margin;
|
||||
|
||||
outLayouts[i] = { x, y, w, h, col, row, tileCols, tileRows };
|
||||
}
|
||||
|
||||
*outCols = cols;
|
||||
*outRows = rows;
|
||||
return tileCount;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Calculate optimal grid dimensions based on display and tile constraints
|
||||
static void calculateGrid(
|
||||
int tileCount, int displayW, int contentH, int* outCols, int* outRows) {
|
||||
// Use 2x2 grid for 4 tiles regardless of aspect ratio
|
||||
// This provides better visual balance than a single row
|
||||
if(tileCount == 4) {
|
||||
*outCols = 2;
|
||||
*outRows = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate aspect ratio to determine preferred layout
|
||||
float aspectRatio = (float)displayW / contentH;
|
||||
|
||||
// Start with simple square-ish grid
|
||||
int cols = (int)std::sqrt(tileCount * aspectRatio);
|
||||
if(cols < 1)
|
||||
cols = 1;
|
||||
if(cols > tileCount)
|
||||
cols = tileCount;
|
||||
|
||||
int rows = (tileCount + cols - 1) / cols;
|
||||
|
||||
// For wide displays (landscape), prefer more columns
|
||||
if(aspectRatio > 1.5f && tileCount <= 6) {
|
||||
cols = tileCount;
|
||||
rows = 1;
|
||||
}
|
||||
// For tall displays (portrait), prefer more rows
|
||||
else if(aspectRatio < 0.8f && tileCount <= 6) {
|
||||
rows = tileCount;
|
||||
cols = 1;
|
||||
}
|
||||
|
||||
*outCols = cols;
|
||||
*outRows = rows;
|
||||
}
|
||||
|
||||
/// Find next available grid position
|
||||
static void findNextPosition(const TileLayout* layouts, int count, int gridCols, int gridRows,
|
||||
int* outCol, int* outRow) {
|
||||
// Simple: find first empty cell
|
||||
// Could be enhanced to pack tightly based on tile sizes
|
||||
for(int r = 0; r < gridRows; r++) {
|
||||
for(int c = 0; c < gridCols; c++) {
|
||||
bool occupied = false;
|
||||
for(int i = 0; i < count; i++) {
|
||||
if(layouts[i].col <= c && c < layouts[i].col + layouts[i].cols
|
||||
&& layouts[i].row <= r && r < layouts[i].row + layouts[i].rows) {
|
||||
occupied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!occupied) {
|
||||
*outCol = c;
|
||||
*outRow = r;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: just use count position
|
||||
*outCol = count % gridCols;
|
||||
*outRow = count / gridCols;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user