LVGL port `colorwheel` from LVGL 8, HASPmota `cpicker` and `msgbox` (#22244)

This commit is contained in:
s-hadinger 2024-10-06 18:53:06 +02:00 committed by GitHub
parent ba687deaf5
commit d9f246f0f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 3469 additions and 1155 deletions

View File

@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
## [14.2.0.6] ## [14.2.0.6]
### Added ### Added
- Support for Sonoff SPM v1.3.0 (#13447) - Support for Sonoff SPM v1.3.0 (#13447)
- LVGL port `colorwheel` from LVGL 8
- HASPmota `cpicker` and `msgbox`
### Breaking Changed ### Breaking Changed

View File

@ -187,7 +187,7 @@ typedef struct {
#endif #endif
#if LV_USE_MSGBOX #if LV_USE_MSGBOX
lv_style_t msgbox_bg, msgbox_btn_bg; lv_style_t msgbox_bg, msgbox_btn_bg, msgbox_backdrop_bg;
#endif #endif
#if LV_USE_KEYBOARD #if LV_USE_KEYBOARD
@ -576,6 +576,10 @@ static void style_init(void)
style_init_reset(&styles->msgbox_bg); style_init_reset(&styles->msgbox_bg);
lv_style_set_max_width(&styles->msgbox_bg, lv_pct(100)); lv_style_set_max_width(&styles->msgbox_bg, lv_pct(100));
style_init_reset(&styles->msgbox_backdrop_bg);
lv_style_set_bg_color(&styles->msgbox_backdrop_bg, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_bg_opa(&styles->msgbox_backdrop_bg, LV_OPA_50);
#endif #endif
#if LV_USE_KEYBOARD #if LV_USE_KEYBOARD
style_init_reset(&styles->keyboard_btn_bg); style_init_reset(&styles->keyboard_btn_bg);
@ -738,19 +742,6 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
#if LV_USE_BUTTONMATRIX #if LV_USE_BUTTONMATRIX
else if(lv_obj_check_type(obj, &lv_buttonmatrix_class)) { else if(lv_obj_check_type(obj, &lv_buttonmatrix_class)) {
#if LV_USE_MSGBOX
if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_msgbox_class)) {
lv_obj_add_style(obj, &styles->msgbox_btn_bg, 0);
lv_obj_add_style(obj, &styles->pad_gap, 0);
lv_obj_add_style(obj, &styles->btn, LV_PART_ITEMS);
lv_obj_add_style(obj, &styles->pressed, LV_PART_ITEMS | LV_STATE_PRESSED);
lv_obj_add_style(obj, &styles->disabled, LV_PART_ITEMS | LV_STATE_DISABLED);
lv_obj_add_style(obj, &styles->bg_color_primary, LV_PART_ITEMS | LV_STATE_CHECKED);
lv_obj_add_style(obj, &styles->bg_color_primary_muted, LV_PART_ITEMS | LV_STATE_FOCUS_KEY);
lv_obj_add_style(obj, &styles->bg_color_secondary_muted, LV_PART_ITEMS | LV_STATE_EDITED);
return;
}
#endif
#if LV_USE_TABVIEW #if LV_USE_TABVIEW
if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_tabview_class)) { if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_tabview_class)) {
lv_obj_add_style(obj, &styles->bg_color_white, 0); lv_obj_add_style(obj, &styles->bg_color_white, 0);
@ -1012,7 +1003,39 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
#if LV_USE_MSGBOX #if LV_USE_MSGBOX
else if(lv_obj_check_type(obj, &lv_msgbox_class)) { else if(lv_obj_check_type(obj, &lv_msgbox_class)) {
lv_obj_add_style(obj, &styles->card, 0); lv_obj_add_style(obj, &styles->card, 0);
lv_obj_add_style(obj, &styles->msgbox_bg, 0); lv_obj_add_style(obj, &styles->pad_zero, 0);
lv_obj_add_style(obj, &styles->clip_corner, 0);
return;
}
else if(lv_obj_check_type(obj, &lv_msgbox_backdrop_class)) {
lv_obj_add_style(obj, &styles->msgbox_backdrop_bg, 0);
return;
}
else if(lv_obj_check_type(obj, &lv_msgbox_header_class)) {
lv_obj_add_style(obj, &styles->pad_tiny, 0);
lv_obj_add_style(obj, &styles->bg_color_grey, 0);
return;
}
else if(lv_obj_check_type(obj, &lv_msgbox_footer_class)) {
lv_obj_add_style(obj, &styles->pad_tiny, 0);
return;
}
else if(lv_obj_check_type(obj, &lv_msgbox_content_class)) {
lv_obj_add_style(obj, &styles->scrollbar, LV_PART_SCROLLBAR);
lv_obj_add_style(obj, &styles->scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED);
lv_obj_add_style(obj, &styles->pad_tiny, 0);
return;
}
else if(lv_obj_check_type(obj, &lv_msgbox_header_button_class) ||
lv_obj_check_type(obj, &lv_msgbox_footer_button_class)) {
lv_obj_add_style(obj, &styles->btn, 0);
lv_obj_add_style(obj, &styles->bg_color_primary, 0);
lv_obj_add_style(obj, &styles->transition_delayed, 0);
lv_obj_add_style(obj, &styles->pressed, LV_STATE_PRESSED);
lv_obj_add_style(obj, &styles->transition_normal, LV_STATE_PRESSED);
lv_obj_add_style(obj, &styles->outline_primary, LV_STATE_FOCUS_KEY);
lv_obj_add_style(obj, &styles->bg_color_secondary, LV_STATE_CHECKED);
lv_obj_add_style(obj, &styles->disabled, LV_STATE_DISABLED);
return; return;
} }
#endif #endif

View File

@ -1570,3 +1570,16 @@ set_light_color|lv.color||[lv_qrcode_set_light_color](https://docs.lvgl.io/9.0/s
set_size|int||[lv_qrcode_set_size](https://docs.lvgl.io/9.0/search.html?q=lv_qrcode_set_size) set_size|int||[lv_qrcode_set_size](https://docs.lvgl.io/9.0/search.html?q=lv_qrcode_set_size)
update|\<any\>, int|int|[lv_qrcode_update](https://docs.lvgl.io/9.0/search.html?q=lv_qrcode_update) update|\<any\>, int|int|[lv_qrcode_update](https://docs.lvgl.io/9.0/search.html?q=lv_qrcode_update)
### widget `lv.colorwheel`
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
get_color_mode||int|[lv_colorwheel_get_color_mode](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_get_color_mode)
get_color_mode_fixed||bool|[lv_colorwheel_get_color_mode_fixed](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_get_color_mode_fixed)
get_hsv||int|[lv_colorwheel_get_hsv](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_get_hsv)
get_rgb||lv.color|[lv_colorwheel_get_rgb](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_get_rgb)
set_hsv|int|bool|[lv_colorwheel_set_hsv](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_set_hsv)
set_mode|int||[lv_colorwheel_set_mode](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_set_mode)
set_mode_fixed|bool||[lv_colorwheel_set_mode_fixed](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_set_mode_fixed)
set_rgb|lv.color|bool|[lv_colorwheel_set_rgb](https://docs.lvgl.io/9.0/search.html?q=lv_colorwheel_set_rgb)

View File

@ -9,6 +9,7 @@ extern "C" {
#include "be_ctypes.h" #include "be_ctypes.h"
#include "be_mapping.h" #include "be_mapping.h"
#include "../src/lv_colorwheel.h"
/* `lv_style` methods */ /* `lv_style` methods */
const be_ntv_func_def_t lv_style_func[] = { const be_ntv_func_def_t lv_style_func[] = {
@ -1422,6 +1423,20 @@ const be_ntv_func_def_t lv_tileview_func[] = {
}; };
#endif // BE_LV_WIDGET_TILEVIEW #endif // BE_LV_WIDGET_TILEVIEW
/* `lv_colorwheel` methods */
#ifdef BE_LV_WIDGET_COLORWHEEL
const be_ntv_func_def_t lv_colorwheel_func[] = {
{ "get_color_mode", { (const void*) &lv_colorwheel_get_color_mode, "i", "(lv.obj)" } },
{ "get_color_mode_fixed", { (const void*) &lv_colorwheel_get_color_mode_fixed, "b", "(lv.obj)" } },
{ "get_hsv", { (const void*) &lv_colorwheel_get_hsv, "i", "(lv.obj)" } },
{ "get_rgb", { (const void*) &lv_colorwheel_get_rgb, "lv.color", "(lv.obj)" } },
{ "set_hsv", { (const void*) &lv_colorwheel_set_hsv, "b", "(lv.obj)i" } },
{ "set_mode", { (const void*) &lv_colorwheel_set_mode, "", "(lv.obj)i" } },
{ "set_mode_fixed", { (const void*) &lv_colorwheel_set_mode_fixed, "", "(lv.obj)b" } },
{ "set_rgb", { (const void*) &lv_colorwheel_set_rgb, "b", "(lv.obj)(lv.color)" } },
};
#endif // BE_LV_WIDGET_COLORWHEEL
extern const bclass be_class_lv_anim; extern const bclass be_class_lv_anim;
extern const bclass be_class_lv_animimg; extern const bclass be_class_lv_animimg;
extern const bclass be_class_lv_arc; extern const bclass be_class_lv_arc;
@ -1433,6 +1448,7 @@ extern const bclass be_class_lv_canvas;
extern const bclass be_class_lv_chart; extern const bclass be_class_lv_chart;
extern const bclass be_class_lv_checkbox; extern const bclass be_class_lv_checkbox;
extern const bclass be_class_lv_color; extern const bclass be_class_lv_color;
extern const bclass be_class_lv_colorwheel;
extern const bclass be_class_lv_display; extern const bclass be_class_lv_display;
extern const bclass be_class_lv_dropdown; extern const bclass be_class_lv_dropdown;
extern const bclass be_class_lv_event; extern const bclass be_class_lv_event;
@ -1503,6 +1519,9 @@ const be_ntv_class_def_t lv_classes[] = {
{ "lv_checkbox", &be_class_lv_checkbox, lv_checkbox_func, sizeof(lv_checkbox_func) / sizeof(lv_checkbox_func[0]) }, { "lv_checkbox", &be_class_lv_checkbox, lv_checkbox_func, sizeof(lv_checkbox_func) / sizeof(lv_checkbox_func[0]) },
#endif // BE_LV_WIDGET_CHECKBOX #endif // BE_LV_WIDGET_CHECKBOX
{ "lv_color", &be_class_lv_color, lv_color_func, sizeof(lv_color_func) / sizeof(lv_color_func[0]) }, { "lv_color", &be_class_lv_color, lv_color_func, sizeof(lv_color_func) / sizeof(lv_color_func[0]) },
#ifdef BE_LV_WIDGET_COLORWHEEL
{ "lv_colorwheel", &be_class_lv_colorwheel, lv_colorwheel_func, sizeof(lv_colorwheel_func) / sizeof(lv_colorwheel_func[0]) },
#endif // BE_LV_WIDGET_COLORWHEEL
{ "lv_display", &be_class_lv_display, lv_display_func, sizeof(lv_display_func) / sizeof(lv_display_func[0]) }, { "lv_display", &be_class_lv_display, lv_display_func, sizeof(lv_display_func) / sizeof(lv_display_func[0]) },
#ifdef BE_LV_WIDGET_DROPDOWN #ifdef BE_LV_WIDGET_DROPDOWN
{ "lv_dropdown", &be_class_lv_dropdown, lv_dropdown_func, sizeof(lv_dropdown_func) / sizeof(lv_dropdown_func[0]) }, { "lv_dropdown", &be_class_lv_dropdown, lv_dropdown_func, sizeof(lv_dropdown_func) / sizeof(lv_dropdown_func[0]) },
@ -1770,6 +1789,10 @@ const size_t lv_classes_size = sizeof(lv_classes) / sizeof(lv_classes[0]);
#ifdef BE_LV_WIDGET_TILEVIEW #ifdef BE_LV_WIDGET_TILEVIEW
int be_ntv_lv_tileview_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_tileview_create, "+_p", "(lv.obj)"); } int be_ntv_lv_tileview_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_tileview_create, "+_p", "(lv.obj)"); }
#endif // BE_LV_WIDGET_TILEVIEW #endif // BE_LV_WIDGET_TILEVIEW
/* `lv_colorwheel` methods */
#ifdef BE_LV_WIDGET_COLORWHEEL
int be_ntv_lv_colorwheel_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_colorwheel_create, "+_p", "(lv.obj)b"); }
#endif // BE_LV_WIDGET_COLORWHEEL
// create font either empty or from parameter on stack // create font either empty or from parameter on stack
int lvbe_font_create(bvm *vm) { return be_call_c_func(vm, NULL, "+_p", ""); } int lvbe_font_create(bvm *vm) { return be_call_c_func(vm, NULL, "+_p", ""); }

View File

@ -29,6 +29,9 @@ BE_EXPORT_VARIABLE extern const bclass be_class_lv_obj;
extern int lvbe_font_create(bvm *vm); extern int lvbe_font_create(bvm *vm);
extern int lvbe_theme_create(bvm *vm); extern int lvbe_theme_create(bvm *vm);
// adding ad-hoc colorwheel from LVGL8 to LVGL9
extern const lv_obj_class_t lv_colorwheel_class;
extern int be_ntv_lv_style_init(bvm *vm); extern int be_ntv_lv_style_init(bvm *vm);
extern int be_ntv_lv_font_init(bvm *vm); extern int be_ntv_lv_font_init(bvm *vm);
@ -78,6 +81,7 @@ extern int be_ntv_lv_table_init(bvm *vm);
extern int be_ntv_lv_tabview_init(bvm *vm); extern int be_ntv_lv_tabview_init(bvm *vm);
extern int be_ntv_lv_textarea_init(bvm *vm); extern int be_ntv_lv_textarea_init(bvm *vm);
extern int be_ntv_lv_tileview_init(bvm *vm); extern int be_ntv_lv_tileview_init(bvm *vm);
extern int be_ntv_lv_colorwheel_init(bvm *vm);
extern const bclass be_class_lv_anim; extern const bclass be_class_lv_anim;
extern const bclass be_class_lv_animimg; extern const bclass be_class_lv_animimg;
@ -90,6 +94,7 @@ extern const bclass be_class_lv_canvas;
extern const bclass be_class_lv_chart; extern const bclass be_class_lv_chart;
extern const bclass be_class_lv_checkbox; extern const bclass be_class_lv_checkbox;
extern const bclass be_class_lv_color; extern const bclass be_class_lv_color;
extern const bclass be_class_lv_colorwheel;
extern const bclass be_class_lv_display; extern const bclass be_class_lv_display;
extern const bclass be_class_lv_dropdown; extern const bclass be_class_lv_dropdown;
extern const bclass be_class_lv_event; extern const bclass be_class_lv_event;
@ -685,3 +690,14 @@ class be_class_lv_tileview (scope: global, name: lv_tileview, super: be_class_lv
} }
@const_object_info_end */ @const_object_info_end */
/********************************************************************
** Solidified class: lv_colorwheel
********************************************************************/
#include "be_fixed_be_class_lv_colorwheel.h"
/* @const_object_info_begin
class be_class_lv_colorwheel (scope: global, name: lv_colorwheel, super: be_class_lv_obj, strings: weak) {
init, func(be_ntv_lv_colorwheel_init)
_class, comptr(&lv_colorwheel_class)
}
@const_object_info_end */

View File

@ -1498,3 +1498,14 @@ void be_load_lvgl_classes(bvm *vm)
void lv_image_set_tasmota_logo(lv_obj_t * img) void lv_image_set_tasmota_logo(lv_obj_t * img)
lv_area_t * lv_bar_get_indic_area(lv_obj_t * bar) lv_area_t * lv_bar_get_indic_area(lv_obj_t * bar)
// ../src/lv_colorwheel.h
lv_obj_t * lv_colorwheel_create(lv_obj_t * parent, bool knob_recolor)
bool lv_colorwheel_set_hsv(lv_obj_t * obj, lv_color_hsv_t hsv)
bool lv_colorwheel_set_rgb(lv_obj_t * obj, lv_color_t color)
void lv_colorwheel_set_mode(lv_obj_t * obj, lv_colorwheel_mode_t mode)
void lv_colorwheel_set_mode_fixed(lv_obj_t * obj, bool fixed)
lv_color_hsv_t lv_colorwheel_get_hsv(lv_obj_t * obj)
lv_color_t lv_colorwheel_get_rgb(lv_obj_t * obj)
lv_colorwheel_mode_t lv_colorwheel_get_color_mode(lv_obj_t * obj)
bool lv_colorwheel_get_color_mode_fixed(lv_obj_t * obj)

View File

@ -0,0 +1,768 @@
/**
* @file lv_colorwheel.c
*
* Based on the work of @AloyseTech and @paulpv.
*/
/*********************
* INCLUDES
*********************/
#include "lv_colorwheel.h"
// #if LV_USE_COLORWHEEL
#include "../../lvgl/src/core/lv_obj_class_private.h"
#include "../../lvgl/src/core/lv_obj_private.h"
#include "../../lvgl/src/core/lv_obj_event_private.h"
#include "../../lvgl/src/misc/lv_area_private.h"
#include "../../lvgl/src/indev/lv_indev_private.h"
#include "../../lvgl/src/themes/lv_theme_private.h"
#include "../../lvgl/src/misc/lv_assert.h"
/*********************
* DEFINES
*********************/
#define MY_CLASS &lv_colorwheel_class
#define LV_CPICKER_DEF_QF 3
/**
* The OUTER_MASK_WIDTH define is required to assist with the placing of a mask over the outer ring of the widget as when the
* multicoloured radial lines are calculated for the outer ring of the widget their lengths are jittering because of the
* integer based arithmetic. From tests the maximum delta was found to be 2 so the current value is set to 3 to achieve
* appropriate masking.
*/
#define OUTER_MASK_WIDTH 3
/**********************
* TYPEDEFS
**********************/
/*Data of color picker*/
typedef struct {
lv_obj_t obj;
lv_color_hsv_t hsv;
struct {
lv_point_t pos;
uint8_t recolor : 1;
} knob;
uint32_t last_click_time;
uint32_t last_change_time;
lv_point_t last_press_point;
lv_colorwheel_mode_t mode : 2;
uint8_t mode_fixed : 1;
} lv_colorwheel_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_colorwheel_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_colorwheel_event(const lv_obj_class_t * class_p, lv_event_t * e);
static void draw_disc_grad(lv_event_t * e);
static void draw_knob(lv_event_t * e);
static void invalidate_knob(lv_obj_t * obj);
static lv_area_t get_knob_area(lv_obj_t * obj);
static void next_color_mode(lv_obj_t * obj);
static lv_res_t double_click_reset(lv_obj_t * obj);
static void refr_knob_pos(lv_obj_t * obj);
static lv_color_t angle_to_mode_color_fast(lv_obj_t * obj, uint16_t angle);
static uint16_t get_angle(lv_obj_t * obj);
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_colorwheel_class = {
.instance_size = sizeof(lv_colorwheel_t),
.base_class = &lv_obj_class,
.constructor_cb = lv_colorwheel_constructor,
.event_cb = lv_colorwheel_event,
.width_def = LV_DPI_DEF * 2,
.height_def = LV_DPI_DEF * 2,
.editable = LV_OBJ_CLASS_EDITABLE_TRUE,
};
static bool create_knob_recolor;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create a color_picker object
* @param parent pointer to an object, it will be the parent of the new color_picker
* @return pointer to the created color_picker
*/
lv_obj_t * lv_colorwheel_create(lv_obj_t * parent, bool knob_recolor)
{
LV_LOG_INFO("begin");
create_knob_recolor = knob_recolor;
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
/*=====================
* Setter functions
*====================*/
/**
* Set the current hsv of a color wheel.
* @param colorwheel pointer to color wheel object
* @param color current selected hsv
* @return true if changed, otherwise false
*/
bool lv_colorwheel_set_hsv(lv_obj_t * obj, lv_color_hsv_t hsv)
{
if(hsv.h > 360) hsv.h %= 360;
if(hsv.s > 100) hsv.s = 100;
if(hsv.v > 100) hsv.v = 100;
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
if(colorwheel->hsv.h == hsv.h && colorwheel->hsv.s == hsv.s && colorwheel->hsv.v == hsv.v) return false;
colorwheel->hsv = hsv;
refr_knob_pos(obj);
lv_obj_invalidate(obj);
return true;
}
/**
* Set the current color of a color wheel.
* @param colorwheel pointer to color wheel object
* @param color current selected color
* @return true if changed, otherwise false
*/
bool lv_colorwheel_set_rgb(lv_obj_t * obj, lv_color_t color)
{
// lv_color32_t c32;
// c32.full = lv_color_to32(color);
return lv_colorwheel_set_hsv(obj, lv_color_rgb_to_hsv(color.red, color.green, color.blue));
}
/**
* Set the current color mode.
* @param colorwheel pointer to color wheel object
* @param mode color mode (hue/sat/val)
*/
void lv_colorwheel_set_mode(lv_obj_t * obj, lv_colorwheel_mode_t mode)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
colorwheel->mode = mode;
refr_knob_pos(obj);
lv_obj_invalidate(obj);
}
/**
* Set if the color mode is changed on long press on center
* @param colorwheel pointer to color wheel object
* @param fixed color mode cannot be changed on long press
*/
void lv_colorwheel_set_mode_fixed(lv_obj_t * obj, bool fixed)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
colorwheel->mode_fixed = fixed;
}
/*=====================
* Getter functions
*====================*/
/**
* Get the current selected hsv of a color wheel.
* @param colorwheel pointer to color wheel object
* @return current selected hsv
*/
lv_color_hsv_t lv_colorwheel_get_hsv(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
return colorwheel->hsv;
}
/**
* Get the current selected color of a color wheel.
* @param colorwheel pointer to color wheel object
* @return color current selected color
*/
lv_color_t lv_colorwheel_get_rgb(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
return lv_color_hsv_to_rgb(colorwheel->hsv.h, colorwheel->hsv.s, colorwheel->hsv.v);
}
/**
* Get the current color mode.
* @param colorwheel pointer to color wheel object
* @return color mode (hue/sat/val)
*/
lv_colorwheel_mode_t lv_colorwheel_get_color_mode(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
return colorwheel->mode;
}
/**
* Get if the color mode is changed on long press on center
* @param colorwheel pointer to color wheel object
* @return mode cannot be changed on long press
*/
bool lv_colorwheel_get_color_mode_fixed(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
return colorwheel->mode_fixed;
}
/*=====================
* Other functions
*====================*/
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_colorwheel_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
colorwheel->hsv.h = 0;
colorwheel->hsv.s = 100;
colorwheel->hsv.v = 100;
colorwheel->mode = LV_COLORWHEEL_MODE_HUE;
colorwheel->mode_fixed = 0;
colorwheel->last_click_time = 0;
colorwheel->last_change_time = 0;
colorwheel->knob.recolor = create_knob_recolor;
// apply default style, which was originally in `lv_theme_default.c` under `#if LV_USE_COLORWHEEL`
// retrieve theme object
lv_theme_t * theme = lv_theme_get_from_obj(obj);
lv_display_t * disp = theme->disp;
int32_t dpi = lv_display_get_dpi(disp);
// apply default styles
// lv_obj_add_style(obj, &styles->colorwheel_main, 0);
lv_obj_set_style_arc_width(obj, LV_DPX_CALC(dpi, 20), 0);
// lv_obj_add_style(obj, &styles->pad_normal, 0);
// lv_style_set_pad_all(&styles->pad_normal, PAD_DEF);
// lv_style_set_pad_row(&styles->pad_normal, PAD_DEF);
// lv_style_set_pad_column(&styles->pad_normal, PAD_DEF);
#define PAD_DEF LV_DPX_CALC(dpi, 16)
lv_obj_set_style_pad_all(obj, PAD_DEF, 0);
lv_obj_set_style_pad_row(obj, PAD_DEF, 0);
lv_obj_set_style_pad_column(obj, PAD_DEF, 0);
// lv_obj_add_style(obj, &styles->bg_color_white, LV_PART_KNOB);
// lv_style_set_bg_color(&styles->bg_color_white, color_card);
// lv_style_set_bg_opa(&styles->bg_color_white, LV_OPA_COVER);
// lv_style_set_text_color(&styles->bg_color_white, color_text);
lv_obj_set_style_bg_color(obj, lv_color_white(), LV_PART_KNOB);
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, LV_PART_KNOB);
lv_obj_set_style_text_color(obj, lv_palette_darken(LV_PALETTE_GREY, 4), LV_PART_KNOB);
// lv_obj_add_style(obj, &styles->pad_normal, LV_PART_KNOB);
// lv_style_set_pad_all(&styles->pad_normal, PAD_DEF);
// lv_style_set_pad_row(&styles->pad_normal, PAD_DEF);
// lv_style_set_pad_column(&styles->pad_normal, PAD_DEF);
lv_obj_set_style_pad_all(obj, PAD_DEF, LV_PART_KNOB);
lv_obj_set_style_pad_row(obj, PAD_DEF, LV_PART_KNOB);
lv_obj_set_style_pad_column(obj, PAD_DEF, LV_PART_KNOB);
// rest of constructor
lv_obj_add_flag(obj, LV_OBJ_FLAG_ADV_HITTEST);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLL_CHAIN);
refr_knob_pos(obj);
}
static void draw_disc_grad(lv_event_t * e)
{
// lv_obj_t * obj = lv_event_get_target(e);
lv_obj_t * obj = lv_event_get_current_target(e);
lv_layer_t * layer = lv_event_get_layer(e);
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
lv_coord_t cx = obj->coords.x1 + w / 2;
lv_coord_t cy = obj->coords.y1 + h / 2;
lv_coord_t r = w / 2;
lv_draw_line_dsc_t line_dsc;
lv_draw_line_dsc_init(&line_dsc);
lv_obj_init_draw_line_dsc(obj, LV_PART_MAIN, &line_dsc);
line_dsc.width = (r * 628 / (256 / LV_CPICKER_DEF_QF)) / 100;
line_dsc.width += 4;
uint16_t i;
uint32_t a = 0;
lv_coord_t cir_w = lv_obj_get_style_arc_width(obj, LV_PART_MAIN);
#if LV_DRAW_COMPLEX
/*Mask outer and inner ring of widget to tidy up ragged edges of lines while drawing outer ring*/
lv_draw_mask_radius_param_t mask_out_param;
lv_draw_mask_radius_init(&mask_out_param, &obj->coords, LV_RADIUS_CIRCLE, false);
int16_t mask_out_id = lv_draw_mask_add(&mask_out_param, 0);
lv_area_t mask_area;
lv_area_copy(&mask_area, &obj->coords);
mask_area.x1 += cir_w;
mask_area.x2 -= cir_w;
mask_area.y1 += cir_w;
mask_area.y2 -= cir_w;
lv_draw_mask_radius_param_t mask_in_param;
lv_draw_mask_radius_init(&mask_in_param, &mask_area, LV_RADIUS_CIRCLE, true);
int16_t mask_in_id = lv_draw_mask_add(&mask_in_param, 0);
/*The inner and outer line ends will be masked out.
*So make lines a little bit longer because the masking makes a more even result*/
lv_coord_t cir_w_extra = line_dsc.width;
#else
lv_coord_t cir_w_extra = 0;
#endif
for(i = 0; i <= 256; i += LV_CPICKER_DEF_QF, a += 360 * LV_CPICKER_DEF_QF) {
line_dsc.color = angle_to_mode_color_fast(obj, i);
uint16_t angle_trigo = (uint16_t)(a >> 8); /*i * 360 / 256 is the scale to apply, but we can skip multiplication here*/
line_dsc.p1.x = cx + ((r + cir_w_extra) * lv_trigo_sin(angle_trigo) >> LV_TRIGO_SHIFT);
line_dsc.p1.y = cy + ((r + cir_w_extra) * lv_trigo_cos(angle_trigo) >> LV_TRIGO_SHIFT);
line_dsc.p2.x = cx + ((r - cir_w - cir_w_extra) * lv_trigo_sin(angle_trigo) >> LV_TRIGO_SHIFT);
line_dsc.p2.y = cy + ((r - cir_w - cir_w_extra) * lv_trigo_cos(angle_trigo) >> LV_TRIGO_SHIFT);
lv_draw_line(layer, &line_dsc);
}
#if LV_DRAW_COMPLEX
lv_draw_mask_free_param(&mask_out_param);
lv_draw_mask_free_param(&mask_in_param);
lv_draw_mask_remove_id(mask_out_id);
lv_draw_mask_remove_id(mask_in_id);
#endif
}
static void draw_knob(lv_event_t * e)
{
// lv_obj_t * obj = lv_event_get_target(e);
lv_obj_t * obj = lv_event_get_current_target(e);
lv_layer_t * layer = lv_event_get_layer(e);
// lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
lv_draw_rect_dsc_t cir_dsc;
lv_draw_rect_dsc_init(&cir_dsc);
lv_obj_init_draw_rect_dsc(obj, LV_PART_KNOB, &cir_dsc);
cir_dsc.radius = LV_RADIUS_CIRCLE;
if(colorwheel->knob.recolor) {
cir_dsc.bg_color = lv_colorwheel_get_rgb(obj);
}
lv_area_t knob_area = get_knob_area(obj);
lv_draw_rect(layer, &cir_dsc, &knob_area);
}
static void invalidate_knob(lv_obj_t * obj)
{
lv_area_t knob_area = get_knob_area(obj);
lv_obj_invalidate_area(obj, &knob_area);
}
static lv_area_t get_knob_area(lv_obj_t * obj)
{
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
/*Get knob's radius*/
uint16_t r = 0;
r = lv_obj_get_style_arc_width(obj, LV_PART_MAIN) / 2;
lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_KNOB);
lv_coord_t right = lv_obj_get_style_pad_right(obj, LV_PART_KNOB);
lv_coord_t top = lv_obj_get_style_pad_top(obj, LV_PART_KNOB);
lv_coord_t bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB);
lv_area_t knob_area;
knob_area.x1 = obj->coords.x1 + colorwheel->knob.pos.x - r - left;
knob_area.y1 = obj->coords.y1 + colorwheel->knob.pos.y - r - right;
knob_area.x2 = obj->coords.x1 + colorwheel->knob.pos.x + r + top;
knob_area.y2 = obj->coords.y1 + colorwheel->knob.pos.y + r + bottom;
return knob_area;
}
static void lv_colorwheel_event(const lv_obj_class_t * class_p, lv_event_t * e)
{
LV_UNUSED(class_p);
lv_result_t res;
/*Call the ancestor's event handler*/
res = lv_obj_event_base(MY_CLASS, e);
if(res != LV_RES_OK) return;
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * obj = lv_event_get_current_target(e);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_KNOB);
lv_coord_t right = lv_obj_get_style_pad_right(obj, LV_PART_KNOB);
lv_coord_t top = lv_obj_get_style_pad_top(obj, LV_PART_KNOB);
lv_coord_t bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB);
lv_coord_t knob_pad = LV_MAX4(left, right, top, bottom) + 2;
lv_coord_t * s = lv_event_get_param(e);
*s = LV_MAX(*s, knob_pad);
}
else if(code == LV_EVENT_SIZE_CHANGED) {
void * param = lv_event_get_param(e);
/*Refresh extended draw area to make knob visible*/
if(lv_obj_get_width(obj) != lv_area_get_width(param) ||
lv_obj_get_height(obj) != lv_area_get_height(param)) {
refr_knob_pos(obj);
}
}
else if(code == LV_EVENT_STYLE_CHANGED) {
/*Refresh extended draw area to make knob visible*/
refr_knob_pos(obj);
}
else if(code == LV_EVENT_KEY) {
uint32_t c = *((uint32_t *)lv_event_get_param(e)); /*uint32_t because can be UTF-8*/
if(c == LV_KEY_RIGHT || c == LV_KEY_UP) {
lv_color_hsv_t hsv_cur;
hsv_cur = colorwheel->hsv;
switch(colorwheel->mode) {
case LV_COLORWHEEL_MODE_HUE:
hsv_cur.h = (colorwheel->hsv.h + 1) % 360;
break;
case LV_COLORWHEEL_MODE_SATURATION:
hsv_cur.s = (colorwheel->hsv.s + 1) % 100;
break;
case LV_COLORWHEEL_MODE_VALUE:
hsv_cur.v = (colorwheel->hsv.v + 1) % 100;
break;
}
if(lv_colorwheel_set_hsv(obj, hsv_cur)) {
res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
if(res != LV_RES_OK) return;
}
}
else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) {
lv_color_hsv_t hsv_cur;
hsv_cur = colorwheel->hsv;
switch(colorwheel->mode) {
case LV_COLORWHEEL_MODE_HUE:
hsv_cur.h = colorwheel->hsv.h > 0 ? (colorwheel->hsv.h - 1) : 360;
break;
case LV_COLORWHEEL_MODE_SATURATION:
hsv_cur.s = colorwheel->hsv.s > 0 ? (colorwheel->hsv.s - 1) : 100;
break;
case LV_COLORWHEEL_MODE_VALUE:
hsv_cur.v = colorwheel->hsv.v > 0 ? (colorwheel->hsv.v - 1) : 100;
break;
}
if(lv_colorwheel_set_hsv(obj, hsv_cur)) {
res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
if(res != LV_RES_OK) return;
}
}
}
else if(code == LV_EVENT_PRESSED) {
colorwheel->last_change_time = lv_tick_get();
lv_indev_get_point(lv_indev_get_act(), &colorwheel->last_press_point);
res = double_click_reset(obj);
if(res != LV_RES_OK) return;
}
else if(code == LV_EVENT_PRESSING) {
lv_indev_t * indev = lv_indev_get_act();
if(indev == NULL) return;
lv_indev_type_t indev_type = lv_indev_get_type(indev);
lv_point_t p;
if(indev_type == LV_INDEV_TYPE_ENCODER || indev_type == LV_INDEV_TYPE_KEYPAD) {
p.x = obj->coords.x1 + lv_obj_get_width(obj) / 2;
p.y = obj->coords.y1 + lv_obj_get_height(obj) / 2;
}
else {
lv_indev_get_point(indev, &p);
}
lv_coord_t drag_limit = indev->scroll_limit;
if((LV_ABS(p.x - colorwheel->last_press_point.x) > drag_limit) ||
(LV_ABS(p.y - colorwheel->last_press_point.y) > drag_limit)) {
colorwheel->last_change_time = lv_tick_get();
colorwheel->last_press_point.x = p.x;
colorwheel->last_press_point.y = p.y;
}
p.x -= obj->coords.x1;
p.y -= obj->coords.y1;
/*Ignore pressing in the inner area*/
uint16_t w = lv_obj_get_width(obj);
int16_t angle = 0;
lv_coord_t cir_w = lv_obj_get_style_arc_width(obj, LV_PART_MAIN);
lv_coord_t r_in = w / 2;
p.x -= r_in;
p.y -= r_in;
bool on_ring = true;
r_in -= cir_w;
if(r_in > LV_DPI_DEF / 2) {
lv_coord_t inner = cir_w / 2;
r_in -= inner;
if(r_in < LV_DPI_DEF / 2) r_in = LV_DPI_DEF / 2;
}
if(p.x * p.x + p.y * p.y < r_in * r_in) {
on_ring = false;
}
/*If the inner area is being pressed, go to the next color mode on long press*/
uint32_t diff = lv_tick_elaps(colorwheel->last_change_time);
if(!on_ring && diff > indev->long_press_time && !colorwheel->mode_fixed) {
next_color_mode(obj);
lv_indev_wait_release(lv_indev_get_act());
return;
}
/*Set the angle only if pressed on the ring*/
if(!on_ring) return;
angle = lv_atan2(p.x, p.y) % 360;
lv_color_hsv_t hsv_cur;
hsv_cur = colorwheel->hsv;
switch(colorwheel->mode) {
case LV_COLORWHEEL_MODE_HUE:
hsv_cur.h = angle;
break;
case LV_COLORWHEEL_MODE_SATURATION:
hsv_cur.s = (angle * 100) / 360;
break;
case LV_COLORWHEEL_MODE_VALUE:
hsv_cur.v = (angle * 100) / 360;
break;
}
if(lv_colorwheel_set_hsv(obj, hsv_cur)) {
res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
if(res != LV_RES_OK) return;
}
}
else if(code == LV_EVENT_HIT_TEST) {
lv_hit_test_info_t * info = lv_event_get_param(e);
/*Valid clicks can be only in the circle*/
info->res = lv_area_is_point_on(&obj->coords, info->point, LV_RADIUS_CIRCLE);
}
else if(code == LV_EVENT_DRAW_MAIN) {
draw_disc_grad(e);
draw_knob(e);
}
else if(code == LV_EVENT_COVER_CHECK) {
lv_cover_check_info_t * info = lv_event_get_param(e);
if(info->res != LV_COVER_RES_MASKED) info->res = LV_COVER_RES_NOT_COVER;
}
}
static void next_color_mode(lv_obj_t * obj)
{
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
colorwheel->mode = (colorwheel->mode + 1) % 3;
refr_knob_pos(obj);
lv_obj_invalidate(obj);
}
static void refr_knob_pos(lv_obj_t * obj)
{
invalidate_knob(obj);
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t scale_w = lv_obj_get_style_arc_width(obj, LV_PART_MAIN);
lv_coord_t r = (w - scale_w) / 2;
uint16_t angle = get_angle(obj);
colorwheel->knob.pos.x = (((int32_t)r * lv_trigo_sin(angle)) >> LV_TRIGO_SHIFT);
colorwheel->knob.pos.y = (((int32_t)r * lv_trigo_cos(angle)) >> LV_TRIGO_SHIFT);
colorwheel->knob.pos.x = colorwheel->knob.pos.x + w / 2;
colorwheel->knob.pos.y = colorwheel->knob.pos.y + w / 2;
invalidate_knob(obj);
}
static lv_res_t double_click_reset(lv_obj_t * obj)
{
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
lv_indev_t * indev = lv_indev_get_act();
/*Double clicked? Use long press time as double click time out*/
if(lv_tick_elaps(colorwheel->last_click_time) < indev->long_press_time) {
lv_color_hsv_t hsv_cur;
hsv_cur = colorwheel->hsv;
switch(colorwheel->mode) {
case LV_COLORWHEEL_MODE_HUE:
hsv_cur.h = 0;
break;
case LV_COLORWHEEL_MODE_SATURATION:
hsv_cur.s = 100;
break;
case LV_COLORWHEEL_MODE_VALUE:
hsv_cur.v = 100;
break;
}
lv_indev_wait_release(indev);
if(lv_colorwheel_set_hsv(obj, hsv_cur)) {
lv_res_t res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
if(res != LV_RES_OK) return res;
}
}
colorwheel->last_click_time = lv_tick_get();
return LV_RES_OK;
}
#define SWAPPTR(A, B) do { uint8_t * t = A; A = B; B = t; } while(0)
#define HSV_PTR_SWAP(sextant,r,g,b) if((sextant) & 2) { SWAPPTR((r), (b)); } if((sextant) & 4) { SWAPPTR((g), (b)); } if(!((sextant) & 6)) { \
if(!((sextant) & 1)) { SWAPPTR((r), (g)); } } else { if((sextant) & 1) { SWAPPTR((r), (g)); } }
/**
* Based on the idea from https://www.vagrearg.org/content/hsvrgb
* Here we want to compute an approximate RGB value from a HSV input color space. We don't want to be accurate
* (for that, there's lv_color_hsv_to_rgb), but we want to be fast.
*
* Few tricks are used here: Hue is in range [0; 6 * 256] (so that the sextant is in the high byte and the fractional part is in the low byte)
* both s and v are in [0; 255] range (very convenient to avoid divisions).
*
* We fold all symmetry by swapping the R, G, B pointers so that the code is the same for all sextants.
* We replace division by 255 by a division by 256, a.k.a a shift right by 8 bits.
* This is wrong, but since this is only used to compute the pixels on the screen and not the final color, it's ok.
*/
static void fast_hsv2rgb(uint16_t h, uint8_t s, uint8_t v, uint8_t * r, uint8_t * g, uint8_t * b)
{
if(!s) {
*r = *g = *b = v;
return;
}
uint8_t sextant = h >> 8;
HSV_PTR_SWAP(sextant, r, g, b); /*Swap pointers so the conversion code is the same*/
*g = v;
uint8_t bb = ~s;
uint16_t ww = v * bb; /*Don't try to be precise, but instead, be fast*/
*b = ww >> 8;
uint8_t h_frac = h & 0xff;
if(!(sextant & 1)) {
/*Up slope*/
ww = !h_frac ? ((uint16_t)s << 8) : (s * (uint8_t)(-h_frac)); /*Skip multiply if not required*/
}
else {
/*Down slope*/
ww = s * h_frac;
}
bb = ww >> 8;
bb = ~bb;
ww = v * bb;
*r = ww >> 8;
}
static lv_color_t angle_to_mode_color_fast(lv_obj_t * obj, uint16_t angle)
{
lv_colorwheel_t * ext = (lv_colorwheel_t *)obj;
uint8_t r = 0, g = 0, b = 0;
static uint16_t h = 0;
static uint8_t s = 0, v = 0, m = 255;
static uint16_t angle_saved = 0xffff;
/*If the angle is different recalculate scaling*/
if(angle_saved != angle) m = 255;
angle_saved = angle;
switch(ext->mode) {
default:
case LV_COLORWHEEL_MODE_HUE:
/*Don't recompute costly scaling if it does not change*/
if(m != ext->mode) {
s = (uint8_t)(((uint16_t)ext->hsv.s * 51) / 20);
v = (uint8_t)(((uint16_t)ext->hsv.v * 51) / 20);
m = ext->mode;
}
fast_hsv2rgb(angle * 6, s, v, &r, &g,
&b); /*A smart compiler will replace x * 6 by (x << 2) + (x << 1) if it's more efficient*/
break;
case LV_COLORWHEEL_MODE_SATURATION:
/*Don't recompute costly scaling if it does not change*/
if(m != ext->mode) {
h = (uint16_t)(((uint32_t)ext->hsv.h * 6 * 256) / 360);
v = (uint8_t)(((uint16_t)ext->hsv.v * 51) / 20);
m = ext->mode;
}
fast_hsv2rgb(h, angle, v, &r, &g, &b);
break;
case LV_COLORWHEEL_MODE_VALUE:
/*Don't recompute costly scaling if it does not change*/
if(m != ext->mode) {
h = (uint16_t)(((uint32_t)ext->hsv.h * 6 * 256) / 360);
s = (uint8_t)(((uint16_t)ext->hsv.s * 51) / 20);
m = ext->mode;
}
fast_hsv2rgb(h, s, angle, &r, &g, &b);
break;
}
return lv_color_make(r, g, b);
}
static uint16_t get_angle(lv_obj_t * obj)
{
lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj;
uint16_t angle;
switch(colorwheel->mode) {
default:
case LV_COLORWHEEL_MODE_HUE:
angle = colorwheel->hsv.h;
break;
case LV_COLORWHEEL_MODE_SATURATION:
angle = (colorwheel->hsv.s * 360) / 100;
break;
case LV_COLORWHEEL_MODE_VALUE:
angle = (colorwheel->hsv.v * 360) / 100 ;
break;
}
return angle;
}
// #endif /*LV_USE_COLORWHEEL*/

