feat(btnmatrix/keyboard): add option to show popovers on button press (#2537)
This adds a new option that, when enabled, shows popovers when pressing buttons, similar to how the system keyboards on Android and iOS behave.
This commit is contained in:
@@ -13,10 +13,13 @@
|
||||
#include "../../../widgets/lv_textarea.h"
|
||||
#include "../../../misc/lv_assert.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS &lv_keyboard_class
|
||||
#define LV_KB_BTN(width) LV_BTNMATRIX_CTRL_POPOVER | width
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -29,6 +32,8 @@ static void lv_keyboard_constructor(const lv_obj_class_t * class_p, lv_obj_t * o
|
||||
|
||||
static void lv_keyboard_update_map(lv_obj_t * obj);
|
||||
|
||||
static void lv_keyboard_update_ctrl_map(lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
@@ -48,9 +53,9 @@ static const char * const default_kb_map_lc[] = {"1#", "q", "w", "e", "r", "t",
|
||||
};
|
||||
|
||||
static const lv_btnmatrix_ctrl_t default_kb_ctrl_lc_map[] = {
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_BTNMATRIX_CTRL_CHECKED | 1, LV_BTNMATRIX_CTRL_CHECKED | 1, 1, 1, 1, 1, 1, 1, 1, LV_BTNMATRIX_CTRL_CHECKED | 1, LV_BTNMATRIX_CTRL_CHECKED | 1, LV_BTNMATRIX_CTRL_CHECKED | 1,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 5, LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 6, LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1),
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 2, LV_BTNMATRIX_CTRL_CHECKED | 2, 6, LV_BTNMATRIX_CTRL_CHECKED | 2, LV_KEYBOARD_CTRL_BTN_FLAGS | 2
|
||||
};
|
||||
|
||||
@@ -61,9 +66,9 @@ static const char * const default_kb_map_uc[] = {"1#", "Q", "W", "E", "R", "T",
|
||||
};
|
||||
|
||||
static const lv_btnmatrix_ctrl_t default_kb_ctrl_uc_map[] = {
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_BTNMATRIX_CTRL_CHECKED | 1, LV_BTNMATRIX_CTRL_CHECKED | 1, 1, 1, 1, 1, 1, 1, 1, LV_BTNMATRIX_CTRL_CHECKED | 1, LV_BTNMATRIX_CTRL_CHECKED | 1, LV_BTNMATRIX_CTRL_CHECKED | 1,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 5, LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 6, LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_KB_BTN(3), LV_BTNMATRIX_CTRL_CHECKED | 7,
|
||||
LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | LV_KB_BTN(1),
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 2, LV_BTNMATRIX_CTRL_CHECKED | 2, 6, LV_BTNMATRIX_CTRL_CHECKED | 2, LV_KEYBOARD_CTRL_BTN_FLAGS | 2
|
||||
};
|
||||
|
||||
@@ -74,9 +79,9 @@ static const char * const default_kb_map_spec[] = {"1", "2", "3", "4", "5", "6",
|
||||
};
|
||||
|
||||
static const lv_btnmatrix_ctrl_t default_kb_ctrl_spec_map[] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, LV_BTNMATRIX_CTRL_CHECKED | 2,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_BTNMATRIX_CTRL_CHECKED | 2,
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 2, LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1),
|
||||
LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1), LV_KB_BTN(1),
|
||||
LV_KEYBOARD_CTRL_BTN_FLAGS | 2, LV_BTNMATRIX_CTRL_CHECKED | 2, 6, LV_BTNMATRIX_CTRL_CHECKED | 2, LV_KEYBOARD_CTRL_BTN_FLAGS | 2
|
||||
};
|
||||
|
||||
@@ -172,8 +177,24 @@ void lv_keyboard_set_mode(lv_obj_t * obj, lv_keyboard_mode_t mode)
|
||||
if(keyboard->mode == mode) return;
|
||||
|
||||
keyboard->mode = mode;
|
||||
lv_btnmatrix_set_map(obj, kb_map[mode]);
|
||||
lv_btnmatrix_set_ctrl_map(obj, kb_ctrl[mode]);
|
||||
lv_keyboard_update_map(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the button title in a popover when pressed.
|
||||
* @param kb pointer to a Keyboard object
|
||||
* @param en whether "popovers" mode is enabled
|
||||
*/
|
||||
void lv_keyboard_set_popovers(lv_obj_t * obj, bool en)
|
||||
{
|
||||
lv_keyboard_t * keyboard = (lv_keyboard_t *)obj;
|
||||
|
||||
if (keyboard->popovers == en) {
|
||||
return;
|
||||
}
|
||||
|
||||
keyboard->popovers = en;
|
||||
lv_keyboard_update_ctrl_map(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,6 +240,17 @@ lv_keyboard_mode_t lv_keyboard_get_mode(const lv_obj_t * obj)
|
||||
return keyboard->mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether "popovers" mode is enabled or not.
|
||||
* @param kb pointer to a Keyboard object
|
||||
* @return true: "popovers" mode is enabled; false: disabled
|
||||
*/
|
||||
bool lv_btnmatrix_get_popovers(const lv_obj_t * obj)
|
||||
{
|
||||
lv_keyboard_t * keyboard = (lv_keyboard_t *)obj;
|
||||
return keyboard->popovers;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
@@ -338,24 +370,52 @@ static void lv_keyboard_constructor(const lv_obj_class_t * class_p, lv_obj_t * o
|
||||
lv_keyboard_t * keyboard = (lv_keyboard_t *)obj;
|
||||
keyboard->ta = NULL;
|
||||
keyboard->mode = LV_KEYBOARD_MODE_TEXT_LOWER;
|
||||
keyboard->popovers = 0;
|
||||
|
||||
lv_obj_align(obj, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_add_event_cb(obj, lv_keyboard_def_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
lv_obj_set_style_base_dir(obj, LV_BASE_DIR_LTR, 0);
|
||||
|
||||
lv_btnmatrix_set_map(obj, kb_map[keyboard->mode]);
|
||||
lv_btnmatrix_set_ctrl_map(obj, kb_ctrl[keyboard->mode]);
|
||||
lv_keyboard_update_map(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the key map for the current mode
|
||||
* @param kb pointer to a keyboard object
|
||||
* Update the key and control map for the current mode
|
||||
* @param obj pointer to a keyboard object
|
||||
*/
|
||||
static void lv_keyboard_update_map(lv_obj_t * obj)
|
||||
{
|
||||
lv_keyboard_t * keyboard = (lv_keyboard_t *)obj;
|
||||
lv_btnmatrix_set_map(obj, kb_map[keyboard->mode]);
|
||||
lv_btnmatrix_set_ctrl_map(obj, kb_ctrl[keyboard->mode]);
|
||||
lv_keyboard_update_ctrl_map(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the control map for the current mode
|
||||
* @param obj pointer to a keyboard object
|
||||
*/
|
||||
static void lv_keyboard_update_ctrl_map(lv_obj_t * obj)
|
||||
{
|
||||
lv_keyboard_t * keyboard = (lv_keyboard_t *)obj;
|
||||
|
||||
if (keyboard->popovers) {
|
||||
/*Apply the current control map (already includes LV_BTNMATRIX_CTRL_POPOVER flags)*/
|
||||
lv_btnmatrix_set_ctrl_map(obj, kb_ctrl[keyboard->mode]);
|
||||
} else {
|
||||
/*Make a copy of the current control map*/
|
||||
lv_btnmatrix_t * btnm = (lv_btnmatrix_t *)obj;
|
||||
lv_btnmatrix_ctrl_t * ctrl_map = malloc(btnm->btn_cnt * sizeof(lv_btnmatrix_ctrl_t));
|
||||
lv_memcpy(ctrl_map, kb_ctrl[keyboard->mode], sizeof(lv_btnmatrix_ctrl_t) * btnm->btn_cnt);
|
||||
|
||||
/*Remove all LV_BTNMATRIX_CTRL_POPOVER flags*/
|
||||
for(uint16_t i = 0; i < btnm->btn_cnt; i++) {
|
||||
ctrl_map[i] &= (~LV_BTNMATRIX_CTRL_POPOVER);
|
||||
}
|
||||
|
||||
/*Apply new control map and clean up*/
|
||||
lv_btnmatrix_set_ctrl_map(obj, ctrl_map);
|
||||
free(ctrl_map);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_USE_KEYBOARD*/
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct {
|
||||
lv_btnmatrix_t btnm;
|
||||
lv_obj_t * ta; /*Pointer to the assigned text area*/
|
||||
lv_keyboard_mode_t mode; /*Key map type*/
|
||||
uint8_t popovers : 1; /*Show button titles in popovers on press*/
|
||||
} lv_keyboard_t;
|
||||
|
||||
extern const lv_obj_class_t lv_keyboard_class;
|
||||
@@ -82,6 +83,13 @@ void lv_keyboard_set_textarea(lv_obj_t * kb, lv_obj_t * ta);
|
||||
*/
|
||||
void lv_keyboard_set_mode(lv_obj_t * kb, lv_keyboard_mode_t mode);
|
||||
|
||||
/**
|
||||
* Show the button title in a popover when pressed.
|
||||
* @param kb pointer to a Keyboard object
|
||||
* @param en whether "popovers" mode is enabled
|
||||
*/
|
||||
void lv_keyboard_set_popovers(lv_obj_t * kb, bool en);
|
||||
|
||||
/**
|
||||
* Set a new map for the keyboard
|
||||
* @param kb pointer to a Keyboard object
|
||||
@@ -110,6 +118,13 @@ lv_obj_t * lv_keyboard_get_textarea(const lv_obj_t * kb);
|
||||
*/
|
||||
lv_keyboard_mode_t lv_keyboard_get_mode(const lv_obj_t * kb);
|
||||
|
||||
/**
|
||||
* Tell whether "popovers" mode is enabled or not.
|
||||
* @param kb pointer to a Keyboard object
|
||||
* @return true: "popovers" mode is enabled; false: disabled
|
||||
*/
|
||||
bool lv_btnmatrix_get_popovers(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the current map of a keyboard
|
||||
* @param kb pointer to a keyboard object
|
||||
|
||||
@@ -43,6 +43,7 @@ static bool button_is_checked(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_is_repeat_disabled(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_is_inactive(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_is_click_trig(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_is_popover(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_is_checkable(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_is_recolor(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
static bool button_get_checked(lv_btnmatrix_ctrl_t ctrl_bits);
|
||||
@@ -51,6 +52,7 @@ static uint16_t get_button_from_point(lv_obj_t * obj, lv_point_t * p);
|
||||
static void allocate_btn_areas_and_controls(const lv_obj_t * obj, const char ** map);
|
||||
static void invalidate_button_area(const lv_obj_t * obj, uint16_t btn_idx);
|
||||
static void make_one_button_checked(lv_obj_t * obj, uint16_t btn_idx);
|
||||
static bool has_popovers_in_top_row(lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -111,15 +113,8 @@ void lv_btnmatrix_set_map(lv_obj_t * obj, const char * map[])
|
||||
lv_coord_t max_w = lv_obj_get_content_width(obj);
|
||||
lv_coord_t max_h = lv_obj_get_content_height(obj);
|
||||
|
||||
/*Count the lines to calculate button height*/
|
||||
uint8_t row_cnt = 1;
|
||||
uint32_t i;
|
||||
for(i = 0; map[i] && map[i][0] != '\0'; i++) {
|
||||
if(strcmp(map[i], "\n") == 0) row_cnt++;
|
||||
}
|
||||
|
||||
/*Calculate the position of each row*/
|
||||
lv_coord_t max_h_no_gap = max_h - (prow * (row_cnt - 1));
|
||||
lv_coord_t max_h_no_gap = max_h - (prow * (btnm->row_cnt - 1));
|
||||
|
||||
/*Count the units and the buttons in a line
|
||||
*(A button can be 1,2,3... unit wide)*/
|
||||
@@ -129,7 +124,7 @@ void lv_btnmatrix_set_map(lv_obj_t * obj, const char * map[])
|
||||
|
||||
/*Count the units and the buttons in a line*/
|
||||
uint32_t row;
|
||||
for(row = 0; row < row_cnt; row++) {
|
||||
for(row = 0; row < btnm->row_cnt; row++) {
|
||||
uint16_t unit_cnt = 0; /*Number of units in a row*/
|
||||
uint16_t btn_cnt = 0; /*Number of buttons in a row*/
|
||||
/*Count the buttons and units in this row*/
|
||||
@@ -144,8 +139,8 @@ void lv_btnmatrix_set_map(lv_obj_t * obj, const char * map[])
|
||||
continue;
|
||||
}
|
||||
|
||||
lv_coord_t row_y1 = ptop + (max_h_no_gap * row) / row_cnt + row * prow;
|
||||
lv_coord_t row_y2 = ptop + (max_h_no_gap * (row + 1)) / row_cnt + row * prow - 1;
|
||||
lv_coord_t row_y1 = ptop + (max_h_no_gap * row) / btnm->row_cnt + row * prow;
|
||||
lv_coord_t row_y2 = ptop + (max_h_no_gap * (row + 1)) / btnm->row_cnt + row * prow - 1;
|
||||
|
||||
/*Set the button size and positions*/
|
||||
lv_coord_t max_w_no_gap = max_w - (pcol * (btn_cnt - 1));
|
||||
@@ -180,6 +175,10 @@ void lv_btnmatrix_set_map(lv_obj_t * obj, const char * map[])
|
||||
map_row = &map_row[btn_cnt + 1]; /*Set the map to the next line*/
|
||||
}
|
||||
|
||||
/*Popovers in the top row will draw outside the widget and the extended draw size depends on
|
||||
*the row height which may have changed when setting the new map*/
|
||||
lv_obj_refresh_ext_draw_size(obj);
|
||||
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
@@ -220,9 +219,13 @@ void lv_btnmatrix_set_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctr
|
||||
|
||||
btnm->ctrl_bits[btn_id] |= ctrl;
|
||||
invalidate_button_area(obj, btn_id);
|
||||
|
||||
if (ctrl & LV_BTNMATRIX_CTRL_POPOVER) {
|
||||
lv_obj_refresh_ext_draw_size(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_btnmatrix_clear_btn_ctrl(const lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl)
|
||||
void lv_btnmatrix_clear_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
@@ -232,6 +235,10 @@ void lv_btnmatrix_clear_btn_ctrl(const lv_obj_t * obj, uint16_t btn_id, lv_btnma
|
||||
|
||||
btnm->ctrl_bits[btn_id] &= (~ctrl);
|
||||
invalidate_button_area(obj, btn_id);
|
||||
|
||||
if (ctrl & LV_BTNMATRIX_CTRL_POPOVER) {
|
||||
lv_obj_refresh_ext_draw_size(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_btnmatrix_set_btn_ctrl_all(lv_obj_t * obj, lv_btnmatrix_ctrl_t ctrl)
|
||||
@@ -353,6 +360,7 @@ static void lv_btnmatrix_constructor(const lv_obj_class_t * class_p, lv_obj_t *
|
||||
LV_TRACE_OBJ_CREATE("begin");
|
||||
lv_btnmatrix_t * btnm = (lv_btnmatrix_t *)obj;
|
||||
btnm->btn_cnt = 0;
|
||||
btnm->row_cnt = 0;
|
||||
btnm->btn_id_sel = LV_BTNMATRIX_BTN_NONE;
|
||||
btnm->button_areas = NULL;
|
||||
btnm->ctrl_bits = NULL;
|
||||
@@ -391,6 +399,15 @@ static void lv_btnmatrix_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
lv_btnmatrix_t * btnm = (lv_btnmatrix_t *)obj;
|
||||
lv_point_t p;
|
||||
|
||||
if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
|
||||
lv_coord_t * s = lv_event_get_param(e);
|
||||
if (has_popovers_in_top_row(obj)) {
|
||||
/*reserve one row worth of extra space to account for popovers in the top row*/
|
||||
*s = btnm->row_cnt > 0 ? lv_obj_get_content_height(obj) / btnm->row_cnt : 0;
|
||||
} else {
|
||||
*s = 0;
|
||||
}
|
||||
}
|
||||
if(code == LV_EVENT_STYLE_CHANGED) {
|
||||
lv_btnmatrix_set_map(obj, btnm->map_p);
|
||||
}
|
||||
@@ -419,6 +436,7 @@ static void lv_btnmatrix_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
|
||||
if(btnm->btn_id_sel != LV_BTNMATRIX_BTN_NONE) {
|
||||
if(button_is_click_trig(btnm->ctrl_bits[btnm->btn_id_sel]) == false &&
|
||||
button_is_popover(btnm->ctrl_bits[btnm->btn_id_sel]) == false &&
|
||||
button_is_inactive(btnm->ctrl_bits[btnm->btn_id_sel]) == false &&
|
||||
button_is_hidden(btnm->ctrl_bits[btnm->btn_id_sel]) == false) {
|
||||
uint32_t b = btnm->btn_id_sel;
|
||||
@@ -451,7 +469,8 @@ static void lv_btnmatrix_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
button_is_hidden(btnm->ctrl_bits[btn_pr]) == false) {
|
||||
invalidate_button_area(obj, btn_pr);
|
||||
/*Send VALUE_CHANGED for the newly pressed button*/
|
||||
if(button_is_click_trig(btnm->ctrl_bits[btn_pr]) == false) {
|
||||
if(button_is_click_trig(btnm->ctrl_bits[btn_pr]) == false &&
|
||||
button_is_popover(btnm->ctrl_bits[btnm->btn_id_sel]) == false) {
|
||||
uint32_t b = btn_pr;
|
||||
res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, &b);
|
||||
if(res != LV_RES_OK) return;
|
||||
@@ -474,7 +493,8 @@ static void lv_btnmatrix_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
}
|
||||
|
||||
|
||||
if(button_is_click_trig(btnm->ctrl_bits[btnm->btn_id_sel]) == true &&
|
||||
if((button_is_click_trig(btnm->ctrl_bits[btnm->btn_id_sel]) == true ||
|
||||
button_is_popover(btnm->ctrl_bits[btnm->btn_id_sel]) == true) &&
|
||||
button_is_inactive(btnm->ctrl_bits[btnm->btn_id_sel]) == false &&
|
||||
button_is_hidden(btnm->ctrl_bits[btnm->btn_id_sel]) == false) {
|
||||
uint32_t b = btnm->btn_id_sel;
|
||||
@@ -744,6 +764,13 @@ static void draw_main(lv_event_t * e)
|
||||
if(btn_area.y2 == obj->coords.y2 - pbottom) draw_rect_dsc_act.border_side &= ~LV_BORDER_SIDE_BOTTOM;
|
||||
}
|
||||
|
||||
lv_coord_t btn_height = lv_area_get_height(&btn_area);
|
||||
|
||||
if ((btn_state & LV_STATE_PRESSED) && (btnm->ctrl_bits[btn_i] & LV_BTNMATRIX_CTRL_POPOVER)) {
|
||||
/*Push up the upper boundary of the btn area to create the popover*/
|
||||
btn_area.y1 -= btn_height;
|
||||
}
|
||||
|
||||
/*Draw the background*/
|
||||
lv_draw_rect(&btn_area, clip_area, &draw_rect_dsc_act);
|
||||
|
||||
@@ -770,6 +797,12 @@ static void draw_main(lv_event_t * e)
|
||||
btn_area.x2 = btn_area.x1 + txt_size.x;
|
||||
btn_area.y2 = btn_area.y1 + txt_size.y;
|
||||
|
||||
if ((btn_state & LV_STATE_PRESSED) && (btnm->ctrl_bits[btn_i] & LV_BTNMATRIX_CTRL_POPOVER)) {
|
||||
/*Push up the button text into the popover*/
|
||||
btn_area.y1 -= btn_height / 2;
|
||||
btn_area.y2 -= btn_height / 2;
|
||||
}
|
||||
|
||||
/*Draw the text*/
|
||||
lv_draw_label(&btn_area, clip_area, &draw_label_dsc_act, txt, NULL);
|
||||
|
||||
@@ -790,10 +823,13 @@ static void allocate_btn_areas_and_controls(const lv_obj_t * obj, const char **
|
||||
{
|
||||
/*Count the buttons in the map*/
|
||||
uint16_t btn_cnt = 0;
|
||||
uint16_t row_cnt = 1;
|
||||
uint16_t i = 0;
|
||||
while(map[i] && map[i][0] != '\0') {
|
||||
if(strcmp(map[i], "\n") != 0) { /*Do not count line breaks*/
|
||||
btn_cnt++;
|
||||
} else {
|
||||
row_cnt++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -821,6 +857,7 @@ static void allocate_btn_areas_and_controls(const lv_obj_t * obj, const char **
|
||||
lv_memset_00(btnm->ctrl_bits, sizeof(lv_btnmatrix_ctrl_t) * btn_cnt);
|
||||
|
||||
btnm->btn_cnt = btn_cnt;
|
||||
btnm->row_cnt = row_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -859,6 +896,11 @@ static bool button_is_click_trig(lv_btnmatrix_ctrl_t ctrl_bits)
|
||||
return (ctrl_bits & LV_BTNMATRIX_CTRL_CLICK_TRIG) ? true : false;
|
||||
}
|
||||
|
||||
static bool button_is_popover(lv_btnmatrix_ctrl_t ctrl_bits)
|
||||
{
|
||||
return (ctrl_bits & LV_BTNMATRIX_CTRL_POPOVER) ? true : false;
|
||||
}
|
||||
|
||||
static bool button_is_checkable(lv_btnmatrix_ctrl_t ctrl_bits)
|
||||
{
|
||||
return (ctrl_bits & LV_BTNMATRIX_CTRL_CHECKABLE) ? true : false;
|
||||
@@ -959,6 +1001,11 @@ static void invalidate_button_area(const lv_obj_t * obj, uint16_t btn_idx)
|
||||
btn_area.x2 += obj_area.x1 + row_gap;
|
||||
btn_area.y2 += obj_area.y1 + col_gap;
|
||||
|
||||
if ((btn_idx == btnm->btn_id_sel) && (btnm->ctrl_bits[btn_idx] & LV_BTNMATRIX_CTRL_POPOVER)) {
|
||||
/*Push up the upper boundary of the btn area to also invalidate the popover*/
|
||||
btn_area.y1 -= lv_area_get_height(&btn_area);
|
||||
}
|
||||
|
||||
lv_obj_invalidate_area(obj, &btn_area);
|
||||
}
|
||||
|
||||
@@ -978,4 +1025,30 @@ static void make_one_button_checked(lv_obj_t * obj, uint16_t btn_idx)
|
||||
if(was_toggled) lv_btnmatrix_set_btn_ctrl(obj, btn_idx, LV_BTNMATRIX_CTRL_CHECKED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any of the buttons in the first row has the LV_BTNMATRIX_CTRL_POPOVER control flag set.
|
||||
* @param obj Button matrix object
|
||||
* @return true if at least one button has the flag, false otherwise
|
||||
*/
|
||||
static bool has_popovers_in_top_row(lv_obj_t * obj)
|
||||
{
|
||||
lv_btnmatrix_t * btnm = (lv_btnmatrix_t *)obj;
|
||||
|
||||
if (btnm->row_cnt <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char ** map_row = btnm->map_p;
|
||||
uint16_t btn_cnt = 0;
|
||||
|
||||
while (map_row[btn_cnt] && strcmp(map_row[btn_cnt], "\n") != 0 && map_row[btn_cnt][0] != '\0') {
|
||||
if (button_is_popover(btnm->ctrl_bits[btn_cnt])) {
|
||||
return true;
|
||||
}
|
||||
btn_cnt++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@ enum {
|
||||
LV_BTNMATRIX_CTRL_CHECKABLE = 0x0040, /**< The button can be toggled.*/
|
||||
LV_BTNMATRIX_CTRL_CHECKED = 0x0080, /**< Button is currently toggled (e.g. checked).*/
|
||||
LV_BTNMATRIX_CTRL_CLICK_TRIG = 0x0100, /**< 1: Send LV_EVENT_VALUE_CHANGE on CLICK, 0: Send LV_EVENT_VALUE_CHANGE on PRESS*/
|
||||
LV_BTNMATRIX_CTRL_POPOVER = 0x0200, /**< Show a popover when pressing this key*/
|
||||
LV_BTNMATRIX_CTRL_RECOLOR = 0x1000, /**< Enable text recoloring with `#color`*/
|
||||
_LV_BTNMATRIX_CTRL_RESERVED = 0x2000, /**< Reserved for later use*/
|
||||
LV_BTNMATRIX_CTRL_CUSTOM_1 = 0x4000, /**< Custom free to use flag*/
|
||||
@@ -57,6 +58,7 @@ typedef struct {
|
||||
lv_area_t * button_areas; /*Array of areas of buttons*/
|
||||
lv_btnmatrix_ctrl_t * ctrl_bits; /*Array of control bytes*/
|
||||
uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/
|
||||
uint16_t row_cnt; /*Number of rows in 'map_p'(Handled by the library)*/
|
||||
uint16_t btn_id_sel; /*Index of the active button (being pressed/released etc) or LV_BTNMATRIX_BTN_NONE*/
|
||||
uint8_t one_check : 1; /*Single button toggled at once*/
|
||||
} lv_btnmatrix_t;
|
||||
@@ -130,7 +132,7 @@ void lv_btnmatrix_set_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctr
|
||||
* @param btn_id 0 based index of the button to modify. (Not counting new lines)
|
||||
* @param ctrl OR-ed attributs. E.g. `LV_BTNMATRIX_CTRL_NO_REPEAT | LV_BTNMATRIX_CTRL_CHECKABLE`
|
||||
*/
|
||||
void lv_btnmatrix_clear_btn_ctrl(const lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl);
|
||||
void lv_btnmatrix_clear_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl);
|
||||
|
||||
/**
|
||||
* Set attributes of all buttons of a button matrix
|
||||
@@ -210,7 +212,6 @@ bool lv_btnmatrix_has_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctr
|
||||
*/
|
||||
bool lv_btnmatrix_get_one_checked(const lv_obj_t * obj);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
Reference in New Issue
Block a user