summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-03-07 10:59:03 +1100
committerjacqueline <me@jacqueline.id.au>2024-03-07 10:59:03 +1100
commitef72b25660912ff247997089abfb93e9f0b52809 (patch)
treed5d9711cb5a4192966d914094e9370c446f145fb /src
parent53c4ea7805f1af6a4d2969fc8eabbc8ae26ac5ca (diff)
downloadtangara-fw-ef72b25660912ff247997089abfb93e9f0b52809.tar.gz
use prototype inheritance for lua screens, rather than functions
this gives us a way to give each screen nice little hooks, like 'onShown' and 'onHidden'. later we can use these hooks to disable bindings for screens that aren't in-use.
Diffstat (limited to 'src')
-rw-r--r--src/lua/CMakeLists.txt1
-rw-r--r--src/lua/bridge.cpp2
-rw-r--r--src/lua/include/lua_screen.hpp15
-rw-r--r--src/lua/lua_screen.cpp75
-rw-r--r--src/ui/include/screen.hpp3
-rw-r--r--src/ui/include/screen_lua.hpp3
-rw-r--r--src/ui/screen_lua.cpp36
-rw-r--r--src/ui/ui_fsm.cpp58
8 files changed, 172 insertions, 21 deletions
diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt
index ff0831c9..cee738bd 100644
--- a/src/lua/CMakeLists.txt
+++ b/src/lua/CMakeLists.txt
@@ -5,6 +5,7 @@
idf_component_register(
SRCS "lua_thread.cpp" "bridge.cpp" "property.cpp" "lua_database.cpp"
"lua_queue.cpp" "lua_version.cpp" "lua_controls.cpp" "registry.cpp"
+ "lua_screen.cpp"
INCLUDE_DIRS "include"
REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database"
"esp_timer" "battery" "esp-idf-lua" "luavgl" "lua-linenoise" "lua-term"
diff --git a/src/lua/bridge.cpp b/src/lua/bridge.cpp
index a26f74bb..2bef1c30 100644
--- a/src/lua/bridge.cpp
+++ b/src/lua/bridge.cpp
@@ -19,6 +19,7 @@
#include "lua_controls.hpp"
#include "lua_database.hpp"
#include "lua_queue.hpp"
+#include "lua_screen.hpp"
#include "lua_version.hpp"
#include "lvgl.h"
@@ -84,6 +85,7 @@ auto Bridge::installBaseModules(lua_State* L) -> void {
RegisterDatabaseModule(L);
RegisterQueueModule(L);
RegisterVersionModule(L);
+ RegisterScreenModule(L);
}
auto Bridge::installLvgl(lua_State* L) -> void {
diff --git a/src/lua/include/lua_screen.hpp b/src/lua/include/lua_screen.hpp
new file mode 100644
index 00000000..1c3bed1a
--- /dev/null
+++ b/src/lua/include/lua_screen.hpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include "lua.hpp"
+
+namespace lua {
+
+auto RegisterScreenModule(lua_State*) -> void;
+
+} // namespace lua
diff --git a/src/lua/lua_screen.cpp b/src/lua/lua_screen.cpp
new file mode 100644
index 00000000..27843bc7
--- /dev/null
+++ b/src/lua/lua_screen.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "lua_screen.hpp"
+
+#include <memory>
+#include <string>
+
+#include "lua.hpp"
+
+#include "esp_log.h"
+#include "lauxlib.h"
+#include "lua.h"
+#include "lvgl.h"
+
+#include "bridge.hpp"
+#include "database.hpp"
+#include "event_queue.hpp"
+#include "index.hpp"
+#include "property.hpp"
+#include "service_locator.hpp"
+#include "track.hpp"
+#include "track_queue.hpp"
+#include "ui_events.hpp"
+
+namespace lua {
+
+static auto screen_new(lua_State* L) -> int {
+ // o = o or {}
+ if (lua_gettop(L) != 2) {
+ lua_settop(L, 1);
+ lua_newtable(L);
+ }
+ // Swap o and self on the stack.
+ lua_insert(L, 1);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, 1);
+ lua_settable(L, 1); // self.__index = self
+
+ lua_setmetatable(L, 1); // setmetatable(o, self)
+
+ return 1; // return o
+}
+
+static auto screen_noop(lua_State* state) -> int {
+ return 0;
+}
+
+static const struct luaL_Reg kScreenFuncs[] = {{"new", screen_new},
+ {"createUi", screen_noop},
+ {"onShown", screen_noop},
+ {"onHidden", screen_noop},
+ {NULL, NULL}};
+
+static auto lua_screen(lua_State* state) -> int {
+ luaL_newlib(state, kScreenFuncs);
+
+ lua_pushliteral(state, "__index");
+ lua_pushvalue(state, -2);
+ lua_rawset(state, -3);
+
+ return 1;
+}
+
+auto RegisterScreenModule(lua_State* s) -> void {
+ luaL_requiref(s, "screen", lua_screen, true);
+
+ lua_pop(s, 1);
+}
+
+} // namespace lua
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
index 60939660..4241c712 100644
--- a/src/ui/include/screen.hpp
+++ b/src/ui/include/screen.hpp
@@ -27,6 +27,9 @@ class Screen {
Screen();
virtual ~Screen();
+ virtual auto onShown() -> void {}
+ virtual auto onHidden() -> void {}
+
auto root() -> lv_obj_t* { return root_; }
auto content() -> lv_obj_t* { return content_; }
auto alert() -> lv_obj_t* { return alert_; }
diff --git a/src/ui/include/screen_lua.hpp b/src/ui/include/screen_lua.hpp
index ee9f6813..0ed3a508 100644
--- a/src/ui/include/screen_lua.hpp
+++ b/src/ui/include/screen_lua.hpp
@@ -18,6 +18,9 @@ class Lua : public Screen {
Lua();
~Lua();
+ auto onShown() -> void override;
+ auto onHidden() -> void override;
+
auto SetObjRef(lua_State*) -> void;
private:
diff --git a/src/ui/screen_lua.cpp b/src/ui/screen_lua.cpp
index 5130b4f7..d6c7a26f 100644
--- a/src/ui/screen_lua.cpp
+++ b/src/ui/screen_lua.cpp
@@ -7,8 +7,10 @@
#include "screen_lua.hpp"
#include "core/lv_obj_tree.h"
+#include "lua.h"
#include "lua.hpp"
+#include "lua_thread.hpp"
#include "luavgl.h"
namespace ui {
@@ -22,6 +24,40 @@ Lua::~Lua() {
}
}
+auto Lua::onShown() -> void {
+ if (!s_ || !obj_ref_) {
+ return;
+ }
+ lua_rawgeti(s_, LUA_REGISTRYINDEX, *obj_ref_);
+ lua_pushliteral(s_, "onShown");
+
+ if (lua_gettable(s_, -2) == LUA_TFUNCTION) {
+ lua_pushvalue(s_, -2);
+ lua::CallProtected(s_, 1, 0);
+ } else {
+ lua_pop(s_, 1);
+ }
+
+ lua_pop(s_, 1);
+}
+
+auto Lua::onHidden() -> void {
+ if (!s_ || !obj_ref_) {
+ return;
+ }
+ lua_rawgeti(s_, LUA_REGISTRYINDEX, *obj_ref_);
+ lua_pushliteral(s_, "onHidden");
+
+ if (lua_gettable(s_, -2) == LUA_TFUNCTION) {
+ lua_pushvalue(s_, -2);
+ lua::CallProtected(s_, 1, 0);
+ } else {
+ lua_pop(s_, 1);
+ }
+
+ lua_pop(s_, 1);
+}
+
auto Lua::SetObjRef(lua_State* s) -> void {
assert(s_ == nullptr);
s_ = s;
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index d98e435d..5c22e90e 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -125,21 +125,24 @@ lua::Property UiState::sPlaybackPlaying{
}};
lua::Property UiState::sPlaybackTrack{};
-lua::Property UiState::sPlaybackPosition{0, [](const lua::LuaValue& val) {
- int current_val = std::get<int>(sPlaybackPosition.Get());
- if (!std::holds_alternative<int>(val)) {
- return false;
- }
- int new_val = std::get<int>(val);
- if (current_val != new_val) {
- auto track = sPlaybackTrack.Get();
- if (!std::holds_alternative<audio::Track>(track)) {
+lua::Property UiState::sPlaybackPosition{
+ 0, [](const lua::LuaValue& val) {
+ int current_val = std::get<int>(sPlaybackPosition.Get());
+ if (!std::holds_alternative<int>(val)) {
return false;
}
- events::Audio().Dispatch(audio::SeekFile{.offset = (uint32_t)new_val, .filename = std::get<audio::Track>(track).filepath});
- }
- return true;
-}};
+ int new_val = std::get<int>(val);
+ if (current_val != new_val) {
+ auto track = sPlaybackTrack.Get();
+ if (!std::holds_alternative<audio::Track>(track)) {
+ return false;
+ }
+ events::Audio().Dispatch(audio::SeekFile{
+ .offset = (uint32_t)new_val,
+ .filename = std::get<audio::Track>(track).filepath});
+ }
+ return true;
+ }};
lua::Property UiState::sQueuePosition{0};
lua::Property UiState::sQueueSize{0};
@@ -294,21 +297,29 @@ auto UiState::InitBootSplash(drivers::IGpios& gpios) -> bool {
}
void UiState::PushScreen(std::shared_ptr<Screen> screen) {
+ lv_obj_set_parent(sAlertContainer, screen->alert());
+
if (sCurrentScreen) {
+ sCurrentScreen->onHidden();
sScreens.push(sCurrentScreen);
}
sCurrentScreen = screen;
- lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
+ sCurrentScreen->onShown();
}
int UiState::PopScreen() {
if (sScreens.empty()) {
return 0;
}
- sCurrentScreen = sScreens.top();
- lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
+ lv_obj_set_parent(sAlertContainer, sScreens.top()->alert());
+
+ sCurrentScreen->onHidden();
+ sCurrentScreen = sScreens.top();
sScreens.pop();
+
+ sCurrentScreen->onShown();
+
return sScreens.size();
}
@@ -539,7 +550,7 @@ void Lua::entry() {
auto Lua::PushLuaScreen(lua_State* s) -> int {
// Ensure the arg looks right before continuing.
- luaL_checktype(s, 1, LUA_TFUNCTION);
+ luaL_checktype(s, 1, LUA_TTABLE);
// First, create a new plain old Screen object. We will use its root and
// group for the Lua screen. Allocate it in external ram so that arbitrarily
@@ -554,10 +565,15 @@ auto Lua::PushLuaScreen(lua_State* s) -> int {
lv_group_set_default(new_screen->group());
// Call the constructor for this screen.
- lua_settop(s, 1); // Make sure the function is actually at top of stack
- lua::CallProtected(s, 0, 1);
+ // lua_settop(s, 1); // Make sure the screen is actually at top of stack
+ lua_pushliteral(s, "createUi");
+ if (lua_gettable(s, 1) == LUA_TFUNCTION) {
+ lua_pushvalue(s, 1);
+ lua::CallProtected(s, 1, 0);
+ }
- // Store the reference for the table the constructor returned.
+ // Store the reference for this screen's table.
+ lua_settop(s, 1);
new_screen->SetObjRef(s);
// Finally, push the now-initialised screen as if it were a regular C++
@@ -585,7 +601,7 @@ auto Lua::PopLuaScreen(lua_State* s) -> int {
}
auto Lua::Ticks(lua_State* s) -> int {
- lua_pushinteger(s, esp_timer_get_time()/1000);
+ lua_pushinteger(s, esp_timer_get_time() / 1000);
return 1;
}