1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00
lvgl/src/lv_objx/lv_imgbtn.c

449 lines
14 KiB
C
Raw Normal View History

2018-09-06 20:57:59 +02:00
/**
* @file lv_imgbtn.c
*
*/
/*********************
* INCLUDES
*********************/
2019-09-24 16:30:38 +02:00
#include "../lv_core/lv_debug.h"
2018-09-06 20:57:59 +02:00
#include "lv_imgbtn.h"
2019-09-27 04:04:57 +02:00
#include "lv_label.h"
2019-09-24 16:30:38 +02:00
#if LV_USE_IMGBTN != 0
2018-09-06 20:57:59 +02:00
/*********************
* DEFINES
*********************/
#define LV_OBJX_NAME "lv_imgbtn"
2018-09-06 20:57:59 +02:00
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
2019-09-06 19:53:39 +02:00
static lv_design_res_t lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * clip_area, lv_design_mode_t mode);
2018-09-06 20:57:59 +02:00
static lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param);
static void refr_img(lv_obj_t * imgbtn);
/**********************
* STATIC VARIABLES
**********************/
static lv_signal_cb_t ancestor_signal;
static lv_design_cb_t ancestor_design;
2018-09-06 20:57:59 +02:00
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create a image button object
* @param par pointer to an object, it will be the parent of the new image button
2019-04-04 07:15:40 +02:00
* @param copy pointer to a image button object, if not NULL then the new object will be copied from
* it
2018-09-06 20:57:59 +02:00
* @return pointer to the created image button
*/
lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy)
{
2018-10-05 17:22:49 +02:00
LV_LOG_TRACE("image button create started");
2018-09-06 20:57:59 +02:00
/*Create the ancestor of image button*/
lv_obj_t * new_imgbtn = lv_btn_create(par, copy);
2019-09-24 23:14:17 +02:00
LV_ASSERT_MEM(new_imgbtn);
2018-09-06 20:57:59 +02:00
if(new_imgbtn == NULL) return NULL;
/*Allocate the image button type specific extended data*/
lv_imgbtn_ext_t * ext = lv_obj_allocate_ext_attr(new_imgbtn, sizeof(lv_imgbtn_ext_t));
2019-09-24 23:14:17 +02:00
LV_ASSERT_MEM(ext);
if(ext == NULL) {
lv_obj_del(new_imgbtn);
return NULL;
}
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(new_imgbtn);
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(new_imgbtn);
2018-09-06 20:57:59 +02:00
2019-04-04 07:15:40 +02:00
/*Initialize the allocated 'ext' */
2018-11-20 17:05:55 +01:00
#if LV_IMGBTN_TILED == 0
2019-12-02 12:20:01 +01:00
memset((void*)ext->img_src, 0, sizeof(ext->img_src));
2018-11-20 17:05:55 +01:00
#else
memset(ext->img_src_left, 0, sizeof(ext->img_src_left));
memset(ext->img_src_mid, 0, sizeof(ext->img_src_mid));
memset(ext->img_src_right, 0, sizeof(ext->img_src_right));
#endif
ext->act_cf = LV_IMG_CF_UNKNOWN;
2018-09-06 20:57:59 +02:00
/*The signal and design functions are not copied so set them here*/
lv_obj_set_signal_cb(new_imgbtn, lv_imgbtn_signal);
lv_obj_set_design_cb(new_imgbtn, lv_imgbtn_design);
2018-09-06 20:57:59 +02:00
/*Init the new image button image button*/
if(copy == NULL) {
}
/*Copy an existing image button*/
else {
lv_imgbtn_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
2018-11-20 17:05:55 +01:00
#if LV_IMGBTN_TILED == 0
2019-12-05 06:44:11 +01:00
memcpy((void*)ext->img_src, copy_ext->img_src, sizeof(ext->img_src));
2018-11-20 17:05:55 +01:00
#else
2019-12-05 06:44:11 +01:00
memcpy((void*)ext->img_src_left, copy_ext->img_src_left, sizeof(ext->img_src_left));
memcpy((void*)ext->img_src_mid, copy_ext->img_src_mid, sizeof(ext->img_src_mid));
memcpy((void*)ext->img_src_right, copy_ext->img_src_right, sizeof(ext->img_src_right));
2018-11-20 17:05:55 +01:00
#endif
2018-09-06 20:57:59 +02:00
/*Refresh the style with new signal function*/
lv_obj_refresh_style(new_imgbtn);
}
2018-10-05 17:22:49 +02:00
LV_LOG_INFO("image button created");
2018-09-06 20:57:59 +02:00
return new_imgbtn;
}
/*=====================
* Setter functions
*====================*/
2018-11-20 17:05:55 +01:00
#if LV_IMGBTN_TILED == 0
2018-09-06 20:57:59 +02:00
/**
* Set images for a state of the image button
* @param imgbtn pointer to an image button object
* @param state for which state set the new image (from `lv_btn_state_t`) `
* @param src pointer to an image source (a C array or path to a file)
*/
2018-09-20 23:31:07 +02:00
void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src)
2018-09-06 20:57:59 +02:00
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2018-09-06 20:57:59 +02:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
ext->img_src[state] = src;
refr_img(imgbtn);
}
2018-11-20 17:05:55 +01:00
#else
/**
* Set images for a state of the image button
* @param imgbtn pointer to an image button object
* @param state for which state set the new image (from `lv_btn_state_t`) `
2019-04-04 07:15:40 +02:00
* @param src_left pointer to an image source for the left side of the button (a C array or path to
* a file)
* @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C
* array or path to a file)
* @param src_right pointer to an image source for the right side of the button (a C array or path
* to a file)
2018-11-20 17:05:55 +01:00
*/
2019-06-06 06:05:40 +02:00
void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid,
const void * src_right)
2018-11-20 17:05:55 +01:00
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2019-09-27 04:04:57 +02:00
if(lv_img_src_get_type(src_left) == LV_IMG_SRC_SYMBOL ||
lv_img_src_get_type(src_mid) == LV_IMG_SRC_SYMBOL ||
lv_img_src_get_type(src_right) == LV_IMG_SRC_SYMBOL )
{
LV_LOG_WARN("lv_imgbtn_set_src: symbols are not supported in tiled mode");
return;
}
2018-11-20 17:05:55 +01:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
ext->img_src_left[state] = src_left;
ext->img_src_mid[state] = src_mid;
ext->img_src_right[state] = src_right;
refr_img(imgbtn);
}
#endif
2018-09-06 20:57:59 +02:00
/**
* Set a style of a image button.
* @param imgbtn pointer to image button object
* @param type which style should be set
* @param style pointer to a style
*/
2019-04-11 19:59:55 +08:00
void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, const lv_style_t * style)
2018-09-06 20:57:59 +02:00
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2018-09-06 20:57:59 +02:00
lv_btn_set_style(imgbtn, type, style);
}
/*=====================
* Getter functions
*====================*/
2019-01-03 15:57:31 +01:00
#if LV_IMGBTN_TILED == 0
2018-09-06 20:57:59 +02:00
/**
* Get the images in a given state
* @param imgbtn pointer to an image button object
* @param state the state where to get the image (from `lv_btn_state_t`) `
* @return pointer to an image source (a C array or path to a file)
*/
2018-09-23 21:54:55 +02:00
const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state)
2018-09-06 20:57:59 +02:00
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2019-01-03 15:57:31 +01:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
return ext->img_src[state];
}
#else
/**
* Get the left image in a given state
* @param imgbtn pointer to an image button object
* @param state the state where to get the image (from `lv_btn_state_t`) `
* @return pointer to the left image source (a C array or path to a file)
*/
const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state)
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2019-01-03 15:57:31 +01:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
return ext->img_src_left[state];
}
/**
* Get the middle image in a given state
* @param imgbtn pointer to an image button object
* @param state the state where to get the image (from `lv_btn_state_t`) `
* @return pointer to the middle image source (a C array or path to a file)
*/
const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state)
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2019-01-03 15:57:31 +01:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
2019-01-11 16:03:40 +01:00
return ext->img_src_mid[state];
2019-01-03 15:57:31 +01:00
}
/**
* Get the right image in a given state
* @param imgbtn pointer to an image button object
* @param state the state where to get the image (from `lv_btn_state_t`) `
* @return pointer to the left image source (a C array or path to a file)
*/
const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state)
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2019-01-03 15:57:31 +01:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
2018-09-06 20:57:59 +02:00
2019-01-03 15:57:31 +01:00
return ext->img_src_right[state];
2018-09-06 20:57:59 +02:00
}
2019-01-03 15:57:31 +01:00
#endif
2018-09-06 20:57:59 +02:00
/**
* Get style of a image button.
* @param imgbtn pointer to image button object
* @param type which style should be get
* @return style pointer to the style
*/
2019-04-11 19:59:55 +08:00
const lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type)
2018-09-06 20:57:59 +02:00
{
LV_ASSERT_OBJ(imgbtn, LV_OBJX_NAME);
2018-09-06 20:57:59 +02:00
return lv_btn_get_style(imgbtn, type);
}
/*=====================
* Other functions
*====================*/
/*
* New object specific "other" functions come here
*/
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Handle the drawing related tasks of the image buttons
* @param imgbtn pointer to an object
2019-09-06 19:53:39 +02:00
* @param clip_area the object will be drawn only in this area
2018-09-06 20:57:59 +02:00
* @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
2019-09-06 19:53:39 +02:00
* @param return an element of `lv_design_res_t`
2018-09-06 20:57:59 +02:00
*/
2019-09-06 19:53:39 +02:00
static lv_design_res_t lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * clip_area, lv_design_mode_t mode)
2018-09-06 20:57:59 +02:00
{
/*Return false if the object is not covers the mask_p area*/
if(mode == LV_DESIGN_COVER_CHK) {
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
2019-09-06 19:53:39 +02:00
lv_design_res_t cover = LV_DESIGN_RES_NOT_COVER;
if(ext->act_cf == LV_IMG_CF_TRUE_COLOR || ext->act_cf == LV_IMG_CF_RAW) {
2019-09-06 19:53:39 +02:00
cover = lv_area_is_in(clip_area, &imgbtn->coords) ? LV_DESIGN_RES_COVER : LV_DESIGN_RES_NOT_COVER;
2018-09-06 20:57:59 +02:00
}
return cover;
}
/*Draw the object*/
else if(mode == LV_DESIGN_DRAW_MAIN) {
/*Just draw an image*/
2019-04-11 19:59:55 +08:00
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
lv_btn_state_t state = lv_imgbtn_get_state(imgbtn);
const lv_style_t * style = lv_imgbtn_get_style(imgbtn, state);
lv_opa_t opa_scale = lv_obj_get_opa_scale(imgbtn);
2018-11-20 17:05:55 +01:00
#if LV_IMGBTN_TILED == 0
const void * src = ext->img_src[state];
2019-09-27 04:04:57 +02:00
if(lv_img_src_get_type(src) == LV_IMG_SRC_SYMBOL) {
2019-11-15 06:53:15 +01:00
lv_draw_label(&imgbtn->coords, clip_area, style, opa_scale, src, LV_TXT_FLAG_NONE, NULL, NULL, NULL, lv_obj_get_base_dir(imgbtn));
2019-09-27 04:04:57 +02:00
} else {
2019-11-29 11:32:22 +08:00
lv_draw_img(&imgbtn->coords, clip_area, src, style, 0, NULL, LV_IMG_ZOOM_NONE, false, opa_scale);
2019-09-27 04:04:57 +02:00
}
2018-11-20 17:05:55 +01:00
#else
2019-10-30 07:07:31 +01:00
const void * src = ext->img_src_left[state];
2019-09-27 04:04:57 +02:00
if(lv_img_src_get_type(src) == LV_IMG_SRC_SYMBOL) {
LV_LOG_WARN("lv_imgbtn_design: SYMBOLS are not supported in tiled mode")
2019-10-30 06:00:13 +01:00
return LV_DESIGN_RES_OK;
2019-09-27 04:04:57 +02:00
}
2018-11-20 17:05:55 +01:00
lv_img_header_t header;
lv_area_t coords;
lv_coord_t left_w = 0;
lv_coord_t right_w = 0;
if(src) {
2019-05-16 10:27:45 +02:00
lv_img_decoder_get_info(src, &header);
2018-11-20 17:05:55 +01:00
left_w = header.w;
coords.x1 = imgbtn->coords.x1;
coords.y1 = imgbtn->coords.y1;
coords.x2 = coords.x1 + header.w - 1;
coords.y2 = coords.y1 + header.h - 1;
lv_draw_img(&coords, clip_area, src, style, 0, LV_IMG_ZOOM_NONE, false, opa_scale);
2018-11-20 17:05:55 +01:00
}
src = ext->img_src_right[state];
if(src) {
2019-05-16 10:27:45 +02:00
lv_img_decoder_get_info(src, &header);
2018-11-20 17:05:55 +01:00
right_w = header.w;
coords.x1 = imgbtn->coords.x2 - header.w + 1;
coords.y1 = imgbtn->coords.y1;
coords.x2 = imgbtn->coords.x2;
coords.y2 = imgbtn->coords.y1 + header.h - 1;
lv_draw_img(&coords, clip_area, src, style, 0, LV_IMG_ZOOM_NONE, false, opa_scale);
2018-11-20 17:05:55 +01:00
}
src = ext->img_src_mid[state];
if(src) {
2019-11-05 13:39:25 +01:00
lv_area_t clip_center_area;
clip_center_area.x1 = imgbtn->coords.x1 + left_w;
clip_center_area.x2 = imgbtn->coords.x2 - right_w;
clip_center_area.y1 = imgbtn->coords.y1;
clip_center_area.y2 = imgbtn->coords.y2;
bool comm_res;
comm_res = lv_area_intersect(&clip_center_area, &clip_center_area, clip_area);
if(comm_res) {
lv_coord_t obj_w = lv_obj_get_width(imgbtn);
lv_coord_t i;
lv_img_decoder_get_info(src, &header);
coords.x1 = imgbtn->coords.x1 + left_w;
coords.y1 = imgbtn->coords.y1;
coords.x2 = coords.x1 + header.w - 1;
coords.y2 = imgbtn->coords.y1 + header.h - 1;
for(i = 0; i < obj_w - right_w - left_w; i += header.w) {
lv_draw_img(&coords, &clip_center_area, src, style, 0, LV_IMG_ZOOM_NONE, false, opa_scale);
2019-11-05 13:39:25 +01:00
coords.x1 = coords.x2 + 1;
coords.x2 += header.w;
}
}
2018-11-20 17:05:55 +01:00
}
#endif
2018-09-06 20:57:59 +02:00
}
/*Post draw when the children are drawn*/
else if(mode == LV_DESIGN_DRAW_POST) {
}
2019-09-06 19:53:39 +02:00
return LV_DESIGN_RES_OK;
2018-09-06 20:57:59 +02:00
}
/**
* Signal function of the image button
* @param imgbtn pointer to a image button 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
*/
static lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param)
{
lv_res_t res;
/* Include the ancient signal function */
res = ancestor_signal(imgbtn, sign, param);
if(res != LV_RES_OK) return res;
if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
2018-09-06 20:57:59 +02:00
if(sign == LV_SIGNAL_STYLE_CHG) {
2019-04-04 07:15:40 +02:00
/* If the style changed then the button was clicked, released etc. so probably the state was
* changed as well Set the new image for the new state.*/
2018-09-06 20:57:59 +02:00
refr_img(imgbtn);
2018-10-05 17:22:49 +02:00
} else if(sign == LV_SIGNAL_CLEANUP) {
2018-09-06 20:57:59 +02:00
/*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
}
return res;
}
static void refr_img(lv_obj_t * imgbtn)
{
lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);
2019-04-04 07:15:40 +02:00
lv_btn_state_t state = lv_imgbtn_get_state(imgbtn);
2018-09-06 20:57:59 +02:00
lv_img_header_t header;
2018-11-20 17:05:55 +01:00
#if LV_IMGBTN_TILED == 0
2018-09-23 21:54:55 +02:00
const void * src = ext->img_src[state];
2018-11-20 17:05:55 +01:00
#else
const void * src = ext->img_src_mid[state];
#endif
2018-09-06 20:57:59 +02:00
2019-09-27 04:04:57 +02:00
lv_res_t info_res = LV_RES_OK;
if(lv_img_src_get_type(src) == LV_IMG_SRC_SYMBOL) {
const lv_style_t * style = ext->btn.styles[state];
header.h = lv_font_get_line_height(style->text.font);
2019-12-02 12:20:01 +01:00
header.w = lv_txt_get_width(src, (uint16_t)strlen(src), style->text.font, style->text.letter_space, LV_TXT_FLAG_NONE);
2019-09-27 04:04:57 +02:00
header.always_zero = 0;
header.cf = LV_IMG_CF_ALPHA_1BIT;
} else {
info_res = lv_img_decoder_get_info(src, &header);
}
2018-09-06 20:57:59 +02:00
if(info_res == LV_RES_OK) {
ext->act_cf = header.cf;
2018-11-20 17:05:55 +01:00
#if LV_IMGBTN_TILED == 0
2018-09-06 20:57:59 +02:00
lv_obj_set_size(imgbtn, header.w, header.h);
2018-11-20 17:05:55 +01:00
#else
lv_obj_set_height(imgbtn, header.h);
#endif
2018-09-06 20:57:59 +02:00
} else {
ext->act_cf = LV_IMG_CF_UNKNOWN;
2018-09-06 20:57:59 +02:00
}
2019-02-18 05:57:18 +01:00
lv_obj_invalidate(imgbtn);
2018-09-06 20:57:59 +02:00
}
#endif