View File

@ -0,0 +1,125 @@
/**
* @file lv_colorwheel.h
*
*/
#ifndef LV_COLORWHEEL_H
#define LV_COLORWHEEL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lvgl.h"
// #if LV_USE_COLORWHEEL
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
enum {
LV_COLORWHEEL_MODE_HUE,
LV_COLORWHEEL_MODE_SATURATION,
LV_COLORWHEEL_MODE_VALUE
};
typedef uint8_t lv_colorwheel_mode_t;
extern const lv_obj_class_t lv_colorwheel_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a color picker object with disc shape
* @param parent pointer to an object, it will be the parent of the new color picker
* @param knob_recolor true: set the knob's color to the current color
* @return pointer to the created color picker
*/
lv_obj_t * lv_colorwheel_create(lv_obj_t * parent, bool knob_recolor);
/*=====================
* Setter functions
*====================*/
/**
* Set the current hsv of a color wheel.
* @param colorwheel pointer to color wheel object
* @param color current selected hsv
* @return true if changed, otherwise false
*/
bool lv_colorwheel_set_hsv(lv_obj_t * obj, lv_color_hsv_t hsv);
/**
* Set the current color of a color wheel.
* @param colorwheel pointer to color wheel object
* @param color current selected color
* @return true if changed, otherwise false
*/
bool lv_colorwheel_set_rgb(lv_obj_t * obj, lv_color_t color);
/**
* Set the current color mode.
* @param colorwheel pointer to color wheel object
* @param mode color mode (hue/sat/val)
*/
void lv_colorwheel_set_mode(lv_obj_t * obj, lv_colorwheel_mode_t mode);
/**
* Set if the color mode is changed on long press on center
* @param colorwheel pointer to color wheel object
* @param fixed color mode cannot be changed on long press
*/
void lv_colorwheel_set_mode_fixed(lv_obj_t * obj, bool fixed);
/*=====================
* Getter functions
*====================*/
/**
* Get the current selected hsv of a color wheel.
* @param colorwheel pointer to color wheel object
* @return current selected hsv
*/
lv_color_hsv_t lv_colorwheel_get_hsv(lv_obj_t * obj);
/**
* Get the current selected color of a color wheel.
* @param colorwheel pointer to color wheel object
* @return color current selected color
*/
lv_color_t lv_colorwheel_get_rgb(lv_obj_t * obj);
/**
* Get the current color mode.
* @param colorwheel pointer to color wheel object
* @return color mode (hue/sat/val)
*/
lv_colorwheel_mode_t lv_colorwheel_get_color_mode(lv_obj_t * obj);
/**
* Get if the color mode is changed on long press on center
* @param colorwheel pointer to color wheel object
* @return mode cannot be changed on long press
*/
bool lv_colorwheel_get_color_mode_fixed(lv_obj_t * obj);
/**********************
* MACROS
**********************/
// #endif /*LV_USE_COLORWHEEL*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_COLORWHEEL_H*/

