From 14552881900bb3ed0e9ed2d4a732e4104b32ccfa Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 6 Mar 2024 13:59:33 +1100 Subject: [PATCH 1/3] Restore the previous track position when booting --- src/audio/audio_fsm.cpp | 43 +++++++++++++++++++++++++++--- src/audio/include/audio_events.hpp | 1 + src/audio/track_queue.cpp | 2 +- src/database/database.cpp | 8 ++++-- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index d4272c3d..05c7c216 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -13,6 +13,8 @@ #include "audio_sink.hpp" #include "bluetooth_types.hpp" +#include "cppbor.h" +#include "cppbor_parse.h" #include "esp_heap_caps.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" @@ -58,6 +60,8 @@ StreamBufferHandle_t AudioState::sDrainBuffer; std::optional AudioState::sCurrentTrack; bool AudioState::sIsPlaybackAllowed; +static std::optional> sLastTrackUpdate; + void AudioState::react(const system_fsm::BluetoothEvent& ev) { if (ev.event != drivers::bluetooth::Event::kConnectionStateChanged) { return; @@ -310,11 +314,15 @@ void Standby::react(const QueueUpdate& ev) { if (!current_track || (sCurrentTrack && (*sCurrentTrack == *current_track))) { return; } + if (ev.reason == QueueUpdate::Reason::kDeserialised && sLastTrackUpdate) { + return; + } clearDrainBuffer(); playTrack(*current_track); } static const char kQueueKey[] = "audio:queue"; +static const char kCurrentFileKey[] = "audio:current"; void Standby::react(const system_fsm::KeyLockChanged& ev) { if (!ev.locking) { @@ -332,6 +340,14 @@ void Standby::react(const system_fsm::KeyLockChanged& ev) { return; } db->put(kQueueKey, queue.serialise()); + + if (sLastTrackUpdate) { + cppbor::Array current_track{ + cppbor::Tstr{sLastTrackUpdate->first}, + cppbor::Uint{sLastTrackUpdate->second}, + }; + db->put(kCurrentFileKey, current_track.toString()); + } }); } @@ -341,13 +357,32 @@ void Standby::react(const system_fsm::StorageMounted& ev) { if (!db) { return; } - auto res = db->get(kQueueKey); - if (res) { + + // Restore the currently playing file before restoring the queue. This way, + // we can fall back to restarting the queue's current track if there's any + // issue restoring the current file. + auto current = db->get(kCurrentFileKey); + if (current) { + // Again, ensure we don't boot-loop by trying to play a track that causes + // a crash over and over again. + db->put(kCurrentFileKey, ""); + auto [parsed, unused, err] = cppbor::parse( + reinterpret_cast(current->data()), current->size()); + if (parsed->type() == cppbor::ARRAY) { + std::string filename = parsed->asArray()->get(0)->asTstr()->value(); + uint32_t pos = parsed->asArray()->get(1)->asUint()->value(); + sLastTrackUpdate = std::make_pair(filename, pos); + sFileSource->SetPath(filename, pos); + } + } + + auto queue = db->get(kQueueKey); + if (queue) { // Don't restore the same queue again. This ideally should do nothing, // but guards against bad edge cases where restoring the queue ends up // causing a crash. db->put(kQueueKey, ""); - sServices->track_queue().deserialise(*res); + sServices->track_queue().deserialise(*queue); } }); } @@ -399,6 +434,7 @@ void Playback::react(const QueueUpdate& ev) { void Playback::react(const PlaybackUpdate& ev) { ESP_LOGI(kTag, "elapsed: %lu, total: %lu", ev.seconds_elapsed, ev.track->duration); + sLastTrackUpdate = std::make_pair(ev.track->filepath, ev.seconds_elapsed); } void Playback::react(const internal::InputFileOpened& ev) {} @@ -407,6 +443,7 @@ void Playback::react(const internal::InputFileClosed& ev) {} void Playback::react(const internal::InputFileFinished& ev) { ESP_LOGI(kTag, "finished playing file"); + sLastTrackUpdate.reset(); sServices->track_queue().finish(); if (!sServices->track_queue().current()) { for (int i = 0; i < 20; i++) { diff --git a/src/audio/include/audio_events.hpp b/src/audio/include/audio_events.hpp index d55e4e0d..a8533646 100644 --- a/src/audio/include/audio_events.hpp +++ b/src/audio/include/audio_events.hpp @@ -44,6 +44,7 @@ struct QueueUpdate : tinyfsm::Event { kExplicitUpdate, kRepeatingLastTrack, kTrackFinished, + kDeserialised, }; Reason reason; }; diff --git a/src/audio/track_queue.cpp b/src/audio/track_queue.cpp index ccadd3a6..a3f4c815 100644 --- a/src/audio/track_queue.cpp +++ b/src/audio/track_queue.cpp @@ -486,7 +486,7 @@ auto TrackQueue::deserialise(const std::string& s) -> void { QueueParseClient client{*this}; const uint8_t* data = reinterpret_cast(s.data()); cppbor::parse(data, data + s.size(), &client); - notifyChanged(true, Reason::kExplicitUpdate); + notifyChanged(true, Reason::kDeserialised); } } // namespace audio diff --git a/src/database/database.cpp b/src/database/database.cpp index ec11455b..ca92cf6b 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -229,13 +229,17 @@ auto Database::sizeOnDiskBytes() -> size_t { } auto Database::put(const std::string& key, const std::string& val) -> void { - db_->Put(leveldb::WriteOptions{}, kKeyCustom + key, val); + if (val.empty()) { + db_->Delete(leveldb::WriteOptions{}, kKeyCustom + key); + } else { + db_->Put(leveldb::WriteOptions{}, kKeyCustom + key, val); + } } auto Database::get(const std::string& key) -> std::optional { std::string val; auto res = db_->Get(leveldb::ReadOptions{}, kKeyCustom + key, &val); - if (!res.ok()) { + if (!res.ok() || val.empty()) { return {}; } return val; From 36a19182bec171d6376e51f5689aaf70b9d6fbad Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 7 Mar 2024 17:22:06 +1100 Subject: [PATCH 2/3] Use luals-stubs as the source of truth for docs, instead of maintaining separate docs stubs Includes introducing a cool new script to turn lua-language-server's json output into markdown documentation. --- ldoc-stubs/alerts.lua | 13 -- ldoc-stubs/backstack.lua | 13 -- ldoc-stubs/bluetooth.lua | 13 -- ldoc-stubs/database.lua | 59 ------ ldoc-stubs/playback.lua | 19 -- ldoc-stubs/power.lua | 18 -- ldoc-stubs/queue.lua | 32 --- ldoc-stubs/types.lua | 35 --- ldoc-stubs/volume.lua | 14 -- luals-stubs/alerts.lua | 6 +- luals-stubs/backstack.lua | 13 +- luals-stubs/bluetooth.lua | 8 +- luals-stubs/controls.lua | 12 ++ luals-stubs/database.lua | 31 ++- luals-stubs/display.lua | 9 + luals-stubs/playback.lua | 3 +- luals-stubs/power.lua | 3 +- luals-stubs/queue.lua | 20 +- luals-stubs/screen.lua | 25 +++ luals-stubs/time.lua | 12 ++ luals-stubs/types.lua | 12 +- luals-stubs/volume.lua | 7 +- tools/luals-gendoc/gendoc.lua | 143 +++++++++++++ tools/luals-gendoc/json.lua | 388 ++++++++++++++++++++++++++++++++++ 24 files changed, 678 insertions(+), 230 deletions(-) delete mode 100644 ldoc-stubs/alerts.lua delete mode 100644 ldoc-stubs/backstack.lua delete mode 100644 ldoc-stubs/bluetooth.lua delete mode 100644 ldoc-stubs/database.lua delete mode 100644 ldoc-stubs/playback.lua delete mode 100644 ldoc-stubs/power.lua delete mode 100644 ldoc-stubs/queue.lua delete mode 100644 ldoc-stubs/types.lua delete mode 100644 ldoc-stubs/volume.lua create mode 100644 luals-stubs/controls.lua create mode 100644 luals-stubs/display.lua create mode 100644 luals-stubs/screen.lua create mode 100644 luals-stubs/time.lua create mode 100755 tools/luals-gendoc/gendoc.lua create mode 100644 tools/luals-gendoc/json.lua diff --git a/ldoc-stubs/alerts.lua b/ldoc-stubs/alerts.lua deleted file mode 100644 index 6fecdd7c..00000000 --- a/ldoc-stubs/alerts.lua +++ /dev/null @@ -1,13 +0,0 @@ ---- Module for showing transient popups over the current screen. --- @module alerts - -local alerts = {} - ---- Shows a new alert, replacing any already visible alerts. --- @tparam function constructor Called to create the UI for the alert. A new default root object and group will be set before calling this function.i Alerts are non-interactable; the group created for the constructor will not be granted focus. -function alerts.show(constructor) end - ---- Dismisses any visible alerts, removing them from the screen. -function alerts.hide() end - -return alerts diff --git a/ldoc-stubs/backstack.lua b/ldoc-stubs/backstack.lua deleted file mode 100644 index d4807d37..00000000 --- a/ldoc-stubs/backstack.lua +++ /dev/null @@ -1,13 +0,0 @@ ---- Module for adding and removing screens from the system's backstack. --- @module backstack - -local backstack = {} - ---- Pushes a new screen onto the backstack. --- @tparam function constructor Called to create the UI for the new screen. A new default root object and group will be set before calling this function. The function provided should return a table holding any bindings used by this screen; the returned value is retained so long as this screen is present in the backstack. -function backstack.push(constructor) end - ---- Removes the currently active screen, and instead shows the screen underneath it on the backstack. Does nothing if this is the only existing screen. -function backstack.pop() end - -return backstack diff --git a/ldoc-stubs/bluetooth.lua b/ldoc-stubs/bluetooth.lua deleted file mode 100644 index 3160ef7e..00000000 --- a/ldoc-stubs/bluetooth.lua +++ /dev/null @@ -1,13 +0,0 @@ ---- Properties and functions for handling Bluetooth connectivity --- @module bluetooth -local bluetooth = {} - ---- Whether or not the Bluetooth stack is currently enabled. This property is writeable, and can be used to enable or disable Bluetooth. --- @see types.Property -bluetooth.enabled = types.Property - ---- Whether or not there is an active connection to another Bluetooth device. --- @see types.Property -bluetooth.connected = types.Property - -return bluetooth diff --git a/ldoc-stubs/database.lua b/ldoc-stubs/database.lua deleted file mode 100644 index 97359ab1..00000000 --- a/ldoc-stubs/database.lua +++ /dev/null @@ -1,59 +0,0 @@ ---- Module for accessing and updating data about the user's library of tracks. --- @module database - -local database = {} - ---- Returns a list of all indexes in the database. --- @treturn Array(Index) -function database.indexes() end - ---- An iterator is a userdata type that behaves like an ordinary Lua iterator. --- @type Iterator -local Iterator = {} - ---- A TrackId is a unique identifier, representing a playable track in the ---- user's library. --- @type TrackId -local TrackId = {} - ---- A record is an item within an Index, representing some value at a specific ---- depth. --- @type Record -local Record = {} - ---- Gets the human-readable text representing this record. The `__tostring` ---- metatable function is an alias of this function. --- @treturn string -function Record:title() end - ---- Returns the value that this record represents. This may be either a track ---- id, for records which uniquely identify a track, or it may be a new ---- Iterator representing the next level of depth for the current index. ---- ---- For example, each Record in the "All Albums" index corresponds to an entire ---- album of tracks; the 'contents' of such a Record is an iterator returning ---- each track in the album represented by the Record. The contents of each of ---- the returned 'track' Records would be a full Track, as there is no further ---- disambiguation needed. --- @treturn TrackId|Iterator(Record) -function Record:contents() end - ---- An index is heirarchical, sorted, view of the tracks within the database. ---- For example, the 'All Albums' index contains, first, a sorted list of every ---- album name in the library. Then, at the second level of the index, a sorted ---- list of every track within each album. --- @type Index -local Index = {} - ---- Gets the human-readable name of this index. This is typically something ---- like "All Albums", or "Albums by Artist". The `__tostring` metatable ---- function is an alias of this function. --- @treturn string -function Index:name() end - ---- Returns a new iterator that can be used to access every record within the ---- first level of this index. --- @treturn Iterator(Record) -function Index:iter() end - -return database diff --git a/ldoc-stubs/playback.lua b/ldoc-stubs/playback.lua deleted file mode 100644 index 07ed65f6..00000000 --- a/ldoc-stubs/playback.lua +++ /dev/null @@ -1,19 +0,0 @@ ---- Properties for interacting with the audio playback system --- @module playback - -local playback = {} - ---- Whether or not any audio is *allowed* to be played. If there is a current track, then this is essentially an indicator of whether playback is paused or unpaused. --- @see types.Property -playback.playing = types.Property - ---- Rich information about the currently playing track. --- @see types.Property --- @see types.Track -playback.track = types.Property - ---- The current playback position within the current track, in seconds. --- @see types.Property -playback.position = types.Property - -return playback diff --git a/ldoc-stubs/power.lua b/ldoc-stubs/power.lua deleted file mode 100644 index 466cafed..00000000 --- a/ldoc-stubs/power.lua +++ /dev/null @@ -1,18 +0,0 @@ ---- Properties and functions that deal with the device's battery and power state --- @module power - -local power = {} - ---- The battery's current charge as a percentage --- @see types.Property -power.battery_pct = types.Property - ---- The battery's current voltage, in millivolts. --- @see types.Property -power.battery_millivolts = types.Property - ---- Whether or not the device is currently receiving external power --- @see types.Property -power.plugged_in = types.Property - -return power diff --git a/ldoc-stubs/queue.lua b/ldoc-stubs/queue.lua deleted file mode 100644 index b3000040..00000000 --- a/ldoc-stubs/queue.lua +++ /dev/null @@ -1,32 +0,0 @@ ---- Properties and functions for inspecting and manipulating the track playback queue --- @module queue - -local queue = {} - ---- The index in the queue of the currently playing track. This may be zero if the queue is empty. --- @see types.Property -queue.position = types.Property - ---- The total number of tracks in the queue, including tracks which have already been played. --- @see types.Property -queue.size = types.Property - ---- Determines whether or not the queue will be restarted after the final track is played. --- @see types.Property -queue.replay = types.Property - --- Determines whether or not the current track will repeat indefinitely --- @see types.Property -queue.repeat_track = types.Property - ---- Determines whether, when progressing to the next track in the queue, the next track will be chosen randomly. The random selection algorithm used is a Miller Shuffle, which guarantees that no repeat selections will be made until every item in the queue has been played. --- @see types.Property -queue.random = types.Property - ---- Moves forward in the play queue, looping back around to the beginning if repeat is on. -function queue.next() end - ---- Moves backward in the play queue, looping back around to the end if repeat is on. -function queue.previous() end - -return queue diff --git a/ldoc-stubs/types.lua b/ldoc-stubs/types.lua deleted file mode 100644 index 3480610c..00000000 --- a/ldoc-stubs/types.lua +++ /dev/null @@ -1,35 +0,0 @@ ---- Userdata-based types used throughout the rest of the API. These types are ---- not generally constructable within Lua code. --- @module types -local types = {} - ---- A observable value, owned by the C++ firmware. --- @type Property -types.Property = {} - ---- Gets the current value --- @return The property's current value. -function Property:get() end - ---- Sets a new value. Not all properties may be set from within Lua code. For ---- example, it makes little sense to attempt to override the current battery ---- level. --- @param val The new value. This should generally be of the same type as the existing value. --- @return true if the new value was applied, or false if the backing C++ code rejected the new value (e.g. if it was out of range, or the wrong type). -function Property:set(val) end - ---- Invokes the given function once immediately with the current value, and then again whenever the value changes. ---- The function is invoked for *all* changes; both from the underlying C++ data, and from calls to `set` (if this is a Lua-writeable property). ---- The binding will be active **only** so long as the given function remains in scope. --- @param fn callback function to apply property values. Must accept one argument; the updated value. --- @return fn, for more ergonmic use with anonymous closures. -function Property:bind(fn) end - ---- Table containing information about a track. Most fields are optional. --- @type Track -types.Track = {} - ---- The title of the track, or the filename if no title is available. -types.Track.title = "" - -return Property diff --git a/ldoc-stubs/volume.lua b/ldoc-stubs/volume.lua deleted file mode 100644 index 7eff24c5..00000000 --- a/ldoc-stubs/volume.lua +++ /dev/null @@ -1,14 +0,0 @@ ---- Module for interacting with playback volume. The Bluetooth and wired outputs store their current volume separately; this API only allows interacting with the volume of the currently used output device. --- @module volume - -local volume = {} - ---- The current volume as a percentage of the current volume limit. --- @see types.Property -volume.current_pct = types.Property - ---- The current volume in terms of decibels relative to line level. --- @see types.Property -volume.current_db = types.Property - -return volume diff --git a/luals-stubs/alerts.lua b/luals-stubs/alerts.lua index d430f12d..420194eb 100644 --- a/luals-stubs/alerts.lua +++ b/luals-stubs/alerts.lua @@ -1,11 +1,15 @@ --- @meta +--- The `alerts` module contains functions for showing transient popups over +--- the current screen. --- @class alerts local alerts = {} ---- @param constructor function +--- Shows a new alert, replacing any other alerts. +--- @param constructor function Called to create the UI for the alert. A new default root object and group will be set before calling this function.i Alerts are non-interactable; the group created for the constructor will not be granted focus. function alerts.show(constructor) end +--- Dismisses any visible alerts, removing them from the screen. function alerts.hide() end return alerts diff --git a/luals-stubs/backstack.lua b/luals-stubs/backstack.lua index 2e4eccb3..b39fcbf2 100644 --- a/luals-stubs/backstack.lua +++ b/luals-stubs/backstack.lua @@ -1,11 +1,20 @@ --- @meta +--- The `backstack` module contains functions that can be used to implement a +--- basic stack-based navigation hierarchy. See also the `screen` module, which +--- provides a class prototype meant for use with this module. --- @class backstack local backstack = {} ---- @param constructor function -function backstack.push(constructor) end +--- Displays the given screen to the user. If there was already a screen being +--- displayed, then the current screen is removed from the display, and added +--- to the backstack. +--- @param screen screen The screen to display. +function backstack.push(screen) end +--- Removes the current screen from the display, then replaces it with the +--- screen that is at the top of the backstack. This function does nothing if +--- there are no other screens in the stack. function backstack.pop() end return backstack diff --git a/luals-stubs/bluetooth.lua b/luals-stubs/bluetooth.lua index 09fc7606..a2dd476d 100644 --- a/luals-stubs/bluetooth.lua +++ b/luals-stubs/bluetooth.lua @@ -1,8 +1,12 @@ --- @meta +--- The 'bluetooth' module contains Properties and functions for interacting +--- with the device's Bluetooth capabilities. --- @class bluetooth ---- @field enabled Property ---- @field connected Property +--- @field enabled Property Whether or not the Bluetooth stack is currently enabled. This property is writeable, and can be used to enable or disable Bluetooth. +--- @field connected Property Whether or not there is an active connection to another Bluetooth device. +--- @field paired_device Property The device that is currently paired. The bluetooth stack will automatically connected to this device if possible. +--- @field devices Property Devices nearby that have been discovered. local bluetooth = {} return bluetooth diff --git a/luals-stubs/controls.lua b/luals-stubs/controls.lua new file mode 100644 index 00000000..7034dc55 --- /dev/null +++ b/luals-stubs/controls.lua @@ -0,0 +1,12 @@ +--- @meta + +--- The `controls` module contains Properties relating to the device's physical +--- controls. These controls include the touchwheel, the lock switch, and the +--- side buttons. +--- @class controls +--- @field scheme Property The currently configured control scheme +--- @field scroll_sensitivity Property How much rotational motion is required on the touchwheel per scroll tick. +--- @field lock_switch Property The current state of the device's lock switch. +local controls = {} + +return controls diff --git a/luals-stubs/database.lua b/luals-stubs/database.lua index e23c085b..753961fe 100644 --- a/luals-stubs/database.lua +++ b/luals-stubs/database.lua @@ -1,33 +1,60 @@ --- @meta +--- The `database` module contains Properties and functions for working with +--- the device's LevelDB-backed track database. --- @class database +--- @field updating Property Whether or not a database re-index is currently in progress. local database = {} +--- Returns a list of all indexes in the database. --- @return Index[] function database.indexes() end +--- An iterator is a userdata type that behaves like an ordinary Lua iterator. --- @class Iterator local Iterator = {} +--- A TrackId is a unique identifier, representing a playable track in the +--- user's library. --- @class TrackId local TrackId = {} +--- Gets the human-readable text representing this record. The `__tostring` +--- metatable function is an alias of this function. --- @class Record local Record = {} --- @return string function Record:title() end ---- @return TrackId|Iterator(Record) +--- Returns the value that this record represents. This may be either a track +--- id, for records which uniquely identify a track, or it may be a new +--- Iterator representing the next level of depth for the current index. +--- +--- For example, each Record in the "All Albums" index corresponds to an entire +--- album of tracks; the 'contents' of such a Record is an iterator returning +--- each track in the album represented by the Record. The contents of each of +--- the returned 'track' Records would be a full Track, as there is no further +--- disambiguation needed. +--- @return TrackId|Iterator r A track id if this is a leaf record, otherwise a new iterator for the next level of this index. function Record:contents() end +--- An index is heirarchical, sorted, view of the tracks within the database. +--- For example, the 'All Albums' index contains, first, a sorted list of every +--- album name in the library. Then, at the second level of the index, a sorted +--- list of every track within each album. --- @class Index local Index = {} +--- Gets the human-readable name of this index. This is typically something +--- like "All Albums", or "Albums by Artist". The `__tostring` metatable +--- function is an alias of this function. --- @return string function Index:name() end ---- @return Iterator(Record) +--- Returns a new iterator that can be used to access every record within the +--- first level of this index. +--- @return Iterator it An iterator that yields `Record`s. function Index:iter() end return database diff --git a/luals-stubs/display.lua b/luals-stubs/display.lua new file mode 100644 index 00000000..74bcdca9 --- /dev/null +++ b/luals-stubs/display.lua @@ -0,0 +1,9 @@ +--- @meta + +--- The `display` module contains Properties relating to the device's physical +--- display. +--- @class display +--- @field brightness Property The screen's current brightness, as a gamma-corrected percentage value from 0 to 100. +local display = {} + +return display diff --git a/luals-stubs/playback.lua b/luals-stubs/playback.lua index cd54ddb3..85392e93 100644 --- a/luals-stubs/playback.lua +++ b/luals-stubs/playback.lua @@ -1,6 +1,7 @@ --- @meta ---- Properties for interacting with the audio playback system +--- The `playback` module contains Properties and functions for interacting +--- the device's audio pipeline. --- @class playback --- @field playing Property Whether or not audio is allowed to be played. if there is a current track, then this indicated whether playback is paused or unpaused. If there is no current track, this determines what will happen when the first track is added to the queue. --- @field track Property The currently playing track. diff --git a/luals-stubs/power.lua b/luals-stubs/power.lua index 226f8200..ac7f15bb 100644 --- a/luals-stubs/power.lua +++ b/luals-stubs/power.lua @@ -1,6 +1,7 @@ --- @meta ---- Properties and functions that deal with the device's battery and power state. +--- The `power` module contains properties and functions that relate to the +--- device's battery and charging state. --- @class power --- @field battery_pct Property The battery's current charge, as a percentage of the maximum charge. --- @field battery_millivolts Property The battery's current voltage, in millivolts. diff --git a/luals-stubs/queue.lua b/luals-stubs/queue.lua index 08247799..353b4823 100644 --- a/luals-stubs/queue.lua +++ b/luals-stubs/queue.lua @@ -1,15 +1,31 @@ --- @meta ---- Properties and functions for inspecting and manipulating the track playback queue +--- The `queue` module contains Properties and functions that relate to the +--- device's playback queue. This is a persistent, disk-backed list of TrackIds +--- that includes the currently playing track, tracks that have been played, +--- and tracks that are scheduled to be played after the current track has +--- finished. --- @class queue --- @field position Property The index in the queue of the currently playing track. This may be zero if the queue is empty. Writeable. --- @field size Property The total number of tracks in the queue, including tracks which have already been played. --- @field replay Property Whether or not the queue will be restarted after the final track is played. Writeable. --- @field repeat_track Property Whether or not the current track will repeat indefinitely. Writeable. ---- @field random Property Determines whether, when progressing to the next track in the queue, the next track will be chosen randomly. The random selection algorithm used is a Miller Shuffle, which guarantees that no repeat selections will be made until every item in the queue has been played. Writeable. +--- @field random Property Determines whether, when progressing to the next track in the queue, the next track will be chosen randomly. The random selection algorithm used is a Miller Shuffle, which guarantees that no repeat selections will be made until every item in the queue has been played. Writeable. local queue = {} +--- Adds the given track or database iterator to the end of the queue. Database +--- iterators passed to this method will be unnested and expanded into the track +--- ids they contain. +--- @param val TrackId|Iterator +function queue.add(val) end + +--- Removes all tracks from the queue. +function queue.clear() end + +--- Moves forward in the play queue, looping back around to the beginning if repeat is on. function queue.next() end + +--- Moves backward in the play queue, looping back around to the end if repeat is on. function queue.previous() end return queue diff --git a/luals-stubs/screen.lua b/luals-stubs/screen.lua new file mode 100644 index 00000000..55253f1c --- /dev/null +++ b/luals-stubs/screen.lua @@ -0,0 +1,25 @@ +--- @meta + +--- A distinct full-screen UI. Each screen has an associated LVGL UI tree and +--- group, and can be shown on-screen using the 'backstack' module. +--- Screens make use of prototype inheritance in order to provide a consistent +--- interface for the C++ firmware to work with. +--- See [Programming in Lua, chapter 16](https://www.lua.org/pil/16.2.html). +--- @class screen +local screen = {} + +--- Creates a new screen instance. +function screen:new(params) end + +--- Called just before this screen is first displayed to the user. +function screen:createUi() end + +--- Called whenever this screen is displayed to the user. +function screen:onShown() end + +--- Called whenever this screen is being hidden by the user; either because a +--- new screen is being pushed on top of this way, or because this screen has +--- been popped off of the stack. +function screen:onHidden() end + +return screen diff --git a/luals-stubs/time.lua b/luals-stubs/time.lua new file mode 100644 index 00000000..95bbabdb --- /dev/null +++ b/luals-stubs/time.lua @@ -0,0 +1,12 @@ +--- @meta + +--- The `time` module contains functions for dealing with the current time +--- since boot. +--- @class time +local time = {} + +--- Returns the time in milliseconds since the device booted. +--- @return integer +function time.ticks() end + +return time diff --git a/luals-stubs/types.lua b/luals-stubs/types.lua index ecfee29b..c974010d 100644 --- a/luals-stubs/types.lua +++ b/luals-stubs/types.lua @@ -1,13 +1,23 @@ --- @meta +--- A observable value, owned by the C++ firmware. ---@class Property local property = {} +--- @return integer|string|table|boolean val Returns the property's current value function property:get() end +--- Sets a new value. Not all properties may be set from within Lua code. For +--- example, it makes little sense to attempt to override the current battery +--- level. +--- @param val? integer|string|table|boolean The new value. Optional; if not argument is passed, the property will be set to 'nil'. +--- @return boolean success whether or not the new value was accepted function property:set(val) end ---- @param fn function +--- Invokes the given function once immediately with the current value, and then again whenever the value changes. +--- The function is invoked for *all* changes; both from the underlying C++ data, and from calls to `set` (if this is a Lua-writeable property). +--- The binding will be active **only** so long as the given function remains in scope. +--- @param fn function callback to apply property values. Must accept one argument; the updated value. function property:bind(fn) end return property diff --git a/luals-stubs/volume.lua b/luals-stubs/volume.lua index 42d65884..50046f66 100644 --- a/luals-stubs/volume.lua +++ b/luals-stubs/volume.lua @@ -1,8 +1,11 @@ --- @meta +--- Module for interacting with playback volume. The Bluetooth and wired outputs store their current volume separately; this API only allows interacting with the volume of the currently used output device. --- @class volume ---- @field current_pct Property ---- @field current_db Property +--- @field current_pct Property The current volume as a percentage of the current volume limit. +--- @field current_db Property The current volume in terms of decibels relative to line level (only applicable to headphone output) +--- @field left_bias Property An additional modifier in decibels to apply to the left channel (only applicable to headphone output) +--- @field limit_db Property The maximum allowed output volume, in terms of decibels relative to line level (only applicable to headphone output) local volume = {} return volume diff --git a/tools/luals-gendoc/gendoc.lua b/tools/luals-gendoc/gendoc.lua new file mode 100755 index 00000000..15f46b3c --- /dev/null +++ b/tools/luals-gendoc/gendoc.lua @@ -0,0 +1,143 @@ +#!/usr/bin/env lua + +local json = require "json" + +if #arg > 0 then + print("usage:", arg[0]) + print([[ +reads a lua-language-server json doc output from stdin, converts it into +markdown, and writes the result to stdout]]) + return +end + +local raw_data = io.read("*all") +local parsed = json.decode(raw_data) + +local definitions_per_module = {} + +for _, class in ipairs(parsed) do + if not class.defines or not class.defines[1] then goto continue end + + -- Filter out any definitions that didn't come from us. + local path = class.defines[1].file + if not string.find(path, "/luals-stubs/", 1, true) then goto continue end + + local module_name = string.gsub(path, ".*/(%a*)%.lua", "%1") + local module = definitions_per_module[module_name] or {} + module[class.name] = class + definitions_per_module[module_name] = module + + ::continue:: +end + +local function sortedPairs(t) + local keys = {} + for key in pairs(t) do + table.insert(keys, key) + end + table.sort(keys) + local generator = coroutine.create(function() + for _, key in ipairs(keys) do + coroutine.yield(key, t[key]) + end + end) + return function() + local _, key, val = coroutine.resume(generator) + return key, val + end +end + +local function printHeading(level, text) + local hashes = "" + for _ = 1, level do hashes = hashes .. "#" end + print(hashes .. " " .. text) +end + +local function filterArgs(field) + if not field.extends.args then return {} end + local ret = {} + for _, arg in ipairs(field.extends.args) do + if arg.name ~= "self" then table.insert(ret, arg) end + end + return ret +end + +local function filterReturns(field) + if not field.extends.returns then return {} end + local ret = {} + for _, r in ipairs(field.extends.returns) do + if r.desc then table.insert(ret, r) end + end + return ret +end + +local function emitField(level, prefix, field) + printHeading(level, "`" .. prefix .. "." .. field.name .. "`") + print() + print("`" .. field.extends.view .. "`") + print() + + if field.rawdesc then + print(field.rawdesc) + print() + end + + local args = filterArgs(field) + if #args > 0 then + printHeading(level + 1, "Arguments") + print() + + for _, arg in ipairs(args) do + print(string.format(" - *%s*: %s", arg.name, arg.desc)) + end + + print() + end + + local rets = filterReturns(field) + if #rets > 0 then + printHeading(level + 1, "Returns") + print() + + for _, ret in ipairs(rets) do + if #rets > 1 then + print(" - " .. ret.desc) + else + print(ret.desc) + end + end + + print() + end +end + +local function emitClass(level, prefix, class) + if not class.name then return end + + printHeading(level, "`" .. prefix .. "." .. class.name .. "`") + if class.desc then print(class.desc) end + + for _, field in ipairs(class.fields) do + emitField(level + 1, class.name, field) + end +end + +local initial_level = 3 + +for name, module in sortedPairs(definitions_per_module) do + printHeading(initial_level, "`" .. name .. "`") + + local top_level_class = module[name] + if top_level_class then + if top_level_class.desc then print(top_level_class.desc) end + for _, field in ipairs(top_level_class.fields) do + emitField(initial_level + 1, name, field) + end + end + + for _, class in sortedPairs(module) do + if class.name ~= name then + emitClass(initial_level + 1, name, class) + end + end +end diff --git a/tools/luals-gendoc/json.lua b/tools/luals-gendoc/json.lua new file mode 100644 index 00000000..711ef786 --- /dev/null +++ b/tools/luals-gendoc/json.lua @@ -0,0 +1,388 @@ +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json From 686ada3d4663d40f30d40368f0b9520e011ccd2d Mon Sep 17 00:00:00 2001 From: jacqueline Date: Fri, 8 Mar 2024 14:01:27 +1100 Subject: [PATCH 3/3] Bring a modified luavgl stub file into our stubs --- .luarc.json | 3 +- config.ld | 3 - luals-stubs/lvgl.lua | 1546 +++++++++++++++++++++++++++++++++ tools/luals-gendoc/gendoc.lua | 65 +- 4 files changed, 1609 insertions(+), 8 deletions(-) delete mode 100644 config.ld create mode 100644 luals-stubs/lvgl.lua diff --git a/.luarc.json b/.luarc.json index a0e9e1b7..e16ba477 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,7 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", - "workspace.library": ["lib/luavgl/src", "luals-stubs"], - "workspace.ignoreDir": ["ldoc-stubs"], + "workspace.library": ["luals-stubs"], "runtime.version": "Lua 5.4", } diff --git a/config.ld b/config.ld deleted file mode 100644 index e1c54172..00000000 --- a/config.ld +++ /dev/null @@ -1,3 +0,0 @@ -file = {'ldoc-stubs'} -project = "Tangara" -description = "Lua modules provided by Tangara's firmware" diff --git a/luals-stubs/lvgl.lua b/luals-stubs/lvgl.lua new file mode 100644 index 00000000..59093000 --- /dev/null +++ b/luals-stubs/lvgl.lua @@ -0,0 +1,1546 @@ +---@meta +--- +--- lvgl comments +--- + +--- The `lvgl` module provides bindings to the LVGL graphics library. These +--- bindings were originally based on [luavgl](https://github.com/XuNeo/luavgl/), +--- but have diverged somewhat. These bindings are also largely a very thin +--- abstraction around LVGL's C API, so [LVGL's documentation](https://docs.lvgl.io/8.3/) +--- may also be useful to reference. +--- This module is currently only available from the UI Lua context; i.e. the +--- `main.lua` script run after boot on-device. +---@class lvgl +lvgl = {} + +--- Event codes for use with `obj:onevent`. See the [LVGL docs](https://docs.lvgl.io/8.3/overview/event.html#event-codes) +--- for a description of each event type. +--- @enum ObjEventCode +lvgl.EVENT = { + ALL = 0, + PRESSED = 0, + PRESSING = 0, + PRESS_LOST = 0, + SHORT_CLICKED = 0, + LONG_PRESSED = 0, + LONG_PRESSED_REPEAT = 0, + CLICKED = 0, + RELEASED = 0, + SCROLL_BEGIN = 0, + SCROLL_END = 0, + SCROLL = 0, + GESTURE = 0, + KEY = 0, + FOCUSED = 0, + DEFOCUSED = 0, + LEAVE = 0, + HIT_TEST = 0, + COVER_CHECK = 0, + REFR_EXT_DRAW_SIZE = 0, + DRAW_MAIN_BEGIN = 0, + DRAW_MAIN = 0, + DRAW_MAIN_END = 0, + DRAW_POST_BEGIN = 0, + DRAW_POST = 0, + DRAW_POST_END = 0, + DRAW_PART_BEGIN = 0, + DRAW_PART_END = 0, + VALUE_CHANGED = 0, + INSERT = 0, + REFRESH = 0, + READY = 0, + CANCEL = 0, + DELETE = 0, + CHILD_CHANGED = 0, + CHILD_CREATED = 0, + CHILD_DELETED = 0, + SCREEN_UNLOAD_START = 0, + SCREEN_LOAD_START = 0, + SCREEN_LOADED = 0, + SCREEN_UNLOADED = 0, + SIZE_CHANGED = 0, + STYLE_CHANGED = 0, + LAYOUT_CHANGED = 0, + GET_SELF_SIZE = 0, +} + +--- Flags that can be set for each LVGL object. +--- @enum ObjFlag +lvgl.FLAG = { + PRESSED = 0, + HIDDEN = 0, + CLICKABLE = 0, + CLICK_FOCUSABLE = 0, + CHECKABLE = 0, + SCROLLABLE = 0, + SCROLL_ELASTIC = 0, + SCROLL_MOMENTUM = 0, + SCROLL_ONE = 0, + SCROLL_CHAIN_HOR = 0, + SCROLL_CHAIN_VER = 0, + SCROLL_CHAIN = 0, + SCROLL_ON_FOCUS = 0, + SCROLL_WITH_ARROW = 0, + SNAPPABLE = 0, + PRESS_LOCK = 0, + EVENT_BUBBLE = 0, + GESTURE_BUBBLE = 0, + ADV_HITTEST = 0, + IGNORE_LAYOUT = 0, + FLOATING = 0, + OVERFLOW_VISIBLE = 0, + LAYOUT_1 = 0, + LAYOUT_2 = 0, + WIDGET_1 = 0, + WIDGET_2 = 0, + USER_1 = 0, + USER_2 = 0, + USER_3 = 0, + USER_4 = 0, +} + +--- States that can be set on each LVGL object. See the [LVGL docs](https://docs.lvgl.io/8.3/overview/object.html#states) +--- for an explanation of what each state means. +--- @enum ObjState +lvgl.STATE = { + DEFAULT = 0, + CHECKED = 0, + FOCUSED = 0, + FOCUS_KEY = 0, + EDITED = 0, + HOVERED = 0, + PRESSED = 0, + SCROLLED = 0, + DISABLED = 0, + USER_1 = 0, + USER_2 = 0, + USER_3 = 0, + USER_4 = 0, + ANY = 0, +} + +--- Enum for specifying what kind of alignment to use for an LVGL object. See +--- the [LVGL docs](https://docs.lvgl.io/8.3/overview/style-props.html#align) +--- for an explanation of each value. +--- @enum ObjAlignType +lvgl.ALIGN = { + DEFAULT = 0, + TOP_LEFT = 0, + TOP_MID = 0, + TOP_RIGHT = 0, + BOTTOM_LEFT = 0, + BOTTOM_MID = 0, + BOTTOM_RIGHT = 0, + LEFT_MID = 0, + RIGHT_MID = 0, + CENTER = 0, + OUT_TOP_LEFT = 0, + OUT_TOP_MID = 0, + OUT_TOP_RIGHT = 0, + OUT_BOTTOM_LEFT = 0, + OUT_BOTTOM_MID = 0, + OUT_BOTTOM_RIGHT = 0, + OUT_LEFT_TOP = 0, + OUT_LEFT_MID = 0, + OUT_LEFT_BOTTOM = 0, + OUT_RIGHT_TOP = 0, + OUT_RIGHT_MID = 0, + OUT_RIGHT_BOTTOM = 0, +} + +--- Long modes for use with labels. +--- @enum LABEL +lvgl.LABEL = { + LONG_WRAP = 0, + LONG_DOT = 0, + LONG_SCROLL = 0, + LONG_SCROLL_CIRCULAR = 0, + LONG_CLIP = 0, +} + +--- Scroll modes +--- @enum ScrollbarMode +lvgl.SCROLLBAR_MODE = { + OFF = 0, + ON = 0, + ACTIVE = 0, + AUTO = 0, +} + +--- Directions values for dropdown and scroll directions +--- @enum Dir +lvgl.DIR = { + NONE = 0, + LEFT = 0, + RIGHT = 0, + TOP = 0, + BOTTOM = 0, + HOR = 0, + VER = 0, + ALL = 0, +} + +--- Keyboard modes +--- @enum KeyboardMode +lvgl.KEYBOARD_MODE = { + TEXT_LOWER = 0, + TEXT_UPPER = 0, + SPECIAL = 0, + NUMBER = 0, + USER_1 = 0, + USER_2 = 0, + USER_3 = 0, + USER_4 = 0, + TEXT_ARABIC = 0, +} + +--- Flow direction for flex layouts. See the [LVGL docs](https://docs.lvgl.io/8.3/layouts/flex.html#flex-flow) +--- for more details. +--- @enum FlexFlow +lvgl.FLEX_FLOW = { + ROW = 0, + COLUMN = 0, + ROW_WRAP = 0, + ROW_REVERSE = 0, + ROW_WRAP_REVERSE = 0, + COLUMN_WRAP = 0, + COLUMN_REVERSE = 0, + COLUMN_WRAP_REVERSE = 0, +} + +--- Alignment values for flex layouts. See the [LVGL docs](https://docs.lvgl.io/8.3/layouts/flex.html#flex-align) +--- for more details. +--- @enum FlexAlign +lvgl.FLEX_ALIGN = { + START = 0, + END = 0, + CENTER = 0, + SPACE_EVENLY = 0, + SPACE_AROUND = 0, + SPACE_BETWEEN = 0, +} + +--- Alignment values for grid layouts. See the [LVGL docs](https://docs.lvgl.io/8.3/layouts/grid.html#grid-align) +--- for more details. +--- @enum GridAlign +lvgl.GRID_ALIGN = { + START = 0, + CENTER = 0, + END = 0, + STRETCH = 0, + SPACE_EVENLY = 0, + SPACE_AROUND = 0, + SPACE_BETWEEN = 0, +} + +--- Values for KEY events. +--- @enum KEY +lvgl.KEY = { + UP = 0, + DOWN = 0, + RIGHT = 0, + LEFT = 0, + ESC = 0, + DEL = 0, + BACKSPACE = 0, + ENTER = 0, + NEXT = 0, + PREV = 0, + HOME = 0, + END = 0, +} + +lvgl.ANIM_REPEAT_INFINITE = 0 +lvgl.ANIM_PLAYTIME_INFINITE = 0 +lvgl.SIZE_CONTENT = 0 +lvgl.RADIUS_CIRCLE = 0 +lvgl.COORD_MAX = 0 +lvgl.COORD_MIN = 0 +lvgl.IMG_ZOOM_NONE = 0 +lvgl.BTNMATRIX_BTN_NONE = 0 +lvgl.CHART_POINT_NONE = 0 +lvgl.DROPDOWN_POS_LAST = 0 +lvgl.LABEL_DOT_NUM = 0 +lvgl.LABEL_POS_LAST = 0 +lvgl.LABEL_TEXT_SELECTION_OFF = 0 +lvgl.TABLE_CELL_NONE = 0 +lvgl.TEXTAREA_CURSOR_LAST = 0 +lvgl.LAYOUT_FLEX = 0 +lvgl.LAYOUT_GRID = 0 + +--- Converts an opacity value as a percentage into the LVGL opacity range of 0 +--- to 255. +---@param p integer opacity value in range of 0..100 +---@return integer opacity value in the range of 0..255 +function lvgl.OPA(p) +end + +--- Converts a size in percent into an LVGL size value. +---@param p integer size percentage +---@return integer size in LVGL units +function lvgl.PCT(p) +end + +--- Returns the horizontal resolution of the display. +---@return integer +function lvgl.HOR_RES() +end + +--- Returns the vertical resolution of the display. +---@return integer +function lvgl.VER_RES() +end + +--- Creates a new base LVGL object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/obj.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? StyleProp Style properties to apply to this object +--- @return Object +function lvgl.Object(parent, property) +end + +--- Create a new Bar widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/bar.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? BarStyle Style properties to apply to this object +--- @return Bar +function lvgl.Bar(parent, property) +end + +--- Create a new Button widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/btn.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? StyleProp Style properties to apply to this object +--- @return Button +function lvgl.Button(parent, property) +end + +--- Create a new Calendar widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/calendar.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? CalendarStyle Style properties to apply to this object +--- @return Calendar +function lvgl.Calendar(parent, property) +end + +--- Create a new Checkbox widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/checkbox.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? CheckboxStyle Style properties to apply to this object +--- @return Checkbox +function lvgl.Checkbox(parent, property) +end + +--- Create a new Dropdown widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/dropdown.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? DropdownStyle Style properties to apply to this object +--- @return Dropdown +function lvgl.Dropdown(parent, property) +end + +--- Create a new Image widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/img.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? ImageStyle Style properties to apply to this object +--- @return Image +function lvgl.Image(parent, property) +end + +--- Create a new Label widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/label.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? LabelStyle Style properties to apply to this object +--- @return Label +function lvgl.Label(parent, property) +end + +--- Create a new Text Area widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/textarea.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? TextareaStyle Style properties to apply to this object +--- @return Textarea +function lvgl.Textarea(parent, property) +end + +--- Create a new Keyboard widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/keyboard.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? KeyboardStyle Style properties to apply to this object +--- @return Keyboard +function lvgl.Keyboard(parent, property) +end + +--- Create a new LED widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/led.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? LedStyle Style properties to apply to this object +--- @return Led +function lvgl.Led(parent, property) +end + +--- Create a new List widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/list.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? ListStyle Style properties to apply to this object +--- @return List +function lvgl.List(parent, property) +end + +--- Create a new Roller widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/roller.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? RollerStyle Style properties to apply to this object +--- @return Roller +function lvgl.Roller(parent, property) +end + +--- Create a new Slider widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/slider.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? BarStyle Style properties to apply to this object. Sliders use the same style properties as Bars. +--- @return Slider +function lvgl.Slider(parent, property) +end + +--- Create a new Switch widget. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/switch.html) +--- for details about this widget. +--- @param parent? Object The parent for this object, or nil to add to the screen root. +--- @param property? StyleProp Style properties to apply to this object +--- @return Switch +function lvgl.Switch(parent, property) +end + +--- Create a new Timer. See the [LVGL docs](https://docs.lvgl.io/8.3/overview/timer.html) +--- for more details on LVGL's Timers system. +--- @param p TimerPara Parameters to use for configuring the timer. +--- @return Timer +function lvgl.Timer(p) +end + +--- Create a new a font. Currently only the inbuilt "fusion" font family is +--- available, in "normal" weight and sizes 12 and 10. +--- @param family string Name of the font family. +--- @param size integer the font size in px +--- @param weight string the weight of the font. e.g.g "normal", "bold", "light" +--- @return Font +function lvgl.Font(family, size, weight) +end + +--- Create a new style that can be applied to objects via `obj:add_style`. +--- @param p? StyleProp Style properties that will be applied by this style. +--- @return Style +function lvgl.Style(p) +end + +--- +--- Base LVGL object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/obj.html) +--- for additional details. +--- @class Object +obj = {} + +--- Creates a new base LVGL object as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/obj.html) +--- for details about this widget. +--- @param property? StyleProp Style properties to apply to this object +--- @return Object +function obj:Object(property) +end + +--- Create a new Bar widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/bar.html) +--- for details about this widget. +--- @param property? BarStyle Style properties to apply to this object +--- @return Bar +function obj:Bar(property) +end + +--- Create a new Button widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/btn.html) +--- for details about this widget. +--- @param property? StyleProp Style properties to apply to this object +--- @return Button +function obj:Button(property) +end + +--- Create a new Calendar widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/calendar.html) +--- for details about this widget. +--- @param property? CalendarStyle Style properties to apply to this object +--- @return Calendar +function obj:Calendar(property) +end + +--- Create a new Checkbox widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/checkbox.html) +--- for details about this widget. +--- @param property? CheckboxStyle Style properties to apply to this object +--- @return Checkbox +function obj:Checkbox(property) +end + +--- Create a new Dropdown widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/dropdown.html) +--- for details about this widget. +--- @param property? DropdownStyle Style properties to apply to this object +--- @return Dropdown +function obj:Dropdown(parent, property) +end + +--- Create a new Image widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/img.html) +--- for details about this widget. +--- @param property? ImageStyle Style properties to apply to this object +--- @return Image +function obj:Image(property) +end + +--- Create a new Label widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/label.html) +--- for details about this widget. +--- @param property? LabelStyle Style properties to apply to this object +--- @return Label +function obj:Label(property) +end + +--- Create a new Text Area widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/textarea.html) +--- for details about this widget. +--- @param property? TextareaStyle Style properties to apply to this object +--- @return Textarea +function obj:Textarea(property) +end + +--- Create a new Keyboard widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/keyboard.html) +--- for details about this widget. +--- @param property? KeyboardStyle Style properties to apply to this object +--- @return Keyboard +function obj:Keyboard(property) +end + +--- Create a new LED widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/led.html) +--- for details about this widget. +--- @param property? LedStyle Style properties to apply to this object +--- @return Led +function obj:Led(property) +end + +--- Create a new List widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/extra/list.html) +--- for details about this widget. +--- @param property? ListStyle Style properties to apply to this object +--- @return List +function obj:List(property) +end + +--- Create a new Roller widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/roller.html) +--- for details about this widget. +--- @param property? RollerStyle Style properties to apply to this object +--- @return Roller +function obj:Roller(parent, property) +end + +--- Create a new Slider widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/slider.html) +--- for details about this widget. +--- @param property? BarStyle Style properties to apply to this object. Sliders use the same style properties as Bars. +--- @return Slider +function obj:Slider(property) +end + +--- Create a new Switch widget as a child of this object. See the [LVGL docs](https://docs.lvgl.io/8.3/widgets/core/switch.html) +--- for details about this widget. +--- @param property? StyleProp Style properties to apply to this object +--- @return Switch +function obj:Switch(property) +end + +--- Sets new style properties on this object. +--- @param p StyleProp Style properties to be applied. +function obj:set(p) +end + +--- Sets new style properties on this object. +--- @param p StyleProp Style properties to be applied. +--- @param selector integer Selector to detemine when the style is used +--- +function obj:set_style(p, selector) +end + +--- Sets this object's position relative to another object. +--- @param p AlignToPara +function obj:align_to(p) +end + +--- Deletes this object, removing it from the view hierarchy. +function obj:delete() +end + +--- Delete all children of this object +function obj:clean() +end + +--- Sets the parent of this object, detaching it from any existing parent. +--- @param p Object The new parent object +function obj:set_parent(p) +end + +--- Gets this object's parent +--- @return Object Parent +function obj:get_parent() +end + +--- +--- set and/or get object's parent +--- @param p Object +--- @return Object +function obj:parent(p) +end + +--- +--- get child object +--- @param id integer 0 the first child, -1 the lastly created child +--- @return Object +function obj:get_child(id) +end + +--- +--- get object children count +--- @return integer +function obj:get_child_cnt() +end + +--- +--- get the state of this object +--- @return ObjState +function obj:get_state(p) +end + +--- +--- Scroll to a given coordinate on an object. +--- @class ScrollToPara +--- @field x integer position x +--- @field y integer +--- @field anim boolean +--- +--- @param p ScrollToPara +--- @return ObjState +function obj:scroll_to(p) +end + +--- +--- Tell whether an object is being scrolled or not at this moment +--- @return boolean +function obj:is_scrolling() +end + +--- +--- Tell whether an object is visible (even partially) now or not +--- @return boolean +function obj:is_visible() +end + +--- +--- add flag to object +--- @param p ObjFlag +--- @return nil +function obj:add_flag(p) +end + +--- +--- clear object flag +--- @param p ObjFlag +--- @return nil +function obj:clear_flag(p) +end + +--- +--- add state to object +--- @param p ObjState +--- @return nil +function obj:add_state(p) +end + +--- +--- clear object state +--- @param p ObjState +--- @return nil +function obj:clear_state(p) +end + +--- +--- add style to object +--- @param s Style +--- @param selector? integer +--- @return nil +function obj:add_style(s, selector) +end + +--- +--- remove style from object +--- @param s Style +--- @param selector? integer +--- @return nil +function obj:remove_style(s, selector) +end + +--- +--- remove all style from object +--- @return nil +function obj:remove_style_all() +end + +---scroll obj by x,y +---@param x integer +---@param y integer +---@param anim_en? boolean +function obj:scroll_by(x, y, anim_en) +end + +---scroll obj by x,y +---@param x integer +---@param y integer +---@param anim_en boolean +function obj:scroll_by_bounded(x, y, anim_en) +end + +--- Scroll to an object until it becomes visible on its parent +---@param anim_en? boolean +function obj:scroll_to_view(anim_en) +end + +--- Scroll to an object until it becomes visible on its parent +--- Do the same on the parent's parent, and so on. +--- Therefore the object will be scrolled into view even it has nested scrollable parents +---@param anim_en? boolean +function obj:scroll_to_view_recursive(anim_en) +end + +---scroll obj by x,y, low level APIs +---@param x integer +---@param y integer +---@param anim_en boolean +function obj:scroll_by_raw(x, y, anim_en) +end + +---Invalidate the area of the scrollbars +function obj:scrollbar_invalidate() +end + +---Checked if the content is scrolled "in" and adjusts it to a normal position. +---@param anim_en boolean +function obj:readjust_scroll(anim_en) +end + +---If object is editable +---@return boolean +function obj:is_editable() +end + +--- class group def +---@return boolean +function obj:is_group_def() +end + +--- Test whether the and object is positioned by a layout or not +---@return boolean +function obj:is_layout_positioned() +end + +--- Mark the object for layout update. +---@return nil +function obj:mark_layout_as_dirty() +end + +--- Align an object to the center on its parent. same as obj:set{align={type = lvgl.ALIGN.CENTER}} +---@return nil +function obj:center() +end + +--- Align an object to the center on its parent. same as obj:set{align={type = lvgl.ALIGN.CENTER}} +---@return nil +function obj:invalidate() +end + +--- Sets this object as the current selection of the object's group. +---@return nil +function obj:focus() +end + +--- +--- Object event callback. `para` is not used for now. +--- @alias EventCallback fun(obj:Object, code: ObjEventCode): nil +--- +--- set object event callback +--- @param code ObjEventCode +--- @param cb EventCallback +--- @return nil +function obj:onevent(code, cb) +end + +--- +--- set object pressed event callback, same as obj:onevent(lvgl.EVENT.PRESSED, cb) +--- @param cb EventCallback +--- @return nil +function obj:onPressed(cb) +end + +--- +--- set object clicked event callback, same as obj:onevent(lvgl.EVENT.CLICKED, cb) +--- @param cb EventCallback +--- @return nil +function obj:onClicked(cb) +end + +--- +--- set object short clicked event callback, same as obj:onevent(lvgl.EVENT.SHORT_CLICKED, cb) +--- @param cb EventCallback +--- @return nil +function obj:onShortClicked(cb) +end + +--- +--- Create anim for object +--- @param p AnimPara +--- @return Anim +function obj:Anim(p) +end + +--- +--- Get coords of object +--- @return Coords coords +function obj:get_coords() +end + +--- +--- Get real postion of object relative to its parent +--- @return Coords coords +function obj:get_pos() +end + +--- +--- Calendar widget +---@class Calendar:Object +--- +local calendar = {} + +--- set method for calendar widget +--- @param p CalendarStyle +--- @return nil +function calendar:set(p) +end + +--- get today para setting from calendar widget +--- @return CalendarDatePara +function calendar:get_today(p) +end + +--- get the currently showed date +--- @return CalendarDatePara +function calendar:get_showed(p) +end + +--- get the currently pressed day +--- @return CalendarDatePara +function calendar:get_pressed(p) +end + +--- get the button matrix object of the calendar. +--- @return Object +function calendar:get_btnm(p) +end + +--- create a calendar header with drop-drowns to select the year and month. +--- @return Object +function calendar:Arrow(p) +end + +--- create a calendar header with drop-drowns to select the year and month +--- @return Object +function calendar:Dropdown(p) +end + +--- +--- Bar widget +---@class Bar:Object +--- +local bar = {} + +--- set method for bar widget +--- @param p BarStyle +--- @return nil +function bar:set(p) +end + +--- +--- Button widget +---@class Button:Object +--- +local button = {} + +--- set method for button widget +--- @param p ButtonStyle +--- @return nil +function button:set(p) +end + +--- +--- Checkbox widget +---@class Checkbox:Object +--- +local checkbox = {} + +--- set method +--- @param p CheckboxStyle +--- @return nil +function checkbox:set(p) +end + +--- +--- Get the text of a label +--- @return string +function checkbox:get_text() +end + +--- +--- Dropdown widget +---@class Dropdown:Object +--- +local dropdown = {} + +--- set method +--- @param p DropdownStyle +--- @return nil +function dropdown:set(p) +end + +--- Gets an attribute of the dropdown. +--- @param which string Which property to retrieve. Valid values are "list", "options", "selected", "option_cnt", "selected_str", "option_index", "symbol", or "dir" +--- @param arg ? string +--- @return string | Dir | Object +function dropdown:get(which, arg) +end + +--- Open the drop down list +function dropdown:open() +end + +--- Close (Collapse) the drop-down list +function dropdown:close() +end + +--- Tells whether the list is opened or not +function dropdown:is_open() +end + +--- Add an options to a drop-down list from a string +--- @param option string +--- @param pos integer +function dropdown:add_option(option, pos) +end + +--- Tells whether the list is opened or not +function dropdown:clear_option() +end + +--- +--- Image widget +---@class Image:Object +--- +local img = {} + +--- Image set method +--- @param p ImageStyle +--- @return nil +function img:set(p) +end + +--- set image source +--- @param src string image source path +--- @return nil +function img:set_src(src) +end + +--- set image offset +--- img:set_offset{x = 0, y = 100} +--- @param p table +--- @return nil +function img:set_offset(p) +end + +--- set image pivot +--- img:set_pivot{x = 0, y = 100} +--- @param p table +--- @return nil +function img:set_pivot(p) +end + +--- get image size, return w,h +--- w, h = img:get_img_size() +--- w, h = img:get_img_size("/path/to/this/image.png") +--- @param src ? string +--- @return integer, integer +function img:get_img_size(src) +end + +--- +--- Label widget +---@class Label: Object +--- +local label = {} + +--- Image set method +--- @param p LabelStyle +--- @return nil +function label:set(p) +end + +--- +--- Get the text of a label +--- @return string +function label:get_text() +end + +--- +--- Get the long mode of a label +--- @return string +function label:get_long_mode() +end + +--- +--- Get the recoloring attribute +--- @return string +function label:get_recolor() +end + +--- +--- Insert a text to a label. +--- @param pos integer +--- @param txt string +--- @return nil +function label:ins_text(pos, txt) +end + +--- +--- Delete characters from a label. +--- @param pos integer +--- @param cnt integer +--- @return nil +function label:cut_text(pos, cnt) +end + +--- +--- Slider widget +---@class Slider:Object +--- +local slider = {} + +--- set method for slider widget. Uses Bar widget's properties. +--- @param p BarStyle +--- @return nil +function slider:set(p) +end + +--- get value of slider +--- @return integer +function slider:value() +end + +--- get whether slider is dragged or not +--- @return boolean +function slider:is_dragged() +end + +--- +--- Switch widget +---@class Switch:Object +--- +local switch = {} + +--- set method for switch widget +--- @param p StyleProp +--- @return nil +function switch:set(p) +end + +--- get checked state of switch +--- @return boolean +function switch:enabled() +end + +--- +--- Textarea widget +---@class Textarea: Object +--- +local textarea = {} + +--- Textarea set method +--- @param p TextareaStyle +--- @return nil +function textarea:set(p) +end + +--- get textarea text +--- @return string +function textarea:get_text(p) +end + +--- +--- Keyboard widget +---@class Keyboard: Object based on btnmatrix object +--- +local keyboard = {} + +--- Keyboard set method +--- @param p KeyboardStyle +--- @return nil +function keyboard:set(p) +end + +--- +--- LED widget +---@class Led: Object +--- +local led = {} + +--- LED set method +--- @param p LedStyle +--- @return nil +function led:set(p) +end + +--- LED set to ON +--- @return nil +function led:on() +end + +--- LED set to OFF +--- @return nil +function led:off() +end + +--- toggle LED status +--- @return nil +function led:toggle() +end + +--- get LED brightness +--- @return integer +function led:get_brightness() +end + +--- +--- List widget +---@class List: Object +--- +local list = {} + +--- List set method +--- @param p ListStyle +--- @return nil +function list:set(p) +end + +--- add text to list +--- @param text string +--- @return Label +function list:add_text(text) +end + +--- add button to list +--- @param icon ImgSrc | nil +--- @param text? string +--- @return Object a button object +function list:add_btn(icon, text) +end + +--- get list button text +--- @param btn Object +--- @return string +function list:get_btn_text(btn) +end + +--- +--- Roller widget +---@class Roller: Object +--- +local roller = {} + +--- Roller set method +--- @param p RollerStyle +--- @return nil +function roller:set(p) +end + +--- Get the options of a roller +--- @return string +function roller:get_options() +end + +--- Get the index of the selected option +--- @return integer +function roller:get_selected() +end + +--- Get the current selected option as a string. +--- @return string +function roller:get_selected_str() +end + +--- Get the total number of options +--- @return integer +function roller:get_options_cnt() +end + +--- +--- Anim +---@class Anim +--- +local Anim = {} + +--- start animation +--- @return nil +function Anim:start() +end + +--- set animation new parameters +--- @param para AnimPara new animation parameters +--- @return nil +function Anim:set(para) +end + +--- stop animation +--- @return nil +function Anim:stop() +end + +--- delete animation +--- @return nil +function Anim:delete() +end + +--- +--- Timer +---@class Timer +--- +local timer = {} + +--- set timer property +--- @param p TimerPara +--- @return nil +function timer:set(p) +end + +--- resume timer +--- @return nil +function timer:resume() +end + +--- pause timer +--- @return nil +function timer:pause() +end + +--- delete timer +--- @return nil +function timer:delete() +end + +--- make timer ready now, cb will be made soon on next loop +--- @return nil +function timer:ready() +end + +--[[ +Font is a light userdata that can be uset to set style text_font. +]] +--- @class Font +--- + +local font = {} + +--- +--- @class Style : lightuserdata +--- +local style = {} + +--- update style properties +--- @param p StyleProp +--- @return nil +function style:set(p) +end + +--- delete style, only delted style could be gc'ed +--- @return nil +function style:delete() +end + +--- remove specified property from style +--- @param p string property name from field of StyleProp +--- @return nil +function style:remove_prop(p) +end + +--- +--- Align parameter +--- @class Align +--- @field type ObjAlignType +--- @field x_ofs integer +--- @field y_ofs integer + +--- AlignTo parameter +--- @class AlignToPara +--- @field type ObjAlignType +--- @field base Object +--- @field x_ofs integer + +--- Style properties +--- @class StyleProp +--- @field w? integer +--- @field width? integer +--- @field min_width? integer +--- @field max_width? integer +--- @field height? integer +--- @field min_height? integer +--- @field max_height? integer +--- @field x? integer +--- @field y? integer +--- @field size? integer set size is equivalent to set w/h to same value +--- @field align? Align | ObjAlignType +--- @field transform_width? integer +--- @field transform_height? integer +--- @field translate_x? integer +--- @field translate_y? integer +--- @field transform_zoom? integer +--- @field transform_angle? integer +--- @field transform_pivot_x? integer +--- @field transform_pivot_y? integer +--- @field pad_all? integer +--- @field pad_top? integer +--- @field pad_bottom? integer +--- @field pad_ver? integer +--- @field pad_left? integer +--- @field pad_right? integer +--- @field pad_hor? integer +--- @field pad_row? integer +--- @field pad_column? integer +--- @field pad_gap? integer +--- @field bg_color? integer | string text color in hex integer or #RGB or #RRGGBB format +--- @field bg_opa? integer +--- @field bg_grad_color? integer +--- @field bg_grad_dir? integer +--- @field bg_main_stop? integer +--- @field bg_grad_stop? integer +--- @field bg_dither_mode? integer +--- @field bg_img_src? integer +--- @field bg_img_opa? integer +--- @field bg_img_recolor? integer +--- @field bg_img_recolor_opa? integer +--- @field bg_img_tiled? integer +--- @field border_color? integer | string +--- @field border_opa? integer +--- @field border_width? integer +--- @field border_side? integer +--- @field border_post? integer +--- @field outline_width? integer +--- @field outline_color? integer | string +--- @field outline_opa? integer +--- @field outline_pad? integer +--- @field shadow_width? integer +--- @field shadow_ofs_x? integer +--- @field shadow_ofs_y? integer +--- @field shadow_spread? integer +--- @field shadow_color? integer | string +--- @field shadow_opa? integer +--- @field img_opa? integer +--- @field img_recolor? integer +--- @field img_recolor_opa? integer +--- @field line_width? integer +--- @field line_dash_width? integer +--- @field line_dash_gap? integer +--- @field line_rounded? integer +--- @field line_color? integer | string +--- @field line_opa? integer +--- @field arc_width? integer +--- @field arc_rounded? integer +--- @field arc_color? integer | string +--- @field arc_opa? integer +--- @field arc_img_src? integer +--- @field text_color? integer | string +--- @field text_opa? integer +--- @field text_font? Font | BuiltinFont +--- @field text_letter_space? integer +--- @field text_line_space/ integer +--- @field text_decor? integer +--- @field text_align? integer +--- @field radius? integer +--- @field clip_corner? integer +--- @field opa? integer +--- @field color_filter_opa? integer +--- @field anim_time? integer +--- @field anim_speed? integer +--- @field blend_mode? integer +--- @field layout? integer +--- @field base_dir? integer +--- @field flex_flow? FlexFlow +--- @field flex_main_place? FlexAlign +--- @field flex_cross_place? FlexAlign +--- @field flex_track_place/ FlexAlign +--- @field flex_grow? integer 0..255 +--- @field flex? FlexLayoutPara + +--- + +--- Object style +--- @class ObjectStyle :StyleProp +--- @field x integer +--- @field y integer +--- @field w integer +--- @field h integer +--- @field align Align | integer +--- @field align_to AlignToPara +--- @field scrollbar_mode ScrollbarMode +--- @field scroll_dir Dir +--- @field scroll_snap_x integer +--- @field scroll_snap_y integer +--- + +--- Image style +--- @class ImageStyle :StyleProp +--- @field src string +--- @field offset_x integer offset of image +--- @field offset_y integer +--- @field angle integer +--- @field zoom integer +--- @field antialias boolean +--- @field pivot table +--- + +--- Label style +--- @class LabelStyle :StyleProp +--- @field text string + +--- Bar style +--- @class BarStyle :StyleProp +--- @field range BarRangePara +--- @field value integer + +--- Button style +--- @class ButtonStyle :StyleProp + +--- Checkbox style +--- @class CalendarStyle :StyleProp +--- @field today CalendarDatePara +--- @field showed CalendarDatePara + +--- Checkbox style +--- @class CheckboxStyle :StyleProp +--- @field text string + +--- Dropdown style +--- @class DropdownStyle :StyleProp +--- @field text string | nil +--- @field options string +--- @field selected integer +--- @field dir Dir +--- @field symbol lightuserdata | string +--- @field highlight boolean + +--- Textarea style +--- @class TextareaStyle :StyleProp +--- @field text string +--- @field placeholder string +--- @field cursor integer cursor position +--- @field password_mode boolean enable password +--- @field one_line boolean enable one line mode +--- @field password_bullet string Set the replacement characters to show in password mode +--- @field accepted_chars string DO NOT USE. Set a list of characters. Only these characters will be accepted by the text area E.g. "+-.,0123456789" +--- @field max_length integer Set max length of a Text Area. +--- @field password_show_time integer Set how long show the password before changing it to '*' + +--- Keyboard style +--- @class KeyboardStyle :StyleProp +--- @field textarea Textarea textarea object +--- @field mode KeyboardMode +--- @field popovers boolean Show the button title in a popover when pressed. + +--- Led style +--- @class LedStyle :StyleProp +--- @field color integer|string color of led +--- @field brightness integer brightness in range of 0..255 + +--- List style +--- @class ListStyle :StyleProp + +--- Roller style +--- @class RollerStyle :StyleProp +--- @field options table | string +--- @field selected table | integer +--- @field visible_cnt integer + +--- +--- Anim(for object) parameter +--- @alias AnimExecCb fun(obj:any, value:integer): nil +--- @alias AnimDoneCb fun(anim:Anim, var:any): nil + +--- @class AnimPara +--- @field run boolean run this anim right now, or later using anim:start(). default: false +--- @field start_value integer start value +--- @field end_value integer +--- @field duration integer Anim duration in milisecond +--- @field delay integer Set a delay before starting the animation +--- @field repeat_count integer Anim repeat count, default: 1, set to 0 to disable repeat, set to lvgl.ANIM_REPEAT_INFINITE for infinite repeat, set to any other integer for specified repeate count +--- @field playback_delay integer +--- @field playback_time integer +--- @field early_apply boolean set start_value right now or not. default: true +--- @field path string | "linear" | "ease_in" | "ease_out" | "ease_in_out" | "overshoot" | "bounce" | "step" +--- @field exec_cb AnimExecCb +--- @field done_cb AnimDoneCb + + +--- +--- Timer para +--- @alias TimerCallback fun(t:Timer): nil +--- @class TimerPara +--- @field paused boolean Do not start timer immediaely +--- @field period integer timer period in ms unit +--- @field repeat_count integer | -1 | +--- @field cb TimerCallback +--- + + +--- +--- @alias ImgSrc string | lightuserdata + +--- Alignment values for flex layouts. See the [LVGL docs](https://docs.lvgl.io/8.3/layouts/flex.html#flex-align) +--- for more details. +--- @alias flexAlignOptions +---| "flex-start" +---| "flex-end" +---| "center" wow +---| "space-between" +---| "space-around" +---| "space-evenly" + +--- @class FlexLayoutPara +--- @field flex_direction? "row" | "column" | "row-reverse" | "column-reverse" +--- @field flex_wrap? "nowrap" | "wrap" | "wrap-reverse" +--- @field justify_content? flexAlignOptions +--- @field align_items? flexAlignOptions +--- @field align_content? flexAlignOptions + + +--- +--- BarRange para +--- @class BarRangePara +--- @field min integer +--- @field max integer +--- + +--- +--- CalendarToday para +--- @class CalendarDatePara +--- @field year integer +--- @field month integer +--- @field day integer +--- + +--- +--- Coordinates +--- @class Coords +--- @field x1 integer +--- @field y1 integer +--- @field x2 integer +--- @field y2 integer +--- + +return lvgl diff --git a/tools/luals-gendoc/gendoc.lua b/tools/luals-gendoc/gendoc.lua index 15f46b3c..ace0b6c9 100755 --- a/tools/luals-gendoc/gendoc.lua +++ b/tools/luals-gendoc/gendoc.lua @@ -14,6 +14,7 @@ local raw_data = io.read("*all") local parsed = json.decode(raw_data) local definitions_per_module = {} +local fields_per_class = {} for _, class in ipairs(parsed) do if not class.defines or not class.defines[1] then goto continue end @@ -27,6 +28,12 @@ for _, class in ipairs(parsed) do module[class.name] = class definitions_per_module[module_name] = module + local fields = {} + for _, field in ipairs(class.fields or {}) do + fields[field.name] = true + end + fields_per_class[class.name] = fields + ::continue:: end @@ -72,6 +79,8 @@ local function filterReturns(field) end local function emitField(level, prefix, field) + if not field.desc then return end + printHeading(level, "`" .. prefix .. "." .. field.name .. "`") print() print("`" .. field.extends.view .. "`") @@ -111,14 +120,64 @@ local function emitField(level, prefix, field) end end +local function baseClassName(class) + for _, define in ipairs(class.defines or {}) do + for _, extend in ipairs(define.extends or {}) do + if extend.type == "doc.extends.name" then + return extend.view + end + end + end +end + +local function isEnum(class) + for _, define in pairs(class.defines) do + if define.type == "doc.enum" then return true end + end + return false +end + +local function isAlias(class) + for _, define in pairs(class.defines) do + if define.type == "doc.alias" then return true end + end + return false +end + local function emitClass(level, prefix, class) if not class.name then return end + if not class.fields then return end + if isAlias(class) then return end + + for _, define in ipairs(class.defines or {}) do + if define.type == "tablefield" then + print(" - " .. class.name) + return + end + end printHeading(level, "`" .. prefix .. "." .. class.name .. "`") + print() + + local base_class = baseClassName(class) + local base_class_fields = {} + if base_class then + base_class_fields = fields_per_class[base_class] or {} + print("`" .. class.name .. ":" .. base_class .. "`") + print() + end + if class.desc then print(class.desc) end - for _, field in ipairs(class.fields) do - emitField(level + 1, class.name, field) + for _, field in ipairs(class.fields or {}) do + if not base_class_fields[field.name] then + emitField(level + 1, class.name, field) + end + end + + if isEnum(class) then + printHeading(level + 1, "Values") + print() end end @@ -130,7 +189,7 @@ for name, module in sortedPairs(definitions_per_module) do local top_level_class = module[name] if top_level_class then if top_level_class.desc then print(top_level_class.desc) end - for _, field in ipairs(top_level_class.fields) do + for _, field in ipairs(top_level_class.fields or {}) do emitField(initial_level + 1, name, field) end end