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:
@@ -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