View File

@ -48,6 +48,9 @@ lv_widgets = lv_widgets + [ 'chart', 'imagebutton', 'led', 'msgbox', 'spinbox',
# add qrcode # add qrcode
lv_widgets = lv_widgets + [ 'qrcode' ] lv_widgets = lv_widgets + [ 'qrcode' ]
# adding ad-hoc colorwheel from LVGL8 to LVGL9
lv_widgets = lv_widgets + [ 'colorwheel' ]
lv_prefix = ['group', 'style', 'indev', 'display', 'timer', 'anim', 'event', 'span'] + lv_widgets lv_prefix = ['group', 'style', 'indev', 'display', 'timer', 'anim', 'event', 'span'] + lv_widgets
# define here widget inheritance because it's hard to deduce from source # define here widget inheritance because it's hard to deduce from source
@ -406,6 +409,9 @@ class type_mapper_class:
"lv_calendar_chinese_t": "c", "lv_calendar_chinese_t": "c",
# adding ad-hoc colorwheel from LVGL8 to LVGL9
"lv_colorwheel_mode_t": "i",
# arrays # arrays
"constchar * []": "str_arr", "constchar * []": "str_arr",
# "char * []": "str_arr", # "char * []": "str_arr",
@ -798,6 +804,7 @@ extern "C" {
#include "be_ctypes.h" #include "be_ctypes.h"
#include "be_mapping.h" #include "be_mapping.h"
#include "../src/lv_colorwheel.h"
""") """)
for subtype, flv in lv.items(): for subtype, flv in lv.items():
@ -914,6 +921,9 @@ BE_EXPORT_VARIABLE extern const bclass be_class_lv_obj;
extern int lvbe_font_create(bvm *vm); extern int lvbe_font_create(bvm *vm);
extern int lvbe_theme_create(bvm *vm); extern int lvbe_theme_create(bvm *vm);
// adding ad-hoc colorwheel from LVGL8 to LVGL9
extern const lv_obj_class_t lv_colorwheel_class;
""") """)
# expose all extern definitions: # expose all extern definitions:

