Begin migration of remaining screens to Lua
This commit is contained in:
@@ -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
|
||||
Vendored
-44
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
*.a
|
||||
*.lib
|
||||
*.o
|
||||
*.pdb
|
||||
.DS_Store
|
||||
@@ -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
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright 2023 jacqueline <me@jacqueline.id.au>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
idf_component_register(
|
||||
INCLUDE_DIRS "include"
|
||||
)
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
};
|
||||
```
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user