hekate/bdk/libs/lvgl/lv_objx/lv_win.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

592 lines
18 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_win.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_win.h"
#if USE_LV_WIN != 0
#include "../lv_themes/lv_theme.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param);
static void lv_win_realign(lv_obj_t * win);
/**********************
* STATIC VARIABLES
**********************/
static lv_signal_func_t ancestor_signal;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create a window objects
* @param par pointer to an object, it will be the parent of the new window
* @param copy pointer to a window object, if not NULL then the new object will be copied from it
* @return pointer to the created window
*/
lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy)
{
LV_LOG_TRACE("window create started");
/*Create the ancestor object*/
lv_obj_t * new_win = lv_obj_create(par, copy);
lv_mem_assert(new_win);
if(new_win == NULL) return NULL;
if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_win);
/*Allocate the object type specific extended data*/
lv_win_ext_t * ext = lv_obj_allocate_ext_attr(new_win, sizeof(lv_win_ext_t));
lv_mem_assert(ext);
if(ext == NULL) return NULL;
ext->page = NULL;
ext->header = NULL;
ext->title = NULL;
ext->style_header = &lv_style_plain_color;
ext->style_btn_rel = &lv_style_btn_rel;
ext->style_btn_pr = &lv_style_btn_pr;
ext->btn_size = (LV_DPI) / 2;
/*Init the new window object*/
if(copy == NULL) {
lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES);
lv_obj_set_pos(new_win, 0, 0);
lv_obj_set_style(new_win, &lv_style_pretty);
ext->page = lv_page_create(new_win, NULL);
lv_obj_set_protect(ext->page, LV_PROTECT_PARENT);
lv_page_set_sb_mode(ext->page, LV_SB_MODE_AUTO);
lv_page_set_arrow_scroll(ext->page, true);
/*Create a holder for the header*/
ext->header = lv_obj_create(new_win, NULL);
/*Move back the header because it is automatically moved to the scrollable */
lv_obj_set_protect(ext->header, LV_PROTECT_PARENT);
lv_obj_set_parent(ext->header, new_win);
lv_obj_set_width(ext->header, LV_HOR_RES - 62);////
ext->btn_size = lv_obj_get_height(ext->header) - 3;////
/*Create a title on the header*/
ext->title = lv_label_create(ext->header, NULL);
lv_label_set_text(ext->title, "My title");
/*Set the default styles*/
lv_theme_t * th = lv_theme_get_current();
if(th) {
lv_win_set_style(new_win, LV_WIN_STYLE_BG, th->win.bg);
lv_win_set_style(new_win, LV_WIN_STYLE_SB, th->win.sb);
lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, th->win.header);
lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, th->win.content.bg);
lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, th->win.content.scrl);
lv_win_set_style(new_win, LV_WIN_STYLE_BTN_REL, th->win.btn.rel);
lv_win_set_style(new_win, LV_WIN_STYLE_BTN_PR, th->win.btn.pr);
} else {
lv_win_set_style(new_win, LV_WIN_STYLE_BG, &lv_style_plain);
lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, &lv_style_plain);
lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, &lv_style_transp);
lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, &lv_style_plain_color);
}
lv_obj_set_signal_func(new_win, lv_win_signal);
lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES);
}
/*Copy an existing object*/
else {
lv_win_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
/*Create the objects*/
ext->header = lv_obj_create(new_win, copy_ext->header);
ext->title = lv_label_create(ext->header, copy_ext->title);
ext->page = lv_page_create(new_win, copy_ext->page);
ext->btn_size = copy_ext->btn_size;
/*Copy the control buttons*/
lv_obj_t * child;
lv_obj_t * cbtn;
child = lv_obj_get_child_back(copy_ext->header, NULL);
child = lv_obj_get_child_back(copy_ext->header, child); /*Sip the title*/
while(child != NULL) {
cbtn = lv_btn_create(ext->header, child);
lv_img_create(cbtn, lv_obj_get_child(child, NULL));
child = lv_obj_get_child_back(copy_ext->header, child);
}
lv_obj_set_signal_func(new_win, lv_win_signal);
/*Refresh the style with new signal function*/
lv_obj_refresh_style(new_win);
}
lv_win_realign(new_win);
LV_LOG_INFO("window created");
return new_win;
}
/**
* Delete all children of the scrl object, without deleting scrl child.
* @param obj pointer to an object
*/
void lv_win_clean(lv_obj_t * obj)
{
lv_obj_t * scrl = lv_page_get_scrl(obj);
lv_obj_clean(scrl);
}
/*======================
* Add/remove functions
*=====================*/
/**
* Add control button to the header of the window
* @param win pointer to a window object
* @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
* @param rel_action a function pointer to call when the button is released
* @return pointer to the created button object
*/
lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_obj_t * btn = lv_btn_create(ext->header, NULL);
lv_btn_set_style(btn, LV_BTN_STYLE_REL, ext->style_btn_rel);
lv_btn_set_style(btn, LV_BTN_STYLE_PR, ext->style_btn_pr);
lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size);
lv_btn_set_fit(btn, true, false);
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, rel_action);
if (img_src)
{
lv_obj_t * img = lv_img_create(btn, NULL);
lv_obj_set_click(img, false);
lv_img_set_src(img, img_src);
}
else if (label_src)
{
lv_obj_t *label = lv_label_create(btn, NULL);
lv_label_set_recolor(label, true);
lv_label_set_text(label, label_src);
}
lv_win_realign(win);
return btn;
}
/*=====================
* Setter functions
*====================*/
/**
* A release action which can be assigned to a window control button to close it
* @param btn pointer to the released button
* @return always LV_ACTION_RES_INV because the button is deleted with the window
*/
lv_res_t lv_win_close_action(lv_obj_t * btn)
{
lv_obj_t * win = lv_win_get_from_btn(btn);
lv_obj_del(win);
return LV_RES_INV;
}
/**
* Set the title of a window
* @param win pointer to a window object
* @param title string of the new title
*/
void lv_win_set_title(lv_obj_t * win, const char * title)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_label_set_text(ext->title, title);
lv_win_realign(win);
}
/**
* Set the control button size of a window
* @param win pointer to a window object
* @param size control button size
*/
void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
if(ext->btn_size == size) return;
ext->btn_size = size;
lv_win_realign(win);
}
/**
* Set the layout of the window
* @param win pointer to a window object
* @param layout the layout from 'lv_layout_t'
*/
void lv_win_set_layout(lv_obj_t * win, lv_layout_t layout)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_page_set_scrl_layout(ext->page, layout);
}
/**
* Set the scroll bar mode of a window
* @param win pointer to a window object
* @param sb_mode the new scroll bar mode from 'lv_sb_mode_t'
*/
void lv_win_set_sb_mode(lv_obj_t * win, lv_sb_mode_t sb_mode)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_page_set_sb_mode(ext->page, sb_mode);
}
/**
* Set a style of a window
* @param win pointer to a window object
* @param type which style should be set
* @param style pointer to a style
*/
void lv_win_set_style(lv_obj_t * win, lv_win_style_t type, lv_style_t * style)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
switch(type) {
case LV_WIN_STYLE_BG:
lv_obj_set_style(win, style);
lv_win_realign(win);
break;
case LV_WIN_STYLE_CONTENT_BG:
lv_page_set_style(ext->page, LV_PAGE_STYLE_BG, style);
break;
case LV_WIN_STYLE_CONTENT_SCRL:
lv_page_set_style(ext->page, LV_PAGE_STYLE_SCRL, style);
break;
case LV_WIN_STYLE_SB:
lv_page_set_style(ext->page, LV_PAGE_STYLE_SB, style);
break;
case LV_WIN_STYLE_HEADER:
lv_obj_set_style(ext->header, style);
lv_win_realign(win);
break;
case LV_WIN_STYLE_BTN_REL:
ext->style_btn_rel = style;
break;
case LV_WIN_STYLE_BTN_PR:
ext->style_btn_pr = style;
break;
}
/*Refresh the existing buttons*/
if(type == LV_WIN_STYLE_BTN_REL || type == LV_WIN_STYLE_BTN_PR) {
lv_obj_t * btn;
btn = lv_obj_get_child_back(ext->header, NULL);
btn = lv_obj_get_child_back(ext->header, btn); /*Skip the title*/
while(btn != NULL) {
if(type == LV_WIN_STYLE_BTN_REL) lv_btn_set_style(btn, LV_BTN_STYLE_REL, style);
else lv_btn_set_style(btn, LV_BTN_STYLE_PR, style);
btn = lv_obj_get_child_back(ext->header, btn);
}
}
}
/**
* Set drag status of a window. If set to 'true' window can be dragged like on a PC.
* @param win pointer to a window object
* @param en whether dragging is enabled
*/
void lv_win_set_drag(lv_obj_t *win, bool en)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_obj_t * win_header = ext->header;
lv_obj_set_drag_parent(win_header, en);
lv_obj_set_drag(win, en);
}
/*=====================
* Getter functions
*====================*/
/**
* Get the title of a window
* @param win pointer to a window object
* @return title string of the window
*/
const char * lv_win_get_title(const lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
return lv_label_get_text(ext->title);
}
/**
* Get the content holder object of window (`lv_page`) to allow additional customization
* @param win pointer to a window object
* @return the Page object where the window's content is
*/
lv_obj_t * lv_win_get_content(const lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
return ext->page;
}
/**
* Get the control button size of a window
* @param win pointer to a window object
* @return control button size
*/
lv_coord_t lv_win_get_btn_size(const lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
return ext->btn_size;
}
/**
* Get the pointer of a widow from one of its control button.
* It is useful in the action of the control buttons where only button is known.
* @param ctrl_btn pointer to a control button of a window
* @return pointer to the window of 'ctrl_btn'
*/
lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn)
{
lv_obj_t * header = lv_obj_get_parent(ctrl_btn);
lv_obj_t * win = lv_obj_get_parent(header);
return win;
}
/**
* Get the layout of a window
* @param win pointer to a window object
* @return the layout of the window (from 'lv_layout_t')
*/
lv_layout_t lv_win_get_layout(lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
return lv_page_get_scrl_layout(ext->page);
}
/**
* Get the scroll bar mode of a window
* @param win pointer to a window object
* @return the scroll bar mode of the window (from 'lv_sb_mode_t')
*/
lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
return lv_page_get_sb_mode(ext->page);
}
/**
* Get width of the content area (page scrollable) of the window
* @param win pointer to a window object
* @return the width of the content_bg area
*/
lv_coord_t lv_win_get_width(lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_obj_t * scrl = lv_page_get_scrl(ext->page);
lv_style_t * style_scrl = lv_obj_get_style(scrl);
return lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor;
}
/**
* Get a style of a window
* @param win pointer to a button object
* @param type which style window be get
* @return style pointer to a style
*/
lv_style_t * lv_win_get_style(const lv_obj_t * win, lv_win_style_t type)
{
lv_style_t * style = NULL;
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
switch(type) {
case LV_WIN_STYLE_BG:
style = lv_obj_get_style(win);
break;
case LV_WIN_STYLE_CONTENT_BG:
style = lv_page_get_style(ext->page, LV_PAGE_STYLE_BG);
break;
case LV_WIN_STYLE_CONTENT_SCRL:
style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SCRL);
break;
case LV_WIN_STYLE_SB:
style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SB);
break;
case LV_WIN_STYLE_HEADER:
style = lv_obj_get_style(ext->header);
break;
case LV_WIN_STYLE_BTN_REL:
style = ext->style_btn_rel;
break;
case LV_WIN_STYLE_BTN_PR:
style = ext->style_btn_pr;
break;
default:
style = NULL;
break;
}
return style;
}
/*=====================
* Other functions
*====================*/
/**
* Focus on an object. It ensures that the object will be visible in the window.
* @param win pointer to a window object
* @param obj pointer to an object to focus (must be in the window)
* @param anim_time scroll animation time in milliseconds (0: no animation)
*/
void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
lv_page_focus(ext->page, obj, anim_time);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Signal function of the window
* @param win pointer to a window 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_win_signal(lv_obj_t * win, lv_signal_t sign, void * param)
{
lv_res_t res;
/* Include the ancient signal function */
res = ancestor_signal(win, sign, param);
if(res != LV_RES_OK) return res;
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
if(sign == LV_SIGNAL_CHILD_CHG) { /*Move children to the page*/
lv_obj_t * page = ext->page;
if(page != NULL) {
lv_obj_t * child;
child = lv_obj_get_child(win, NULL);
while(child != NULL) {
if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) {
lv_obj_t * tmp = child;
child = lv_obj_get_child(win, child); /*Get the next child before move this*/
lv_obj_set_parent(tmp, page);
} else {
child = lv_obj_get_child(win, child);
}
}
}
} else if(sign == LV_SIGNAL_STYLE_CHG) {
lv_win_realign(win);
} else if(sign == LV_SIGNAL_CORD_CHG) {
/*If the size is changed refresh the window*/
if(lv_area_get_width(param) != lv_obj_get_width(win) ||
lv_area_get_height(param) != lv_obj_get_height(win)) {
lv_win_realign(win);
}
} else if(sign == LV_SIGNAL_CLEANUP) {
ext->header = NULL; /*These objects were children so they are already invalid*/
ext->page = NULL;
ext->title = NULL;
} else if(sign == LV_SIGNAL_CONTROLL) {
/*Forward all the control signals to the page*/
ext->page->signal_func(ext->page, sign, param);
} 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_win";
}
return res;
}
/**
* Realign the building elements of a window
* @param win pointer to window objectker
*/
static void lv_win_realign(lv_obj_t * win)
{
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
if(ext->page == NULL || ext->header == NULL || ext->title == NULL) return;
lv_style_t * header_style = lv_win_get_style(win, LV_WIN_STYLE_HEADER);
lv_obj_set_size(ext->header, lv_obj_get_width(win) - 62, ext->btn_size + 2 * header_style->body.padding.ver);
bool first_btn = true;
lv_obj_t * btn;
lv_obj_t * btn_prev = NULL;
/*Refresh the size of all control buttons*/
btn = lv_obj_get_child_back(ext->header, NULL);
btn = lv_obj_get_child_back(ext->header, btn); /*Skip the title*/
while(btn != NULL) {
lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size);
if(first_btn) {
lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, - header_style->body.padding.hor, 0);
first_btn = false;
} else {
lv_obj_align(btn, btn_prev, LV_ALIGN_OUT_LEFT_MID, - header_style->body.padding.inner, 0);
}
btn_prev = btn;
btn = lv_obj_get_child_back(ext->header, btn);
}
lv_obj_align(ext->title, NULL, LV_ALIGN_IN_LEFT_MID, ext->style_header->body.padding.hor, 0);
lv_obj_set_pos(ext->header, 31, 0);
lv_obj_set_size(ext->page, lv_obj_get_width(win), lv_obj_get_height(win) - lv_obj_get_height(ext->header));
lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
}
#endif