View File

@ -91,7 +91,7 @@ headers_exlude_suffix = [
headers_names = list_files(lv_src_prefix, lv_fun_globs) headers_names = list_files(lv_src_prefix, lv_fun_globs)
headers_names += list_files("../../LVGL_assets/src/", ["lv_theme_haspmota.h"]) headers_names += list_files("../../LVGL_assets/src/", ["lv_theme_haspmota.h"])
headers_names += list_files("../src/", ["lv_berry.h"]) headers_names += list_files("../src/", ["lv_berry.h", "lv_colorwheel.h"])
# filter out from headers_exlude_suffix # filter out from headers_exlude_suffix
headers_names = [x for x in headers_names if not any(x.endswith(suffix) for suffix in headers_exlude_suffix)] headers_names = [x for x in headers_names if not any(x.endswith(suffix) for suffix in headers_exlude_suffix)]

View File

@ -31,6 +31,9 @@ extern const bclass be_class_lv_span;
extern const bclass be_class_lv_button; extern const bclass be_class_lv_button;
extern const bclass be_class_lv_image; extern const bclass be_class_lv_image;
extern const bclass be_class_lv_buttonmatrix; extern const bclass be_class_lv_buttonmatrix;
extern const bclass be_class_lv_msgbox;
// ported from LVGL 8
extern const bclass be_class_lv_colorwheel;
#include "solidify/solidified_lv_haspmota.h" #include "solidify/solidified_lv_haspmota.h"

View File

@ -13,8 +13,10 @@ var classes = [
"bar", "slider", "arc", "textarea", "led", "dropdown", "bar", "slider", "arc", "textarea", "led", "dropdown",
"scale", "scale",
"qrcode", "chart", "spangroup", "span", "qrcode", "chart", "spangroup", "span",
# ported from LVGL 8
"colorwheel",
# new internal names # new internal names
"button", "image", "buttonmatrix", "button", "image", "buttonmatrix", "msgbox"
] ]
for cl: classes for cl: classes

