chore: lsp + formatting
This commit is contained in:
+96
-72
@@ -21,17 +21,19 @@ esp32lua::Paths slatePaths() {
|
||||
}
|
||||
|
||||
// Reads an optional positive integer field off the bar module on the stack top.
|
||||
lua_Integer barField(lua_State* state, const char* key, lua_Integer fallback) {
|
||||
lua_Integer barField(lua_State *state, const char *key, lua_Integer fallback) {
|
||||
lua_getfield(state, -1, key);
|
||||
const lua_Integer value = lua_isinteger(state, -1) ? lua_tointeger(state, -1) : fallback;
|
||||
const lua_Integer value =
|
||||
lua_isinteger(state, -1) ? lua_tointeger(state, -1) : fallback;
|
||||
lua_pop(state, 1);
|
||||
return value > 0 ? value : fallback;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
// Called from the initializer list once every provider member exists, which declaration order
|
||||
// guarantees: the runtime holds pointers to them for its whole life.
|
||||
// Called from the initializer list once every provider member exists, which
|
||||
// declaration order guarantees: the runtime holds pointers to them for its
|
||||
// whole life.
|
||||
esp32lua::Providers LuaHost::wire() {
|
||||
esp32lua::Providers providers;
|
||||
providers.log = &logProvider;
|
||||
@@ -44,126 +46,140 @@ esp32lua::Providers LuaHost::wire() {
|
||||
providers.wifi = &wifiProvider;
|
||||
providers.ble = &bleProvider;
|
||||
providers.touch = &touchProvider;
|
||||
// No buttons on this board, so sys.hasFeature("buttons") is false and input gains nothing.
|
||||
// No buttons on this board, so sys.hasFeature("buttons") is false and input
|
||||
// gains nothing.
|
||||
return providers;
|
||||
}
|
||||
|
||||
LuaHost::LuaHost(TFT_eSPI& tft, XPT2046_Touchscreen& touch)
|
||||
: tft(tft),
|
||||
touchPanel(touch),
|
||||
settingsProvider(*this),
|
||||
guiProvider(tft, *this),
|
||||
touchProvider(touch, *this),
|
||||
LuaHost::LuaHost(TFT_eSPI &tft, XPT2046_Touchscreen &touch)
|
||||
: tft(tft), touchPanel(touch), settingsProvider(*this),
|
||||
guiProvider(tft, *this), touchProvider(touch, *this),
|
||||
runtime(wire(), slatePaths()) {}
|
||||
|
||||
void LuaHost::mapTouch(const TS_Point& point, int16_t& x, int16_t& y) const {
|
||||
const int16_t nx = constrain(map(point.y, settings.touchX0, settings.touchX1, 0, PANEL_W), 0, PANEL_W - 1);
|
||||
const int16_t ny = constrain(map(point.x, settings.touchY0, settings.touchY1, 0, PANEL_H), 0, PANEL_H - 1);
|
||||
void LuaHost::mapTouch(const TS_Point &point, int16_t &x, int16_t &y) const {
|
||||
const int16_t nx =
|
||||
constrain(map(point.y, settings.touchX0, settings.touchX1, 0, PANEL_W), 0,
|
||||
PANEL_W - 1);
|
||||
const int16_t ny =
|
||||
constrain(map(point.x, settings.touchY0, settings.touchY1, 0, PANEL_H), 0,
|
||||
PANEL_H - 1);
|
||||
switch (tft.getRotation() & 3) {
|
||||
case 1:
|
||||
x = ny;
|
||||
y = PANEL_W - 1 - nx;
|
||||
break;
|
||||
case 2:
|
||||
x = PANEL_W - 1 - nx;
|
||||
y = PANEL_H - 1 - ny;
|
||||
break;
|
||||
case 3:
|
||||
x = PANEL_H - 1 - ny;
|
||||
y = nx;
|
||||
break;
|
||||
default:
|
||||
x = nx;
|
||||
y = ny;
|
||||
break;
|
||||
case 1:
|
||||
x = ny;
|
||||
y = PANEL_W - 1 - nx;
|
||||
break;
|
||||
case 2:
|
||||
x = PANEL_W - 1 - nx;
|
||||
y = PANEL_H - 1 - ny;
|
||||
break;
|
||||
case 3:
|
||||
x = PANEL_H - 1 - ny;
|
||||
y = nx;
|
||||
break;
|
||||
default:
|
||||
x = nx;
|
||||
y = ny;
|
||||
break;
|
||||
}
|
||||
// App space starts below the bar, matching the viewport apps draw into. A tap on the bar
|
||||
// itself lands at a negative y, which pollTouch() drops.
|
||||
// App space starts below the bar, matching the viewport apps draw into. A tap
|
||||
// on the bar itself lands at a negative y, which pollTouch() drops.
|
||||
y -= barInset();
|
||||
}
|
||||
|
||||
// resetViewport() first: width()/height() report the viewport once one is set, so re-applying
|
||||
// over an existing one would shrink the app area again every time. setRotation() leaves the old
|
||||
// viewport metrics behind, so every rotation needs this too.
|
||||
// resetViewport() first: width()/height() report the viewport once one is set,
|
||||
// so re-applying over an existing one would shrink the app area again every
|
||||
// time. setRotation() leaves the old viewport metrics behind, so every rotation
|
||||
// needs this too.
|
||||
void LuaHost::applyViewport() {
|
||||
const int16_t inset = barInset();
|
||||
tft.resetViewport();
|
||||
if (inset > 0) tft.setViewport(0, inset, tft.width(), tft.height() - inset, true);
|
||||
if (inset > 0)
|
||||
tft.setViewport(0, inset, tft.width(), tft.height() - inset, true);
|
||||
}
|
||||
|
||||
void LuaHost::applyRotation() {
|
||||
tft.setRotation(settings.rotationIndex());
|
||||
applyViewport();
|
||||
refreshStatusBar(); // every slot in the bar just moved
|
||||
refreshStatusBar(); // every slot in the bar just moved
|
||||
}
|
||||
|
||||
void LuaHost::setFullscreen(bool on) {
|
||||
fullscreen = on;
|
||||
applyViewport();
|
||||
nextBarMs = 0; // leaving fullscreen left the bar's rows painted by the app
|
||||
nextBarMs = 0; // leaving fullscreen left the bar's rows painted by the app
|
||||
}
|
||||
|
||||
bool LuaHost::begin() {
|
||||
prepareForApp();
|
||||
if (!runtime.startApp("Home")) return false;
|
||||
if (!runtime.startApp("Home"))
|
||||
return false;
|
||||
settleNewApp();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LuaHost::prepareForApp() {
|
||||
tft.setRotation(settings.rotationIndex()); // the previous app may have rotated the frame
|
||||
tft.setRotation(
|
||||
settings.rotationIndex()); // the previous app may have rotated the frame
|
||||
fullscreen = false;
|
||||
// Applied before the app loads, because init() measures the panel it was given. The height
|
||||
// is the last app's, which is the same module, and settleNewApp() corrects it if that changes.
|
||||
// Applied before the app loads, because init() measures the panel it was
|
||||
// given. The height is the last app's, which is the same module, and
|
||||
// settleNewApp() corrects it if that changes.
|
||||
applyViewport();
|
||||
lastTouched = true; // the tap that launched this app may still be down
|
||||
ignoreRelease = true; // and its release is not this app's gesture
|
||||
lastTouched = true; // the tap that launched this app may still be down
|
||||
ignoreRelease = true; // and its release is not this app's gesture
|
||||
backArmed = false;
|
||||
Serial.printf("[lua] launching free=%u largest=%u\n", ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
Serial.printf("[lua] launching free=%u largest=%u\n", ESP.getFreeHeap(),
|
||||
ESP.getMaxAllocHeap());
|
||||
}
|
||||
|
||||
void LuaHost::settleNewApp() {
|
||||
hasBack = runtime.canGoBack(); // the runtime keeps the history; the bar only offers the control
|
||||
hasBack = runtime.canGoBack(); // the runtime keeps the history; the bar only
|
||||
// offers the control
|
||||
loadStatusBar();
|
||||
applyViewport();
|
||||
if (barInset() > 0 && !barBroken) drawStatusBar();
|
||||
if (barInset() > 0 && !barBroken)
|
||||
drawStatusBar();
|
||||
const uint32_t now = millis();
|
||||
nextDrawMs = now;
|
||||
lastDrawMs = now;
|
||||
Serial.printf("[lua] running %s\n", runtime.appPath().c_str());
|
||||
}
|
||||
|
||||
// The bar is a Lua module like any other, loaded per app because the state is too.
|
||||
// The bar is a Lua module like any other, loaded per app because the state is
|
||||
// too.
|
||||
void LuaHost::loadStatusBar() {
|
||||
lua_State* state = runtime.state();
|
||||
lua_State *state = runtime.state();
|
||||
barBroken = false;
|
||||
barIntervalMs = BAR_INTERVAL_MS;
|
||||
|
||||
lua_getglobal(state, "require");
|
||||
lua_pushstring(state, "statusbar");
|
||||
if (lua_pcall(state, 1, 1, 0) != LUA_OK || !lua_istable(state, -1)) {
|
||||
Serial.printf("[statusbar] unavailable: %s\n", luaL_tolstring(state, -1, nullptr));
|
||||
// Nothing has measured the panel yet, so surrendering the strip here is free.
|
||||
Serial.printf("[statusbar] unavailable: %s\n",
|
||||
luaL_tolstring(state, -1, nullptr));
|
||||
// Nothing has measured the panel yet, so surrendering the strip here is
|
||||
// free.
|
||||
barBroken = true;
|
||||
barHeight = 0;
|
||||
lua_pop(state, 2);
|
||||
return;
|
||||
}
|
||||
barHeight = barField(state, "height", DEFAULT_BAR_H);
|
||||
barIntervalMs = std::max<lua_Integer>(DRAW_INTERVAL_MS, barField(state, "interval", BAR_INTERVAL_MS));
|
||||
barIntervalMs = std::max<lua_Integer>(
|
||||
DRAW_INTERVAL_MS, barField(state, "interval", BAR_INTERVAL_MS));
|
||||
lua_setglobal(state, "__statusbar");
|
||||
nextBarMs = 0;
|
||||
}
|
||||
|
||||
// Errors here disable the bar rather than killing the app: chrome that fails should not take
|
||||
// the running program with it.
|
||||
// Errors here disable the bar rather than killing the app: chrome that fails
|
||||
// should not take the running program with it.
|
||||
void LuaHost::drawStatusBar() {
|
||||
lua_State* state = runtime.state();
|
||||
lua_State *state = runtime.state();
|
||||
lua_getglobal(state, "__statusbar");
|
||||
lua_getfield(state, -1, "draw");
|
||||
lua_remove(state, -2);
|
||||
lua_pushboolean(state, hasBack);
|
||||
tft.resetViewport(); // the bar paints in panel coordinates, the app does not
|
||||
tft.resetViewport(); // the bar paints in panel coordinates, the app does not
|
||||
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
|
||||
Serial.printf("[statusbar] %s\n", luaL_tolstring(state, -1, nullptr));
|
||||
lua_pop(state, 2);
|
||||
@@ -172,9 +188,9 @@ void LuaHost::drawStatusBar() {
|
||||
applyViewport();
|
||||
}
|
||||
|
||||
// Deliberately not themed: this can fire when the settings naming the theme are themselves
|
||||
// unreadable, so it stays high contrast.
|
||||
void LuaHost::fail(const char* message) {
|
||||
// Deliberately not themed: this can fire when the settings naming the theme are
|
||||
// themselves unreadable, so it stays high contrast.
|
||||
void LuaHost::fail(const char *message) {
|
||||
Serial.printf("[lua] %s\n", message ? message : "(unknown)");
|
||||
tft.resetViewport();
|
||||
tft.fillScreen(TFT_WHITE);
|
||||
@@ -187,10 +203,12 @@ void LuaHost::fail(const char* message) {
|
||||
|
||||
void LuaHost::pollTouch() {
|
||||
bool touched = touchPanel.touched();
|
||||
if (touched) mapTouch(touchPanel.getPoint(), lastX, lastY);
|
||||
if (touched)
|
||||
mapTouch(touchPanel.getPoint(), lastX, lastY);
|
||||
|
||||
// The bar is the host's: apps never see a touch in it, and its one control acts on release,
|
||||
// so a press that slides off into the app cancels like any other button.
|
||||
// The bar is the host's: apps never see a touch in it, and its one control
|
||||
// acts on release, so a press that slides off into the app cancels like any
|
||||
// other button.
|
||||
if (touched && lastY < 0) {
|
||||
backArmed = backArmed || inBackButton();
|
||||
touched = false;
|
||||
@@ -207,8 +225,9 @@ void LuaHost::pollTouch() {
|
||||
movedY = lastY;
|
||||
runtime.callTouch(esp32lua::TouchPhase::Down, lastX, lastY);
|
||||
} else if (touched && lastTouched) {
|
||||
// The XPT2046 jitters a pixel or two under a still finger. Below this every poll would
|
||||
// fire a move, and a painting app would draw a blur where nothing moved.
|
||||
// The XPT2046 jitters a pixel or two under a still finger. Below this every
|
||||
// poll would fire a move, and a painting app would draw a blur where
|
||||
// nothing moved.
|
||||
if (abs(lastX - movedX) + abs(lastY - movedY) >= MOVE_EPSILON_PX) {
|
||||
movedX = lastX;
|
||||
movedY = lastY;
|
||||
@@ -228,7 +247,8 @@ void LuaHost::pollTimers() {
|
||||
timerProvider.collectDue(millis(), due);
|
||||
for (size_t at = 0; at < due.size(); at++) {
|
||||
runtime.callTimer(due[at]);
|
||||
if (runtime.hasPendingNavigation()) return; // the app is leaving; its other timers can wait
|
||||
if (runtime.hasPendingNavigation())
|
||||
return; // the app is leaving; its other timers can wait
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,10 +262,12 @@ void LuaHost::navigate() {
|
||||
}
|
||||
|
||||
void LuaHost::loop() {
|
||||
if (!runtime.hasApp()) return;
|
||||
if (!runtime.hasApp())
|
||||
return;
|
||||
|
||||
pollTouch();
|
||||
if (!runtime.hasPendingNavigation()) pollTimers();
|
||||
if (!runtime.hasPendingNavigation())
|
||||
pollTimers();
|
||||
|
||||
const uint32_t now = millis();
|
||||
if (!runtime.hasPendingNavigation() && now >= nextDrawMs) {
|
||||
@@ -254,12 +276,14 @@ void LuaHost::loop() {
|
||||
lastDrawMs = now;
|
||||
}
|
||||
|
||||
if (!runtime.hasPendingNavigation() && barInset() > 0 && !barBroken && now >= nextBarMs) {
|
||||
if (!runtime.hasPendingNavigation() && barInset() > 0 && !barBroken &&
|
||||
now >= nextBarMs) {
|
||||
nextBarMs = now + barIntervalMs;
|
||||
drawStatusBar();
|
||||
}
|
||||
|
||||
// Between batches, never inside one: swapping the lua_State mid-callback would free the VM
|
||||
// that is still executing.
|
||||
if (runtime.hasPendingNavigation()) navigate();
|
||||
// Between batches, never inside one: swapping the lua_State mid-callback
|
||||
// would free the VM that is still executing.
|
||||
if (runtime.hasPendingNavigation())
|
||||
navigate();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user