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.
custom
jacqueline 1 year ago
parent 53c4ea7805
commit ef72b25660
  1. 64
      lua/browser.lua
  2. 13
      lua/licenses.lua
  3. 19
      lua/main_menu.lua
  4. 35
      lua/playing.lua
  5. 159
      lua/settings.lua
  6. 1
      src/lua/CMakeLists.txt
  7. 2
      src/lua/bridge.cpp
  8. 15
      src/lua/include/lua_screen.hpp
  9. 75
      src/lua/lua_screen.cpp
  10. 3
      src/ui/include/screen.hpp
  11. 3
      src/ui/include/screen_lua.hpp
  12. 36
      src/ui/screen_lua.cpp
  13. 38
      src/ui/ui_fsm.cpp

@ -6,12 +6,11 @@ local queue = require("queue")
local playing = require("playing")
local theme = require("theme")
local playback = require("playback")
local screen = require("screen")
local browser = {}
function browser.create(opts)
local screen = {}
screen.root = lvgl.Object(nil, {
return screen:new {
createUi = function(self)
self.root = lvgl.Object(nil, {
flex = {
flex_direction = "column",
flex_wrap = "wrap",
@ -22,14 +21,14 @@ function browser.create(opts)
w = lvgl.HOR_RES(),
h = lvgl.VER_RES(),
})
screen.root:center()
self.root:center()
screen.status_bar = widgets.StatusBar(screen.root, {
title = opts.title,
self.status_bar = widgets.StatusBar(self.root, {
title = self.title,
})
if opts.breadcrumb then
local header = screen.root:Object {
if self.breadcrumb then
local header = self.root:Object {
flex = {
flex_direction = "column",
flex_wrap = "wrap",
@ -48,7 +47,7 @@ function browser.create(opts)
}
header:Label {
text = opts.breadcrumb,
text = self.breadcrumb,
text_font = font.fusion_10,
}
@ -64,7 +63,7 @@ function browser.create(opts)
h = lvgl.SIZE_CONTENT,
pad_column = 4,
})
local original_iterator = opts.iterator:clone()
local original_iterator = self.iterator:clone()
local enqueue = widgets.IconBtn(buttons, "//lua/img/enqueue.png", "Enqueue")
enqueue:onClicked(function()
queue.add(original_iterator)
@ -81,57 +80,52 @@ function browser.create(opts)
)
end
screen.list = lvgl.List(screen.root, {
self.list = lvgl.List(self.root, {
w = lvgl.PCT(100),
h = lvgl.PCT(100),
flex_grow = 1,
scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF,
})
local back = screen.list:add_btn(nil, "< Back")
local back = self.list:add_btn(nil, "< Back")
back:onClicked(backstack.pop)
back:add_style(theme.list_item)
screen.focused_item = 0
screen.last_item = 0
screen.add_item = function(item)
self.focused_item = 0
self.last_item = 0
self.add_item = function(item)
if not item then return end
screen.last_item = screen.last_item + 1
local this_item = screen.last_item
local btn = screen.list:add_btn(nil, tostring(item))
self.last_item = self.last_item + 1
local this_item = self.last_item
local btn = self.list:add_btn(nil, tostring(item))
btn:onClicked(function()
local contents = item:contents()
if type(contents) == "userdata" then
backstack.push(function()
return browser.create({
title = opts.title,
backstack.push(require("browser"):new {
title = self.title,
iterator = contents,
breadcrumb = tostring(item),
})
end)
else
queue.clear()
queue.add(contents)
playback.playing:set(true)
backstack.push(playing)
backstack.push(playing:new())
end
end)
btn:onevent(lvgl.EVENT.FOCUSED, function()
screen.focused_item = this_item
if screen.last_item - 5 < this_item then
screen.add_item(opts.iterator())
self.focused_item = this_item
if self.last_item - 5 < this_item then
self.add_item(self.iterator())
end
end)
btn:add_style(theme.list_item)
end
for _ = 1, 8 do
local val = opts.iterator()
local val = self.iterator()
if not val then break end
screen.add_item(val)
self.add_item(val)
end
return screen
end
return browser.create
end
}

@ -2,20 +2,23 @@ local backstack = require("backstack")
local widgets = require("widgets")
local font = require("font")
local theme = require("theme")
local screen = require("screen")
local function show_license(text)
backstack.push(function()
local screen = widgets.MenuScreen {
backstack.push(screen:new {
createUi = function(self)
self.menu = widgets.MenuScreen {
show_back = true,
title = "Licenses",
}
screen.root:Label {
self.menu.root:Label {
w = lvgl.PCT(100),
h = lvgl.SIZE_CONTENT,
text_font = font.fusion_10,
text = text,
}
end)
end
})
end
local function gpl(copyright)
@ -175,4 +178,6 @@ return function()
library("tremor", "bsd", function()
xiphbsd("Copyright (c) 2002, Xiph.org Foundation")
end)
return menu
end

@ -5,8 +5,10 @@ local backstack = require("backstack")
local browser = require("browser")
local playing = require("playing")
local theme = require("theme")
local screen = require("screen")
return function()
return screen:new {
createUi = function()
local menu = widgets.MenuScreen({})
menu.list = lvgl.List(menu.root, {
@ -17,7 +19,7 @@ return function()
local now_playing = menu.list:add_btn(nil, "Now Playing")
now_playing:onClicked(function()
backstack.push(playing)
backstack.push(playing:new())
end)
now_playing:add_style(theme.list_item)
@ -25,21 +27,20 @@ return function()
for _, idx in ipairs(indexes) do
local btn = menu.list:add_btn(nil, tostring(idx))
btn:onClicked(function()
backstack.push(function()
return browser {
backstack.push(browser:new {
title = tostring(idx),
iterator = idx:iter()
}
end)
iterator = idx:iter(),
})
end)
btn:add_style(theme.list_item)
end
local settings = menu.list:add_btn(nil, "Settings")
settings:onClicked(function()
backstack.push(require("settings").root)
backstack.push(require("settings"):new())
end)
settings:add_style(theme.list_item)
return menu
end
end,
}

@ -4,6 +4,7 @@ local backstack = require("backstack")
local font = require("font")
local playback = require("playback")
local queue = require("queue")
local screen = require("screen")
local img = {
play = "//lua/img/play.png",
@ -18,9 +19,11 @@ local img = {
repeat_disabled = "//lua/img/repeat_disabled.png",
}
return function(opts)
local screen = {}
screen.root = lvgl.Object(nil, {
local is_now_playing_shown = false
return screen:new {
createUi = function(self)
self.root = lvgl.Object(nil, {
flex = {
flex_direction = "column",
flex_wrap = "wrap",
@ -31,14 +34,14 @@ return function(opts)
w = lvgl.HOR_RES(),
h = lvgl.VER_RES(),
})
screen.root:center()
self.root:center()
screen.status_bar = widgets.StatusBar(screen.root, {
self.status_bar = widgets.StatusBar(self.root, {
back_cb = backstack.pop,
transparent_bg = true,
})
local info = screen.root:Object {
local info = self.root:Object {
flex = {
flex_direction = "column",
flex_wrap = "wrap",
@ -66,7 +69,7 @@ return function(opts)
text_align = 2,
}
local playlist = screen.root:Object {
local playlist = self.root:Object {
flex = {
flex_direction = "row",
justify_content = "center",
@ -112,7 +115,7 @@ return function(opts)
}
playlist:Object({ w = 3, h = 1 }) -- spacer
local scrubber = screen.root:Slider {
local scrubber = self.root:Slider {
w = lvgl.PCT(100),
h = 5,
range = { min = 0, max = 100 },
@ -123,7 +126,7 @@ return function(opts)
playback.position:set(scrubber:value())
end)
local controls = screen.root:Object {
local controls = self.root:Object {
flex = {
flex_direction = "row",
justify_content = "center",
@ -173,7 +176,7 @@ return function(opts)
return string.format("%d:%02d", time // 60, time % 60)
end
screen.bindings = {
self.bindings = {
playback.playing:bind(function(playing)
if playing then
play_pause_img:set_src(img.pause)
@ -231,6 +234,12 @@ return function(opts)
playlist_total:set { text = tostring(num) }
end),
}
return screen
end
end,
onShown = function() is_now_playing_shown = true end,
onHidden = function() is_now_playing_shown = false end,
pushIfNotShown = function(self)
if not is_now_playing_shown then
backstack.push(self:new())
end
end
}

@ -7,8 +7,7 @@ local display = require("display")
local controls = require("controls")
local bluetooth = require("bluetooth")
local database = require("database")
local settings = {}
local screen = require("screen")
local function SettingsScreen(title)
local menu = widgets.MenuScreen {
@ -31,10 +30,11 @@ local function SettingsScreen(title)
return menu
end
function settings.bluetooth()
local menu = SettingsScreen("Bluetooth")
local BluetoothSettings = screen:new {
createUi = function(self)
self.menu = SettingsScreen("Bluetooth")
local enable_container = menu.content:Object {
local enable_container = self.menu.content:Object {
flex = {
flex_direction = "row",
justify_content = "flex-start",
@ -52,12 +52,12 @@ function settings.bluetooth()
bluetooth.enabled:set(enabled)
end)
menu.content:Label {
self.menu.content:Label {
text = "Paired Device",
pad_bottom = 1,
}:add_style(theme.settings_title)
local paired_container = menu.content:Object {
local paired_container = self.menu.content:Object {
flex = {
flex_direction = "row",
justify_content = "flex-start",
@ -78,17 +78,17 @@ function settings.bluetooth()
bluetooth.paired_device:set()
end)
menu.content:Label {
self.menu.content:Label {
text = "Nearby Devices",
pad_bottom = 1,
}:add_style(theme.settings_title)
local devices = menu.content:List {
local devices = self.menu.content:List {
w = lvgl.PCT(100),
h = lvgl.SIZE_CONTENT,
}
menu.bindings = {
self.bindings = {
bluetooth.enabled:bind(function(en)
if en then
enable_sw:add_state(lvgl.STATE.CHECKED)
@ -114,16 +114,18 @@ function settings.bluetooth()
end
end)
}
end
end
}
function settings.headphones()
local menu = SettingsScreen("Headphones")
local HeadphonesSettings = screen:new {
createUi = function(self)
self.menu = SettingsScreen("Headphones")
menu.content:Label {
self.menu.content:Label {
text = "Maximum volume limit",
}:add_style(theme.settings_title)
local volume_chooser = menu.content:Dropdown {
local volume_chooser = self.menu.content:Dropdown {
options = "Line Level (-10 dB)\nCD Level (+6 dB)\nMaximum (+10dB)",
selected = 1,
}
@ -134,11 +136,11 @@ function settings.headphones()
volume.limit_db:set(limits[selection])
end)
menu.content:Label {
self.menu.content:Label {
text = "Left/Right balance",
}:add_style(theme.settings_title)
local balance = menu.content:Slider {
local balance = self.menu.content:Slider {
w = lvgl.PCT(100),
h = 5,
range = { min = -100, max = 100 },
@ -148,9 +150,9 @@ function settings.headphones()
volume.left_bias:set(balance:value())
end)
local balance_label = menu.content:Label {}
local balance_label = self.menu.content:Label {}
menu.bindings = {
self.bindings = {
volume.limit_db:bind(function(limit)
for i = 1, #limits do
if limits[i] == limit then
@ -175,14 +177,14 @@ function settings.headphones()
end
end),
}
end
}
return menu
end
function settings.display()
local menu = SettingsScreen("Display")
local DisplaySettings = screen:new {
createUi = function(self)
self.menu = SettingsScreen("Display")
local brightness_title = menu.content:Object {
local brightness_title = self.menu.content:Object {
flex = {
flex_direction = "row",
justify_content = "flex-start",
@ -196,7 +198,7 @@ function settings.display()
local brightness_pct = brightness_title:Label {}
brightness_pct:add_style(theme.settings_title)
local brightness = menu.content:Slider {
local brightness = self.menu.content:Slider {
w = lvgl.PCT(100),
h = 5,
range = { min = 0, max = 100 },
@ -206,19 +208,19 @@ function settings.display()
display.brightness:set(brightness:value())
end)
menu.bindings = {
self.bindings = {
display.brightness:bind(function(b)
brightness_pct:set { text = tostring(b) .. "%" }
end)
}
end
}
return menu
end
function settings.input()
local menu = SettingsScreen("Input Method")
local InputSettings = screen:new {
createUi = function(self)
self.menu = SettingsScreen("Input Method")
menu.content:Label {
self.menu.content:Label {
text = "Control scheme",
}:add_style(theme.settings_title)
@ -239,11 +241,11 @@ function settings.input()
option_idx = option_idx + 1
end
local controls_chooser = menu.content:Dropdown {
local controls_chooser = self.menu.content:Dropdown {
options = options,
}
menu.bindings = {
self.bindings = {
controls.scheme:bind(function(s)
local option = scheme_to_option[s]
controls_chooser:set({ selected = option })
@ -256,31 +258,31 @@ function settings.input()
controls.scheme:set(scheme)
end)
menu.content:Label {
self.menu.content:Label {
text = "Scroll Sensitivity",
}:add_style(theme.settings_title)
local slider_scale = 4; -- Power steering
local sensitivity = menu.content:Slider {
local sensitivity = self.menu.content:Slider {
w = lvgl.PCT(90),
h = 5,
range = { min = 0, max = 255/slider_scale },
value = controls.scroll_sensitivity:get()/slider_scale,
range = { min = 0, max = 255 / slider_scale },
value = controls.scroll_sensitivity:get() / slider_scale,
}
sensitivity:onevent(lvgl.EVENT.VALUE_CHANGED, function()
controls.scroll_sensitivity:set(sensitivity:value()*slider_scale)
controls.scroll_sensitivity:set(sensitivity:value() * slider_scale)
end)
end
}
return menu
end
function settings.database()
local menu = SettingsScreen("Database")
local DatabaseSettings = screen:new {
createUi = function(self)
self.menu = SettingsScreen("Database")
local db = require("database")
widgets.Row(menu.content, "Schema version", db.version())
widgets.Row(menu.content, "Size on disk", string.format("%.1f KiB", db.size() / 1024))
widgets.Row(self.menu.content, "Schema version", db.version())
widgets.Row(self.menu.content, "Size on disk", string.format("%.1f KiB", db.size() / 1024))
local actions_container = menu.content:Object {
local actions_container = self.menu.content:Object {
w = lvgl.PCT(100),
h = lvgl.SIZE_CONTENT,
flex = {
@ -299,55 +301,60 @@ function settings.database()
update:onClicked(function()
database.update()
end)
end
end
}
function settings.firmware()
local menu = SettingsScreen("Firmware")
local FirmwareSettings = screen:new {
createUi = function(self)
self.menu = SettingsScreen("Firmware")
local version = require("version")
widgets.Row(menu.content, "ESP32", version.esp())
widgets.Row(menu.content, "SAMD21", version.samd())
widgets.Row(menu.content, "Collator", version.collator())
end
widgets.Row(self.menu.content, "ESP32", version.esp())
widgets.Row(self.menu.content, "SAMD21", version.samd())
widgets.Row(self.menu.content, "Collator", version.collator())
end
}
function settings.root()
local menu = widgets.MenuScreen {
local LicensesScreen = screen:new {
createUi = function(self)
self.root = require("licenses")()
end
}
return screen:new {
createUi = function(self)
self.menu = widgets.MenuScreen {
show_back = true,
title = "Settings",
}
menu.list = menu.root:List {
self.list = self.menu.root:List {
w = lvgl.PCT(100),
h = lvgl.PCT(100),
flex_grow = 1,
}
local function section(name)
menu.list:add_text(name):add_style(theme.list_heading)
self.list:add_text(name):add_style(theme.list_heading)
end
local function submenu(name, fn)
local item = menu.list:add_btn(nil, name)
local function submenu(name, class)
local item = self.list:add_btn(nil, name)
item:onClicked(function()
backstack.push(fn)
backstack.push(class:new())
end)
item:add_style(theme.list_item)
end
section("Audio")
submenu("Bluetooth", settings.bluetooth)
submenu("Headphones", settings.headphones)
submenu("Bluetooth", BluetoothSettings)
submenu("Headphones", HeadphonesSettings)
section("Interface")
submenu("Display", settings.display)
submenu("Input Method", settings.input)
submenu("Display", DisplaySettings)
submenu("Input Method", InputSettings)
section("System")
submenu("Database", settings.database)
submenu("Firmware", settings.firmware)
submenu("Licenses", function()
return require("licenses")()
end)
return menu
end
return settings
submenu("Database", DatabaseSettings)
submenu("Firmware", FirmwareSettings)
submenu("Licenses", LicensesScreen)
end
}

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

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

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

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

@ -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_; }

@ -18,6 +18,9 @@ class Lua : public Screen {
Lua();
~Lua();
auto onShown() -> void override;
auto onHidden() -> void override;
auto SetObjRef(lua_State*) -> void;
private:

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

@ -125,7 +125,8 @@ lua::Property UiState::sPlaybackPlaying{
}};
lua::Property UiState::sPlaybackTrack{};
lua::Property UiState::sPlaybackPosition{0, [](const lua::LuaValue& val) {
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;
@ -136,10 +137,12 @@ lua::Property UiState::sPlaybackPosition{0, [](const lua::LuaValue& val) {
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});
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;
}

Loading…
Cancel
Save