View File

@ -257,10 +257,11 @@ class lvh_root
#==================================================================== #====================================================================
# init HASPmota object from its jsonl definition # init HASPmota object from its jsonl definition
# #
# arg1: LVGL parent object (used to create a sub-object) # parent: LVGL parent object (used to create a sub-object)
# arg2: `jline` JSONL definition of the object from HASPmota template (used in sub-classes) # page: HASPmota page object
# arg3: (opt) LVGL object if it already exists and was created prior to init() # jline: JSONL definition of the object from HASPmota template (used in sub-classes)
# arg4: HASPmota parent object defined by `parentid` # obj: (opt) LVGL object if it already exists and was created prior to init()
# parent_lvh: HASPmota parent object defined by `parentid`
#==================================================================== #====================================================================
def init(parent, page, jline, obj, parent_lvh) def init(parent, page, jline, obj, parent_lvh)
self._page = page self._page = page
@ -557,10 +558,11 @@ class lvh_obj : lvh_root
#==================================================================== #====================================================================
# init HASPmota object from its jsonl definition # init HASPmota object from its jsonl definition
# #
# arg1: LVGL parent object (used to create a sub-object) # parent: LVGL parent object (used to create a sub-object)
# arg2: `jline` JSONL definition of the object from HASPmota template (used in sub-classes) # page: HASPmota page object
# arg3: (opt) LVGL object if it already exists and was created prior to init() # jline: JSONL definition of the object from HASPmota template (used in sub-classes)
# arg4: HASPmota parent object defined by `parentid` # obj: (opt) LVGL object if it already exists and was created prior to init()
# parent_lvh: HASPmota parent object defined by `parentid`
#==================================================================== #====================================================================
def init(parent, page, jline, obj, parent_lvh) def init(parent, page, jline, obj, parent_lvh)
super(self).init(parent, page, jline, obj, parent_lvh) super(self).init(parent, page, jline, obj, parent_lvh)
@ -640,11 +642,11 @@ class lvh_obj : lvh_root
var tas_event_more = "" # complementary data var tas_event_more = "" # complementary data
if code == lv.EVENT_VALUE_CHANGED if code == lv.EVENT_VALUE_CHANGED
import introspect import introspect
var val = introspect.get(self, "val") # does not raise an exception if not found var val = introspect.get(self, true) # does not raise an exception if not found
if (val != nil && type(val) != 'module') if (val != nil && type(val) != 'module')
tas_event_more = f',"val":{json.dump(val)}' tas_event_more = f',"val":{json.dump(val)}'
end end
var text = introspect.get(self, "text") # does not raise an exception if not found var text = introspect.get(self, true) # does not raise an exception if not found
if (text != nil && type(text) != 'module') if (text != nil && type(text) != 'module')
tas_event_more += f',"text":{json.dump(text)}' tas_event_more += f',"text":{json.dump(text)}'
end end
@ -1269,6 +1271,145 @@ class lvh_switch : lvh_obj
end end
end end
#====================================================================
# msgbox
#====================================================================
#@ solidify:lvh_msgbox,weak
class lvh_msgbox : lvh_obj
static var _lv_class = lv.msgbox
var _modal
# sub_objects
var _header, _footer, _content, _title
var _buttons # array containing the buttons, to apply styles later
#====================================================================
# init
#
# parent: LVGL parent object (used to create a sub-object)
# page: HASPmota page object
# jline: JSONL definition of the object from HASPmota template (used in sub-classes)
# obj: (opt) LVGL object if it already exists and was created prior to init()
# parent_lvh: HASPmota parent object defined by `parentid`
#====================================================================
def init(parent, page, jline, obj, parent_lvh)
self._buttons = []
self._modal = bool(jline.find("modal", false))
if (self._modal)
# the object created as modal is on top of everything
self._lv_obj = lv.msgbox(0)
end
super(self).init(parent, page, jline, self._lv_obj, parent_lvh)
# apply some default styles
self.text_align = 2 # can be overriden
self.bg_opa = 255 # can be overriden
end
#====================================================================
# register_event_cb
#
# Override the normal event handler, we are only interested
# in events on buttons
#====================================================================
def register_event_cb()
# nothing to register for now, event_cb is allocated when buttons are allocted in `setoptions`
end
# update after parsing
#
def post_config()
var lvh_class = self._page._hm.lvh_obj # get `lvh_obj` class from root instance
var _lv_obj = self._lv_obj # get msgbox lvgl object
# read the method, and return nil if exception 'value_error' occured
def get_obj_safe(method)
try
var lv_obj = method(_lv_obj) # equivalent of `self._lv_obj.get_XXX()` where XXX is header/footer/title/content
return lvh_class(nil, self._page, {}, lv_obj, self) # instanciate a local lvh object
except 'value_error'
return nil
end
end
super(self).post_config()
# get sub-objects
self._header = get_obj_safe(_lv_obj.get_header)
self._footer = get_obj_safe(_lv_obj.get_footer)
self._content = get_obj_safe(_lv_obj.get_content)
self._title = get_obj_safe(_lv_obj.get_title)
end
#- ------------------------------------------------------------#
# `setmember` virtual setter
#
# If the key starts with `footer_`, `header_`, `title_` or `content_`
# send to the corresponding object
#- ------------------------------------------------------------#
def setmember(k, v)
import string
if string.startswith(k, 'footer_') && self._footer
self._footer.setmember(k[7..], v)
elif string.startswith(k, 'header_') && self._header
self._header.setmember(k[7..], v)
elif string.startswith(k, 'title_') && self._title
self._title.setmember(k[6..], v)
elif string.startswith(k, 'content_') && self._content
self._content.setmember(k[8..], v)
elif string.startswith(k, 'buttons_') && self._buttons
for btn: self._buttons
btn.setmember(k[8..], v)
end
else
super(self).setmember(k, v)
end
end
def member(k)
import string
if string.startswith(k, 'footer_') && self._footer
return self._footer.member(k[7..])
elif string.startswith(k, 'header_') && self._header
return self._header.member(k[7..])
elif string.startswith(k, 'title_') && self._title
return self._title.member(k[6..])
elif string.startswith(k, 'content_') && self._content
return self._content.member(k[8..])
else
return super(self).member(k)
end
end
# private function to add a button, create the lvh class and register callbacks
def _add_button(msg)
var lvh_class = self._page._hm.lvh_obj # get `lvh_obj` class from root instance
var btn_lv = self._lv_obj.add_footer_button(msg)
var btn_lvh = lvh_class(nil, self._page, {}, btn_lv, self) # instanciate a local lvh object
self._buttons.push(btn_lvh)
end
def set_options(l)
if (isinstance(l, list) && size(l) > 0)
for msg: l
self._add_button(msg)
end
else
print("HTP: 'msgbox' needs 'options' to be a list of strings")
end
end
def get_options()
end
def set_title(t)
self._lv_obj.add_title(str(t))
end
def get_title()
# self._lv_obj.get_title()
end
def set_text(t)
self._lv_obj.add_text(str(t))
end
def get_text()
# self._lv_obj.get_text()
end
end
#==================================================================== #====================================================================
# spinner # spinner
#==================================================================== #====================================================================
@ -1278,17 +1419,21 @@ class lvh_spinner : lvh_arc
# static var _EVENTS = EVENTS_ALL # inherited # static var _EVENTS = EVENTS_ALL # inherited
var _speed, _angle var _speed, _angle
#====================================================================
# init # init
# - create the LVGL encapsulated object #
# arg1: parent object # parent: LVGL parent object (used to create a sub-object)
# arg2: json line object # page: HASPmota page object
# jline: JSONL definition of the object from HASPmota template (used in sub-classes)
# obj: (opt) LVGL object if it already exists and was created prior to init()
# parent_lvh: HASPmota parent object defined by `parentid`
#====================================================================
def init(parent, page, jline) def init(parent, page, jline)
self._page = page
var angle = jline.find("angle", 60) var angle = jline.find("angle", 60)
var speed = jline.find("speed", 1000) var speed = jline.find("speed", 1000)
self._lv_obj = lv.spinner(parent) self._lv_obj = lv.spinner(parent)
self._lv_obj.set_anim_params(speed, angle) self._lv_obj.set_anim_params(speed, angle)
self.post_init() super(self).init(parent, page, jline, self._lv_obj)
end end
def set_angle(t) end def set_angle(t) end
@ -2082,6 +2227,71 @@ class lvh_btnmatrix : lvh_obj
end end
end end
#====================================================================
# cpicker - color picker
#
# OpenHASP maps to LVGL 7 `cpicker`
# However `cpicker` was replaced with `colorwheel` in LVGL 8
# and removed in LVGL 9.
# We have ported back `colorwheel` from LVGL 8 to LVGL 9
#====================================================================
#@ solidify:lvh_cpicker,weak
class lvh_cpicker : lvh_obj
static var _lv_class = lv.colorwheel
static var _CW_MODES = ['hue', 'saturation', 'value']
# we need a non-standard initialization of lvgl object
def init(parent, page, jline, obj, parent_lvh)
obj = lv.colorwheel(parent, true #-knob_recolor = true-#)
super(self).init(parent, page, jline, obj, parent_lvh)
self.set_scale_width(25) # align to OpenHASP default value
end
def set_color(t)
var v = self.parse_color(t)
self._lv_obj.set_rgb(v)
end
def get_color()
var color = self._lv_obj.get_rgb()
return f"#{color:06X}"
end
def set_mode(s)
var mode = self._CW_MODES.find(s)
if (mode != nil)
self._lv_obj.set_mode(mode)
else
raise "value_error", f"unknown color mode '{mode}'"
end
end
def get_mode()
var mode = self._lv_obj.get_color_mode()
if (mode >= 0) && (mode < size(self._CW_MODES))
return self._CW_MODES[mode]
else
return 'unknown'
end
end
def set_mode_fixed(b)
b = bool(b)
self._lv_obj.set_mode_fixed(b)
end
def get_mode_fixed()
return self._lv_obj.get_color_mode_fixed()
end
def set_scale_width(v)
self._lv_obj.set_style_arc_width(int(v), 0)
end
def get_scale_width()
return self._lv_obj.get_style_arc_width(0)
end
# pad_inner is ignored (for now?)
def set_pad_inner() end
def get_pad_inner() end
end
################################################################################# #################################################################################
# #
# All other subclasses than just map the LVGL object # All other subclasses than just map the LVGL object
@ -2292,10 +2502,10 @@ class HASPmota
static lvh_dropdown_list = lvh_dropdown_list static lvh_dropdown_list = lvh_dropdown_list
static lvh_roller = lvh_roller static lvh_roller = lvh_roller
static lvh_btnmatrix = lvh_btnmatrix static lvh_btnmatrix = lvh_btnmatrix
# static lvh_msgbox = lvh_msgbox static lvh_msgbox = lvh_msgbox
# static lvh_tabview = lvh_tabview # static lvh_tabview = lvh_tabview
# static lvh_tab = lvh_tab # static lvh_tab = lvh_tab
# static lvh_cpiker = lvh_cpiker static lvh_cpicker = lvh_cpicker
static lvh_bar = lvh_bar static lvh_bar = lvh_bar
static lvh_slider = lvh_slider static lvh_slider = lvh_slider
static lvh_arc = lvh_arc static lvh_arc = lvh_arc

View File

@ -1239,6 +1239,9 @@
#define BE_LV_WIDGET_TABLE #define BE_LV_WIDGET_TABLE
// #define BE_LV_WIDGET_TEXTAREA // #define BE_LV_WIDGET_TEXTAREA
// adding ad-hoc colorwheel from LVGL8 to LVGL9
#define BE_LV_WIDGET_COLORWHEEL
#define BE_LV_WIDGET_ANIMIMG #define BE_LV_WIDGET_ANIMIMG
#define BE_LV_WIDGET_CHART #define BE_LV_WIDGET_CHART
#define BE_LV_WIDGET_IMGBTN // LVGL 8 #define BE_LV_WIDGET_IMGBTN // LVGL 8