lv_ddlist: drop down list new object type added
This commit is contained in:
410
lv_objx/lv_ddlist.c
Normal file
410
lv_objx/lv_ddlist.c
Normal file
@@ -0,0 +1,410 @@
|
||||
/**
|
||||
* @file lv_ddlist.c
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_conf.h"
|
||||
#if USE_LV_DDLIST != 0
|
||||
|
||||
#include "lv_ddlist.h"
|
||||
#include "../lv_draw/lv_draw.h"
|
||||
#include "../lv_misc/anim.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool lv_ddlist_design(lv_obj_t * ddlist, const area_t * mask, lv_design_mode_t mode);
|
||||
static lv_action_res_t lv_ddlist_rel_action(lv_obj_t * ddlist, lv_dispi_t * dispi);
|
||||
static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en);
|
||||
static void lv_ddlist_pos_act_option(lv_obj_t * ddlist);
|
||||
static void lv_ddlists_init(void);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_ddlists_t lv_ddlists_def; /*Default drop down list style*/
|
||||
static lv_design_f_t ancestor_design_f;
|
||||
static const char * def_options[] = {"Option 1", "Option 2", "Option 3", ""};
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/*-----------------
|
||||
* Create function
|
||||
*-----------------*/
|
||||
|
||||
/**
|
||||
* Create a drop down list objects
|
||||
* @param par pointer to an object, it will be the parent of the new drop down list
|
||||
* @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created drop down list
|
||||
*/
|
||||
lv_obj_t * lv_ddlist_create(lv_obj_t * par, lv_obj_t * copy)
|
||||
{
|
||||
/*Create the ancestor drop down list*/
|
||||
lv_obj_t * new_ddlist = lv_page_create(par, copy);
|
||||
dm_assert(new_ddlist);
|
||||
|
||||
/*Allocate the drop down list type specific extended data*/
|
||||
lv_ddlist_ext_t * ext = lv_obj_alloc_ext(new_ddlist, sizeof(lv_ddlist_ext_t));
|
||||
dm_assert(ext);
|
||||
|
||||
/*Initialize the allocated 'ext' */
|
||||
ext->opt_label = NULL;
|
||||
ext->cb = NULL;
|
||||
ext->opened = 0;
|
||||
ext->act_opt = 0;
|
||||
|
||||
/*The signal and design functions are not copied so set them here*/
|
||||
if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_f(new_ddlist);
|
||||
|
||||
lv_obj_set_signal_f(new_ddlist, lv_ddlist_signal);
|
||||
lv_obj_set_design_f(new_ddlist, lv_ddlist_design);
|
||||
|
||||
/*Init the new drop down list drop down list*/
|
||||
if(copy == NULL) {
|
||||
ext->opt_label = lv_label_create(new_ddlist, NULL);
|
||||
lv_rect_set_fit(new_ddlist, true, false);
|
||||
lv_page_set_rel_action(new_ddlist, lv_ddlist_rel_action);
|
||||
lv_obj_set_style(new_ddlist, lv_ddlists_get(LV_DDLISTS_DEF, NULL));
|
||||
lv_ddlist_set_options(new_ddlist, def_options);
|
||||
}
|
||||
/*Copy an existing drop down list*/
|
||||
else {
|
||||
lv_ddlist_ext_t * copy_ext = lv_obj_get_ext(copy);
|
||||
ext->opt_label = lv_label_create(new_ddlist, copy_ext->opt_label);
|
||||
lv_label_set_text(ext->opt_label, lv_label_get_text(copy_ext->opt_label));
|
||||
/*Refresh the style with new signal function*/
|
||||
lv_obj_refr_style(new_ddlist);
|
||||
}
|
||||
|
||||
return new_ddlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the drop down list
|
||||
* @param ddlist pointer to a drop down list object
|
||||
* @param sign a signal type from lv_signal_t enum
|
||||
* @param param pointer to a signal specific variable
|
||||
* @return true: the object is still valid (not deleted), false: the object become invalid
|
||||
*/
|
||||
bool lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param)
|
||||
{
|
||||
bool valid;
|
||||
|
||||
/* Include the ancient signal function */
|
||||
valid = lv_page_signal(ddlist, sign, param);
|
||||
|
||||
/* The object can be deleted so check its validity and then
|
||||
* make the object specific signal handling */
|
||||
if(valid != false) {
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
lv_ddlists_t * style = lv_obj_get_style(ddlist);
|
||||
|
||||
switch(sign) {
|
||||
case LV_SIGNAL_CLEANUP:
|
||||
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
|
||||
break;
|
||||
case LV_SIGNAL_STYLE_CHG:
|
||||
lv_obj_set_style(ext->opt_label, &style->list_labels);
|
||||
lv_ddlist_refr_size(ddlist, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set the options in a drop down list
|
||||
* @param ddlist pointer to drop down list object
|
||||
* @param options an array of strings wit the text of the options.
|
||||
* The lest element has to be "" (empty string)
|
||||
* E.g. const char * opts[] = {"apple", "banana", "orange", ""};
|
||||
*/
|
||||
void lv_ddlist_set_options(lv_obj_t * ddlist, const char ** options)
|
||||
{
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
|
||||
lv_label_set_text(ext->opt_label, "");
|
||||
uint16_t i = 0;
|
||||
while(options[i][0] != '\0') {
|
||||
lv_label_append_text(ext->opt_label, options[i]);
|
||||
if(options[i + 1][0] != '\0') lv_label_append_text(ext->opt_label, "\n");
|
||||
i++;
|
||||
}
|
||||
|
||||
lv_ddlist_refr_size(ddlist, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a function to call when a new option is chosen
|
||||
* @param ddlist pointer to drop down list
|
||||
* @param cb pointer to a call back function. Its prototype is:
|
||||
* parameter 1: pointer to the drop down list
|
||||
* parameter 2: id of the chosen item (0 ... number of options - 1)
|
||||
* return LV_ACTION_RES_INV if the drop down list is deleted in the function else LV_ACTION_RES_OK
|
||||
*/
|
||||
void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_res_t (*cb)(lv_obj_t *, uint16_t))
|
||||
{
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
ext->cb = cb;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the options of a drop down list
|
||||
* @param ddlist pointer to drop down list object
|
||||
* @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3")
|
||||
*/
|
||||
const char * lv_ddlist_get_options(lv_obj_t * ddlist)
|
||||
{
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
return lv_label_get_text(ext->opt_label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with a pointer to a built-in style and/or copy it to a variable
|
||||
* @param style a style name from lv_ddlists_builtin_t enum
|
||||
* @param copy copy the style to this variable. (NULL if unused)
|
||||
* @return pointer to an lv_ddlists_t style
|
||||
*/
|
||||
lv_ddlists_t * lv_ddlists_get(lv_ddlists_builtin_t style, lv_ddlists_t * copy)
|
||||
{
|
||||
static bool style_inited = false;
|
||||
|
||||
/*Make the style initialization if it is not done yet*/
|
||||
if(style_inited == false) {
|
||||
lv_ddlists_init();
|
||||
style_inited = true;
|
||||
}
|
||||
|
||||
lv_ddlists_t *style_p;
|
||||
|
||||
switch(style) {
|
||||
case LV_DDLISTS_DEF:
|
||||
style_p = &lv_ddlists_def;
|
||||
break;
|
||||
default:
|
||||
style_p = &lv_ddlists_def;
|
||||
}
|
||||
|
||||
if(copy != NULL) {
|
||||
if(style_p != NULL) memcpy(copy, style_p, sizeof(lv_ddlists_t));
|
||||
else memcpy(copy, &lv_ddlists_def, sizeof(lv_ddlists_t));
|
||||
}
|
||||
|
||||
return style_p;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Handle the drawing related tasks of the drop down lists
|
||||
* @param ddlist pointer to an object
|
||||
* @param mask the object will be drawn only in this area
|
||||
* @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
|
||||
* (return 'true' if yes)
|
||||
* LV_DESIGN_DRAW: draw the object (always return 'true')
|
||||
* LV_DESIGN_DRAW_POST: drawing after every children are drawn
|
||||
* @param return true/false, depends on 'mode'
|
||||
*/
|
||||
static bool lv_ddlist_design(lv_obj_t * ddlist, const area_t * mask, lv_design_mode_t mode)
|
||||
{
|
||||
/*Return false if the object is not covers the mask_p area*/
|
||||
if(mode == LV_DESIGN_COVER_CHK) {
|
||||
return ancestor_design_f(ddlist, mask, mode);
|
||||
}
|
||||
/*Draw the object*/
|
||||
else if(mode == LV_DESIGN_DRAW_MAIN) {
|
||||
ancestor_design_f(ddlist, mask, mode);
|
||||
|
||||
/*If the list is opened draw a rectangle below the selected item*/
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
if(ext->opened != 0) {
|
||||
lv_ddlists_t * style = lv_obj_get_style(ddlist);
|
||||
const font_t * font = font_get(style->list_labels.font);
|
||||
area_t rect_area;
|
||||
rect_area.y1 = ext->opt_label->cords.y1;
|
||||
rect_area.y1 += ext->act_opt * (font_get_height(font) + style->list_labels.line_space);
|
||||
rect_area.y1 -= style->sel_rects.vpad;
|
||||
|
||||
rect_area.y2 = rect_area.y1 + font_get_height(font) + 2 * style->sel_rects.vpad;
|
||||
rect_area.x1 = ext->opt_label->cords.x1 - style->pages.scrl_rects.hpad;
|
||||
rect_area.x2 = rect_area.x1 + lv_obj_get_width(lv_page_get_scrl(ddlist));
|
||||
|
||||
lv_draw_rect(&rect_area, mask, &style->sel_rects, OPA_COVER);
|
||||
}
|
||||
}
|
||||
/*Post draw when the children are drawn*/
|
||||
else if(mode == LV_DESIGN_DRAW_POST) {
|
||||
ancestor_design_f(ddlist, mask, mode);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a drop down list is released to open it or set new option
|
||||
* @param ddlist pointer to a drop down list object
|
||||
* @param dispi pointer to the called display input
|
||||
* @return LV_ACTION_RES_INV if the ddlist it deleted in the user callback else LV_ACTION_RES_OK
|
||||
*/
|
||||
static lv_action_res_t lv_ddlist_rel_action(lv_obj_t * ddlist, lv_dispi_t * dispi)
|
||||
{
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
|
||||
if(ext->opened == 0) { /*Open the list*/
|
||||
ext->opened = 1;
|
||||
lv_obj_set_drag(lv_page_get_scrl(ddlist), true);
|
||||
} else {
|
||||
ext->opened = 0;
|
||||
/*Search the clicked option*/
|
||||
point_t p;
|
||||
lv_dispi_get_point(dispi, &p);
|
||||
p.x -= ext->opt_label->cords.x1;
|
||||
p.y -= ext->opt_label->cords.y1;
|
||||
uint16_t letter_i;
|
||||
letter_i = lv_label_get_letter_on(ext->opt_label, &p);
|
||||
|
||||
uint16_t new_opt = 0;
|
||||
const char * txt = lv_label_get_text(ext->opt_label);
|
||||
uint16_t i;
|
||||
for(i = 0; i < letter_i; i++) {
|
||||
if(txt[i] == '\n') new_opt ++;
|
||||
}
|
||||
|
||||
ext->act_opt = new_opt;
|
||||
|
||||
if(ext->cb != NULL) {
|
||||
ext->cb(ddlist, ext->act_opt);
|
||||
}
|
||||
}
|
||||
#if LV_DDLIST_ANIM_TIME == 0
|
||||
lv_ddlist_refr_size(ddlist, false);
|
||||
#else
|
||||
lv_ddlist_refr_size(ddlist, true);
|
||||
#endif
|
||||
|
||||
return LV_ACTION_RES_OK;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the size of drop down list according its start (open or closed)
|
||||
* @param ddlist poinr to a drop down list object
|
||||
* @param anim_en true: refresh the size with an animation, false: do not use animations
|
||||
*/
|
||||
static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en)
|
||||
{
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
lv_ddlists_t * style = lv_obj_get_style(ddlist);
|
||||
cord_t new_height;
|
||||
if(ext->opened != 0) { /*Open the list*/
|
||||
new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->pages.bg_rects.vpad;
|
||||
lv_obj_t * parent = lv_obj_get_parent(ddlist);
|
||||
if(new_height + ddlist->cords.y1 > parent->cords.y2) {
|
||||
new_height = parent->cords.y2 - ddlist->cords.y1;
|
||||
}
|
||||
} else { /*Close the list*/
|
||||
const font_t * font = font_get(style->list_labels.font);
|
||||
new_height = font_get_height(font) + 2 * style->sel_rects.vpad;
|
||||
}
|
||||
if(anim_en == false) {
|
||||
lv_obj_set_height(ddlist, new_height);
|
||||
lv_ddlist_pos_act_option(ddlist);
|
||||
} else {
|
||||
anim_t a;
|
||||
a.var = ddlist;
|
||||
a.start = lv_obj_get_height(ddlist);
|
||||
a.end = new_height;
|
||||
a.fp = (anim_fp_t)lv_obj_set_height;
|
||||
a.path = anim_get_path(ANIM_PATH_LIN);
|
||||
a.end_cb = (anim_cb_t)lv_ddlist_pos_act_option;
|
||||
a.act_time = 0;
|
||||
a.time = LV_DDLIST_ANIM_TIME;
|
||||
a.playback = 0;
|
||||
a.playback_pause = 0;
|
||||
a.repeat = 0;
|
||||
a.repeat_pause = 0;
|
||||
|
||||
anim_create(&a);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the position of list when it is closed to show the selected item
|
||||
* @param ddlist pointer to a drop down list
|
||||
*/
|
||||
static void lv_ddlist_pos_act_option(lv_obj_t * ddlist)
|
||||
{
|
||||
lv_ddlist_ext_t * ext = lv_obj_get_ext(ddlist);
|
||||
lv_ddlists_t * style = lv_obj_get_style(ddlist);
|
||||
const font_t * font = font_get(style->list_labels.font);
|
||||
|
||||
lv_obj_set_y(lv_page_get_scrl(ddlist),
|
||||
-(ext->act_opt * (font_get_height(font) + style->list_labels.line_space) +
|
||||
style->pages.scrl_rects.vpad) + style->sel_rects.vpad);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the built-in drop down list styles
|
||||
*/
|
||||
static void lv_ddlists_init(void)
|
||||
{
|
||||
/*Default style*/
|
||||
lv_pages_get(LV_PAGES_SIMPLE, &lv_ddlists_def.pages);
|
||||
lv_ddlists_def.pages.bg_rects.objs.color = COLOR_WHITE;
|
||||
lv_ddlists_def.pages.bg_rects.gcolor = COLOR_SILVER;
|
||||
lv_ddlists_def.pages.bg_rects.bcolor = COLOR_GRAY;
|
||||
|
||||
lv_ddlists_def.pages.bg_rects.hpad = 0 * LV_DOWNSCALE;
|
||||
lv_ddlists_def.pages.bg_rects.vpad = 0 * LV_DOWNSCALE;
|
||||
lv_ddlists_def.pages.bg_rects.opad = 0;
|
||||
|
||||
lv_ddlists_def.pages.scrl_rects.hpad = 5 * LV_DOWNSCALE;
|
||||
lv_ddlists_def.pages.scrl_rects.vpad = 5 * LV_DOWNSCALE;
|
||||
lv_ddlists_def.pages.scrl_rects.opad = 0 * LV_DOWNSCALE;
|
||||
|
||||
lv_ddlists_def.pages.sb_mode = LV_PAGE_SB_MODE_OFF;
|
||||
|
||||
lv_labels_get(LV_LABELS_DEF, &lv_ddlists_def.list_labels);
|
||||
lv_ddlists_def.list_labels.line_space = 15 * LV_DOWNSCALE;
|
||||
|
||||
lv_rects_get(LV_RECTS_DEF, &lv_ddlists_def.sel_rects);
|
||||
lv_ddlists_def.sel_rects.bwidth = 0;
|
||||
lv_ddlists_def.sel_rects.round = 0;
|
||||
lv_ddlists_def.sel_rects.vpad = 5 * LV_DOWNSCALE;
|
||||
}
|
||||
|
||||
#endif
|
||||
113
lv_objx/lv_ddlist.h
Normal file
113
lv_objx/lv_ddlist.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file lv_ddlist.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DDLIST_H
|
||||
#define LV_DDLIST_H
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_conf.h"
|
||||
#if USE_LV_DDLIST != 0
|
||||
|
||||
#include "../lv_obj/lv_obj.h"
|
||||
#include "../lv_objx/lv_page.h"
|
||||
#include "../lv_objx/lv_label.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
/*Data of drop down list*/
|
||||
typedef struct
|
||||
{
|
||||
lv_page_ext_t page; /*Ext. of ancestor*/
|
||||
/*New data for this type */
|
||||
lv_obj_t * opt_label; /*Label for the options*/
|
||||
lv_action_res_t (*cb)(lv_obj_t *, uint16_t);
|
||||
uint16_t act_opt;
|
||||
uint8_t opened :1;
|
||||
}lv_ddlist_ext_t;
|
||||
|
||||
/*Style of drop down list*/
|
||||
typedef struct
|
||||
{
|
||||
lv_pages_t pages; /*Style of ancestor*/
|
||||
/*New style element for this type */
|
||||
lv_rects_t sel_rects;
|
||||
lv_labels_t list_labels;
|
||||
}lv_ddlists_t;
|
||||
|
||||
/*Built-in styles of drop down list*/
|
||||
typedef enum
|
||||
{
|
||||
LV_DDLISTS_DEF,
|
||||
}lv_ddlists_builtin_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a drop down list objects
|
||||
* @param par pointer to an object, it will be the parent of the new drop down list
|
||||
* @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it
|
||||
* @return pointer to the created drop down list
|
||||
*/
|
||||
lv_obj_t * lv_ddlist_create(lv_obj_t * par, lv_obj_t * copy);
|
||||
|
||||
/**
|
||||
* Signal function of the drop down list
|
||||
* @param ddlist pointer to a drop down list object
|
||||
* @param sign a signal type from lv_signal_t enum
|
||||
* @param param pointer to a signal specific variable
|
||||
* @return true: the object is still valid (not deleted), false: the object become invalid
|
||||
*/
|
||||
bool lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param);
|
||||
|
||||
/**
|
||||
* Set the options in a drop down list
|
||||
* @param ddlist pointer to drop down list object
|
||||
* @param options an array of strings wit the text of the options.
|
||||
* The lest element has to be "" (empty string)
|
||||
* E.g. const char * opts[] = {"apple", "banana", "orange", ""};
|
||||
*/
|
||||
void lv_ddlist_set_options(lv_obj_t * ddlist, const char ** options);
|
||||
|
||||
/**
|
||||
* Set a function to call when a new option is chosen
|
||||
* @param ddlist pointer to drop down list
|
||||
* @param cb pointer to a call back function. Its prototype is:
|
||||
* parameter 1: pointer to the drop down list
|
||||
* parameter 2: id of the chosen item (0 ... number of options - 1)
|
||||
* return LV_ACTION_RES_INV if the drop down list is deleted in the function else LV_ACTION_RES_OK
|
||||
*/
|
||||
void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_res_t (*cb)(lv_obj_t *, uint16_t));
|
||||
|
||||
/**
|
||||
* Get the options of a drop down list
|
||||
* @param ddlist pointer to drop down list object
|
||||
* @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3")
|
||||
*/
|
||||
const char * lv_ddlist_get_options(lv_obj_t * ddlist);
|
||||
|
||||
/**
|
||||
* Return with a pointer to a built-in style and/or copy it to a variable
|
||||
* @param style a style name from lv_ddlists_builtin_t enum
|
||||
* @param copy copy the style to this variable. (NULL if unused)
|
||||
* @return pointer to an lv_ddlists_t style
|
||||
*/
|
||||
lv_ddlists_t * lv_ddlists_get(lv_ddlists_builtin_t style, lv_ddlists_t * copy);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user