hekate/bdk/libs/lvgl/lv_objx/lv_mbox.c
CTCaer 185526d134 Introducing Bootloader Development Kit (BDK)
BDK will allow developers to use the full collection of drivers,
with limited editing, if any, for making payloads for Nintendo Switch.

Using a single source for everything will also help decoupling
Switch specific code and easily port it to other Tegra X1/X1+ platforms.
And maybe even to lower targets.

Everything is now centrilized into bdk folder.
Every module or project can utilize it by simply including it.

This is just the start and it will continue to improve.
2020-06-14 15:25:21 +03:00

533 lines
15 KiB
C

/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lv_mbox.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_mbox.h"
#if USE_LV_MBOX != 0
#include "../lv_core/lv_group.h"
#include "../lv_themes/lv_theme.h"
#include "../lv_misc/lv_anim.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
*********************/
#if USE_LV_ANIMATION
# ifndef LV_MBOX_CLOSE_ANIM_TIME
# define LV_MBOX_CLOSE_ANIM_TIME 200 /*List close animation time) */
# endif
#else
# undef LV_MBOX_CLOSE_ANIM_TIME
# define LV_MBOX_CLOSE_ANIM_TIME 0 /*No animations*/
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param);
static void mbox_realign(lv_obj_t * mbox);
static lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt);
#if USE_LV_ANIMATION
static void lv_mbox_close_end_cb(lv_obj_t * mbox);
#endif
/**********************
* STATIC VARIABLES
**********************/
static lv_signal_func_t ancestor_signal;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create a message box objects
* @param par pointer to an object, it will be the parent of the new message box
* @param copy pointer to a message box object, if not NULL then the new object will be copied from it
* @return pointer to the created message box
*/
lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy)
{
LV_LOG_TRACE("mesasge box create started");
/*Create the ancestor message box*/
lv_obj_t * new_mbox = lv_cont_create(par, copy);
lv_mem_assert(new_mbox);
if(new_mbox == NULL) return NULL;
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_mbox);
/*Allocate the message box type specific extended data*/
lv_mbox_ext_t * ext = lv_obj_allocate_ext_attr(new_mbox, sizeof(lv_mbox_ext_t));
lv_mem_assert(ext);
if(ext == NULL) return NULL;
ext->text = NULL;
ext->btnm = NULL;
ext->anim_time = LV_MBOX_CLOSE_ANIM_TIME;
/*The signal and design functions are not copied so set them here*/
lv_obj_set_signal_func(new_mbox, lv_mbox_signal);
/*Init the new message box message box*/
if(copy == NULL) {
ext->text = lv_label_create(new_mbox, NULL);
lv_label_set_align(ext->text, LV_LABEL_ALIGN_CENTER);
lv_label_set_long_mode(ext->text, LV_LABEL_LONG_BREAK);
lv_label_set_text(ext->text, "Message");
lv_cont_set_layout(new_mbox, LV_LAYOUT_COL_M);
lv_cont_set_fit(new_mbox, false, true);
lv_obj_set_width(new_mbox, LV_HOR_RES / 2);
lv_obj_align(new_mbox, NULL, LV_ALIGN_CENTER, 0, 0);
/*Set the default styles*/
lv_theme_t * th = lv_theme_get_current();
if(th) {
lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, th->mbox.bg);
} else {
lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, &lv_style_pretty);
}
}
/*Copy an existing message box*/
else {
lv_mbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
ext->text = lv_label_create(new_mbox, copy_ext->text);
/*Copy the buttons and the label on them*/
if(copy_ext->btnm) ext->btnm = lv_btnm_create(new_mbox, copy_ext->btnm);
/*Refresh the style with new signal function*/
lv_obj_refresh_style(new_mbox);
}
LV_LOG_INFO("mesasge box created");
return new_mbox;
}
/*======================
* Add/remove functions
*=====================*/
/**
* Add button to the message box
* @param mbox pointer to message box object
* @param btn_map button descriptor (button matrix map).
* E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable)
* @param action a function which will be called when a button is released
*/
void lv_mbox_add_btns(lv_obj_t * mbox, const char ** btn_map, lv_btnm_action_t action)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
/*Create a button matrix if not exists yet*/
if(ext->btnm == NULL) {
ext->btnm = lv_btnm_create(mbox, NULL);
/*Set the default styles*/
lv_theme_t * th = lv_theme_get_current();
if(th) {
lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_BG, th->mbox.btn.bg);
lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_REL, th->mbox.btn.rel);
lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_PR, th->mbox.btn.pr);
} else {
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, &lv_style_transp_fit);
}
}
lv_btnm_set_map(ext->btnm, btn_map);
if(action == NULL) lv_btnm_set_action(ext->btnm, lv_mbox_close_action); /*Set a default action anyway*/
else lv_btnm_set_action(ext->btnm, action);
mbox_realign(mbox);
}
/*=====================
* Setter functions
*====================*/
/**
* Set the text of the message box
* @param mbox pointer to a message box
* @param txt a '\0' terminated character string which will be the message box text
*/
void lv_mbox_set_text(lv_obj_t * mbox, const char * txt)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
lv_label_set_text(ext->text, txt);
mbox_realign(mbox);
}
/**
* Stop the action to call when button is released
* @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`.
* @param pointer to an 'lv_btnm_action_t' action
*/
void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
lv_btnm_set_action(ext->btnm, action);
}
/**
* Set animation duration
* @param mbox pointer to a message box object
* @param anim_time animation length in milliseconds (0: no animation)
*/
void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
#if USE_LV_ANIMATION == 0
anim_time = 0;
#endif
ext->anim_time = anim_time;
}
/**
* Automatically delete the message box after a given time
* @param mbox pointer to a message box object
* @param delay a time (in milliseconds) to wait before delete the message box
*/
void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay)
{
#if USE_LV_ANIMATION
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
if(ext->anim_time != 0) {
/*Add shrinking animations*/
lv_obj_animate(mbox, LV_ANIM_GROW_H | LV_ANIM_OUT, ext->anim_time, delay, NULL);
lv_obj_animate(mbox, LV_ANIM_GROW_V | LV_ANIM_OUT, ext->anim_time, delay, lv_mbox_close_end_cb);
/*Disable fit to let shrinking work*/
lv_cont_set_fit(mbox, false, false);
} else {
lv_obj_animate(mbox, LV_ANIM_NONE, ext->anim_time, delay, lv_mbox_close_end_cb);
}
#else
(void)delay; /*Unused*/
lv_obj_del(mbox);
#endif
}
/**
* Stop the auto. closing of message box
* @param mbox pointer to a message box object
*/
void lv_mbox_stop_auto_close(lv_obj_t * mbox)
{
#if USE_LV_ANIMATION
lv_anim_del(mbox, NULL);
#else
(void)mbox; /*Unused*/
#endif
}
/**
* Set a style of a message box
* @param mbox pointer to a message box object
* @param type which style should be set
* @param style pointer to a style
*/
void lv_mbox_set_style(lv_obj_t * mbox, lv_mbox_style_t type, lv_style_t * style)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
switch(type) {
case LV_MBOX_STYLE_BG:
lv_obj_set_style(mbox, style);
break;
case LV_MBOX_STYLE_BTN_BG:
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, style);
break;
case LV_MBOX_STYLE_BTN_REL:
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_REL, style);
break;
case LV_MBOX_STYLE_BTN_PR:
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_PR, style);
break;
case LV_MBOX_STYLE_BTN_TGL_REL:
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL, style);
break;
case LV_MBOX_STYLE_BTN_TGL_PR:
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR, style);
break;
case LV_MBOX_STYLE_BTN_INA:
lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_INA, style);
break;
}
mbox_realign(mbox);
}
/**
* Set whether recoloring is enabled
* @param btnm pointer to button matrix object
* @param en whether recoloring is enabled
*/
void lv_mbox_set_recolor(lv_obj_t * mbox, bool en)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
if(ext->btnm)
lv_btnm_set_recolor(ext->btnm, en);
}
void lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
if (ext->text)
lv_label_set_recolor(ext->text, en);
}
/*=====================
* Getter functions
*====================*/
/**
* Get the text of the message box
* @param mbox pointer to a message box object
* @return pointer to the text of the message box
*/
const char * lv_mbox_get_text(const lv_obj_t * mbox)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
return lv_label_get_text(ext->text);
}
/**
* Get the message box object from one of its button.
* It is useful in the button release actions where only the button is known
* @param btn pointer to a button of a message box
* @return pointer to the button's message box
*/
lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn)
{
lv_obj_t * mbox = lv_obj_get_parent(btn);
return mbox;
}
/**
* Get the animation duration (close animation time)
* @param mbox pointer to a message box object
* @return animation length in milliseconds (0: no animation)
*/
uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
return ext->anim_time;
}
/**
* Get a style of a message box
* @param mbox pointer to a message box object
* @param type which style should be get
* @return style pointer to a style
*/
lv_style_t * lv_mbox_get_style(const lv_obj_t * mbox, lv_mbox_style_t type)
{
lv_style_t * style = NULL;
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
switch(type) {
case LV_MBOX_STYLE_BG:
style = lv_obj_get_style(mbox);
break;
case LV_MBOX_STYLE_BTN_BG:
style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BG);
break;
case LV_MBOX_STYLE_BTN_REL:
style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_REL);
break;
case LV_MBOX_STYLE_BTN_PR:
style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_PR);
break;
case LV_MBOX_STYLE_BTN_TGL_REL:
style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL);
break;
case LV_MBOX_STYLE_BTN_TGL_PR:
style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR);
break;
case LV_MBOX_STYLE_BTN_INA:
style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_INA);
break;
default:
style = NULL;
break;
}
return style;
}
/**
* Get whether recoloring is enabled
* @param btnm pointer to button matrix object
* @return whether recoloring is enabled
*/
bool lv_mbox_get_recolor(const lv_obj_t * mbox)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
if(!ext->btnm)
return false;
return lv_btnm_get_recolor(ext->btnm);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Signal function of the message box
* @param mbox pointer to a message box 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_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param)
{
lv_res_t res;
/*Translate LV_GROUP_KEY_UP/DOWN to LV_GROUP_KEY_LEFT/RIGHT */
char c_trans = 0;
if(sign == LV_SIGNAL_CONTROLL) {
c_trans = *((char *)param);
if(c_trans == LV_GROUP_KEY_DOWN) c_trans = LV_GROUP_KEY_LEFT;
if(c_trans == LV_GROUP_KEY_UP) c_trans = LV_GROUP_KEY_RIGHT;
param = &c_trans;
}
/* Include the ancient signal function */
res = ancestor_signal(mbox, sign, param);
if(res != LV_RES_OK) return res;
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
if(sign == LV_SIGNAL_CORD_CHG) {
if(lv_obj_get_width(mbox) != lv_area_get_width(param)) {
mbox_realign(mbox);
}
} else if(sign == LV_SIGNAL_STYLE_CHG) {
mbox_realign(mbox);
} else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS ||
sign == LV_SIGNAL_CONTROLL || sign == LV_SIGNAL_GET_EDITABLE) {
if(ext->btnm) {
ext->btnm->signal_func(ext->btnm, sign, param);
}
/* The button matrix with ENCODER input supposes it's in a group but in this case it isn't (Only the message box's container)
* So so some actions here instead*/
if(sign == LV_SIGNAL_FOCUS) {
#if USE_LV_GROUP
lv_indev_t * indev = lv_indev_get_act();
lv_hal_indev_type_t indev_type = lv_indev_get_type(indev);
if(indev_type == LV_INDEV_TYPE_ENCODER) {
/*In navigation mode don't select any button but in edit mode select the fist*/
lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btnm);
if(lv_group_get_editing(lv_obj_get_group(mbox))) btnm_ext->btn_id_pr = 0;
else btnm_ext->btn_id_pr = LV_BTNM_PR_NONE;
}
#endif
}
} else if(sign == LV_SIGNAL_GET_TYPE) {
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_mbox";
}
return res;
}
/**
* Resize the button holder to fit
* @param mbox pointer to message box object
*/
static void mbox_realign(lv_obj_t * mbox)
{
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
lv_style_t * style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BG);
lv_coord_t w = lv_obj_get_width(mbox) - 2 * style->body.padding.hor;
if(ext->text) {
lv_obj_set_width(ext->text, w);
}
if(ext->btnm) {
lv_style_t * btn_bg_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_BG);
lv_style_t * btn_rel_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_REL);
lv_coord_t font_h = lv_font_get_height(btn_rel_style->text.font);
lv_obj_set_size(ext->btnm, w, font_h + 2 * btn_rel_style->body.padding.ver + 2 * btn_bg_style->body.padding.ver);
}
}
static lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt)
{
lv_obj_t * mbox = lv_mbox_get_from_btn(btn);
if(txt[0] != '\0') {
lv_mbox_start_auto_close(mbox, 0);
return LV_RES_INV;
}
return LV_RES_OK;
}
#if USE_LV_ANIMATION
static void lv_mbox_close_end_cb(lv_obj_t * mbox)
{
lv_obj_del(mbox);
}
#endif
#endif