1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00
lvgl/lv_objx/lv_ddlist.c

727 lines
23 KiB
C
Raw Normal View History

/**
* @file lv_ddlist.c
2018-06-19 09:49:58 +02:00
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_ddlist.h"
#if USE_LV_DDLIST != 0
#include "../lv_draw/lv_draw.h"
2017-11-30 11:35:33 +01:00
#include "../lv_core/lv_group.h"
#include "../lv_core/lv_indev.h"
#include "../lv_themes/lv_theme.h"
#include "../lv_misc/lv_symbol_def.h"
2017-11-23 20:42:14 +01:00
#include "../lv_misc/lv_anim.h"
/*********************
* DEFINES
*********************/
#if USE_LV_ANIMATION
2017-12-20 17:04:08 +01:00
# ifndef LV_DDLIST_ANIM_TIME
2018-06-19 09:49:58 +02:00
# define LV_DDLIST_ANIM_TIME 200 /*ms*/
2017-11-27 17:48:54 +01:00
# endif
#else
2017-12-11 15:42:23 +01:00
# undef LV_DDLIST_ANIM_TIME
2018-06-19 09:49:58 +02:00
# define LV_DDLIST_ANIM_TIME 0 /*No animation*/
2017-11-27 17:48:54 +01:00
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
2017-11-23 21:28:36 +01:00
static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode);
2017-11-16 10:20:30 +01:00
static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param);
static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);
2017-11-10 15:26:35 +01:00
static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist);
static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en);
static void lv_ddlist_pos_current_option(lv_obj_t * ddlist);
/**********************
* STATIC VARIABLES
**********************/
static lv_signal_func_t ancestor_signal;
static lv_signal_func_t ancestor_scrl_signal;
static lv_design_func_t ancestor_design;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* 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);
2017-11-26 11:38:28 +01:00
lv_mem_assert(new_ddlist);
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ddlist);
if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ddlist));
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ddlist);
2018-06-19 09:49:58 +02:00
/*Allocate the drop down list type specific extended data*/
lv_ddlist_ext_t * ext = lv_obj_allocate_ext_attr(new_ddlist, sizeof(lv_ddlist_ext_t));
2017-11-26 11:38:28 +01:00
lv_mem_assert(ext);
/*Initialize the allocated 'ext' */
2017-11-16 10:20:30 +01:00
ext->label = NULL;
ext->action = NULL;
ext->opened = 0;
2017-10-05 11:29:21 +02:00
ext->fix_height = 0;
2017-11-16 10:20:30 +01:00
ext->sel_opt_id = 0;
ext->sel_opt_id_ori = 0;
ext->option_cnt = 0;
2017-12-11 15:42:23 +01:00
ext->anim_time = LV_DDLIST_ANIM_TIME;
2017-11-16 10:20:30 +01:00
ext->sel_style = &lv_style_plain_color;
/*The signal and design functions are not copied so set them here*/
lv_obj_set_signal_func(new_ddlist, lv_ddlist_signal);
lv_obj_set_signal_func(lv_page_get_scrl(new_ddlist), lv_ddlist_scrl_signal);
lv_obj_set_design_func(new_ddlist, lv_ddlist_design);
/*Init the new drop down list drop down list*/
if(copy == NULL) {
lv_obj_t * scrl = lv_page_get_scrl(new_ddlist);
lv_obj_set_drag(scrl, false);
lv_page_set_scrl_fit(new_ddlist, true, true);
2017-02-06 16:05:02 +01:00
2017-11-16 10:20:30 +01:00
ext->label = lv_label_create(new_ddlist, NULL);
2017-04-13 16:12:03 +02:00
lv_cont_set_fit(new_ddlist, true, false);
2017-12-11 23:11:15 +01:00
lv_page_set_rel_action(new_ddlist, lv_ddlist_release_action);
lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_DRAG);
lv_page_set_style(new_ddlist, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight);
2017-11-05 22:37:03 +01:00
lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3");
/*Set the default styles*/
2018-06-19 09:49:58 +02:00
lv_theme_t * th = lv_theme_get_current();
if(th) {
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, th->ddlist.bg);
2018-06-19 09:49:58 +02:00
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, th->ddlist.sel);
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, th->ddlist.sb);
} else {
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, &lv_style_pretty);
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color);
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color);
}
}
/*Copy an existing drop down list*/
else {
2018-06-19 09:49:58 +02:00
lv_ddlist_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
2017-11-16 10:20:30 +01:00
ext->label = lv_label_create(new_ddlist, copy_ext->label);
lv_label_set_text(ext->label, lv_label_get_text(copy_ext->label));
ext->sel_opt_id = copy_ext->sel_opt_id;
2017-10-05 11:29:21 +02:00
ext->fix_height = copy_ext->fix_height;
2017-11-16 10:20:30 +01:00
ext->action = copy_ext->action;
ext->option_cnt = copy_ext->option_cnt;
2017-11-16 10:20:30 +01:00
ext->sel_style = copy_ext->sel_style;
ext->anim_time = copy_ext->anim_time;
2017-02-06 16:05:02 +01:00
/*Refresh the style with new signal function*/
lv_obj_refresh_style(new_ddlist);
}
2018-06-19 09:49:58 +02:00
return new_ddlist;
}
/*=====================
* Setter functions
*====================*/
2017-06-07 12:38:43 +02:00
/**
* Set the options in a drop down list from a string
* @param ddlist pointer to drop down list object
* @param options a string with '\n' separated options. E.g. "One\nTwo\nThree"
*/
2017-11-05 22:37:03 +01:00
void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options)
2017-06-07 12:38:43 +02:00
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
/*Count the '\n'-s to determine the number of options*/
ext->option_cnt = 0;
uint16_t i;
for(i = 0; options[i] != '\0'; i++) {
if(options[i] == '\n') ext->option_cnt++;
}
ext->option_cnt++; /*Last option in the at row*/
2017-11-16 10:20:30 +01:00
lv_label_set_text(ext->label, options);
lv_ddlist_refr_size(ddlist, false);
2017-06-07 12:38:43 +02:00
}
2017-02-06 16:05:02 +01:00
/**
* Set the selected option
* @param ddlist pointer to drop down list object
* @param sel_opt id of the selected option (0 ... number of option - 1);
*/
void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
if(ext->sel_opt_id == sel_opt) return;
2017-02-06 16:05:02 +01:00
2017-11-16 10:20:30 +01:00
ext->sel_opt_id = sel_opt < ext->option_cnt ? sel_opt : ext->option_cnt - 1;
2017-02-06 16:05:02 +01:00
/*Move the list to show the current option*/
if(ext->opened == 0) {
lv_ddlist_pos_current_option(ddlist);
2017-10-05 11:29:21 +02:00
} else {
lv_obj_invalidate(ddlist);
2017-02-06 16:05:02 +01:00
}
}
/**
* Set a function to call when a new option is chosen
2017-02-06 16:05:02 +01:00
* @param ddlist pointer to a drop down list
2017-11-05 22:37:03 +01:00
* @param action pointer to a call back function
*/
void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-11-16 10:20:30 +01:00
ext->action = action;
}
2017-02-06 16:05:02 +01:00
/**
* Set the fix height for the drop down list
2017-10-05 11:29:21 +02:00
* If 0 then the opened ddlist will be auto. sized else the set height will be applied.
2017-02-06 16:05:02 +01:00
* @param ddlist pointer to a drop down list
2017-10-05 11:29:21 +02:00
* @param h the height when the list is opened (0: auto size)
2017-02-06 16:05:02 +01:00
*/
2017-11-23 21:28:36 +01:00
void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h)
2017-02-06 16:05:02 +01:00
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
if(ext->fix_height == h) return;
2017-10-05 11:29:21 +02:00
ext->fix_height = h;
lv_ddlist_refr_size(ddlist, false);
2017-02-06 16:05:02 +01:00
}
/**
* Enable or disable the horizontal fit to the content
* @param ddlist pointer to a drop down list
* @param fit en true: enable auto fit; false: disable auto fit
*/
void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool fit_en)
{
lv_cont_set_fit(ddlist, fit_en, lv_cont_get_ver_fit(ddlist));
lv_page_set_scrl_fit(ddlist, fit_en, lv_page_get_scrl_fit_ver(ddlist));
lv_ddlist_refr_size(ddlist, false);
}
/**
* Set the open/close animation time.
* @param ddlist pointer to a drop down list
* @param anim_time: open/close animation time [ms]
*/
void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
#if USE_LV_ANIMATION == 0
anim_time = 0;
#endif
ext->anim_time = anim_time;
}
/**
* Set a style of a drop down list
* @param ddlist pointer to a drop down list object
* @param type which style should be set
* @param style pointer to a style
*/
2018-06-19 09:49:58 +02:00
void lv_ddlist_set_style(lv_obj_t * ddlist, lv_ddlist_style_t type, lv_style_t * style)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2018-06-19 09:49:58 +02:00
switch(type) {
case LV_DDLIST_STYLE_BG:
lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style);
break;
case LV_DDLIST_STYLE_SB:
lv_page_set_style(ddlist, LV_PAGE_STYLE_SB, style);
break;
2017-11-16 10:20:30 +01:00
case LV_DDLIST_STYLE_SEL:
ext->sel_style = style;
2018-06-19 09:49:58 +02:00
lv_obj_t * scrl = lv_page_get_scrl(ddlist);
lv_obj_refresh_ext_size(scrl); /*Because of the wider selected rectangle*/
break;
}
}
/*=====================
* 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_attr(ddlist);
2017-11-16 10:20:30 +01:00
return lv_label_get_text(ext->label);
}
2017-02-06 16:05:02 +01:00
/**
* Get the selected option
* @param ddlist pointer to drop down list object
* @return id of the selected option (0 ... number of option - 1);
*/
uint16_t lv_ddlist_get_selected(lv_obj_t * ddlist)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-02-06 16:05:02 +01:00
2017-11-16 10:20:30 +01:00
return ext->sel_opt_id;
2017-02-06 16:05:02 +01:00
}
2017-06-07 12:38:43 +02:00
/**
* Get the current selected option as a string
* @param ddlist pointer to ddlist object
* @param buf pointer to an array to store the string
*/
void lv_ddlist_get_selected_str(lv_obj_t * ddlist, char * buf)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-06-07 12:38:43 +02:00
uint16_t i;
uint16_t line = 0;
2017-11-16 10:20:30 +01:00
const char * opt_txt = lv_label_get_text(ext->label);
2017-06-07 12:38:43 +02:00
uint16_t txt_len = strlen(opt_txt);
2018-06-19 09:49:58 +02:00
2017-11-16 10:20:30 +01:00
for(i = 0; i < txt_len && line != ext->sel_opt_id; i++) {
2017-06-07 12:38:43 +02:00
if(opt_txt[i] == '\n') line ++;
}
2018-06-19 09:49:58 +02:00
2017-06-07 12:38:43 +02:00
uint16_t c;
for(c = 0; opt_txt[i] != '\n' && i < txt_len; c++, i++) buf[c] = opt_txt[i];
2018-06-19 09:49:58 +02:00
2017-06-07 12:38:43 +02:00
buf[c] = '\0';
}
2017-11-05 22:37:03 +01:00
/**
* Get the "option selected" callback function
* @param ddlist pointer to a drop down list
* @return pointer to the call back function
*/
lv_action_t lv_ddlist_get_action(lv_obj_t * ddlist)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-11-16 10:20:30 +01:00
return ext->action;
2017-11-05 22:37:03 +01:00
}
2017-02-06 16:05:02 +01:00
/**
2017-10-05 11:29:21 +02:00
* Get the fix height value.
* @param ddlist pointer to a drop down list object
2017-10-05 11:29:21 +02:00
* @return the height if the ddlist is opened (0: auto size)
2017-02-06 16:05:02 +01:00
*/
2017-11-23 21:28:36 +01:00
lv_coord_t lv_ddlist_get_fix_height(lv_obj_t * ddlist)
2017-02-06 16:05:02 +01:00
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-10-05 11:29:21 +02:00
return ext->fix_height;
2017-02-06 16:05:02 +01:00
}
2017-11-10 15:01:40 +01:00
/**
* Get the open/close animation time.
* @param ddlist pointer to a drop down list
* @return open/close animation time [ms]
*/
uint16_t lv_ddlist_get_anim_time(lv_obj_t * ddlist)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
return ext->anim_time;
}
/**
* Get a style of a drop down list
* @param ddlist pointer to a drop down list object
* @param type which style should be get
* @return style pointer to a style
*/
2018-06-19 09:49:58 +02:00
lv_style_t * lv_ddlist_get_style(lv_obj_t * ddlist, lv_ddlist_style_t type)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2018-06-19 09:49:58 +02:00
switch(type) {
case LV_DDLIST_STYLE_BG:
return lv_page_get_style(ddlist, LV_PAGE_STYLE_BG);
case LV_DDLIST_STYLE_SB:
return lv_page_get_style(ddlist, LV_PAGE_STYLE_SB);
case LV_DDLIST_STYLE_SEL:
return ext->sel_style;
default:
return NULL;
}
2017-11-05 22:37:03 +01:00
/*To avoid warning*/
return NULL;
}
2017-11-10 15:01:40 +01:00
/*=====================
* Other functions
*====================*/
/**
2017-11-10 15:01:40 +01:00
* Open the drop down list with or without animation
* @param ddlist pointer to drop down list object
* @param anim_en true: use animation; false: not use animations
*/
void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en)
{
#if USE_LV_ANIMATION == 0
anim_en = false;
#endif
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-11-10 15:01:40 +01:00
ext->opened = 1;
lv_obj_set_drag(lv_page_get_scrl(ddlist), true);
lv_ddlist_refr_size(ddlist, anim_en);
2017-11-10 15:01:40 +01:00
}
/**
* Close (Collapse) the drop down list
* @param ddlist pointer to drop down list object
* @param anim_en true: use animation; false: not use animations
2017-11-10 15:01:40 +01:00
*/
void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en)
2017-11-10 15:01:40 +01:00
{
#if USE_LV_ANIMATION == 0
anim_en = false;
#endif
2017-11-10 15:01:40 +01:00
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
ext->opened = 0;
lv_obj_set_drag(lv_page_get_scrl(ddlist), false);
lv_ddlist_refr_size(ddlist, anim_en);
}
/**********************
* 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'
*/
2017-11-23 21:28:36 +01:00
static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_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) {
2018-06-19 09:49:58 +02:00
return ancestor_design(ddlist, mask, mode);
}
/*Draw the object*/
else if(mode == LV_DESIGN_DRAW_MAIN) {
ancestor_design(ddlist, mask, mode);
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2018-06-14 13:08:19 +02:00
lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist);
2017-11-19 20:45:40 +01:00
/*If the list is opened draw a rectangle under the selected item*/
if(ext->opened != 0) {
2018-06-19 09:49:58 +02:00
lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);
2017-11-23 21:28:36 +01:00
const lv_font_t * font = style->text.font;
2018-02-09 12:40:00 +01:00
lv_coord_t font_h = lv_font_get_height(font);
2017-11-19 20:45:40 +01:00
/*Draw the selected*/
2017-11-23 21:28:36 +01:00
lv_area_t rect_area;
2017-11-16 10:20:30 +01:00
rect_area.y1 = ext->label->coords.y1;
rect_area.y1 += ext->sel_opt_id * (font_h + style->text.line_space);
rect_area.y1 -= style->text.line_space / 2;
rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1;
2017-11-05 22:37:03 +01:00
rect_area.x1 = ddlist->coords.x1;
rect_area.x2 = ddlist->coords.x2;
2018-06-14 13:08:19 +02:00
lv_draw_rect(&rect_area, mask, ext->sel_style, opa_scale);
}
}
/*Post draw when the children are drawn*/
else if(mode == LV_DESIGN_DRAW_POST) {
ancestor_design(ddlist, mask, mode);
2017-12-17 20:11:14 +01:00
/*Redraw the text on the selected area with a different color*/
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2018-06-14 13:08:19 +02:00
lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist);
2017-12-17 20:11:14 +01:00
/*Redraw only in opened state*/
if(ext->opened == 0) return true;
2018-06-19 09:49:58 +02:00
lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);
2017-12-17 20:11:14 +01:00
const lv_font_t * font = style->text.font;
2018-02-09 12:40:00 +01:00
lv_coord_t font_h = lv_font_get_height(font);
2017-12-17 20:11:14 +01:00
lv_area_t area_sel;
area_sel.y1 = ext->label->coords.y1;
area_sel.y1 += ext->sel_opt_id * (font_h + style->text.line_space);
area_sel.y1 -= style->text.line_space / 2;
area_sel.y2 = area_sel.y1 + font_h + style->text.line_space - 1;
2017-12-17 20:11:14 +01:00
area_sel.x1 = ddlist->coords.x1;
area_sel.x2 = ddlist->coords.x2;
lv_area_t mask_sel;
bool area_ok;
area_ok = lv_area_union(&mask_sel, mask, &area_sel);
if(area_ok) {
2018-06-19 09:49:58 +02:00
lv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_SEL);
2017-12-17 20:11:14 +01:00
lv_style_t new_style;
lv_style_copy(&new_style, style);
new_style.text.color = sel_style->text.color;
new_style.text.opa = sel_style->text.opa;
2018-06-14 13:08:19 +02:00
lv_draw_label(&ext->label->coords, &mask_sel, &new_style, opa_scale,
2017-12-17 20:11:14 +01:00
lv_label_get_text(ext->label), LV_TXT_FLAG_NONE, NULL);
}
}
return true;
}
/**
* 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 LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
*/
2017-11-16 10:20:30 +01:00
static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param)
{
lv_res_t res;
/* Include the ancient signal function */
res = ancestor_signal(ddlist, sign, param);
if(res != LV_RES_OK) return res;
2017-12-03 00:35:39 +01:00
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
if(sign == LV_SIGNAL_STYLE_CHG) {
lv_ddlist_refr_size(ddlist, 0);
2018-06-19 09:49:58 +02:00
} else if(sign == LV_SIGNAL_CLEANUP) {
2017-12-03 00:35:39 +01:00
ext->label = NULL;
2018-06-19 09:49:58 +02:00
} else if(sign == LV_SIGNAL_FOCUS) {
if(ext->opened == false) {
ext->opened = true;
lv_ddlist_refr_size(ddlist, true);
ext->sel_opt_id_ori = ext->sel_opt_id;
}
2018-06-19 09:49:58 +02:00
} else if(sign == LV_SIGNAL_DEFOCUS) {
if(ext->opened != false) {
ext->opened = false;
ext->sel_opt_id = ext->sel_opt_id_ori;
lv_ddlist_refr_size(ddlist, true);
}
2018-06-19 09:49:58 +02:00
} else if(sign == LV_SIGNAL_CONTROLL) {
char c = *((char *)param);
if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) {
if(!ext->opened) {
ext->opened = 1;
lv_ddlist_refr_size(ddlist, true);
}
if(ext->sel_opt_id + 1 < ext->option_cnt) {
2017-11-16 10:20:30 +01:00
ext->sel_opt_id ++;
lv_ddlist_pos_current_option(ddlist);
lv_obj_invalidate(ddlist);
}
} else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) {
if(!ext->opened) {
ext->opened = 1;
lv_ddlist_refr_size(ddlist, true);
}
2017-11-16 10:20:30 +01:00
if(ext->sel_opt_id > 0) {
ext->sel_opt_id --;
lv_ddlist_pos_current_option(ddlist);
lv_obj_invalidate(ddlist);
}
} else if(c == LV_GROUP_KEY_ENTER) {
if(ext->opened) {
ext->sel_opt_id_ori = ext->sel_opt_id;
ext->opened = 0;
if(ext->action) ext->action(ddlist);
2018-06-19 09:49:58 +02:00
} else {
ext->opened = 1;
}
lv_ddlist_refr_size(ddlist, true);
2018-06-19 09:49:58 +02:00
} else if(c == LV_GROUP_KEY_ESC) {
if(ext->opened) {
ext->opened = 0;
lv_ddlist_refr_size(ddlist, true);
}
}
2018-06-19 09:49:58 +02:00
} else if(sign == LV_SIGNAL_GET_TYPE) {
2018-02-28 15:37:41 +01:00
lv_obj_type_t * buf = param;
uint8_t i;
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
if(buf->type[i] == NULL) break;
}
buf->type[i] = "lv_ddlist";
}
return res;
}
/**
* Signal function of the drop down list's scrollable part
* @param scrl pointer to a drop down list's scrollable part
* @param sign a signal type from lv_signal_t enum
* @param param pointer to a signal specific variable
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
*/
static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param)
{
lv_res_t res;
/* Include the ancient signal function */
res = ancestor_scrl_signal(scrl, sign, param);
if(res != LV_RES_OK) return res;
2018-06-19 09:49:58 +02:00
lv_obj_t * ddlist = lv_obj_get_parent(scrl);
2017-12-03 00:35:39 +01:00
if(sign == LV_SIGNAL_REFR_EXT_SIZE) {
/* Because of the wider selected rectangle ext. size
* In this way by dragging the scrollable part the wider rectangle area can be redrawn too*/
2018-06-19 09:49:58 +02:00
lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);
if(scrl->ext_size < style->body.padding.hor) scrl->ext_size = style->body.padding.hor;
2018-06-19 09:49:58 +02:00
} else if(sign == LV_SIGNAL_CLEANUP) {
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
2017-12-03 00:35:39 +01:00
ext->label = NULL; /*The label is already deleted*/
}
return res;
}
/**
* Called when a drop down list is released to open it or set new option
* @param ddlist pointer to a drop down list object
* @return LV_ACTION_RES_INV if the ddlist it deleted in the user callback else LV_ACTION_RES_OK
*/
2017-11-10 15:26:35 +01:00
static lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(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;
2017-02-06 16:05:02 +01:00
lv_obj_set_drag(lv_page_get_scrl(ddlist), false);
/*Search the clicked option*/
2018-06-19 09:49:58 +02:00
lv_indev_t * indev = lv_indev_get_act();
2017-11-23 21:28:36 +01:00
lv_point_t p;
2017-10-09 15:21:26 +02:00
lv_indev_get_point(indev, &p);
2017-11-16 10:20:30 +01:00
p.x -= ext->label->coords.x1;
p.y -= ext->label->coords.y1;
uint16_t letter_i;
2017-11-16 10:20:30 +01:00
letter_i = lv_label_get_letter_on(ext->label, &p);
uint16_t new_opt = 0;
2017-11-16 10:20:30 +01:00
const char * txt = lv_label_get_text(ext->label);
uint32_t i = 0;
uint32_t line_cnt = 0;
uint32_t letter;
for(line_cnt = 0; line_cnt < letter_i; line_cnt++) {
letter = lv_txt_utf8_next(txt, &i);
if(letter == '\n') new_opt ++;
}
2017-11-16 10:20:30 +01:00
ext->sel_opt_id = new_opt;
2017-11-16 10:20:30 +01:00
if(ext->action != NULL) {
ext->action(ddlist);
}
}
lv_ddlist_refr_size(ddlist, true);
return LV_RES_OK;
}
/**
2017-10-05 11:29:21 +02:00
* Refresh the size of drop down list according to its status (open or closed)
* @param ddlist pointer to a drop down list object
* @param anim_en Change the size (open/close) with or without animation (true/false)
*/
static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en)
{
#if USE_LV_ANIMATION == 0
anim_en = false;
#endif
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
lv_style_t * style = lv_obj_get_style(ddlist);
2017-11-23 21:28:36 +01:00
lv_coord_t new_height;
2017-10-05 11:29:21 +02:00
if(ext->opened) { /*Open the list*/
if(ext->fix_height == 0) new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver;
2017-10-05 11:29:21 +02:00
else new_height = ext->fix_height;
} else { /*Close the list*/
2017-11-23 21:28:36 +01:00
const lv_font_t * font = style->text.font;
2017-11-16 10:20:30 +01:00
lv_style_t * label_style = lv_obj_get_style(ext->label);
2018-02-09 12:40:00 +01:00
lv_coord_t font_h = lv_font_get_height(font);
new_height = font_h + 2 * label_style->text.line_space;
}
if(anim_en == 0) {
lv_obj_set_height(ddlist, new_height);
lv_ddlist_pos_current_option(ddlist);
#if USE_LV_ANIMATION
lv_anim_del(ddlist, (lv_anim_fp_t)lv_obj_set_height); /*If an animation is in progress then it will overwrite this changes*/
} else {
2017-11-23 21:28:36 +01:00
lv_anim_t a;
a.var = ddlist;
a.start = lv_obj_get_height(ddlist);
a.end = new_height;
2017-11-23 21:28:36 +01:00
a.fp = (lv_anim_fp_t)lv_obj_set_height;
2017-12-17 01:54:09 +01:00
a.path = lv_anim_path_linear;
2017-11-23 21:28:36 +01:00
a.end_cb = (lv_anim_cb_t)lv_ddlist_pos_current_option;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
2017-11-23 21:28:36 +01:00
lv_anim_create(&a);
2017-11-27 17:48:54 +01:00
#endif
}
}
/**
* 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_current_option(lv_obj_t * ddlist)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
lv_style_t * style = lv_obj_get_style(ddlist);
2017-11-23 21:28:36 +01:00
const lv_font_t * font = style->text.font;
2018-02-09 12:40:00 +01:00
lv_coord_t font_h = lv_font_get_height(font);
2017-11-16 10:20:30 +01:00
lv_style_t * label_style = lv_obj_get_style(ext->label);
lv_obj_t * scrl = lv_page_get_scrl(ddlist);
2017-11-23 21:28:36 +01:00
lv_coord_t h = lv_obj_get_height(ddlist);
lv_coord_t line_y1 = ext->sel_opt_id * (font_h + label_style->text.line_space) + ext->label->coords.y1 - scrl->coords.y1;
2017-10-05 11:29:21 +02:00
lv_obj_set_y(scrl, - line_y1 + (h - font_h) / 2);
}
#endif