From b17f8a3dcc36ec2479412f603c7b5e77003b80a2 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 18 Apr 2024 11:38:53 +1000 Subject: [PATCH] Merge the StatusBar bindings table with each screen's bindings table --- lua/browser.lua | 2 +- lua/licenses.lua | 22 ++----- lua/main_menu.lua | 16 ++--- lua/playing.lua | 4 +- lua/settings.lua | 161 ++++++++++++++++++++++++---------------------- lua/widgets.lua | 102 +++++++++++++++-------------- 6 files changed, 155 insertions(+), 152 deletions(-) diff --git a/lua/browser.lua b/lua/browser.lua index 5c00e8d1..926fac64 100644 --- a/lua/browser.lua +++ b/lua/browser.lua @@ -24,7 +24,7 @@ return screen:new{ }) self.root:center() - self.status_bar = widgets.StatusBar(self.root, { + self.status_bar = widgets.StatusBar(self, { back_cb = backstack.pop, title = self.title }) diff --git a/lua/licenses.lua b/lua/licenses.lua index 1fa392cf..8d5813c4 100644 --- a/lua/licenses.lua +++ b/lua/licenses.lua @@ -5,13 +5,12 @@ local styles = require("styles") local screen = require("screen") local function show_license(text) - backstack.push(screen:new { + backstack.push(widgets.MenuScreen:new { + show_back = true, + title = "Licenses", createUi = function(self) - self.menu = widgets.MenuScreen { - show_back = true, - title = "Licenses", - } - self.menu.root:Label { + widgets.MenuScreen.createUi(self) + self.root:Label { w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, text_font = font.fusion_10, @@ -74,13 +73,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI end -return function() - local menu = widgets.MenuScreen({ - show_back = true, - title = "Licenses" - }) - - local container = menu.root:Object { +return function(self) + local container = self.root:Object { flex = { flex_direction = "column", flex_wrap = "nowrap", @@ -178,6 +172,4 @@ return function() library("tremor", "bsd", function() xiphbsd("Copyright (c) 2002, Xiph.org Foundation") end) - - return menu end diff --git a/lua/main_menu.lua b/lua/main_menu.lua index ac9190be..5fd6417f 100644 --- a/lua/main_menu.lua +++ b/lua/main_menu.lua @@ -7,17 +7,17 @@ local playing = require("playing") local styles = require("styles") local screen = require("screen") -return screen:new { - createUi = function() - local menu = widgets.MenuScreen({}) +return widgets.MenuScreen:new { + createUi = function(self) + widgets.MenuScreen.createUi(self) - menu.list = lvgl.List(menu.root, { + local list = lvgl.List(self.root, { w = lvgl.PCT(100), h = lvgl.PCT(100), flex_grow = 1, }) - local now_playing = menu.list:add_btn(nil, "Now Playing") + local now_playing = list:add_btn(nil, "Now Playing") now_playing:onClicked(function() backstack.push(playing:new()) end) @@ -25,7 +25,7 @@ return screen:new { local indexes = database.indexes() for _, idx in ipairs(indexes) do - local btn = menu.list:add_btn(nil, tostring(idx)) + local btn = list:add_btn(nil, tostring(idx)) btn:onClicked(function() backstack.push(browser:new { title = tostring(idx), @@ -35,12 +35,10 @@ return screen:new { btn:add_style(styles.list_item) end - local settings = menu.list:add_btn(nil, "Settings") + local settings = list:add_btn(nil, "Settings") settings:onClicked(function() backstack.push(require("settings"):new()) end) settings:add_style(styles.list_item) - - return menu end, } diff --git a/lua/playing.lua b/lua/playing.lua index deee6987..bfca8b68 100644 --- a/lua/playing.lua +++ b/lua/playing.lua @@ -41,7 +41,7 @@ return screen:new { }) self.root:center() - self.status_bar = widgets.StatusBar(self.root, { + self.status_bar = widgets.StatusBar(self, { back_cb = backstack.pop, transparent_bg = true, }) @@ -201,7 +201,7 @@ return screen:new { controls:Object({ flex_grow = 1, h = 1 }) -- spacer - self.bindings = { + self.bindings = self.bindings + { playback.playing:bind(function(playing) if playing then play_pause_img:set_src(img.pause) diff --git a/lua/settings.lua b/lua/settings.lua index 282fc04a..7059a02d 100644 --- a/lua/settings.lua +++ b/lua/settings.lua @@ -8,35 +8,33 @@ local controls = require("controls") local bluetooth = require("bluetooth") local theme = require("theme") local database = require("database") -local screen = require("screen") local usb = require("usb") -local function SettingsScreen(title) - local menu = widgets.MenuScreen { - show_back = true, - title = title, - } - menu.content = menu.root:Object { - flex = { - flex_direction = "column", - flex_wrap = "nowrap", - justify_content = "flex-start", - align_items = "flex-start", - align_content = "flex-start", - }, - w = lvgl.PCT(100), - flex_grow = 1, - pad_left = 4, - pad_right = 4, - } - return menu -end - -local BluetoothSettings = screen:new { +local SettingsScreen = widgets.MenuScreen:new { + show_back = true, createUi = function(self) - self.menu = SettingsScreen("Bluetooth") + widgets.MenuScreen.createUi(self) + self.content = self.root:Object { + flex = { + flex_direction = "column", + flex_wrap = "nowrap", + justify_content = "flex-start", + align_items = "flex-start", + align_content = "flex-start", + }, + w = lvgl.PCT(100), + flex_grow = 1, + pad_left = 4, + pad_right = 4, + } + end +} - local enable_container = self.menu.content:Object { +local BluetoothSettings = SettingsScreen:new { + title = "Bluetooth", + createUi = function(self) + SettingsScreen.createUi(self) + local enable_container = self.content:Object { flex = { flex_direction = "row", justify_content = "flex-start", @@ -54,12 +52,12 @@ local BluetoothSettings = screen:new { bluetooth.enabled:set(enabled) end) - theme.set_style(self.menu.content:Label { + theme.set_style(self.content:Label { text = "Paired Device", pad_bottom = 1, }, "settings_title") - local paired_container = self.menu.content:Object { + local paired_container = self.content:Object { flex = { flex_direction = "row", justify_content = "flex-start", @@ -80,17 +78,17 @@ local BluetoothSettings = screen:new { bluetooth.paired_device:set() end) - theme.set_style(self.menu.content:Label { + theme.set_style(self.content:Label { text = "Nearby Devices", pad_bottom = 1, }, "settings_title") - local devices = self.menu.content:List { + local devices = self.content:List { w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, } - self.bindings = { + self.bindings = self.bindings + { bluetooth.enabled:bind(function(en) if en then enable_sw:add_state(lvgl.STATE.CHECKED) @@ -119,15 +117,16 @@ local BluetoothSettings = screen:new { end } -local HeadphonesSettings = screen:new { +local HeadphonesSettings = SettingsScreen:new { + title = "Headphones", createUi = function(self) - self.menu = SettingsScreen("Headphones") + SettingsScreen.createUi(self) - theme.set_style(self.menu.content:Label { + theme.set_style(self.content:Label { text = "Maxiumum volume limit", }, "settings_title") - local volume_chooser = self.menu.content:Dropdown { + local volume_chooser = self.content:Dropdown { options = "Line Level (-10 dB)\nCD Level (+6 dB)\nMaximum (+10dB)", selected = 1, } @@ -138,11 +137,11 @@ local HeadphonesSettings = screen:new { volume.limit_db:set(limits[selection]) end) - theme.set_style(self.menu.content:Label { + theme.set_style(self.content:Label { text = "Left/Right balance", }, "settings_title") - local balance = self.menu.content:Slider { + local balance = self.content:Slider { w = lvgl.PCT(100), h = 5, range = { min = -100, max = 100 }, @@ -152,9 +151,9 @@ local HeadphonesSettings = screen:new { volume.left_bias:set(balance:value()) end) - local balance_label = self.menu.content:Label {} + local balance_label = self.content:Label {} - self.bindings = { + self.bindings = self.bindings + { volume.limit_db:bind(function(limit) for i = 1, #limits do if limits[i] == limit then @@ -182,11 +181,12 @@ local HeadphonesSettings = screen:new { end } -local DisplaySettings = screen:new { +local DisplaySettings = SettingsScreen:new { + title = "Display", createUi = function(self) - self.menu = SettingsScreen("Display") + SettingsScreen.createUi(self) - local brightness_title = self.menu.content:Object { + local brightness_title = self.content:Object { flex = { flex_direction = "row", justify_content = "flex-start", @@ -201,7 +201,7 @@ local DisplaySettings = screen:new { local brightness_pct = brightness_title:Label {} theme.set_style(brightness_pct, "settings_title") - local brightness = self.menu.content:Slider { + local brightness = self.content:Slider { w = lvgl.PCT(100), h = 5, range = { min = 0, max = 100 }, @@ -211,7 +211,7 @@ local DisplaySettings = screen:new { display.brightness:set(brightness:value()) end) - self.bindings = { + self.bindings = self.bindings + { display.brightness:bind(function(b) brightness_pct:set { text = tostring(b) .. "%" } end) @@ -219,11 +219,12 @@ local DisplaySettings = screen:new { end } -local InputSettings = screen:new { +local InputSettings = SettingsScreen:new { + title = "Input Method", createUi = function(self) - self.menu = SettingsScreen("Input Method") + SettingsScreen.createUi(self) - theme.set_style(self.menu.content:Label { + theme.set_style(self.content:Label { text = "Control scheme", }, "settings_title") @@ -244,11 +245,11 @@ local InputSettings = screen:new { option_idx = option_idx + 1 end - local controls_chooser = self.menu.content:Dropdown { + local controls_chooser = self.content:Dropdown { options = options, } - self.bindings = { + self.bindings = self.bindings + { controls.scheme:bind(function(s) local option = scheme_to_option[s] controls_chooser:set({ selected = option }) @@ -266,7 +267,7 @@ local InputSettings = screen:new { }, "settings_title") local slider_scale = 4; -- Power steering - local sensitivity = self.menu.content:Slider { + local sensitivity = self.content:Slider { w = lvgl.PCT(90), h = 5, range = { min = 0, max = 255 / slider_scale }, @@ -278,19 +279,21 @@ local InputSettings = screen:new { end } -local MassStorageSettings = screen:new { +local MassStorageSettings = SettingsScreen:new { + title = "USB Storage", createUi = function(self) - self.menu = SettingsScreen("USB Storage") + SettingsScreen.createUi(self) + local version = require("version").samd() if tonumber(version) < 3 then - self.menu.content:Label { + self.content:Label { w = lvgl.PCT(100), text = "Usb Mass Storage requires a SAMD21 firmware version >=3." } return end - local enable_container = self.menu.content:Object { + local enable_container = self.content:Object { flex = { flex_direction = "row", justify_content = "flex-start", @@ -304,7 +307,7 @@ local MassStorageSettings = screen:new { enable_container:Label { text = "Enable", flex_grow = 1 } local enable_sw = enable_container:Switch {} - local busy_text = self.menu.content:Label { + local busy_text = self.content:Label { w = lvgl.PCT(100), text = "USB is currently busy. Do not unplug or remove the SD card.", long_mode = lvgl.LABEL.LONG_WRAP, @@ -325,7 +328,7 @@ local MassStorageSettings = screen:new { bind_switch() end) - self.bindings = { + self.bindings = self.bindings + { usb.msc_enabled:bind(bind_switch), usb.msc_busy:bind(function(busy) if busy then @@ -341,14 +344,16 @@ local MassStorageSettings = screen:new { end } -local DatabaseSettings = screen:new { +local DatabaseSettings = SettingsScreen:new { + title = "Database", createUi = function(self) - self.menu = SettingsScreen("Database") + SettingsScreen.createUi(self) + local db = require("database") - widgets.Row(self.menu.content, "Schema version", db.version()) - widgets.Row(self.menu.content, "Size on disk", string.format("%.1f KiB", db.size() / 1024)) + widgets.Row(self.content, "Schema version", db.version()) + widgets.Row(self.content, "Size on disk", string.format("%.1f KiB", db.size() / 1024)) - local auto_update_container = self.menu.content:Object { + local auto_update_container = self.content:Object { flex = { flex_direction = "row", justify_content = "flex-start", @@ -366,7 +371,7 @@ local DatabaseSettings = screen:new { database.auto_update:set(auto_update_sw:enabled()) end) - local actions_container = self.menu.content:Object { + local actions_container = self.content:Object { w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, flex = { @@ -386,7 +391,7 @@ local DatabaseSettings = screen:new { database.update() end) - self.bindings = { + self.bindings = self.bindings + { database.auto_update:bind(function(en) if en then auto_update_sw:add_state(lvgl.STATE.CHECKED) @@ -398,36 +403,38 @@ local DatabaseSettings = screen:new { end } -local FirmwareSettings = screen:new { +local FirmwareSettings = SettingsScreen:new { + title = "Firmware", createUi = function(self) - self.menu = SettingsScreen("Firmware") + SettingsScreen.createUi(self) local version = require("version") - widgets.Row(self.menu.content, "ESP32", version.esp()) - widgets.Row(self.menu.content, "SAMD21", version.samd()) - widgets.Row(self.menu.content, "Collator", version.collator()) + widgets.Row(self.content, "ESP32", version.esp()) + widgets.Row(self.content, "SAMD21", version.samd()) + widgets.Row(self.content, "Collator", version.collator()) end } -local LicensesScreen = screen:new { +local LicensesScreen = SettingsScreen:new { + title = "Licenses", createUi = function(self) - self.root = require("licenses")() + SettingsScreen.createUi(self) + self.root = require("licenses")(self) end } -return screen:new { +return widgets.MenuScreen:new { + show_back = true, + title = "Settings", createUi = function(self) - self.menu = widgets.MenuScreen { - show_back = true, - title = "Settings", - } - self.list = self.menu.root:List { + widgets.MenuScreen.createUi(self) + local list = self.root:List { w = lvgl.PCT(100), h = lvgl.PCT(100), flex_grow = 1, } local function section(name) - local elem = self.list:Label { + local elem = list:Label { text = name, pad_left = 4, } @@ -435,7 +442,7 @@ return screen:new { end local function submenu(name, class) - local item = self.list:add_btn(nil, name) + local item = list:add_btn(nil, name) item:onClicked(function() backstack.push(class:new()) end) diff --git a/lua/widgets.lua b/lua/widgets.lua index fa991758..be018e19 100644 --- a/lua/widgets.lua +++ b/lua/widgets.lua @@ -6,6 +6,7 @@ local backstack = require("backstack") local styles = require("styles") local database = require("database") local theme = require("theme") +local screen = require("screen") local img = { db = lvgl.ImgData("//lua/img/db.png"), @@ -23,27 +24,29 @@ local img = { local widgets = {} -function widgets.MenuScreen(opts) - local screen = {} - screen.root = lvgl.Object(nil, { - flex = { - flex_direction = "column", - flex_wrap = "nowrap", - justify_content = "flex-start", - align_items = "flex-start", - align_content = "flex-start", - }, - w = lvgl.PCT(100), - h = lvgl.PCT(100), - }) - screen.root:center() - screen.status_bar = widgets.StatusBar(screen.root, { - back_cb = opts.show_back and backstack.pop or nil, - title = opts.title, - transparent_bg = true - }) - return screen -end +widgets.MenuScreen = screen:new { + show_back = false, + title = "", + createUi = function(self) + self.root = lvgl.Object(nil, { + flex = { + flex_direction = "column", + flex_wrap = "nowrap", + justify_content = "flex-start", + align_items = "flex-start", + align_content = "flex-start", + }, + w = lvgl.PCT(100), + h = lvgl.PCT(100), + }) + self.root:center() + self.status_bar = widgets.StatusBar(self, { + back_cb = self.show_back and backstack.pop or nil, + title = self.title, + transparent_bg = true + }) + end +} function widgets.Row(parent, left, right) local container = parent:Object { @@ -61,10 +64,14 @@ function widgets.Row(parent, left, right) container:Label { text = right } end -function widgets.StatusBar(parent, opts) - local status_bar = {} +local bindings_meta = { + __add = function(a, b) + return table.move(a, 1, #a, #b + 1, b) + end +} - status_bar.root = parent:Object { +function widgets.StatusBar(parent, opts) + local root = parent.root:Object { flex = { flex_direction = "row", justify_content = "flex-start", @@ -81,19 +88,19 @@ function widgets.StatusBar(parent, opts) } if not opts.transparent_bg then - theme.set_style(status_bar.root, "header"); + theme.set_style(root, "header"); end if opts.back_cb then - status_bar.back = status_bar.root:Button { + local back = root:Button { w = lvgl.SIZE_CONTENT, h = 12, } - status_bar.back:Label({ text = "<", align = lvgl.ALIGN.CENTER }) - status_bar.back:onClicked(opts.back_cb) + back:Label({ text = "<", align = lvgl.ALIGN.CENTER }) + back:onClicked(opts.back_cb) end - status_bar.title = status_bar.root:Label { + local title = root:Label { w = lvgl.PCT(100), h = lvgl.SIZE_CONTENT, text_font = font.fusion_10, @@ -102,15 +109,15 @@ function widgets.StatusBar(parent, opts) flex_grow = 1, } if opts.title then - status_bar.title:set { text = opts.title } + title:set { text = opts.title } end - status_bar.db_updating = status_bar.root:Image { src = img.db } - theme.set_style(status_bar.db_updating, "database_indicator") - status_bar.bluetooth = status_bar.root:Image {} - status_bar.battery = status_bar.root:Image {} - status_bar.chg = status_bar.battery:Image { src = img.chg } - status_bar.chg:center() + local db_updating = root:Image { src = img.db } + theme.set_style(db_updating, "database_indicator") + local bt_icon = root:Image {} + local battery_icon = root:Image {} + local charge_icon = battery_icon:Image { src = img.chg } + charge_icon:center() local is_charging = nil local percent = nil @@ -136,19 +143,19 @@ function widgets.StatusBar(parent, opts) end end if is_charging then - status_bar.chg:clear_flag(lvgl.FLAG.HIDDEN) + charge_icon:clear_flag(lvgl.FLAG.HIDDEN) else - status_bar.chg:add_flag(lvgl.FLAG.HIDDEN) + charge_icon:add_flag(lvgl.FLAG.HIDDEN) end - status_bar.battery:set_src(src) + battery_icon:set_src(src) end - status_bar.bindings = { + parent.bindings = { database.updating:bind(function(yes) if yes then - status_bar.db_updating:clear_flag(lvgl.FLAG.HIDDEN) + db_updating:clear_flag(lvgl.FLAG.HIDDEN) else - status_bar.db_updating:add_flag(lvgl.FLAG.HIDDEN) + db_updating:add_flag(lvgl.FLAG.HIDDEN) end end), power.battery_pct:bind(function(pct) @@ -161,21 +168,20 @@ function widgets.StatusBar(parent, opts) end), bluetooth.enabled:bind(function(en) if en then - status_bar.bluetooth:clear_flag(lvgl.FLAG.HIDDEN) + bt_icon:clear_flag(lvgl.FLAG.HIDDEN) else - status_bar.bluetooth:add_flag(lvgl.FLAG.HIDDEN) + bt_icon:add_flag(lvgl.FLAG.HIDDEN) end end), bluetooth.connected:bind(function(connected) if connected then - status_bar.bluetooth:set_src(img.bt_conn) + bt_icon:set_src(img.bt_conn) else - status_bar.bluetooth:set_src(img.bt) + bt_icon:set_src(img.bt) end end), } - - return status_bar + setmetatable(parent.bindings, bindings_meta) end function widgets.IconBtn(parent, icon, text)