Begin migration of remaining screens to Lua

This commit is contained in:
jacqueline
2024-01-15 12:31:20 +11:00
parent 0e04eb918e
commit 7cdcd44e0c
53 changed files with 1242 additions and 2908 deletions
-72
View File
@@ -1,72 +0,0 @@
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
ColumnLimit: 120
CommentPragmas: '^!'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, BOOST_FOREACH ]
IndentCaseLabels: true
IndentFunctionDeclarationAfterType: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
Language: Cpp
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 600
PointerAlignment: Left
SpaceAfterCStyleCast: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: true
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
-44
View File
@@ -1,44 +0,0 @@
name: ci
on: [pull_request]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
Build-And-Test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{runner.workspace}}/build
- name: Configure
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake $GITHUB_WORKSPACE -GXcode -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBINDEY_BUILD_TESTS=ON
env:
CC: clang
CXX: clang
- name: Build
working-directory: ${{runner.workspace}}/build
shell: bash
run: cmake --build . --config $BUILD_TYPE
env:
CC: clang
CXX: clang
- name: Test
working-directory: ${{runner.workspace}}/build
shell: bash
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C $BUILD_TYPE
-5
View File
@@ -1,5 +0,0 @@
*.a
*.lib
*.o
*.pdb
.DS_Store
-6
View File
@@ -1,6 +0,0 @@
[submodule "lib/Catch2"]
path = lib/Catch2
url = git@github.com:catchorg/Catch2.git
[submodule "lib/nod"]
path = lib/nod
url = git@github.com:fr00b0/nod.git
-6
View File
@@ -1,6 +0,0 @@
# Copyright 2023 jacqueline <me@jacqueline.id.au>
#
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
INCLUDE_DIRS "include"
)
-21
View File
@@ -1,21 +0,0 @@
## The MIT License (MIT)
Copyright (c) 2021 Kevin Dixon
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.
-116
View File
@@ -1,116 +0,0 @@
# bindey
Everyone knows Model-View-ViewModel is the best architecture, but how can we realize it in C++ applications with minimal overhead, and no complicated framework impositions?
`bindey` provides the basic building block of MVVM -- an observable "Property" and a databinding mechanism.
## Property Usage
At minimum, `bindey::property` can allow you to avoid writing getters and setters. Consider this example:
```
#include <bindey/property.h>
using namespace bindey;
class Person
{
public:
property<std::string> name;
property<int> age;
};
```
Then we can use it like this:
```
Person p;
p.name("Kevin");
p.age(666);
auto thatDudesName = p.name();
auto ageIsJustANumber = p.age();
```
`property` default initializes its value with `{}`, and of course allows initialization.
```
Person::Person()
: name("Default Name")
, age(0)
{}
```
## Data Binding
`bindey` provides a simple binding mechanism to connect a "source" `property` to an arbitrary object. This base signature is
```
template <typename T, typename To>
binding bind( property<T>& from, To& to );
```
And a specialization for `property` to `property` binding of the same type is provided.
```
template<typename T>
binding bind( property<T>& from, property<T>& to )
{
return from.onChanged( [&]( const auto& newValue ) { to( newValue ); } );
}
```
### Writing Your Own Bindings
Where this becomes fun is when you get to reduce boilerplate. For example, assume a `Button` class from some UI Framework.
```
struct Button
{
void setText(const std::string& text)
{
this->text = text;
}
std::string text;
};
```
To make your life better, simply implement a template speciailization in the `bindey` namespace.
```
namespace bindey
{
template <>
binding bind( property<std::string>& from, Button& to )
{
return from.onChanged( [&]( const auto& newValue ){ to.setText( newValue ); } );
}
} // namespace bindey
```
Then, bind your property to the button as needed:
```
bindey::property<std::string> name;
...
Button someButton;
...
bindey::bind( name, someButton );
```
### Binding Lifetimes
The result of a call to `bind` is a `bindey::binding` object. If this return value is discarded, then the binding's lifetime is coupled to the `property`'s.
Otherwise, this token can be used to disconnect the binding as needed, the easiest way is to capture it in a `scoped_binding` object.
For example, if your binding involves objects who's lifetime you do not control, you should certainly capture the binding to avoid crashes.
```
struct GreatObj
{
GreatObj(Button* b)
{
mSomeButton = b;
mButtonBinding = bindey::bind( name, *mSomeButton );
}
void updateButton(Button* newB)
{
mSomeButton = nullptr;
mButtonBinding = {}; // disconnect from old button
if( newB != nullptr )
{
mSomeButton = newB;
mButtonBinding = bindey::bind( name, *mSomeButton );
}
}
bindey::scoped_binding mButtonBinding;
};
```
-47
View File
@@ -1,47 +0,0 @@
#pragma once
#include "property.h"
#include <nod/nod.hpp>
#include <functional>
#include <type_traits>
namespace bindey
{
using binding = nod::connection;
using scoped_binding = nod::scoped_connection;
/**
* base binding signature
*/
template <typename T, typename To>
binding bind( property<T>& from, To& to );
/**
* binds two properties of the same type
*/
template <typename T>
binding bind( property<T>& from, property<T>& to )
{
return from.onChanged( [&]( const auto& newValue ) { to( newValue ); } );
}
/**
* binds two properties of differing types using a Converter callable
* @param from property to observe
* @param to property to write to
* @param bindingConverter a callable to invoke to convert between the types
*/
template <typename TFrom, typename TTo, typename Converter>
binding bind( property<TFrom>& from, property<TTo>& to, Converter&& bindingConverter )
{
static_assert( std::is_convertible<Converter&&, std::function<TTo( const TFrom& )>>::value,
"Wrong Signature for binding converter!" );
return from.onChanged(
[&to, converter = bindingConverter]( const auto& newValue ) { to( converter( newValue ) ); } );
}
} // namespace bindey
-137
View File
@@ -1,137 +0,0 @@
#pragma once
#include <nod/nod.hpp>
#include <functional>
namespace bindey
{
/**
* Optional always_update policy to notify subscribers everytime the property value is set, not just when it changes
*/
class always_update
{
public:
template <typename T>
bool operator()( const T&, const T& ) const
{
return true;
}
};
template <typename T,
typename UpdatePolicy = std::not_equal_to<T>,
typename Signal = nod::unsafe_signal<void( const T& )>>
class property
{
public:
property()
{
}
property( T&& value )
: mStorage( std::move( value ) )
{
}
property( const property& ) = delete;
property& operator=(const property&) = delete;
/**
* gets the current value
* @return const reference to the value
*/
const T& get() const
{
return mStorage;
}
/**
* gets the current value
* @return mutable reference to the value
*/
T& get()
{
return mStorage;
}
const T& operator()() const
{
return get();
}
T& operator()()
{
return get();
}
/**
* sets the value of the property.
* @param value the new value
* @discussion the value will only be updated if the UpdatePolicy's critera is met.
* if the value is changed, then the @ref changed event will be fired.
*/
void set( const T& value )
{
if ( UpdatePolicy{}( mStorage, value ) )
{
mStorage = value;
changed( mStorage );
}
}
void set( T&& value )
{
if ( UpdatePolicy{}( mStorage, value ) )
{
mStorage = std::move( value );
changed( mStorage );
}
}
void operator()( const T& value )
{
set( value );
}
void operator()( T&& value )
{
set( std::move( value ) );
}
/**
* this signal is invoked whenever the the value changes per the UpdatePolicy
* @discussion nod::unsafe_signal is used here for speed. Take care of your own threading.
*/
Signal changed;
/**
* convience function to attach a change listener to this property
*/
auto onChanged( typename decltype( changed )::slot_type&& c )
{
return changed.connect( std::move( c ) );
}
/**
* convience function to attach a change listener to this property and call it right away
*/
auto onChangedAndNow( typename decltype( changed )::slot_type&& c )
{
auto connection = onChanged( std::move( c ) );
changed( mStorage );
return connection;
}
private:
T mStorage{};
};
/**
* thread safe property type based on nod::signal
*/
template <typename T, typename UpdatePolicy = std::not_equal_to<T>>
using safe_property = property<T, UpdatePolicy, nod::signal<void( const T& )>>;
} // namespace bindey
-681
View File
@@ -1,681 +0,0 @@
#ifndef IG_NOD_INCLUDE_NOD_HPP
#define IG_NOD_INCLUDE_NOD_HPP
#include <vector> // std::vector
#include <functional> // std::function
#include <mutex> // std::mutex, std::lock_guard
#include <memory> // std::shared_ptr, std::weak_ptr
#include <algorithm> // std::find_if()
#include <cassert> // assert()
#include <thread> // std::this_thread::yield()
#include <type_traits> // std::is_same
#include <iterator> // std::back_inserter
namespace nod {
// implementational details
namespace detail {
/// Interface for type erasure when disconnecting slots
struct disconnector {
virtual ~disconnector() {}
virtual void operator()( std::size_t index ) const = 0;
};
/// Deleter that doesn't delete
inline void no_delete(disconnector*){
};
} // namespace detail
/// Base template for the signal class
template <class P, class T>
class signal_type;
/// Connection class.
///
/// This is used to be able to disconnect slots after they have been connected.
/// Used as return type for the connect method of the signals.
///
/// Connections are default constructible.
/// Connections are not copy constructible or copy assignable.
/// Connections are move constructible and move assignable.
///
class connection {
public:
/// Default constructor
connection() :
_index()
{}
// Connection are not copy constructible or copy assignable
connection( connection const& ) = delete;
connection& operator=( connection const& ) = delete;
/// Move constructor
/// @param other The instance to move from.
connection( connection&& other ) :
_weak_disconnector( std::move(other._weak_disconnector) ),
_index( other._index )
{}
/// Move assign operator.
/// @param other The instance to move from.
connection& operator=( connection&& other ) {
_weak_disconnector = std::move( other._weak_disconnector );
_index = other._index;
return *this;
}
/// @returns `true` if the connection is connected to a signal object,
/// and `false` otherwise.
bool connected() const {
return !_weak_disconnector.expired();
}
/// Disconnect the slot from the connection.
///
/// If the connection represents a slot that is connected to a signal object, calling
/// this method will disconnect the slot from that object. The result of this operation
/// is that the slot will stop receiving calls when the signal is invoked.
void disconnect();
private:
/// The signal template is a friend of the connection, since it is the
/// only one allowed to create instances using the meaningful constructor.
template<class P,class T> friend class signal_type;
/// Create a connection.
/// @param shared_disconnector Disconnector instance that will be used to disconnect
/// the connection when the time comes. A weak pointer
/// to the disconnector will be held within the connection
/// object.
/// @param index The slot index of the connection.
connection( std::shared_ptr<detail::disconnector> const& shared_disconnector, std::size_t index ) :
_weak_disconnector( shared_disconnector ),
_index( index )
{}
/// Weak pointer to the current disconnector functor.
std::weak_ptr<detail::disconnector> _weak_disconnector;
/// Slot index of the connected slot.
std::size_t _index;
};
/// Scoped connection class.
///
/// This type of connection is automatically disconnected when
/// the connection object is destructed.
///
class scoped_connection
{
public:
/// Scoped are default constructible
scoped_connection() = default;
/// Scoped connections are not copy constructible
scoped_connection( scoped_connection const& ) = delete;
/// Scoped connections are not copy assingable
scoped_connection& operator=( scoped_connection const& ) = delete;
/// Move constructor
scoped_connection( scoped_connection&& other ) :
_connection( std::move(other._connection) )
{}
/// Move assign operator.
/// @param other The instance to move from.
scoped_connection& operator=( scoped_connection&& other ) {
reset( std::move( other._connection ) );
return *this;
}
/// Construct a scoped connection from a connection object
/// @param connection The connection object to manage
scoped_connection( connection&& c ) :
_connection( std::forward<connection>(c) )
{}
/// destructor
~scoped_connection() {
disconnect();
}
/// Assignment operator moving a new connection into the instance.
/// @note If the scoped_connection instance already contains a
/// connection, that connection will be disconnected as if
/// the scoped_connection was destroyed.
/// @param c New connection to manage
scoped_connection& operator=( connection&& c ) {
reset( std::forward<connection>(c) );
return *this;
}
/// Reset the underlying connection to another connection.
/// @note The connection currently managed by the scoped_connection
/// instance will be disconnected when resetting.
/// @param c New connection to manage
void reset( connection&& c = {} ) {
disconnect();
_connection = std::move(c);
}
/// Release the underlying connection, without disconnecting it.
/// @returns The newly released connection instance is returned.
connection release() {
connection c = std::move(_connection);
_connection = connection{};
return c;
}
///
/// @returns `true` if the connection is connected to a signal object,
/// and `false` otherwise.
bool connected() const {
return _connection.connected();
}
/// Disconnect the slot from the connection.
///
/// If the connection represents a slot that is connected to a signal object, calling
/// this method will disconnect the slot from that object. The result of this operation
/// is that the slot will stop receiving calls when the signal is invoked.
void disconnect() {
_connection.disconnect();
}
private:
/// Underlying connection object
connection _connection;
};
/// Policy for multi threaded use of signals.
///
/// This policy provides mutex and lock types for use in
/// a multithreaded environment, where signals and slots
/// may exists in different threads.
///
/// This policy is used in the `nod::signal` type provided
/// by the library.
struct multithread_policy
{
using mutex_type = std::mutex;
using mutex_lock_type = std::unique_lock<mutex_type>;
/// Function that yields the current thread, allowing
/// the OS to reschedule.
static void yield_thread() {
std::this_thread::yield();
}
/// Function that defers a lock to a lock function that prevents deadlock
static mutex_lock_type defer_lock(mutex_type & m){
return mutex_lock_type{m, std::defer_lock};
}
/// Function that locks two mutexes and prevents deadlock
static void lock(mutex_lock_type & a,mutex_lock_type & b) {
std::lock(a,b);
}
};
/// Policy for single threaded use of signals.
///
/// This policy provides dummy implementations for mutex
/// and lock types, resulting in that no synchronization
/// will take place.
///
/// This policy is used in the `nod::unsafe_signal` type
/// provided by the library.
struct singlethread_policy
{
/// Dummy mutex type that doesn't do anything
struct mutex_type{};
/// Dummy lock type, that doesn't do any locking.
struct mutex_lock_type
{
/// A lock type must be constructible from a
/// mutex type from the same thread policy.
explicit mutex_lock_type( mutex_type const& ) {
}
};
/// Dummy implementation of thread yielding, that
/// doesn't do any actual yielding.
static void yield_thread() {
}
/// Dummy implemention of defer_lock that doesn't
/// do anything
static mutex_lock_type defer_lock(mutex_type &m){
return mutex_lock_type{m};
}
/// Dummy implemention of lock that doesn't
/// do anything
static void lock(mutex_lock_type &,mutex_lock_type &) {
}
};
/// Signal accumulator class template.
///
/// This acts sort of as a proxy for triggering a signal and
/// accumulating the slot return values.
///
/// This class is not really intended to instantiate by client code.
/// Instances are aquired as return values of the method `accumulate()`
/// called on signals.
///
/// @tparam S Type of signal. The signal_accumulator acts
/// as a type of proxy for a signal instance of
/// this type.
/// @tparam T Type of initial value of the accumulate algorithm.
/// This type must meet the requirements of `CopyAssignable`
/// and `CopyConstructible`
/// @tparam F Type of accumulation function.
/// @tparam A... Argument types of the underlying signal type.
///
template <class S, class T, class F, class...A>
class signal_accumulator
{
public:
/// Result type when calling the accumulating function operator.
using result_type = typename std::result_of<F(T, typename S::slot_type::result_type)>::type;
/// Construct a signal_accumulator as a proxy to a given signal
//
/// @param signal Signal instance.
/// @param init Initial value of the accumulate algorithm.
/// @param func Binary operation function object that will be
/// applied to all slot return values.
/// The signature of the function should be
/// equivalent of the following:
/// `R func( T1 const& a, T2 const& b )`
/// - The signature does not need to have `const&`.
/// - The initial value, type `T`, must be implicitly
/// convertible to `R`
/// - The return type `R` must be implicitly convertible
/// to type `T1`.
/// - The type `R` must be `CopyAssignable`.
/// - The type `S::slot_type::result_type` (return type of
/// the signals slots) must be implicitly convertible to
/// type `T2`.
signal_accumulator( S const& signal, T init, F func ) :
_signal( signal ),
_init( init ),
_func( func )
{}
/// Function call operator.
///
/// Calling this will trigger the underlying signal and accumulate
/// all of the connected slots return values with the current
/// initial value and accumulator function.
///
/// When called, this will invoke the accumulator function will
/// be called for each return value of the slots. The semantics
/// are similar to the `std::accumulate` algorithm.
///
/// @param args Arguments to propagate to the slots of the
/// underlying when triggering the signal.
result_type operator()( A const& ... args ) const {
return _signal.trigger_with_accumulator( _init, _func, args... );
}
private:
/// Reference to the underlying signal to proxy.
S const& _signal;
/// Initial value of the accumulate algorithm.
T _init;
/// Accumulator function.
F _func;
};
/// Signal template specialization.
///
/// This is the main signal implementation, and it is used to
/// implement the observer pattern whithout the overhead
/// boilerplate code that typically comes with it.
///
/// Any function or function object is considered a slot, and
/// can be connected to a signal instance, as long as the signature
/// of the slot matches the signature of the signal.
///
/// @tparam P Threading policy for the signal.
/// A threading policy must provide two type definitions:
/// - P::mutex_type, this type will be used as a mutex
/// in the signal_type class template.
/// - P::mutex_lock_type, this type must implement a
/// constructor that takes a P::mutex_type as a parameter,
/// and it must have the semantics of a scoped mutex lock
/// like std::lock_guard, i.e. locking in the constructor
/// and unlocking in the destructor.
///
/// @tparam R Return value type of the slots connected to the signal.
/// @tparam A... Argument types of the slots connected to the signal.
template <class P, class R, class... A >
class signal_type<P,R(A...)>
{
public:
/// signals are not copy constructible
signal_type( signal_type const& ) = delete;
/// signals are not copy assignable
signal_type& operator=( signal_type const& ) = delete;
/// signals are move constructible
signal_type(signal_type&& other)
{
mutex_lock_type lock{other._mutex};
_slot_count = std::move(other._slot_count);
_slots = std::move(other._slots);
if(other._shared_disconnector != nullptr)
{
_disconnector = disconnector{ this };
_shared_disconnector = std::move(other._shared_disconnector);
// replace the disconnector with our own disconnector
*static_cast<disconnector*>(_shared_disconnector.get()) = _disconnector;
}
}
/// signals are move assignable
signal_type& operator=(signal_type&& other)
{
auto lock = thread_policy::defer_lock(_mutex);
auto other_lock = thread_policy::defer_lock(other._mutex);
thread_policy::lock(lock,other_lock);
_slot_count = std::move(other._slot_count);
_slots = std::move(other._slots);
if(other._shared_disconnector != nullptr)
{
_disconnector = disconnector{ this };
_shared_disconnector = std::move(other._shared_disconnector);
// replace the disconnector with our own disconnector
*static_cast<disconnector*>(_shared_disconnector.get()) = _disconnector;
}
return *this;
}
/// signals are default constructible
signal_type() :
_slot_count(0)
{}
// Destruct the signal object.
~signal_type() {
invalidate_disconnector();
}
/// Type that will be used to store the slots for this signal type.
using slot_type = std::function<R(A...)>;
/// Type that is used for counting the slots connected to this signal.
using size_type = typename std::vector<slot_type>::size_type;
/// Connect a new slot to the signal.
///
/// The connected slot will be called every time the signal
/// is triggered.
/// @param slot The slot to connect. This must be a callable with
/// the same signature as the signal itself.
/// @return A connection object is returned, and can be used to
/// disconnect the slot.
template <class T>
connection connect( T&& slot ) {
mutex_lock_type lock{ _mutex };
_slots.push_back( std::forward<T>(slot) );
std::size_t index = _slots.size()-1;
if( _shared_disconnector == nullptr ) {
_disconnector = disconnector{ this };
_shared_disconnector = std::shared_ptr<detail::disconnector>{&_disconnector, detail::no_delete};
}
++_slot_count;
return connection{ _shared_disconnector, index };
}
/// Function call operator.
///
/// Calling this is how the signal is triggered and the
/// connected slots are called.
///
/// @note The slots will be called in the order they were
/// connected to the signal.
///
/// @param args Arguments that will be propagated to the
/// connected slots when they are called.
void operator()( A const&... args ) const {
for( auto const& slot : copy_slots() ) {
if( slot ) {
slot( args... );
}
}
}
/// Construct a accumulator proxy object for the signal.
///
/// The intended purpose of this function is to create a function
/// object that can be used to trigger the signal and accumulate
/// all the slot return values.
///
/// The algorithm used to accumulate slot return values is similar
/// to `std::accumulate`. A given binary function is called for
/// each return value with the parameters consisting of the
/// return value of the accumulator function applied to the
/// previous slots return value, and the current slots return value.
/// A initial value must be provided for the first slot return type.
///
/// @note This can only be used on signals that have slots with
/// non-void return types, since we can't accumulate void
/// values.
///
/// @tparam T The type of the initial value given to the accumulator.
/// @tparam F The accumulator function type.
/// @param init Initial value given to the accumulator.
/// @param op Binary operator function object to apply by the accumulator.
/// The signature of the function should be
/// equivalent of the following:
/// `R func( T1 const& a, T2 const& b )`
/// - The signature does not need to have `const&`.
/// - The initial value, type `T`, must be implicitly
/// convertible to `R`
/// - The return type `R` must be implicitly convertible
/// to type `T1`.
/// - The type `R` must be `CopyAssignable`.
/// - The type `S::slot_type::result_type` (return type of
/// the signals slots) must be implicitly convertible to
/// type `T2`.
template <class T, class F>
signal_accumulator<signal_type, T, F, A...> accumulate( T init, F op ) const {
static_assert( std::is_same<R,void>::value == false, "Unable to accumulate slot return values with 'void' as return type." );
return { *this, init, op };
}
/// Trigger the signal, calling the slots and aggregate all
/// the slot return values into a container.
///
/// @tparam C The type of container. This type must be
/// `DefaultConstructible`, and usable with
/// `std::back_insert_iterator`. Additionally it
/// must be either copyable or moveable.
/// @param args The arguments to propagate to the slots.
template <class C>
C aggregate( A const&... args ) const {
static_assert( std::is_same<R,void>::value == false, "Unable to aggregate slot return values with 'void' as return type." );
C container;
auto iterator = std::back_inserter( container );
for( auto const& slot : copy_slots() ) {
if( slot ) {
(*iterator) = slot( args... );
}
}
return container;
}
/// Count the number of slots connected to this signal
/// @returns The number of connected slots
size_type slot_count() const {
return _slot_count;
}
/// Determine if the signal is empty, i.e. no slots are connected
/// to it.
/// @returns `true` is returned if the signal has no connected
/// slots, and `false` otherwise.
bool empty() const {
return slot_count() == 0;
}
/// Disconnects all slots
/// @note This operation invalidates all scoped_connection objects
void disconnect_all_slots() {
mutex_lock_type lock{ _mutex };
_slots.clear();
_slot_count = 0;
invalidate_disconnector();
}
private:
template<class, class, class, class...> friend class signal_accumulator;
/// Thread policy currently in use
using thread_policy = P;
/// Type of mutex, provided by threading policy
using mutex_type = typename thread_policy::mutex_type;
/// Type of mutex lock, provided by threading policy
using mutex_lock_type = typename thread_policy::mutex_lock_type;
/// Invalidate the internal disconnector object in a way
/// that is safe according to the current thread policy.
///
/// This will effectively make all current connection objects to
/// to this signal incapable of disconnecting, since they keep a
/// weak pointer to the shared disconnector object.
void invalidate_disconnector() {
// If we are unlucky, some of the connected slots
// might be in the process of disconnecting from other threads.
// If this happens, we are risking to destruct the disconnector
// object managed by our shared pointer before they are done
// disconnecting. This would be bad. To solve this problem, we
// discard the shared pointer (that is pointing to the disconnector
// object within our own instance), but keep a weak pointer to that
// instance. We then stall the destruction until all other weak
// pointers have released their "lock" (indicated by the fact that
// we will get a nullptr when locking our weak pointer).
std::weak_ptr<detail::disconnector> weak{_shared_disconnector};
_shared_disconnector.reset();
while( weak.lock() != nullptr ) {
// we just yield here, allowing the OS to reschedule. We do
// this until all threads has released the disconnector object.
thread_policy::yield_thread();
}
}
/// Retrieve a copy of the current slots
///
/// It's useful and necessary to copy the slots so we don't need
/// to hold the lock while calling the slots. If we hold the lock
/// we prevent the called slots from modifying the slots vector.
/// This simple "double buffering" will allow slots to disconnect
/// themself or other slots and connect new slots.
std::vector<slot_type> copy_slots() const
{
mutex_lock_type lock{ _mutex };
return _slots;
}
/// Implementation of the signal accumulator function call
template <class T, class F>
typename signal_accumulator<signal_type, T, F, A...>::result_type trigger_with_accumulator( T value, F& func, A const&... args ) const {
for( auto const& slot : copy_slots() ) {
if( slot ) {
value = func( value, slot( args... ) );
}
}
return value;
}
/// Implementation of the disconnection operation.
///
/// This is private, and only called by the connection
/// objects created when connecting slots to this signal.
/// @param index The slot index of the slot that should
/// be disconnected.
void disconnect( std::size_t index ) {
mutex_lock_type lock( _mutex );
assert( _slots.size() > index );
if( _slots[ index ] != nullptr ) {
--_slot_count;
}
_slots[ index ] = slot_type{};
while( _slots.size()>0 && !_slots.back() ) {
_slots.pop_back();
}
}
/// Implementation of the shared disconnection state
/// used by all connection created by signal instances.
///
/// This inherits the @ref detail::disconnector interface
/// for type erasure.
struct disconnector :
detail::disconnector
{
/// Default constructor, resulting in a no-op disconnector.
disconnector() :
_ptr(nullptr)
{}
/// Create a disconnector that works with a given signal instance.
/// @param ptr Pointer to the signal instance that the disconnector
/// should work with.
disconnector( signal_type<P,R(A...)>* ptr ) :
_ptr( ptr )
{}
/// Disconnect a given slot on the current signal instance.
/// @note If the instance is default constructed, or created
/// with `nullptr` as signal pointer this operation will
/// effectively be a no-op.
/// @param index The index of the slot to disconnect.
void operator()( std::size_t index ) const override {
if( _ptr ) {
_ptr->disconnect( index );
}
}
/// Pointer to the current signal.
signal_type<P,R(A...)>* _ptr;
};
/// Mutex to synchronize access to the slot vector
mutable mutex_type _mutex;
/// Vector of all connected slots
std::vector<slot_type> _slots;
/// Number of connected slots
size_type _slot_count;
/// Disconnector operation, used for executing disconnection in a
/// type erased manner.
disconnector _disconnector;
/// Shared pointer to the disconnector. All connection objects has a
/// weak pointer to this pointer for performing disconnections.
std::shared_ptr<detail::disconnector> _shared_disconnector;
};
// Implementation of the disconnect operation of the connection class
inline void connection::disconnect() {
auto ptr = _weak_disconnector.lock();
if( ptr ) {
(*ptr)( _index );
}
_weak_disconnector.reset();
}
/// Signal type that is safe to use in multithreaded environments,
/// where the signal and slots exists in different threads.
/// The multithreaded policy provides mutexes and locks to synchronize
/// access to the signals internals.
///
/// This is the recommended signal type, even for single threaded
/// environments.
template <class T> using signal = signal_type<multithread_policy, T>;
/// Signal type that is unsafe in multithreaded environments.
/// No synchronizations are provided to the signal_type for accessing
/// the internals.
///
/// Only use this signal type if you are sure that your environment is
/// single threaded and performance is of importance.
template <class T> using unsafe_signal = signal_type<singlethread_policy, T>;
} // namespace nod
#endif // IG_NOD_INCLUDE_NOD_HPP
+278 -217
View File
@@ -9,278 +9,278 @@ lvgl = {}
--- @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,
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,
}
--- object flag for obj:add_flag obj:clear_flag
--- @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,
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,
}
--- @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,
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 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,
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,
}
--- @enum BuiltinFont
lvgl.BUILTIN_FONT = {
MONTSERRAT_8 = 0,
MONTSERRAT_10 = 0,
MONTSERRAT_12 = 0,
MONTSERRAT_14 = 0,
MONTSERRAT_16 = 0,
MONTSERRAT_18 = 0,
MONTSERRAT_20 = 0,
MONTSERRAT_22 = 0,
MONTSERRAT_24 = 0,
MONTSERRAT_26 = 0,
MONTSERRAT_28 = 0,
MONTSERRAT_30 = 0,
MONTSERRAT_32 = 0,
MONTSERRAT_34 = 0,
MONTSERRAT_36 = 0,
MONTSERRAT_38 = 0,
MONTSERRAT_40 = 0,
MONTSERRAT_42 = 0,
MONTSERRAT_44 = 0,
MONTSERRAT_46 = 0,
MONTSERRAT_48 = 0,
MONTSERRAT_12_SUBPX = 0,
MONTSERRAT_28_COMPRESSED = 0,
DEJAVU_16_PERSIAN_HEBREW = 0,
SIMSUN_16_CJK = 0,
UNSCII_8 = 0,
UNSCII_16 = 0,
MONTSERRAT_8 = 0,
MONTSERRAT_10 = 0,
MONTSERRAT_12 = 0,
MONTSERRAT_14 = 0,
MONTSERRAT_16 = 0,
MONTSERRAT_18 = 0,
MONTSERRAT_20 = 0,
MONTSERRAT_22 = 0,
MONTSERRAT_24 = 0,
MONTSERRAT_26 = 0,
MONTSERRAT_28 = 0,
MONTSERRAT_30 = 0,
MONTSERRAT_32 = 0,
MONTSERRAT_34 = 0,
MONTSERRAT_36 = 0,
MONTSERRAT_38 = 0,
MONTSERRAT_40 = 0,
MONTSERRAT_42 = 0,
MONTSERRAT_44 = 0,
MONTSERRAT_46 = 0,
MONTSERRAT_48 = 0,
MONTSERRAT_12_SUBPX = 0,
MONTSERRAT_28_COMPRESSED = 0,
DEJAVU_16_PERSIAN_HEBREW = 0,
SIMSUN_16_CJK = 0,
UNSCII_8 = 0,
UNSCII_16 = 0,
}
--- @enum LABEL
lvgl.LABEL = {
LONG_WRAP = 0,
LONG_DOT = 0,
LONG_SCROLL = 0,
LONG_SCROLL_CIRCULAR = 0,
LONG_CLIP = 0,
LONG_WRAP = 0,
LONG_DOT = 0,
LONG_SCROLL = 0,
LONG_SCROLL_CIRCULAR = 0,
LONG_CLIP = 0,
}
--- @enum SCR_LOAD_ANIM
lvgl.SCR_LOAD_ANIM = {
NONE = 0,
OVER_LEFT = 0,
OVER_RIGHT = 0,
OVER_TOP = 0,
OVER_BOTTOM = 0,
MOVE_LEFT = 0,
MOVE_RIGHT = 0,
MOVE_TOP = 0,
MOVE_BOTTOM = 0,
FADE_IN = 0,
FADE_ON = 0,
FADE_OUT = 0,
OUT_LEFT = 0,
OUT_RIGHT = 0,
OUT_TOP = 0,
OUT_BOTTOM = 0,
NONE = 0,
OVER_LEFT = 0,
OVER_RIGHT = 0,
OVER_TOP = 0,
OVER_BOTTOM = 0,
MOVE_LEFT = 0,
MOVE_RIGHT = 0,
MOVE_TOP = 0,
MOVE_BOTTOM = 0,
FADE_IN = 0,
FADE_ON = 0,
FADE_OUT = 0,
OUT_LEFT = 0,
OUT_RIGHT = 0,
OUT_TOP = 0,
OUT_BOTTOM = 0,
}
--- @enum ScrollbarMode
lvgl.SCROLLBAR_MODE = {
OFF = 0,
ON = 0,
ACTIVE = 0,
AUTO = 0,
OFF = 0,
ON = 0,
ACTIVE = 0,
AUTO = 0,
}
--- @enum Dir
lvgl.DIR = {
NONE = 0,
LEFT = 0,
RIGHT = 0,
TOP = 0,
BOTTOM = 0,
HOR = 0,
VER = 0,
ALL = 0,
NONE = 0,
LEFT = 0,
RIGHT = 0,
TOP = 0,
BOTTOM = 0,
HOR = 0,
VER = 0,
ALL = 0,
}
--- @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,
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,
}
--- @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,
ROW = 0,
COLUMN = 0,
ROW_WRAP = 0,
ROW_REVERSE = 0,
ROW_WRAP_REVERSE = 0,
COLUMN_WRAP = 0,
COLUMN_REVERSE = 0,
COLUMN_WRAP_REVERSE = 0,
}
--- @enum FlexAlign
lvgl.FLEX_ALIGN = {
START = 0,
END = 0,
CENTER = 0,
SPACE_EVENLY = 0,
SPACE_AROUND = 0,
SPACE_BETWEEN = 0,
START = 0,
END = 0,
CENTER = 0,
SPACE_EVENLY = 0,
SPACE_AROUND = 0,
SPACE_BETWEEN = 0,
}
--- @enum GridAlign
lvgl.GRID_ALIGN = {
START = 0,
CENTER = 0,
END = 0,
STRETCH = 0,
SPACE_EVENLY = 0,
SPACE_AROUND = 0,
SPACE_BETWEEN = 0,
START = 0,
CENTER = 0,
END = 0,
STRETCH = 0,
SPACE_EVENLY = 0,
SPACE_AROUND = 0,
SPACE_BETWEEN = 0,
}
--- @enum RollerMode
lvgl.ROLLER_MODE = {
NORMAL = 0,
INFINITE = 0,
NORMAL = 0,
INFINITE = 0,
}
--- @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,
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
@@ -404,7 +404,6 @@ end
function lvgl.Keyboard(parent, property)
end
---
--- Create Led Widget on parent
--- @param parent? Object | nil
@@ -429,6 +428,20 @@ end
function lvgl.Roller(parent, property)
end
--- Create Slider widget on parent
--- @param parent? Object | nil
--- @param property? BarStyle
--- @return Slider
function lvgl.Slider(parent, property)
end
--- Create Switch widget on parent
--- @param parent? Object | nil
--- @param property? StyleProp
--- @return Switch
function lvgl.Switch(parent, property)
end
---
--- Create Timer
--- @param p TimerPara
@@ -555,13 +568,27 @@ end
function obj:List(property)
end
---
--- Create Roller Widget on parent
--- @param property? RollerStyle
--- @return Roller
function obj:Roller(parent, property)
end
---
--- Create Slider on object
--- @param property? BarStyle
--- @return Slider
function obj:Slider(property)
end
---
--- Create switch on object
--- @param property? StyleProp
--- @return Switch
function obj:Switch(property)
end
---
--- Set object property
--- @param p StyleProp
@@ -1049,6 +1076,40 @@ end
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
---
--- 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
+88
View File
@@ -0,0 +1,88 @@
#include "lua.h"
#include "luavgl.h"
#include "private.h"
#include <src/widgets/lv_slider.h>
static int luavgl_slider_create(lua_State *L) {
return luavgl_obj_create_helper(L, lv_slider_create);
}
static void _lv_slider_set_range(void *obj, lua_State *L) {
int min = 0, max = 100;
int type = lua_type(L, -1);
if (type == LUA_TTABLE) {
lua_getfield(L, -1, "min");
min = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "max");
max = luavgl_tointeger(L, -1);
lua_pop(L, 1);
}
lv_slider_set_range(obj, min, max);
}
static void _lv_slider_set_value(void *obj, int value) {
lv_slider_set_value(obj, value, LV_ANIM_OFF);
}
static const luavgl_value_setter_t slider_property_table[] = {
{"range", SETTER_TYPE_STACK, {.setter_stack = _lv_slider_set_range}},
{"value", SETTER_TYPE_INT, {.setter = (setter_int_t)_lv_slider_set_value}},
};
LUALIB_API int luavgl_slider_set_property_kv(lua_State *L, void *data) {
lv_obj_t *obj = data;
int ret = luavgl_set_property(L, obj, slider_property_table);
if (ret == 0) {
return 0;
}
/* a base obj property? */
ret = luavgl_obj_set_property_kv(L, obj);
if (ret != 0) {
debug("unkown property for slider.\n");
}
return ret;
}
static int luavgl_slider_set(lua_State *L) {
lv_obj_t *obj = luavgl_to_obj(L, 1);
if (!lua_istable(L, -1)) {
luaL_error(L, "expect a table on 2nd para.");
return 0;
}
luavgl_iterate(L, -1, luavgl_slider_set_property_kv, obj);
return 0;
}
static int luavgl_slider_value(lua_State *L) {
lv_obj_t *obj = luavgl_to_obj(L, 1);
lua_pushinteger(L, lv_slider_get_value(obj));
return 1;
}
static int luavgl_slider_tostring(lua_State *L) {
lv_obj_t *obj = luavgl_to_obj(L, 1);
lua_pushfstring(L, "lv_slider:%p", obj);
return 1;
}
static const luaL_Reg luavgl_slider_methods[] = {
{"set", luavgl_slider_set},
{"value", luavgl_slider_value},
{NULL, NULL},
};
static void luavgl_slider_init(lua_State *L) {
luavgl_obj_newmetatable(L, &lv_slider_class, "lv_slider",
luavgl_slider_methods);
lua_pushcfunction(L, luavgl_slider_tostring);
lua_setfield(L, -2, "__tostring");
lua_pop(L, 1);
}
+57
View File
@@ -0,0 +1,57 @@
#include "luavgl.h"
#include "private.h"
#include <src/widgets/lv_switch.h>
static int luavgl_switch_create(lua_State *L) {
return luavgl_obj_create_helper(L, lv_switch_create);
}
LUALIB_API int luavgl_switch_set_property_kv(lua_State *L, void *data) {
lv_obj_t *obj = data;
/* switches only use base properties */
int ret = luavgl_obj_set_property_kv(L, obj);
if (ret != 0) {
debug("unkown property for switch.\n");
}
return ret;
}
static int luavgl_switch_set(lua_State *L) {
lv_obj_t *obj = luavgl_to_obj(L, 1);
if (!lua_istable(L, -1)) {
luaL_error(L, "expect a table on 2nd para.");
return 0;
}
luavgl_iterate(L, -1, luavgl_switch_set_property_kv, obj);
return 0;
}
static int luavgl_switch_enabled(lua_State *L) {
lv_obj_t *obj = luavgl_to_obj(L, 1);
lua_pushboolean(L, lv_obj_has_state(obj, LV_STATE_CHECKED));
return 1;
}
static int luavgl_switch_tostring(lua_State *L) {
lv_obj_t *obj = luavgl_to_obj(L, 1);
lua_pushfstring(L, "lv_switch:%p", obj);
return 1;
}
static const luaL_Reg luavgl_switch_methods[] = {
{"set", luavgl_switch_set},
{"enabled", luavgl_switch_enabled},
{NULL, NULL},
};
static void luavgl_switch_init(lua_State *L) {
luavgl_obj_newmetatable(L, &lv_switch_class, "lv_switch",
luavgl_switch_methods);
lua_pushcfunction(L, luavgl_switch_tostring);
lua_setfield(L, -2, "__tostring");
lua_pop(L, 1);
}
+24
View File
@@ -45,6 +45,14 @@
#include "roller.c"
#endif
#if LV_USE_SLIDER
#include "slider.c"
#endif
#if LV_USE_SWITCH
#include "switch.c"
#endif
#if LV_USE_TEXTAREA
#include "textarea.c"
#endif
@@ -98,6 +106,14 @@ static const luaL_Reg widget_create_methods[] = {
{"Roller", luavgl_roller_create },
#endif
#if LV_USE_SLIDER
{"Slider", luavgl_slider_create},
#endif
#if LV_USE_SWITCH
{"Switch", luavgl_switch_create},
#endif
#if LV_USE_TEXTAREA
{"Textarea", luavgl_textarea_create},
#endif
@@ -154,4 +170,12 @@ static void luavgl_widgets_init(lua_State *L)
luavgl_bar_init(L);
#endif
#if LV_USE_SLIDER
luavgl_slider_init(L);
#endif
#if LV_USE_SWITCH
luavgl_switch_init(L);
#endif
}