mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
refactor(msg): remove lv_msg in favor of lv_observer
This commit is contained in:
parent
9bf50c65cf
commit
80149e7f98
@ -1,151 +0,0 @@
|
||||
=========
|
||||
Messaging
|
||||
=========
|
||||
|
||||
Messaging (``lv_msg``) is a classic `publisher subscriber <https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern>`__
|
||||
implementation for LVGL.
|
||||
|
||||
IDs
|
||||
---
|
||||
|
||||
Both the publishers and the subscribers needs to know the message
|
||||
identifiers. In ``lv_msg`` these are simple integers. For example:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define MSG_DOOR_OPENED 1
|
||||
#define MSG_DOOR_CLOSED 2
|
||||
#define MSG_USER_NAME_CHANGED 100
|
||||
#define MSG_USER_AVATAR_CHANGED 101
|
||||
|
||||
You can organize the message IDs as you wish.
|
||||
|
||||
Both parties also need to know about the format of the payload. E.g. in
|
||||
the above example :c:enumerator:`MSG_DOOR_OPENED` and :c:enumerator:`MSG_DOOR_CLOSED` might have
|
||||
no payload but :c:enumerator:`MSG_USER_NAME_CHANGED` can have a :c:expr:`const char *`
|
||||
payload containing the user name, and :c:enumerator:`MSG_USER_AVATAR_CHANGED` a
|
||||
:c:expr:`const void *` image source with the new avatar image.
|
||||
|
||||
To be more precise the message ID's type is declared like this:
|
||||
|
||||
.. code:: c
|
||||
|
||||
typedef lv_uintptr_t lv_msg_id_t;
|
||||
|
||||
This way, if a value in stored in a global variable (e.g. the current
|
||||
temperature) then the address of that variable can be used as message ID
|
||||
too by simply casting it to :c:type:`lv_msg_id_t`. It saves the creation of
|
||||
message IDs manually as the variable itself serves as message ID too.
|
||||
|
||||
Subscribe to a message
|
||||
----------------------
|
||||
|
||||
:c:expr:`lv_msg_subscribe(msg_id, callback, user_data)` can be used to
|
||||
subscribe to message.
|
||||
|
||||
Don't forget that ``msg_id`` can be a constant or a variable address
|
||||
too:
|
||||
|
||||
.. code:: c
|
||||
|
||||
lv_msg_subscribe(45, my_callback_1, NULL);
|
||||
|
||||
int v;
|
||||
lv_msg_subscribe((lv_msg_id_t)&v, my_callback_2, NULL);
|
||||
|
||||
The callback should look like this:
|
||||
|
||||
.. code:: c
|
||||
|
||||
|
||||
static void user_name_subscriber_cb(lv_msg_t * m)
|
||||
{
|
||||
/*m: a message object with the msg_id, payload, and user_data (set during subscription)*/
|
||||
|
||||
...do something...
|
||||
}
|
||||
|
||||
From :c:struct:`lv_msg_t` the following can be used to get some data:
|
||||
|
||||
- :c:expr:`lv_msg_get_id(m)`
|
||||
- :c:expr:`lv_msg_get_payload(m)`
|
||||
- :c:expr:`lv_msg_get_user_data(m)`
|
||||
|
||||
Subscribe with an lv_obj
|
||||
------------------------
|
||||
|
||||
It's quite typical that an LVGL widget is interested in some messages.
|
||||
To make it simpler :c:expr:`lv_msg_subscribe_obj(msg_id, obj, user_data)` can
|
||||
be used. If a new message is published with ``msg_id`` an
|
||||
:c:enumerator:`LV_EVENT_MSG_RECEIVED` event will be sent to the object.
|
||||
|
||||
For example:
|
||||
|
||||
.. code:: c
|
||||
|
||||
lv_obj_add_event(user_name_label, user_name_label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_msg_subscribe_obj(MSG_USER_NAME_CHANGED, user_name_label, NULL);
|
||||
|
||||
...
|
||||
|
||||
void user_name_label_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
lv_label_set_text(label, lv_msg_get_payload(m));
|
||||
}
|
||||
|
||||
Here ``msg_id`` also can be a variable's address:
|
||||
|
||||
.. code:: c
|
||||
|
||||
char name[64];
|
||||
lv_msg_subscribe_obj(name, user_name_label, NULL);
|
||||
|
||||
Unsubscribe
|
||||
~~~~~~~~~~~
|
||||
|
||||
:c:func:`lv_msg_subscribe` returns a pointer which can be used to unsubscribe:
|
||||
|
||||
.. code:: c
|
||||
|
||||
void * s1;
|
||||
s1 = lv_msg_subscribe(MSG_USER_DOOR_OPENED, some_callback, NULL);
|
||||
|
||||
...
|
||||
|
||||
lv_msg_unsubscribe(s1);
|
||||
|
||||
Send message
|
||||
------------
|
||||
|
||||
Messages can be sent with :c:expr:`lv_msg_send(msg_id, payload)`. E.g.
|
||||
|
||||
.. code:: c
|
||||
|
||||
lv_msg_send(MSG_USER_DOOR_OPENED, NULL);
|
||||
lv_msg_send(MSG_USER_NAME_CHANGED, "John Smith");
|
||||
|
||||
If have subscribed to a variable with
|
||||
:c:expr:`lv_msg_subscribe((lv_msg_id_t)&v, callback, NULL)` and changed the
|
||||
variable's value the subscribers can be notified like this:
|
||||
|
||||
.. code:: c
|
||||
|
||||
v = 10;
|
||||
lv_msg_update_value(&v); //Notify all the subscribers of `(lv_msg_id_t)&v`
|
||||
|
||||
It's handy way of creating API for the UI too. If the UI provides some
|
||||
global variables (e.g. ``int current_temperature``) and anyone can
|
||||
read and write this variable. After writing they can notify all the
|
||||
elements who are interested in that value. E.g. an ``lv_label`` can
|
||||
subscribe to :c:expr:`(lv_msg_id_t)¤t_temperature` and update its text
|
||||
when it's notified about the new temperature.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. include:: ../examples/others/msg/index.rst
|
||||
|
||||
API
|
||||
---
|
@ -1,11 +1,9 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_USE_TINY_TTF && LV_BUILD_EXAMPLES && LV_USE_MSG
|
||||
#if LV_USE_TINY_TTF && LV_BUILD_EXAMPLES && LV_USE_OBSERVER
|
||||
|
||||
#define DISPLAY_TEXT "Hello World!"
|
||||
#define MSG_NEW_SIZE 1
|
||||
static void font_size_observer_cb(lv_subject_t * subject, lv_observer_t * observer);
|
||||
|
||||
static void slider_event_cb(lv_event_t * e);
|
||||
static void label_event_cb(lv_event_t * e);
|
||||
static lv_subject_t subject_font;
|
||||
|
||||
/**
|
||||
* Change font size with Tiny_TTF
|
||||
@ -15,59 +13,47 @@ void lv_example_tiny_ttf_3(void)
|
||||
extern const uint8_t ubuntu_font[];
|
||||
extern const int ubuntu_font_size;
|
||||
|
||||
int lsize = 25;
|
||||
lv_subject_init_int(&subject_font, 25);
|
||||
|
||||
/*Create style with the new font*/
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
lv_font_t * font = lv_tiny_ttf_create_data(ubuntu_font, ubuntu_font_size, lsize);
|
||||
lv_font_t * font = lv_tiny_ttf_create_data(ubuntu_font, ubuntu_font_size, 25);
|
||||
lv_style_set_text_font(&style, font);
|
||||
lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);
|
||||
|
||||
lv_obj_t * slider = lv_slider_create(lv_scr_act());
|
||||
lv_obj_center(slider);
|
||||
lv_slider_set_range(slider, 5, 50);
|
||||
lv_slider_set_value(slider, lsize, LV_ANIM_OFF);
|
||||
lv_obj_align(slider, LV_ALIGN_BOTTOM_MID, 0, -50);
|
||||
lv_slider_bind_value(slider, &subject_font);
|
||||
|
||||
lv_obj_t * slider_label = lv_label_create(lv_scr_act());
|
||||
lv_label_set_text_fmt(slider_label, "%d", lsize);
|
||||
lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
||||
lv_label_bind_text(slider_label, &subject_font, "%d");
|
||||
|
||||
lv_obj_add_event(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, slider_label);
|
||||
|
||||
/*Create a label with the new style*/
|
||||
lv_obj_t * label = lv_label_create(lv_scr_act());
|
||||
lv_obj_add_style(label, &style, 0);
|
||||
lv_obj_add_event(label, label_event_cb, LV_EVENT_MSG_RECEIVED, font);
|
||||
lv_obj_set_size(label, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_label_set_text(label, "Hello world!");
|
||||
lv_obj_center(label);
|
||||
|
||||
lv_msg_subscribe_obj(MSG_NEW_SIZE, label, NULL);
|
||||
lv_msg_send(MSG_NEW_SIZE, &lsize);
|
||||
|
||||
lv_subject_add_observer(&subject_font, font_size_observer_cb, &style);
|
||||
}
|
||||
|
||||
static void slider_event_cb(lv_event_t * e)
|
||||
static void font_size_observer_cb(lv_subject_t * subject, lv_observer_t * observer)
|
||||
{
|
||||
lv_obj_t * slider = lv_event_get_target(e);
|
||||
lv_obj_t * label = lv_event_get_user_data(e);
|
||||
int lsize;
|
||||
lv_style_t * style = observer->user_data;
|
||||
lv_style_value_t v;
|
||||
lv_style_get_prop(style, LV_STYLE_TEXT_FONT, &v);
|
||||
lv_font_t * font = (lv_font_t *) v.ptr;
|
||||
int32_t size = lv_subject_get_int(subject);
|
||||
|
||||
lsize = (int)lv_slider_get_value(slider);
|
||||
lv_tiny_ttf_set_size(font, size);
|
||||
|
||||
lv_label_set_text_fmt(label, "%d", lsize);
|
||||
|
||||
lv_msg_send(MSG_NEW_SIZE, &lsize);
|
||||
}
|
||||
|
||||
static void label_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_font_t * font = lv_event_get_user_data(e);
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
const int32_t * v = lv_msg_get_payload(m);
|
||||
|
||||
lv_tiny_ttf_set_size(font, *v);
|
||||
lv_label_set_text(label, DISPLAY_TEXT);
|
||||
lv_obj_report_style_change(style);
|
||||
}
|
||||
#endif
|
||||
|
@ -19,7 +19,6 @@ extern "C" {
|
||||
#include "ime/lv_example_ime_pinyin.h"
|
||||
#include "imgfont/lv_example_imgfont.h"
|
||||
#include "monkey/lv_example_monkey.h"
|
||||
#include "msg/lv_example_msg.h"
|
||||
#include "observer/lv_example_observer.h"
|
||||
#include "snapshot/lv_example_snapshot.h"
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
|
||||
Slider to label messaging
|
||||
-------------------------
|
||||
|
||||
.. lv_example:: others/msg/lv_example_msg_1
|
||||
:language: c
|
||||
|
||||
Handling login and its states
|
||||
-----------------------------
|
||||
|
||||
.. lv_example:: others/msg/lv_example_msg_2
|
||||
:language: c
|
||||
|
||||
Setting the same value from many sources
|
||||
----------------------------------------
|
||||
|
||||
.. lv_example:: others/msg/lv_example_msg_3
|
||||
:language: c
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
/**
|
||||
* @file lv_example_msg.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_EXAMPLE_MSG_H
|
||||
#define LV_EXAMPLE_MSG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void lv_example_msg_1(void);
|
||||
void lv_example_msg_2(void);
|
||||
void lv_example_msg_3(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_EXAMPLE_MSG_H*/
|
@ -1,49 +0,0 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
|
||||
|
||||
/*Define a message ID*/
|
||||
#define MSG_NEW_TEMPERATURE 1
|
||||
|
||||
static void slider_event_cb(lv_event_t * e);
|
||||
static void label_event_cb(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* A slider sends a message on value change and a label display's that value
|
||||
*/
|
||||
void lv_example_msg_1(void)
|
||||
{
|
||||
/*Create a slider in the center of the display*/
|
||||
lv_obj_t * slider = lv_slider_create(lv_scr_act());
|
||||
lv_obj_center(slider);
|
||||
lv_obj_add_event(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
||||
/*Create a label below the slider*/
|
||||
lv_obj_t * label = lv_label_create(lv_scr_act());
|
||||
lv_obj_add_event(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_label_set_text(label, "0%");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 30);
|
||||
|
||||
/*Subscribe the label to a message. Also use the user_data to set a format string here.*/
|
||||
lv_msg_subscribe_obj(MSG_NEW_TEMPERATURE, label, "%d °C");
|
||||
}
|
||||
|
||||
static void slider_event_cb(lv_event_t * e)
|
||||
{
|
||||
/*Notify all subscribers (only the label now) that the slider value has been changed*/
|
||||
lv_obj_t * slider = lv_event_get_target(e);
|
||||
int32_t v = lv_slider_get_value(slider);
|
||||
lv_msg_send(MSG_NEW_TEMPERATURE, &v);
|
||||
}
|
||||
|
||||
static void label_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
|
||||
const char * fmt = lv_msg_get_user_data(m);
|
||||
const int32_t * v = lv_msg_get_payload(m);
|
||||
|
||||
lv_label_set_text_fmt(label, fmt, *v);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
|
||||
# Define a message ID
|
||||
MSG_NEW_TEMPERATURE = const(1)
|
||||
|
||||
# Define the object that will be sent as msg payload
|
||||
class Temperature:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __repr__(self):
|
||||
return f"{self.value} °C"
|
||||
|
||||
def slider_event_cb(e):
|
||||
slider = e.get_target_obj()
|
||||
v = slider.get_value()
|
||||
# Notify all subscribers (only the label now) that the slider value has been changed
|
||||
lv.msg_send(MSG_NEW_TEMPERATURE, Temperature(v))
|
||||
|
||||
def label_event_cb(e):
|
||||
label = e.get_target_obj()
|
||||
msg = e.get_msg()
|
||||
# Respond only to MSG_NEW_TEMPERATURE message
|
||||
if msg.get_id() == MSG_NEW_TEMPERATURE:
|
||||
payload = msg.get_payload()
|
||||
temperature = payload.__cast__()
|
||||
label.set_text(str(temperature))
|
||||
|
||||
# Create a slider in the center of the display
|
||||
slider = lv.slider(lv.scr_act())
|
||||
slider.center()
|
||||
slider.add_event(slider_event_cb, lv.EVENT.VALUE_CHANGED, None)
|
||||
|
||||
# Create a label below the slider
|
||||
label = lv.label(lv.scr_act())
|
||||
label.add_event(label_event_cb, lv.EVENT.MSG_RECEIVED, None)
|
||||
label.set_text("0%")
|
||||
label.align(lv.ALIGN.CENTER, 0, 30)
|
||||
|
||||
# Subscribe the label to a message
|
||||
lv.msg_subscribe_obj(MSG_NEW_TEMPERATURE, label, None)
|
@ -1,170 +0,0 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
|
||||
|
||||
/*Define a message ID*/
|
||||
#define MSG_LOGIN_ATTEMPT 1
|
||||
#define MSG_LOG_OUT 2
|
||||
#define MSG_LOGIN_ERROR 3
|
||||
#define MSG_LOGIN_OK 4
|
||||
|
||||
static void auth_manager(lv_msg_t * m);
|
||||
static void textarea_event_cb(lv_event_t * e);
|
||||
static void log_out_event_cb(lv_event_t * e);
|
||||
static void start_engine_msg_event_cb(lv_event_t * e);
|
||||
static void info_label_msg_event_cb(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Simple PIN login screen.
|
||||
* No global variables are used, all state changes are communicated via messages.
|
||||
*/
|
||||
void lv_example_msg_2(void)
|
||||
{
|
||||
lv_msg_subscribe(MSG_LOGIN_ATTEMPT, auth_manager, "hello");
|
||||
|
||||
/*Create a slider in the center of the display*/
|
||||
lv_obj_t * ta = lv_textarea_create(lv_scr_act());
|
||||
lv_obj_set_pos(ta, 10, 10);
|
||||
lv_obj_set_width(ta, 200);
|
||||
lv_textarea_set_one_line(ta, true);
|
||||
lv_textarea_set_password_mode(ta, true);
|
||||
lv_textarea_set_placeholder_text(ta, "The password is: hello");
|
||||
lv_obj_add_event(ta, textarea_event_cb, LV_EVENT_ALL, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_ERROR, ta, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, ta, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, ta, NULL);
|
||||
|
||||
lv_obj_t * kb = lv_keyboard_create(lv_scr_act());
|
||||
lv_keyboard_set_textarea(kb, ta);
|
||||
|
||||
lv_obj_t * btn;
|
||||
lv_obj_t * label;
|
||||
|
||||
/*Create a log out button which will be active only when logged in*/
|
||||
btn = lv_button_create(lv_scr_act());
|
||||
lv_obj_set_pos(btn, 240, 10);
|
||||
lv_obj_add_event(btn, log_out_event_cb, LV_EVENT_ALL, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, btn, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, btn, NULL);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "LOG OUT");
|
||||
|
||||
/*Create a label to show info*/
|
||||
label = lv_label_create(lv_scr_act());
|
||||
lv_label_set_text(label, "");
|
||||
lv_obj_add_event(label, info_label_msg_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_obj_set_pos(label, 10, 60);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_ERROR, label, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, label, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, label, NULL);
|
||||
|
||||
/*Create button which will be active only when logged in*/
|
||||
btn = lv_button_create(lv_scr_act());
|
||||
lv_obj_set_pos(btn, 10, 80);
|
||||
lv_obj_add_event(btn, start_engine_msg_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
|
||||
lv_msg_subscribe_obj(MSG_LOGIN_OK, btn, NULL);
|
||||
lv_msg_subscribe_obj(MSG_LOG_OUT, btn, NULL);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "START ENGINE");
|
||||
|
||||
lv_msg_send(MSG_LOG_OUT, NULL);
|
||||
}
|
||||
|
||||
static void auth_manager(lv_msg_t * m)
|
||||
{
|
||||
const char * pin_act = lv_msg_get_payload(m);
|
||||
const char * pin_expexted = lv_msg_get_user_data(m);
|
||||
if(strcmp(pin_act, pin_expexted) == 0) {
|
||||
lv_msg_send(MSG_LOGIN_OK, NULL);
|
||||
}
|
||||
else {
|
||||
lv_msg_send(MSG_LOGIN_ERROR, "Incorrect PIN");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void textarea_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if(code == LV_EVENT_READY) {
|
||||
lv_msg_send(MSG_LOGIN_ATTEMPT, lv_textarea_get_text(ta));
|
||||
}
|
||||
else if(code == LV_EVENT_MSG_RECEIVED) {
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
switch(lv_msg_get_id(m)) {
|
||||
case MSG_LOGIN_ERROR:
|
||||
/*If there was an error, clean the text area*/
|
||||
if(strlen(lv_msg_get_payload(m))) lv_textarea_set_text(ta, "");
|
||||
break;
|
||||
case MSG_LOGIN_OK:
|
||||
lv_obj_add_state(ta, LV_STATE_DISABLED);
|
||||
lv_obj_clear_state(ta, LV_STATE_FOCUSED | LV_STATE_FOCUS_KEY);
|
||||
break;
|
||||
case MSG_LOG_OUT:
|
||||
lv_textarea_set_text(ta, "");
|
||||
lv_obj_clear_state(ta, LV_STATE_DISABLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void log_out_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if(code == LV_EVENT_CLICKED) {
|
||||
lv_msg_send(MSG_LOG_OUT, NULL);
|
||||
}
|
||||
else if(code == LV_EVENT_MSG_RECEIVED) {
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
switch(lv_msg_get_id(m)) {
|
||||
case MSG_LOGIN_OK:
|
||||
lv_obj_clear_state(btn, LV_STATE_DISABLED);
|
||||
break;
|
||||
case MSG_LOG_OUT:
|
||||
lv_obj_add_state(btn, LV_STATE_DISABLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void start_engine_msg_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
switch(lv_msg_get_id(m)) {
|
||||
case MSG_LOGIN_OK:
|
||||
lv_obj_clear_state(btn, LV_STATE_DISABLED);
|
||||
break;
|
||||
case MSG_LOG_OUT:
|
||||
lv_obj_add_state(btn, LV_STATE_DISABLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void info_label_msg_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
switch(lv_msg_get_id(m)) {
|
||||
case MSG_LOGIN_ERROR:
|
||||
lv_label_set_text(label, lv_msg_get_payload(m));
|
||||
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_RED), 0);
|
||||
break;
|
||||
case MSG_LOGIN_OK:
|
||||
lv_label_set_text(label, "Login successful");
|
||||
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_GREEN), 0);
|
||||
break;
|
||||
case MSG_LOG_OUT:
|
||||
lv_label_set_text(label, "Logged out");
|
||||
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_GREY), 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,142 +0,0 @@
|
||||
from micropython import const
|
||||
|
||||
# Define a message ID
|
||||
MSG_LOGIN_ATTEMPT = const(1)
|
||||
MSG_LOG_OUT = const(2)
|
||||
MSG_LOGIN_ERROR = const(3)
|
||||
MSG_LOGIN_OK = const(4)
|
||||
|
||||
# Define the object that will be sent as msg payload
|
||||
class Message:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def message(self):
|
||||
return self.value
|
||||
|
||||
def auth_manager(m,passwd):
|
||||
payload = m.get_payload()
|
||||
pin_act = payload.__cast__().message()
|
||||
# print("pin act: ",pin_act,end="")
|
||||
# print(", pin axpected: ",passwd)
|
||||
pin_expected = passwd
|
||||
if pin_act == pin_expected:
|
||||
lv.msg_send(MSG_LOGIN_OK, None)
|
||||
else:
|
||||
lv.msg_send(MSG_LOGIN_ERROR, Message("Incorrect PIN"))
|
||||
|
||||
def textarea_event_cb(e):
|
||||
ta = e.get_target_obj()
|
||||
code = e.get_code()
|
||||
if code == lv.EVENT.READY:
|
||||
passwd = Message(ta.get_text())
|
||||
lv.msg_send(MSG_LOGIN_ATTEMPT, passwd)
|
||||
elif code == lv.EVENT.MSG_RECEIVED:
|
||||
m = e.get_msg()
|
||||
id = m.get_id()
|
||||
if id == MSG_LOGIN_ERROR:
|
||||
# If there was an error, clean the text area
|
||||
msg = m.get_payload().__cast__()
|
||||
if len(msg.message()):
|
||||
ta.set_text("")
|
||||
elif id == MSG_LOGIN_OK:
|
||||
ta.add_state(lv.STATE.DISABLED)
|
||||
ta.clear_state(lv.STATE.FOCUSED | lv.STATE.FOCUS_KEY)
|
||||
elif id == MSG_LOG_OUT:
|
||||
ta.set_text("");
|
||||
ta.clear_state(lv.STATE.DISABLED)
|
||||
|
||||
def log_out_event_cb(e):
|
||||
code = e.get_code()
|
||||
if code == lv.EVENT.CLICKED:
|
||||
lv.msg_send(MSG_LOG_OUT, None)
|
||||
elif code == lv.EVENT.MSG_RECEIVED:
|
||||
m = e.get_msg()
|
||||
button = e.get_target_obj()
|
||||
id = m.get_id()
|
||||
if id == MSG_LOGIN_OK:
|
||||
button.clear_state(lv.STATE.DISABLED)
|
||||
elif id == MSG_LOG_OUT:
|
||||
button.add_state(lv.STATE.DISABLED)
|
||||
|
||||
def start_engine_msg_event_cb(e):
|
||||
|
||||
m = e.get_msg()
|
||||
button = e.get_target_obj()
|
||||
id = m.get_id()
|
||||
if id == MSG_LOGIN_OK:
|
||||
button.clear_state(lv.STATE.DISABLED)
|
||||
elif id == MSG_LOG_OUT:
|
||||
button.add_state(lv.STATE.DISABLED)
|
||||
|
||||
|
||||
def info_label_msg_event_cb(e):
|
||||
label = e.get_target_obj()
|
||||
m = e.get_msg()
|
||||
id = m.get_id()
|
||||
if id == MSG_LOGIN_ERROR:
|
||||
payload = m.get_payload()
|
||||
label.set_text(payload.__cast__().message())
|
||||
label.set_style_text_color(lv.palette_main(lv.PALETTE.RED), 0)
|
||||
elif id == MSG_LOGIN_OK:
|
||||
label.set_text("Login successful")
|
||||
label.set_style_text_color(lv.palette_main(lv.PALETTE.GREEN), 0)
|
||||
elif id == MSG_LOG_OUT:
|
||||
label.set_text("Logged out")
|
||||
label.set_style_text_color(lv.palette_main(lv.PALETTE.GREY), 0)
|
||||
|
||||
def register_auth(msg_id,auth_msg):
|
||||
lv.msg_subscribe(MSG_LOGIN_ATTEMPT, lambda m: auth_msg(m,"hello"), None)
|
||||
#
|
||||
# Simple PIN login screen.
|
||||
# No global variables are used, all state changes are communicated via messages.
|
||||
|
||||
register_auth(MSG_LOGIN_ATTEMPT,auth_manager)
|
||||
# lv.msg_subscribe_obj(MSG_LOGIN_ATTEMPT, auth_manager, "Hello")
|
||||
|
||||
# Create a slider in the center of the display
|
||||
ta = lv.textarea(lv.scr_act())
|
||||
ta.set_pos(10, 10)
|
||||
ta.set_width(200)
|
||||
ta.set_one_line(True)
|
||||
ta.set_password_mode(True)
|
||||
ta.set_placeholder_text("The password is: hello")
|
||||
ta.add_event(textarea_event_cb, lv.EVENT.ALL, None)
|
||||
lv.msg_subscribe_obj(MSG_LOGIN_ERROR, ta, None)
|
||||
lv.msg_subscribe_obj(MSG_LOGIN_OK, ta, None)
|
||||
lv.msg_subscribe_obj(MSG_LOG_OUT, ta, None)
|
||||
|
||||
kb = lv.keyboard(lv.scr_act())
|
||||
kb.set_textarea(ta)
|
||||
|
||||
# Create a log out button which will be active only when logged in
|
||||
button = lv.button(lv.scr_act())
|
||||
button.set_pos(240, 10)
|
||||
button.add_event(log_out_event_cb, lv.EVENT.ALL, None)
|
||||
lv.msg_subscribe_obj(MSG_LOGIN_OK, button, None)
|
||||
lv.msg_subscribe_obj(MSG_LOG_OUT, button, None)
|
||||
|
||||
label = lv.label(button);
|
||||
label.set_text("LOG OUT")
|
||||
|
||||
# Create a label to show info
|
||||
label = lv.label(lv.scr_act());
|
||||
label.set_text("")
|
||||
label.add_event(info_label_msg_event_cb, lv.EVENT.MSG_RECEIVED, None)
|
||||
label.set_pos(10, 60)
|
||||
lv.msg_subscribe_obj(MSG_LOGIN_ERROR, label, None)
|
||||
lv.msg_subscribe_obj(MSG_LOGIN_OK, label, None)
|
||||
lv.msg_subscribe_obj(MSG_LOG_OUT, label, None)
|
||||
|
||||
#Create button which will be active only when logged in
|
||||
button = lv.button(lv.scr_act())
|
||||
button.set_pos(10, 80)
|
||||
button.add_event(start_engine_msg_event_cb, lv.EVENT.MSG_RECEIVED, None)
|
||||
button.add_flag(lv.obj.FLAG.CHECKABLE)
|
||||
lv.msg_subscribe_obj(MSG_LOGIN_OK, button, None)
|
||||
lv.msg_subscribe_obj(MSG_LOG_OUT, button, None)
|
||||
|
||||
label = lv.label(button)
|
||||
label.set_text("START ENGINE")
|
||||
|
||||
lv.msg_send(MSG_LOG_OUT, None)
|
||||
|
@ -1,112 +0,0 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
|
||||
|
||||
static int32_t limit_value(int32_t v);
|
||||
static void btn_event_cb(lv_event_t * e);
|
||||
static void label_event_cb(lv_event_t * e);
|
||||
static void slider_event_cb(lv_event_t * e);
|
||||
|
||||
static int32_t power_value;
|
||||
|
||||
/**
|
||||
* Show how an increment button, a decrement button, as slider can set a value
|
||||
* and a label display it.
|
||||
* The current value (i.e. the system's state) is stored only in one static variable in a function
|
||||
* and no global variables are required.
|
||||
*/
|
||||
void lv_example_msg_3(void)
|
||||
{
|
||||
|
||||
lv_obj_t * panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_size(panel, 250, LV_SIZE_CONTENT);
|
||||
lv_obj_center(panel);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(panel, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START);
|
||||
|
||||
lv_obj_t * btn;
|
||||
lv_obj_t * label;
|
||||
|
||||
/*Up button*/
|
||||
btn = lv_button_create(panel);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_add_event(btn, btn_event_cb, LV_EVENT_ALL, NULL);
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_LEFT);
|
||||
lv_obj_center(label);
|
||||
|
||||
/*Current value*/
|
||||
label = lv_label_create(panel);
|
||||
lv_obj_set_flex_grow(label, 2);
|
||||
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_label_set_text(label, "?");
|
||||
lv_msg_subscribe_obj((lv_msg_id_t)&power_value, label, NULL);
|
||||
lv_obj_add_event(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
|
||||
/*Down button*/
|
||||
btn = lv_button_create(panel);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_add_event(btn, btn_event_cb, LV_EVENT_ALL, NULL);
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_RIGHT);
|
||||
lv_obj_center(label);
|
||||
|
||||
/*Slider*/
|
||||
lv_obj_t * slider = lv_slider_create(panel);
|
||||
lv_obj_set_flex_grow(slider, 1);
|
||||
lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
|
||||
lv_msg_subscribe_obj((lv_msg_id_t)&power_value, slider, NULL);
|
||||
lv_obj_add_event(slider, slider_event_cb, LV_EVENT_ALL, NULL);
|
||||
|
||||
power_value = 30;
|
||||
lv_msg_update_value(&power_value);
|
||||
}
|
||||
|
||||
static int32_t limit_value(int32_t v)
|
||||
{
|
||||
return LV_CLAMP(30, v, 80);
|
||||
}
|
||||
|
||||
|
||||
static void btn_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if(code == LV_EVENT_CLICKED || code == LV_EVENT_LONG_PRESSED_REPEAT) {
|
||||
if(lv_obj_get_index(btn) == 0) { /*First object is the dec. button*/
|
||||
power_value = limit_value(power_value - 1);
|
||||
lv_msg_update_value(&power_value);
|
||||
}
|
||||
else {
|
||||
power_value = limit_value(power_value + 1);
|
||||
lv_msg_update_value(&power_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void label_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if(code == LV_EVENT_MSG_RECEIVED) {
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
const int32_t * v = lv_msg_get_payload(m);
|
||||
lv_label_set_text_fmt(label, "%"LV_PRId32" %%", *v);
|
||||
}
|
||||
}
|
||||
|
||||
static void slider_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * slider = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if(code == LV_EVENT_VALUE_CHANGED) {
|
||||
power_value = limit_value(lv_slider_get_value(slider));
|
||||
lv_msg_update_value(&power_value);
|
||||
}
|
||||
else if(code == LV_EVENT_MSG_RECEIVED) {
|
||||
lv_msg_t * m = lv_event_get_msg(e);
|
||||
const int32_t * v = lv_msg_get_payload(m);
|
||||
lv_slider_set_value(slider, *v, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,122 +0,0 @@
|
||||
# Define a message ID
|
||||
MSG_INC = 1
|
||||
MSG_DEC = 2
|
||||
MSG_SET = 3
|
||||
MSG_UPDATE = 4
|
||||
MSG_UPDATE_REQUEST = 5
|
||||
|
||||
# Define the object that will be sent as msg payload
|
||||
class NewValue:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __repr__(self):
|
||||
return f"{self.value} %"
|
||||
class LV_Example_Msg_2:
|
||||
|
||||
def __init__(self):
|
||||
self.value = 10
|
||||
lv.msg_subscribe(MSG_INC, self.value_handler, None)
|
||||
lv.msg_subscribe(MSG_DEC, self.value_handler, None)
|
||||
lv.msg_subscribe(MSG_SET, self.value_handler, None)
|
||||
lv.msg_subscribe(MSG_UPDATE, self.value_handler, None)
|
||||
lv.msg_subscribe(MSG_UPDATE_REQUEST, self.value_handler, None)
|
||||
|
||||
panel = lv.obj(lv.scr_act())
|
||||
panel.set_size(250, lv.SIZE_CONTENT)
|
||||
panel.center()
|
||||
panel.set_flex_flow(lv.FLEX_FLOW.ROW)
|
||||
panel.set_flex_align(lv.FLEX_ALIGN.SPACE_BETWEEN, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START)
|
||||
|
||||
# Up button
|
||||
button = lv.button(panel)
|
||||
button.set_flex_grow(1)
|
||||
button.add_event(self.button_event_cb, lv.EVENT.ALL, None)
|
||||
label = lv.label(button)
|
||||
label.set_text(lv.SYMBOL.LEFT)
|
||||
label.center()
|
||||
|
||||
# Current value
|
||||
label = lv.label(panel)
|
||||
label.set_flex_grow(2)
|
||||
label.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0)
|
||||
label.set_text("?")
|
||||
lv.msg_subscribe_obj(MSG_UPDATE, label, None)
|
||||
label.add_event(self.label_event_cb, lv.EVENT.MSG_RECEIVED, None)
|
||||
|
||||
# Down button
|
||||
button = lv.button(panel)
|
||||
button.set_flex_grow(1)
|
||||
button.add_event(self.button_event_cb, lv.EVENT.ALL, None)
|
||||
label = lv.label(button)
|
||||
label.set_text(lv.SYMBOL.RIGHT)
|
||||
label.center()
|
||||
|
||||
# Slider
|
||||
slider = lv.slider(panel)
|
||||
slider.set_flex_grow(1)
|
||||
slider.add_flag(lv.obj.FLAG.FLEX_IN_NEW_TRACK)
|
||||
slider.add_event(self.slider_event_cb, lv.EVENT.ALL, None)
|
||||
lv.msg_subscribe_obj(MSG_UPDATE, slider, None)
|
||||
|
||||
|
||||
# As there are new UI elements that don't know the system's state
|
||||
# send an UPDATE REQUEST message which will trigger an UPDATE message with the current value
|
||||
lv.msg_send(MSG_UPDATE_REQUEST, None)
|
||||
|
||||
def value_handler(self,m):
|
||||
old_value = self.value
|
||||
id = m.get_id()
|
||||
if id == MSG_INC:
|
||||
if self.value < 100:
|
||||
self.value +=1
|
||||
elif id == MSG_DEC:
|
||||
if self.value > 0:
|
||||
self.value -=1
|
||||
elif id == MSG_SET:
|
||||
payload = m.get_payload()
|
||||
new_value=payload.__cast__()
|
||||
self.value = new_value.value
|
||||
# print("value_handler: new value: {:d}".format(new_value.value))
|
||||
elif id == MSG_UPDATE_REQUEST:
|
||||
lv.msg_send(MSG_UPDATE, NewValue(self.value))
|
||||
|
||||
if self.value != old_value:
|
||||
lv.msg_send(MSG_UPDATE, NewValue(self.value));
|
||||
|
||||
def button_event_cb(self,e):
|
||||
button = e.get_target_obj()
|
||||
code = e.get_code()
|
||||
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
|
||||
if button.get_index() == 0: # rst object is the dec. button
|
||||
lv.msg_send(MSG_DEC, None)
|
||||
else :
|
||||
lv.msg_send(MSG_INC, None)
|
||||
|
||||
def label_event_cb(self,e):
|
||||
label = e.get_target_obj()
|
||||
code = e.get_code()
|
||||
if code == lv.EVENT.MSG_RECEIVED:
|
||||
m = e.get_msg()
|
||||
if m.get_id() == MSG_UPDATE:
|
||||
payload = m.get_payload()
|
||||
value=payload.__cast__()
|
||||
# print("label_event_cb: " + str(value))
|
||||
label.set_text(str(value))
|
||||
|
||||
def slider_event_cb(self,e):
|
||||
slider = e.get_target_obj()
|
||||
code = e.get_code()
|
||||
if code == lv.EVENT.VALUE_CHANGED:
|
||||
v = slider.get_value()
|
||||
# print("slider_event_cb: {:d}".format(v))
|
||||
lv.msg_send(MSG_SET, NewValue(v))
|
||||
|
||||
elif code == lv.EVENT.MSG_RECEIVED:
|
||||
m = e.get_msg()
|
||||
if m.get_id() == MSG_UPDATE:
|
||||
v = m.get_payload()
|
||||
value = v.__cast__()
|
||||
slider.set_value(value.value, lv.ANIM.OFF)
|
||||
|
||||
lv_example_msg_2 = LV_Example_Msg_2()
|
||||
|
1
lvgl.h
1
lvgl.h
@ -85,7 +85,6 @@ extern "C" {
|
||||
#include "src/others/gridnav/lv_gridnav.h"
|
||||
#include "src/others/fragment/lv_fragment.h"
|
||||
#include "src/others/imgfont/lv_imgfont.h"
|
||||
#include "src/others/msg/lv_msg.h"
|
||||
#include "src/others/observer/lv_observer.h"
|
||||
#include "src/others/ime/lv_ime_pinyin.h"
|
||||
#include "src/others/file_explorer/lv_file_explorer.h"
|
||||
|
@ -207,10 +207,6 @@ void lv_init(void)
|
||||
LV_LOG_WARN("Log level is set to 'Trace' which makes LVGL much slower");
|
||||
#endif
|
||||
|
||||
#if LV_USE_MSG
|
||||
lv_msg_init();
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_FATFS != '\0'
|
||||
lv_fs_fatfs_init();
|
||||
#endif
|
||||
|
@ -1,229 +0,0 @@
|
||||
/**
|
||||
* @file lv_msg.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_msg.h"
|
||||
#if LV_USE_MSG
|
||||
|
||||
#include "../../core/lv_global.h"
|
||||
#include "../../misc/lv_assert.h"
|
||||
#include "../../misc/lv_ll.h"
|
||||
#include "../../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define restart_notify LV_GLOBAL_DEFAULT()->msg_restart_notify
|
||||
#define _recursion_counter LV_GLOBAL_DEFAULT()->msg_recursion_counter
|
||||
#define _msg_subs_ll_p &(LV_GLOBAL_DEFAULT()->msg_subs_ll)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_msg_id_t msg_id;
|
||||
lv_msg_subscribe_cb_t callback;
|
||||
void * user_data;
|
||||
void * _priv_data; /*Internal: used only store 'obj' in lv_obj_subscribe*/
|
||||
uint8_t _checked : 1; /*Internal: used to prevent multiple notifications*/
|
||||
} sub_dsc_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void notify(lv_msg_t * m);
|
||||
static void obj_notify_cb(lv_msg_t * m);
|
||||
static void obj_delete_event_cb(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#if LV_USE_LOG && LV_LOG_TRACE_MSG
|
||||
#define LV_TRACE_MSG(...) LV_LOG_TRACE(__VA_ARGS__)
|
||||
#else
|
||||
#define LV_TRACE_MSG(...)
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_msg_init(void)
|
||||
{
|
||||
_lv_ll_init(_msg_subs_ll_p, sizeof(sub_dsc_t));
|
||||
}
|
||||
|
||||
void * lv_msg_subscribe(lv_msg_id_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data)
|
||||
{
|
||||
sub_dsc_t * s = _lv_ll_ins_tail(_msg_subs_ll_p);
|
||||
LV_ASSERT_MALLOC(s);
|
||||
if(s == NULL) return NULL;
|
||||
|
||||
lv_memzero(s, sizeof(*s));
|
||||
|
||||
s->msg_id = msg_id;
|
||||
s->callback = cb;
|
||||
s->user_data = user_data;
|
||||
s->_checked = 0; /*if subsribed during `notify`, it should be notified immediately*/
|
||||
restart_notify = true;
|
||||
return s;
|
||||
}
|
||||
|
||||
void * lv_msg_subscribe_obj(lv_msg_id_t msg_id, lv_obj_t * obj, void * user_data)
|
||||
{
|
||||
sub_dsc_t * s = lv_msg_subscribe(msg_id, obj_notify_cb, user_data);
|
||||
if(s == NULL) return NULL;
|
||||
s->_priv_data = obj;
|
||||
|
||||
/*If not added yet, add a delete_event_cb which automatically unsubcribes the object when its deleted*/
|
||||
uint32_t i;
|
||||
uint32_t event_cnt = lv_obj_get_event_count(obj);
|
||||
sub_dsc_t * s_first = NULL;
|
||||
for(i = 0; i < event_cnt; i++) {
|
||||
lv_event_dsc_t * event_dsc = lv_obj_get_event_dsc(obj, i);
|
||||
if(lv_event_dsc_get_cb(event_dsc) == obj_delete_event_cb) {
|
||||
s_first = lv_event_dsc_get_user_data(event_dsc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(s_first == NULL) {
|
||||
lv_obj_add_event(obj, obj_delete_event_cb, LV_EVENT_DELETE, s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void lv_msg_unsubscribe(void * s)
|
||||
{
|
||||
LV_ASSERT_NULL(s);
|
||||
_lv_ll_remove(_msg_subs_ll_p, s);
|
||||
restart_notify = true;
|
||||
lv_free(s);
|
||||
}
|
||||
|
||||
void lv_msg_send(lv_msg_id_t msg_id, const void * payload)
|
||||
{
|
||||
lv_msg_t m;
|
||||
lv_memzero(&m, sizeof(m));
|
||||
m.id = msg_id;
|
||||
m.payload = payload;
|
||||
notify(&m);
|
||||
}
|
||||
|
||||
void lv_msg_update_value(void * v)
|
||||
{
|
||||
lv_msg_send((lv_msg_id_t)v, v);
|
||||
}
|
||||
|
||||
lv_msg_id_t lv_msg_get_id(lv_msg_t * m)
|
||||
{
|
||||
return m->id;
|
||||
}
|
||||
|
||||
const void * lv_msg_get_payload(lv_msg_t * m)
|
||||
{
|
||||
return m->payload;
|
||||
}
|
||||
|
||||
void * lv_msg_get_user_data(lv_msg_t * m)
|
||||
{
|
||||
return m->user_data;
|
||||
}
|
||||
|
||||
lv_msg_t * lv_event_get_msg(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_MSG_RECEIVED) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void notify(lv_msg_t * m)
|
||||
{
|
||||
_recursion_counter++;
|
||||
|
||||
/*First clear all _checked flags*/
|
||||
sub_dsc_t * s;
|
||||
if(_recursion_counter == 1) {
|
||||
_LV_LL_READ(_msg_subs_ll_p, s) {
|
||||
s->_checked = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*Run all sub_dsc_t from the list*/
|
||||
do {
|
||||
restart_notify = false;
|
||||
s = _lv_ll_get_head(_msg_subs_ll_p);
|
||||
while(s) {
|
||||
/*get next element while current is surely valid*/
|
||||
sub_dsc_t * next = _lv_ll_get_next(_msg_subs_ll_p, s);
|
||||
|
||||
/*Notify only once*/
|
||||
if(!s->_checked) {
|
||||
/*Check if this sub_dsc_t is about this msg_id*/
|
||||
if(s->msg_id == m->id && s->callback) {
|
||||
/* Set this flag and notify*/
|
||||
s->_checked = 1;
|
||||
m->user_data = s->user_data;
|
||||
m->_priv_data = s->_priv_data;
|
||||
s->callback(m);
|
||||
}
|
||||
}
|
||||
|
||||
/*restart or load next*/
|
||||
if(restart_notify) {
|
||||
LV_TRACE_MSG("Start from the first sub_dsc_t again because _subs_ll may have changed");
|
||||
break;
|
||||
}
|
||||
s = next;
|
||||
}
|
||||
} while(s);
|
||||
|
||||
_recursion_counter--;
|
||||
restart_notify = (_recursion_counter > 0);
|
||||
}
|
||||
|
||||
static void obj_notify_cb(lv_msg_t * m)
|
||||
{
|
||||
lv_obj_send_event(m->_priv_data, LV_EVENT_MSG_RECEIVED, m);
|
||||
}
|
||||
|
||||
static void obj_delete_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
|
||||
sub_dsc_t * s = _lv_ll_get_head(_msg_subs_ll_p);
|
||||
sub_dsc_t * s_next;
|
||||
while(s) {
|
||||
/*On unsubscribe the list changes s becomes invalid so get next item while it's surely valid*/
|
||||
s_next = _lv_ll_get_next(_msg_subs_ll_p, s);
|
||||
if(s->_priv_data == obj) {
|
||||
lv_msg_unsubscribe(s);
|
||||
}
|
||||
s = s_next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_USE_MSG*/
|
@ -1,133 +0,0 @@
|
||||
/**
|
||||
* @file lv_msg.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_MSG_H
|
||||
#define LV_MSG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../core/lv_obj.h"
|
||||
#if LV_USE_MSG
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef lv_uintptr_t lv_msg_id_t;
|
||||
|
||||
typedef struct {
|
||||
lv_msg_id_t id; /*Identifier of the message*/
|
||||
void * user_data; /*Set the the user_data set in `lv_msg_subscribe`*/
|
||||
void * _priv_data; /*Used internally*/
|
||||
const void * payload; /*Pointer to the data of the message*/
|
||||
} lv_msg_t;
|
||||
|
||||
|
||||
typedef void (*lv_msg_subscribe_cb_t)(lv_msg_t * msg);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Called internally to initialize the message module
|
||||
*/
|
||||
void lv_msg_init(void);
|
||||
|
||||
/**
|
||||
* Subscribe to an `msg_id`
|
||||
* @param msg_id the message ID to listen to
|
||||
* @param cb callback to call if a message with `msg_id` was sent
|
||||
* @param user_data arbitrary data which will be available in `cb` too
|
||||
* @return pointer to a "subscribe object". It can be used the unsubscribe.
|
||||
*/
|
||||
void * lv_msg_subscribe(lv_msg_id_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Subscribe an `lv_obj` to a message.
|
||||
* `LV_EVENT_MSG_RECEIVED` will be triggered if a message with matching ID was sent
|
||||
* @param msg_id the message ID to listen to
|
||||
* @param obj pointer to an `lv_obj`
|
||||
* @param user_data arbitrary data which will be available in `cb` too
|
||||
* @return pointer to a "subscribe object". It can be used the unsubscribe.
|
||||
*/
|
||||
void * lv_msg_subscribe_obj(lv_msg_id_t msg_id, lv_obj_t * obj, void * user_data);
|
||||
|
||||
/**
|
||||
* Cancel a previous subscription
|
||||
* @param s pointer to a "subscribe object".
|
||||
* Return value of `lv_msg_subscribe` or `lv_msg_subscribe_obj`
|
||||
*/
|
||||
void lv_msg_unsubscribe(void * s);
|
||||
|
||||
/**
|
||||
* Send a message with a given ID and payload
|
||||
* @param msg_id ID of the message to send
|
||||
* @param payload pointer to the data to send
|
||||
*/
|
||||
void lv_msg_send(lv_msg_id_t msg_id, const void * payload);
|
||||
|
||||
/**
|
||||
* Send a message where the message ID is `v` (the value of the pointer)
|
||||
* and the payload is `v`.
|
||||
* It can be used to send unique messages when a variable changed.
|
||||
* @param v pointer to a variable.
|
||||
* @note to subscribe to a variable use `lv_msg_subscribe((lv_msg_id_t)v, msg_cb, user_data)`
|
||||
* or `lv_msg_subscribe_obj((lv_msg_id_t)v, obj, user_data)`
|
||||
*/
|
||||
void lv_msg_update_value(void * v);
|
||||
|
||||
/**
|
||||
* Get the ID of a message object. Typically used in the subscriber callback.
|
||||
* @param m pointer to a message object
|
||||
* @return the ID of the message
|
||||
*/
|
||||
lv_msg_id_t lv_msg_get_id(lv_msg_t * m);
|
||||
|
||||
/**
|
||||
* Get the payload of a message object. Typically used in the subscriber callback.
|
||||
* @param m pointer to a message object
|
||||
* @return the payload of the message
|
||||
*/
|
||||
const void * lv_msg_get_payload(lv_msg_t * m);
|
||||
|
||||
/**
|
||||
* Get the user data of a message object. Typically used in the subscriber callback.
|
||||
* @param m pointer to a message object
|
||||
* @return the user data of the message
|
||||
*/
|
||||
void * lv_msg_get_user_data(lv_msg_t * m);
|
||||
|
||||
/**
|
||||
* Get the message object from an event object. Can be used in `LV_EVENT_MSG_RECEIVED` events.
|
||||
* @param e pointer to an event object
|
||||
* @return the message object or NULL if called with unrelated event code.
|
||||
*/
|
||||
lv_msg_t * lv_event_get_msg(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_MSG*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_MSG_H*/
|
@ -1,55 +0,0 @@
|
||||
#if LV_BUILD_TEST
|
||||
#include "../lvgl.h"
|
||||
|
||||
#include "unity/unity.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
/* Function run before every test */
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
/* Function run after every test */
|
||||
}
|
||||
|
||||
|
||||
static uint32_t value_received;
|
||||
|
||||
static void msg_cb(lv_msg_t * msg)
|
||||
{
|
||||
const uint32_t * v = lv_msg_get_payload(msg);
|
||||
value_received = *v;
|
||||
}
|
||||
static void event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_msg_t * msg = lv_event_get_msg(e);
|
||||
const uint32_t * v = lv_msg_get_payload(msg);
|
||||
lv_label_set_text_fmt(lv_event_get_target(e), "%d", *v);
|
||||
}
|
||||
|
||||
void test_add_entry_and_send_msg(void)
|
||||
{
|
||||
static uint32_t value = 100;
|
||||
lv_msg_subscribe((lv_msg_id_t)&value, msg_cb, NULL);
|
||||
|
||||
value_received = 0;
|
||||
value = 100;
|
||||
lv_msg_update_value(&value);
|
||||
TEST_ASSERT_EQUAL_UINT32(100, value_received);
|
||||
|
||||
value = 200;
|
||||
lv_msg_update_value(&value);
|
||||
TEST_ASSERT_EQUAL_UINT32(200, value_received);
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_scr_act());
|
||||
lv_msg_subscribe_obj((lv_msg_id_t)&value, label, NULL);
|
||||
lv_obj_add_event(label, event_cb, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
|
||||
value = 300;
|
||||
lv_msg_update_value(&value);
|
||||
TEST_ASSERT_EQUAL_STRING("300", lv_label_get_text(label));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user