LVGL 库提交
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file ui_task.c
|
||||
* @brief UI 主任务:等待网络就绪 -> 初始化显示/菜单/推流 -> 周期刷新
|
||||
* @note 单任务内同时驱动 LVGL 刷新与网络推流轮询,避免任一方阻塞导致界面不刷新。
|
||||
*/
|
||||
#include "ui_task.h"
|
||||
|
||||
#include "cmsis_os.h"
|
||||
#include "sys_events.h"
|
||||
|
||||
#include "ui_port.h"
|
||||
#include "ui_menu.h"
|
||||
#include "ui_net_sink.h"
|
||||
|
||||
static void ui_task_wait_net_ready(void)
|
||||
{
|
||||
if (sys_evtHandle != NULL) {
|
||||
osEventFlagsWait(sys_evtHandle, SYS_EVT_NET_READY,
|
||||
osFlagsWaitAny, osWaitForever);
|
||||
}
|
||||
}
|
||||
|
||||
void ui_task_func(void *argument)
|
||||
{
|
||||
(void)argument;
|
||||
|
||||
ui_task_wait_net_ready();
|
||||
|
||||
if (ui_port_init() != 0) {
|
||||
for (;;) { osDelay(1000); }
|
||||
}
|
||||
if (ui_menu_init() != 0) {
|
||||
for (;;) { osDelay(1000); }
|
||||
}
|
||||
ui_net_sink_start(UI_NET_SINK_PORT);
|
||||
|
||||
while (1) {
|
||||
ui_port_step(10);
|
||||
ui_net_sink_poll();
|
||||
osDelay(10);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 模块名称:UI Task (UI 主任务)
|
||||
* 模块功能:UI 主任务,协调显示端口、菜单与网络推流的启动与周期运行
|
||||
* 适用平台:STM32F407ZGTx + FreeRTOS
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
*/
|
||||
#ifndef __UI_TASK_H
|
||||
#define __UI_TASK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 函数功能:UI 主任务入口
|
||||
* 入口参数:argument - FreeRTOS 传入参数(未使用) void * 可空
|
||||
* 返回值:无(任务不返回)
|
||||
* 限定条件:FreeRTOS 已启动,SYS_EVT_NET_READY 事件最终会被置位
|
||||
* 函数说明:1. 等待网络就绪事件后初始化显示端口与菜单
|
||||
* 2. 启动 UI 网络推流监听,并周期刷新 LVGL 与轮询推流
|
||||
* 3. 循环内同时驱动界面刷新与网络,避免任一方阻塞
|
||||
*/
|
||||
void ui_task_func(void *argument);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UI_TASK_H */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 模块名称:UI Menu (菜单页面构建)
|
||||
* 模块功能:基于 lv_menu 复现 DTU-HMI 树形菜单,支持方向键导航与返回
|
||||
* 适用平台:STM32F407ZGTx
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
*/
|
||||
#include "ui_menu.h"
|
||||
|
||||
#include "lvgl.h"
|
||||
|
||||
/* 菜单节点表(简化自 DTU-HMI menuTab):层级 + 名称 */
|
||||
typedef struct {
|
||||
uint8_t level; /* 0=根页面, 1..3=子层次 */
|
||||
const char *name;
|
||||
} ui_menu_node_t;
|
||||
|
||||
static const ui_menu_node_t g_menu_tab[] = {
|
||||
{0, "主界面"},
|
||||
{1, "装置信息"},
|
||||
{1, "实时数据"},
|
||||
{2, "交流量"},
|
||||
{2, "直流量"},
|
||||
{2, "开入量"},
|
||||
{1, "定值参数"},
|
||||
{2, "定值"},
|
||||
{3, "定值"},
|
||||
{3, "遥调"},
|
||||
{3, "零压"},
|
||||
{3, "电压"},
|
||||
{2, "查看"},
|
||||
{3, "定值"},
|
||||
{3, "遥调"},
|
||||
{3, "零压"},
|
||||
{3, "电压"},
|
||||
{1, "遥测量"},
|
||||
{2, "测量值"},
|
||||
{2, "遥调系数"},
|
||||
{2, "遥测系数"},
|
||||
{2, "双字节"},
|
||||
{2, "装置遥调"},
|
||||
{1, "装置维护"},
|
||||
{2, "时间设置"},
|
||||
{2, "强制复归"},
|
||||
{2, "手动录波"},
|
||||
{2, "自动录波"},
|
||||
{1, "通讯设置"},
|
||||
{2, "通讯参数"},
|
||||
{2, "网络配置"},
|
||||
{2, "SNTP设置"},
|
||||
{1, "记录查询"},
|
||||
{2, "SOE记录"},
|
||||
{2, "事故记录"},
|
||||
{2, "操作记录"},
|
||||
{2, "告警记录"},
|
||||
{2, "变位告警"},
|
||||
{2, "遥信记录"},
|
||||
{2, "自检记录"},
|
||||
{2, "定值记录"},
|
||||
{2, "录波记录"},
|
||||
{0, "厂家设置"},
|
||||
{1, "元件设置"},
|
||||
{1, "恢复默认"},
|
||||
{2, "全部恢复"},
|
||||
{2, "默认参数"},
|
||||
{2, "默认定值"},
|
||||
{2, "默认系数"},
|
||||
{2, "电压"},
|
||||
{2, "元件参数"},
|
||||
{1, "版本显示"},
|
||||
{1, "装置遥调"},
|
||||
{2, "测量遥调"},
|
||||
{2, "装置遥调"},
|
||||
{2, "直流遥调"},
|
||||
{2, "开出遥调"},
|
||||
{2, "装置记录"},
|
||||
{2, "告警记录"},
|
||||
{2, "遥调记录"},
|
||||
{2, "信号复归"},
|
||||
{1, "版本信息"},
|
||||
};
|
||||
|
||||
/*
|
||||
* 函数功能:构建菜单(lv_menu 页面树),复现参考项目菜单结构
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 成功,其他 - 失败(对象创建失败)
|
||||
* 限定条件:ui_port_init() 已成功调用,活动屏幕存在
|
||||
* 函数说明:1. 依据紧凑节点表按层级生成 lv_menu 页面与返回栈
|
||||
* 2. 将菜单对象加入默认输入组,支持远端按键导航
|
||||
* 3. 叶子节点挂占位页,等待后续逐项填充具体功能
|
||||
*/
|
||||
int ui_menu_init(void)
|
||||
{
|
||||
lv_obj_t *menu = lv_menu_create(lv_screen_active());
|
||||
if (menu == NULL) {
|
||||
return -1;
|
||||
}
|
||||
lv_obj_set_size(menu, 160, 160);
|
||||
lv_menu_set_mode_root_back_button(menu, LV_MENU_ROOT_BACK_BUTTON_ENABLED);
|
||||
lv_group_add_obj(lv_group_get_default(), menu);
|
||||
|
||||
uint32_t n = sizeof(g_menu_tab) / sizeof(g_menu_tab[0]);
|
||||
lv_obj_t *root_page = NULL;
|
||||
lv_obj_t *parent_stack[4] = {NULL, NULL, NULL, NULL};
|
||||
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
uint8_t L = g_menu_tab[i].level;
|
||||
const char *name = g_menu_tab[i].name;
|
||||
|
||||
if (i == 0) {
|
||||
/* 第 0 节点为根(主界面) */
|
||||
root_page = lv_menu_page_create(menu, name);
|
||||
parent_stack[0] = root_page;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 当前节点页面 */
|
||||
lv_obj_t *page = lv_menu_page_create(menu, name);
|
||||
|
||||
/* 叶子:页内挂占位内容 */
|
||||
int leaf = (i + 1 >= n) || (g_menu_tab[i + 1].level <= L);
|
||||
if (leaf) {
|
||||
lv_obj_t *ph = lv_menu_cont_create(page);
|
||||
lv_obj_t *pl = lv_label_create(ph);
|
||||
lv_label_set_text(pl, "功能未实现(占位)");
|
||||
}
|
||||
|
||||
/* 挂到父页:level0 直挂根,其余挂到上一级页面 */
|
||||
lv_obj_t *parent = (L == 0) ? root_page : parent_stack[L - 1];
|
||||
|
||||
/* 在父页创建一个容器项,点击加载当前页 */
|
||||
lv_obj_t *item = lv_menu_cont_create(parent);
|
||||
lv_obj_t *lbl = lv_label_create(item);
|
||||
lv_label_set_text(lbl, name);
|
||||
lv_menu_set_load_page_event(menu, item, page);
|
||||
|
||||
parent_stack[L] = page;
|
||||
}
|
||||
|
||||
lv_menu_set_page(menu, root_page);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 模块名称:UI Menu (菜单页面构建)
|
||||
* 模块功能:基于 lv_menu 复现 DTU-HMI 树形菜单,支持方向键导航与返回
|
||||
* 适用平台:STM32F407ZGTx
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
*/
|
||||
#ifndef __UI_MENU_H
|
||||
#define __UI_MENU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 函数功能:构建菜单(lv_menu 页面树),复现参考项目菜单结构
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 成功,其他 - 失败(对象创建失败)
|
||||
* 限定条件:ui_port_init() 已成功调用,活动屏幕存在
|
||||
* 函数说明:1. 依据紧凑节点表按层级生成 lv_menu 页面与返回栈
|
||||
* 2. 将菜单对象加入默认输入组,支持远端按键导航
|
||||
* 3. 叶子节点挂占位页,等待后续逐项填充具体功能
|
||||
*/
|
||||
int ui_menu_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UI_MENU_H */
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 模块名称:UI Network Sink (RemoDispBus 服务端)
|
||||
* 模块功能:实现 RemoDispBus 协议服务端,接收远端连接与导航按键,回送 1bpp 帧缓冲
|
||||
* 适用平台:STM32F407ZGTx + CH395F 以太网
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
* 2026-08-29 王建锋 修正监听端口为 7003;移除连接后主动上报 INIT(避免污染客户端首帧读取)
|
||||
*/
|
||||
#include "ui_net_sink.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "ui_port.h"
|
||||
#include "net_socket.h"
|
||||
#include "net_types.h"
|
||||
|
||||
/* ---------------- RemoDispBus 协议 ---------------- */
|
||||
#define TAG_CLIENT 0xAA
|
||||
#define TAG_DEVICE 0xBB
|
||||
#define CMD_KEEPLIVE 0
|
||||
#define CMD_INIT 1
|
||||
#define CMD_KEY 2
|
||||
#define CMD_LCDMEM 3
|
||||
|
||||
#define UI_W 160
|
||||
#define UI_H 160
|
||||
#define UI_MEMSIZE (UI_W * UI_H / 8) /* 3200 字节 */
|
||||
|
||||
/* 发送帧缓冲(最大:LCDMEM 应答 = 4 字节偏移 + 3200 帧 + 头4 + 校验1) */
|
||||
static uint8_t g_tx[4 + 4 + UI_MEMSIZE + 1];
|
||||
/* LCDMEM 应答数据区(4 字节大端偏移 + 整帧) */
|
||||
static uint8_t g_lcdmem_data[4 + UI_MEMSIZE];
|
||||
static uint8_t g_rx[64];
|
||||
|
||||
static int g_listen = -1;
|
||||
static int g_client = -1;
|
||||
|
||||
/*
|
||||
* 函数功能:计算 RemoDispBus 数据段异或校验值
|
||||
* 入口参数:d - 数据首地址 const uint8_t * 非空
|
||||
* len - 数据长度 int >= 0
|
||||
* 返回值:校验值 uint8_t 0 - 255
|
||||
* 限定条件:无
|
||||
* 函数说明:逐字节异或,结果为单字节,与 DTU-HMI 协议保持一致
|
||||
*/
|
||||
static uint8_t remo_crc(const uint8_t *d, int len)
|
||||
{
|
||||
uint8_t c = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
c ^= d[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:以大端序写入 16 位无符号整数
|
||||
* 入口参数:p - 目标缓冲区 uint8_t * 至少 2 字节
|
||||
* v - 待写入数值 uint16_t 0 - 65535
|
||||
* 返回值:无
|
||||
* 限定条件:p 指向有效内存
|
||||
* 函数说明:高位在前、低位在后(网络字节序)
|
||||
*/
|
||||
static void put_u16(uint8_t *p, uint16_t v)
|
||||
{
|
||||
p[0] = (uint8_t)(v >> 8);
|
||||
p[1] = (uint8_t)(v & 0xFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:以大端序写入 32 位无符号整数
|
||||
* 入口参数:p - 目标缓冲区 uint8_t * 至少 4 字节
|
||||
* v - 待写入数值 uint32_t 0 - 0xFFFFFFFF
|
||||
* 返回值:无
|
||||
* 限定条件:p 指向有效内存
|
||||
* 函数说明:最高位在前,依次存放 4 字节(网络字节序)
|
||||
*/
|
||||
static void put_u32(uint8_t *p, uint32_t v)
|
||||
{
|
||||
p[0] = (uint8_t)(v >> 24);
|
||||
p[1] = (uint8_t)(v >> 16);
|
||||
p[2] = (uint8_t)(v >> 8);
|
||||
p[3] = (uint8_t)(v & 0xFF);
|
||||
}
|
||||
|
||||
/* 组包并发送一帧(tag = DEVICE) */
|
||||
/*
|
||||
* 函数功能:组包并发送一帧(设备 -> 客户端)
|
||||
* 入口参数:cmd - 命令字 uint8_t CMD_*
|
||||
* data - 数据段首地址 const uint8_t * 可为 NULL
|
||||
* len - 数据段长度 uint16_t 0 - 65535
|
||||
* 返回值:无
|
||||
* 限定条件:g_client >= 0(已有连接)
|
||||
* 函数说明:1. 帧格式 [TAG_DEVICE][cmd][len_hi][len_lo][data][crc]
|
||||
* 2. 无连接时直接返回,不发送
|
||||
* 3. 阻塞发送,直至整帧写入 Socket
|
||||
*/
|
||||
static void remo_send(uint8_t cmd, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (g_client < 0) {
|
||||
return;
|
||||
}
|
||||
uint8_t *p = g_tx;
|
||||
p[0] = TAG_DEVICE;
|
||||
p[1] = cmd;
|
||||
p[2] = (uint8_t)(len >> 8);
|
||||
p[3] = (uint8_t)(len & 0xFF);
|
||||
if (len && data) {
|
||||
memcpy(p + 4, data, len);
|
||||
}
|
||||
p[4 + len] = remo_crc(data, len);
|
||||
net_send(g_client, p, 4 + len + 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:发送 INIT 应答(上报分辨率与帧大小)
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:g_client >= 0
|
||||
* 函数说明:数据段为 [宽][高][帧字节数(4)],供客户端分配显示缓冲
|
||||
*/
|
||||
static void remo_send_init(void)
|
||||
{
|
||||
uint8_t init[8];
|
||||
put_u16(init, UI_W);
|
||||
put_u16(init + 2, UI_H);
|
||||
put_u32(init + 4, UI_MEMSIZE);
|
||||
remo_send(CMD_INIT, init, 6);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:解析一帧 RemoDispBus 请求并分发处理
|
||||
* 入口参数:f - 整帧数据首地址 const uint8_t * 非空
|
||||
* n - 帧字节数 int >= 0
|
||||
* 返回值:无
|
||||
* 限定条件:f 指向完整帧缓冲
|
||||
* 函数说明:1. 校验长度与 CRC,标签必须为客户端 TAG
|
||||
* 2. 按命令字分发:KEEPLIVE/INIT 应答,KEY 驱动菜单,LCDMEM 回送帧
|
||||
* 3. 校验失败或格式错误时静默丢弃
|
||||
*/
|
||||
static void remo_handle(const uint8_t *f, int n)
|
||||
{
|
||||
if (n < 6) {
|
||||
return;
|
||||
}
|
||||
uint8_t tag = f[0];
|
||||
uint8_t cmd = f[1];
|
||||
uint16_t len = ((uint16_t)f[2] << 8) | f[3];
|
||||
const uint8_t *data = f + 4;
|
||||
if ((int)(4 + len + 1) > n) {
|
||||
return; /* 帧不完整 */
|
||||
}
|
||||
uint8_t crc = f[4 + len];
|
||||
if (crc != remo_crc(data, len)) {
|
||||
return; /* 校验失败,丢弃 */
|
||||
}
|
||||
if (tag != TAG_CLIENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_KEEPLIVE:
|
||||
remo_send(CMD_KEEPLIVE, NULL, 0);
|
||||
break;
|
||||
case CMD_INIT:
|
||||
remo_send_init();
|
||||
break;
|
||||
case CMD_KEY:
|
||||
if (len >= 1) {
|
||||
ui_port_queue_key(data[0]);
|
||||
}
|
||||
remo_send(CMD_KEY, NULL, 0);
|
||||
break;
|
||||
case CMD_LCDMEM: {
|
||||
if (len < 4) {
|
||||
break;
|
||||
}
|
||||
uint32_t off = ((uint32_t)data[0] << 24) |
|
||||
((uint32_t)data[1] << 16) |
|
||||
((uint32_t)data[2] << 8) |
|
||||
(uint32_t)data[3];
|
||||
if (off == 0) {
|
||||
uint8_t *fb = ui_port_get_framebuffer();
|
||||
g_lcdmem_data[0] = data[0];
|
||||
g_lcdmem_data[1] = data[1];
|
||||
g_lcdmem_data[2] = data[2];
|
||||
g_lcdmem_data[3] = data[3];
|
||||
memcpy(g_lcdmem_data + 4, fb, UI_MEMSIZE);
|
||||
remo_send(CMD_LCDMEM, g_lcdmem_data, 4 + UI_MEMSIZE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:启动 UI 专用 TCP 监听 Socket
|
||||
* 入口参数:port - 监听端口号 uint16_t 1 - 65535
|
||||
* 返回值:0 - 成功,其他 - 失败(socket 创建/绑定/监听失败)
|
||||
* 限定条件:net_init() 已完成,网络子系统就绪
|
||||
* 函数说明:创建流式 Socket 并绑定端口,进入监听等待连接
|
||||
*/
|
||||
int ui_net_sink_start(uint16_t port)
|
||||
{
|
||||
g_listen = net_socket(NET_AF_INET, NET_SOCK_STREAM);
|
||||
if (g_listen < 0) {
|
||||
return -1;
|
||||
}
|
||||
struct net_sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = NET_AF_INET;
|
||||
addr.sin_port = net_htons(port);
|
||||
addr.sin_addr.s_addr = NET_INADDR_ANY;
|
||||
|
||||
if (net_bind(g_listen, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
net_close(g_listen);
|
||||
g_listen = -1;
|
||||
return -1;
|
||||
}
|
||||
if (net_listen(g_listen) < 0) {
|
||||
net_close(g_listen);
|
||||
g_listen = -1;
|
||||
return -1;
|
||||
}
|
||||
g_client = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:非阻塞轮询 RemoDispBus 协议
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:ui_net_sink_start() 已成功调用
|
||||
* 函数说明:1. 无客户端时尝试接受连接(不主动上报 INIT,由客户端按需请求)
|
||||
* 2. 有客户端时非阻塞收帧并解析
|
||||
* 3. 连接关闭或异常时复位,等待重监听,不阻塞界面刷新
|
||||
*/
|
||||
void ui_net_sink_poll(void)
|
||||
{
|
||||
if (g_listen < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_client < 0) {
|
||||
int c = net_accept(g_listen, NULL, NULL);
|
||||
if (c >= 0) {
|
||||
g_client = c;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int n = net_recv(g_client, g_rx, sizeof(g_rx), NET_MSG_DONTWAIT);
|
||||
if (n > 0) {
|
||||
remo_handle(g_rx, n);
|
||||
} else if (n == 0) {
|
||||
g_client = -1; /* 对端关闭:等待下次 accept 自动重监听,不释放控制块 */
|
||||
} else {
|
||||
if (net_get_errno() != NET_ERR_WOULDBLOCK) {
|
||||
g_client = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 模块名称:UI Network Sink (RemoDispBus 服务端)
|
||||
* 模块功能:实现 RemoDispBus 协议服务端,接收远端连接与导航按键,回送 1bpp 帧缓冲
|
||||
* 适用平台:STM32F407ZGTx + CH395F 以太网
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
* 2026-08-29 王建锋 修正监听端口为 7003,与 DTU-RemoteLCD 客户端默认端口对齐
|
||||
*/
|
||||
#ifndef __UI_NET_SINK_H
|
||||
#define __UI_NET_SINK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* RemoDispBus 标签与命令 */
|
||||
#define UI_REMO_TAG_CLIENT 0xAA
|
||||
#define UI_REMO_TAG_DEVICE 0xBB
|
||||
#define UI_REMO_CMD_KEEP 0
|
||||
#define UI_REMO_CMD_INIT 1
|
||||
#define UI_REMO_CMD_KEY 2
|
||||
#define UI_REMO_CMD_LCDMEM 3
|
||||
|
||||
/* UI 推流监听端口(须与 DTU-RemoteLCD 客户端默认端口 7003 一致) */
|
||||
#define UI_NET_SINK_PORT 7003
|
||||
|
||||
/*
|
||||
* 函数功能:启动 UI 专用 TCP 监听 Socket
|
||||
* 入口参数:port - 监听端口号 uint16_t 1 - 65535
|
||||
* 返回值:0 - 成功,其他 - 失败(socket 创建/绑定/监听失败)
|
||||
* 限定条件:net_init() 已完成,网络子系统就绪
|
||||
* 函数说明:1. 创建流式 Socket 并绑定到指定端口与任意本地地址
|
||||
* 2. 进入监听状态,等待远端客户端连接
|
||||
* 3. 调用前需确保 CH395F 网络已初始化
|
||||
*/
|
||||
int ui_net_sink_start(uint16_t port);
|
||||
|
||||
/*
|
||||
* 函数功能:非阻塞轮询 RemoDispBus 协议
|
||||
* 入口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:ui_net_sink_start() 已成功调用
|
||||
* 函数说明:1. 无客户端时尝试接受连接,成功即上报 INIT
|
||||
* 2. 有客户端时用 DONTWAIT 收帧并解析(KEEPLIVE/INIT/KEY/LCDMEM)
|
||||
* 3. 对端关闭或异常时复位客户端,等待下次重监听,不阻塞 LVGL 刷新
|
||||
*/
|
||||
void ui_net_sink_poll(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UI_NET_SINK_H */
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 模块名称:UI Display Port (LVGL 离屏显示端口)
|
||||
* 模块功能:提供 LVGL 1bpp 离屏渲染端口与远程 keypad 输入设备
|
||||
* 适用平台:STM32F407ZGTx
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
*/
|
||||
#include "ui_port.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "lvgl.h"
|
||||
|
||||
/* 160x160 1bpp 帧 = 3200 字节 */
|
||||
static uint8_t g_ui_fbuf[UI_FB_SIZE];
|
||||
/* LVGL 绘制缓冲(与帧同尺寸,整屏渲染) */
|
||||
static uint8_t g_ui_draw_buf[UI_FB_SIZE];
|
||||
|
||||
/* 单键缓冲:菜单无需多键队列,仅保存最近一次待处理键 */
|
||||
static volatile uint8_t g_pending_key = 0;
|
||||
|
||||
/* 远端键 -> LVGL 键 */
|
||||
/*
|
||||
* 函数功能:将远端键码映射为 LVGL 按键枚举值
|
||||
* 入口参数:remo_key - 远端键码 uint8_t UI_KEY_* 取值之一
|
||||
* 返回值:LVGL 按键值 uint8_t LV_KEY_*;未匹配返回 0
|
||||
* 限定条件:无
|
||||
* 函数说明:仅映射方向/确认/返回等导航键,其余返回 0 表示忽略
|
||||
*/
|
||||
static uint8_t ui_map_key(uint8_t remo_key)
|
||||
{
|
||||
switch (remo_key) {
|
||||
case UI_KEY_UP: return (uint8_t)LV_KEY_UP;
|
||||
case UI_KEY_DOWN: return (uint8_t)LV_KEY_DOWN;
|
||||
case UI_KEY_LEFT: return (uint8_t)LV_KEY_LEFT;
|
||||
case UI_KEY_RIGHT: return (uint8_t)LV_KEY_RIGHT;
|
||||
case UI_KEY_ENTER: return (uint8_t)LV_KEY_ENTER;
|
||||
case UI_KEY_ESC: return (uint8_t)LV_KEY_ESC;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* keypad 读取回调,上报待处理键 */
|
||||
/*
|
||||
* 函数功能:keypad 输入设备读取回调,上报待处理按键
|
||||
* 入口参数:indev - 输入设备句柄 lv_indev_t * 未使用
|
||||
* data - 读取结果 lv_indev_data_t * 由本函数填充
|
||||
* 返回值:无
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 若有缓存键则上报 PRESSED 并清除缓存
|
||||
* 2. 否则上报 RELEASED,等待下次按键
|
||||
*/
|
||||
static void ui_keypad_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
(void)indev;
|
||||
if (g_pending_key != 0) {
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
data->key = g_pending_key;
|
||||
g_pending_key = 0;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
data->key = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush 回调:把 LVGL 1bpp 渲染结果拷到内存帧缓冲 */
|
||||
/*
|
||||
* 函数功能:显示刷新回调,将 LVGL 渲染结果写入内存帧缓冲
|
||||
* 入口参数:disp - 显示设备 lv_display_t * 未使用
|
||||
* area - 刷新区域 const lv_area_t * 未使用
|
||||
* color_p - 1bpp 像素数据首地址 uint8_t *
|
||||
* 返回值:无
|
||||
* 限定条件:ui_port_init() 已成功调用
|
||||
* 函数说明:整帧拷贝到 g_ui_fbuf,供 RemoDispBus 推送至远端
|
||||
*/
|
||||
static void ui_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p)
|
||||
{
|
||||
(void)disp;
|
||||
(void)area;
|
||||
memcpy(g_ui_fbuf, color_p, UI_FB_SIZE);
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:初始化 LVGL 显示端口与按键输入设备
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 成功,其他 - 失败(显示或输入设备创建失败)
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 初始化 LVGL 并创建 1bpp 离屏显示设备与绘制缓冲
|
||||
* 2. 创建 keypad 设备及默认输入组,绑定刷新回调
|
||||
* 3. 后续须周期调用 ui_port_step 驱动刷新
|
||||
*/
|
||||
int ui_port_init(void)
|
||||
{
|
||||
lv_init();
|
||||
|
||||
static lv_display_t *disp = NULL;
|
||||
disp = lv_display_create(UI_SCREEN_W, UI_SCREEN_H);
|
||||
if (disp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
lv_display_set_color_format(disp, LV_COLOR_FORMAT_I1);
|
||||
lv_display_set_buffers(disp, g_ui_draw_buf, NULL, UI_FB_SIZE,
|
||||
LV_DISPLAY_RENDER_MODE_FULL);
|
||||
lv_display_set_flush_cb(disp, ui_flush_cb);
|
||||
|
||||
static lv_indev_t *indev = NULL;
|
||||
indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
|
||||
lv_indev_set_read_cb(indev, ui_keypad_read);
|
||||
|
||||
lv_group_t *g = lv_group_create();
|
||||
if (g == NULL) {
|
||||
return -1;
|
||||
}
|
||||
lv_group_set_default(g);
|
||||
lv_indev_set_group(indev, g);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取内存帧缓冲首地址
|
||||
* 入口参数:无
|
||||
* 返回值:帧缓冲首地址 uint8_t * 固定长度 UI_FB_SIZE 字节
|
||||
* 限定条件:ui_port_init() 已成功调用
|
||||
* 函数说明:缓冲由 flush 回调更新,供网络推流读取
|
||||
*/
|
||||
uint8_t *ui_port_get_framebuffer(void)
|
||||
{
|
||||
return g_ui_fbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:向输入队列喂入一个远端按键值
|
||||
* 入口参数:remo_key - 远端键码 uint8_t UI_KEY_* 取值之一
|
||||
* 返回值:无
|
||||
* 限定条件:无
|
||||
* 函数说明:映射后缓存,由 keypad 回调在下次轮询上报
|
||||
*/
|
||||
void ui_port_queue_key(uint8_t remo_key)
|
||||
{
|
||||
uint8_t k = ui_map_key(remo_key);
|
||||
if (k != 0) {
|
||||
g_pending_key = k;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:UI 周期步进(推进节拍并刷新 LVGL)
|
||||
* 入口参数:tick_ms - 距上次调用毫秒数 uint32_t 建议 10
|
||||
* 返回值:无
|
||||
* 限定条件:ui_port_init() 已成功调用
|
||||
* 函数说明:依次调用 lv_tick_inc 与 lv_timer_handler,须由任务周期调用
|
||||
*/
|
||||
void ui_port_step(uint32_t tick_ms)
|
||||
{
|
||||
lv_tick_inc(tick_ms);
|
||||
lv_timer_handler();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 模块名称:UI Display Port (LVGL 离屏显示端口)
|
||||
* 模块功能:提供 LVGL 1bpp 离屏渲染端口与远程 keypad 输入设备
|
||||
* 适用平台:STM32F407ZGTx
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-08-29
|
||||
* 修改记录:
|
||||
* 2026-08-29 王建锋 创建初始版本
|
||||
*/
|
||||
#ifndef __UI_PORT_H
|
||||
#define __UI_PORT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 屏幕尺寸与帧缓冲(160x160 1bpp = 3200 字节) */
|
||||
#define UI_SCREEN_W 160
|
||||
#define UI_SCREEN_H 160
|
||||
#define UI_FB_SIZE ((UI_SCREEN_W * UI_SCREEN_H) / 8)
|
||||
|
||||
/* 远端按键码(与 DTU-HMI key.h 保持一致) */
|
||||
#define UI_KEY_UP 0x02
|
||||
#define UI_KEY_DOWN 0x40
|
||||
#define UI_KEY_LEFT 0x10
|
||||
#define UI_KEY_RIGHT 0x08
|
||||
#define UI_KEY_ENTER 0x20
|
||||
#define UI_KEY_ESC 0x01
|
||||
|
||||
/*
|
||||
* 函数功能:初始化 LVGL 显示端口与按键输入设备
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 成功,其他 - 失败(显示或输入设备创建失败)
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 初始化 LVGL 内核并创建 1bpp 离屏显示设备
|
||||
* 2. 创建 keypad 输入设备及默认输入组,用于菜单导航
|
||||
* 3. 需在 lv_tick_inc/lv_timer_handler 被周期调用后方可刷新
|
||||
*/
|
||||
int ui_port_init(void);
|
||||
|
||||
/*
|
||||
* 函数功能:获取内存帧缓冲首地址
|
||||
* 入口参数:无
|
||||
* 返回值:帧缓冲首地址 uint8_t * 固定长度 UI_FB_SIZE 字节
|
||||
* 限定条件:ui_port_init() 已成功调用
|
||||
* 函数说明:1. 帧缓冲由 flush 回调写入最新渲染结果
|
||||
* 2. 供 RemoDispBus 服务端读取并推送至远端
|
||||
*/
|
||||
uint8_t *ui_port_get_framebuffer(void);
|
||||
|
||||
/*
|
||||
* 函数功能:向输入队列喂入一个远端按键值
|
||||
* 入口参数:key_val - 远端键码 uint8_t UI_KEY_* 取值之一
|
||||
* 返回值:无
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 将远端键码映射为 LVGL 按键后缓存
|
||||
* 2. 由 keypad 读取回调在下次轮询时上报,驱动菜单导航
|
||||
*/
|
||||
void ui_port_queue_key(uint8_t key_val);
|
||||
|
||||
/*
|
||||
* 函数功能:UI 周期步进(更新系统节拍并刷新 LVGL)
|
||||
* 入口参数:tick_ms - 距上次调用的毫秒数 uint32_t 建议 10
|
||||
* 返回值:无
|
||||
* 限定条件:ui_port_init() 已成功调用
|
||||
* 函数说明:1. 调用 lv_tick_inc 推进 LVGL 内部时钟
|
||||
* 2. 调用 lv_timer_handler 处理重绘,结果经 flush 写入帧缓冲
|
||||
* 3. 须由任务以固定周期调用,否则界面停止刷新
|
||||
*/
|
||||
void ui_port_step(uint32_t tick_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UI_PORT_H */
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file lv_conf.h
|
||||
* @brief LVGL v9 配置(STM32F407ZGTx,160x160 单色 1bpp,离屏渲染+网络推流)
|
||||
* @note 本项目仅用作离屏渲染:flush 把 1bpp 像素写入内存帧缓冲,
|
||||
* 由 RemoDispBus 协议按需经网络发出。无真实屏、无触摸。
|
||||
*/
|
||||
#ifndef LV_CONF_H
|
||||
#define LV_CONF_H
|
||||
|
||||
/* 1bpp 单色 */
|
||||
#define LV_COLOR_DEPTH 1
|
||||
#define LV_COLOR_CHROMA_KEY 0x000000
|
||||
|
||||
/* 必需控件(lv_menu 依赖 flex/label/button) */
|
||||
#define LV_USE_OBJ 1
|
||||
#define LV_USE_FLEX 1
|
||||
#define LV_USE_LABEL 1
|
||||
#define LV_USE_BUTTON 1
|
||||
#define LV_USE_MENU 1
|
||||
|
||||
/* 刷新周期(ms):离屏渲染,无需高刷 */
|
||||
#define LV_DEF_REFR_PERIOD 20
|
||||
|
||||
/* 关闭动画/日志,省 RAM 与代码 */
|
||||
#define LV_USE_ANIMATION 0
|
||||
#define LV_USE_LOG 0
|
||||
|
||||
/* 不使用 LVGL 自带 OS 抽象,由 ui_task 手动调用 lv_timer_handler */
|
||||
#define LV_USE_OS 0
|
||||
#define LV_OS_PRIORITY 0
|
||||
#define LV_OS_TASK_NAME "ui"
|
||||
|
||||
/* 内存池:1bpp 小界面,菜单页较多,给 40KB */
|
||||
#define LV_MEM_SIZE (40 * 1024)
|
||||
#define LV_MEM_ADR 0 /* 0 = 内部静态分配 */
|
||||
|
||||
/* 断言全部关闭,减少体积 */
|
||||
#define LV_USE_ASSERT_NULL 0
|
||||
#define LV_USE_ASSERT_MALLOC 0
|
||||
#define LV_USE_ASSERT_USER_CODE 0
|
||||
#define LV_USE_ASSERT_OBJ 0
|
||||
#define LV_USE_ASSERT_STYLE 0
|
||||
#define LV_USE_ASSERT_LAYOUT 0
|
||||
|
||||
/* 内置字体:先启用 Latin 以通过编译;
|
||||
* 中文 1bpp 字库由 fontconverter 生成后通过 ui_font_cn_12 接入并替换默认字体 */
|
||||
#define LV_FONT_MONTSERRAT_12 1
|
||||
#define LV_FONT_MONTSERRAT_14 0
|
||||
#define LV_FONT_MONTSERRAT_16 0
|
||||
#define LV_FONT_MONTSERRAT_18 0
|
||||
#define LV_FONT_MONTSERRAT_20 0
|
||||
#define LV_FONT_MONTSERRAT_22 0
|
||||
#define LV_FONT_MONTSERRAT_24 0
|
||||
#define LV_FONT_MONTSERRAT_28 0
|
||||
#define LV_FONT_MONTSERRAT_32 0
|
||||
#define LV_FONT_MONTSERRAT_48 0
|
||||
#define LV_FONT_UNSCII_8 0
|
||||
#define LV_FONT_UNSCII_16 0
|
||||
#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0
|
||||
#define LV_FONT_SIMSUN_16_CJK 0 /* 预留:中文全字库(若启用需对应源文件) */
|
||||
|
||||
/* 默认字体:阶段一先用 Latin 12;中文接入后改为 &ui_font_cn_12 */
|
||||
#define LV_FONT_DEFAULT &lv_font_montserrat_12
|
||||
|
||||
/* 文本编码 UTF-8(菜单含中文) */
|
||||
#define LV_TXT_ENC LV_TXT_ENC_UTF8
|
||||
|
||||
/* 主题:关闭默认主题,控件用内置基础样式,省代码 */
|
||||
#define LV_USE_THEME_DEFAULT 0
|
||||
#define LV_USE_THEME_BASIC 0
|
||||
|
||||
/* 绘制相关:1bpp 无需 GPU/抗锯齿 */
|
||||
#define LV_DRAW_SW_COMPLEX_GRAD 0
|
||||
#define LV_DRAW_SW_YIELD 0
|
||||
#define LV_DRAW_SW_ASYNC 0
|
||||
|
||||
/* 输入设备:启用键盘/编码器(远程按键走 keypad) */
|
||||
#define LV_USE_KEYBOARD 0
|
||||
#define LV_USE_MOUSEWHEEL 0
|
||||
#define LV_USE_ENCODER 0
|
||||
|
||||
/* 不使用的第三方扩展 */
|
||||
#define LV_USE_PNG 0
|
||||
#define LV_USE_BMP 0
|
||||
#define LV_USE_JPG 0
|
||||
#define LV_USE_GIF 0
|
||||
#define LV_USE_QRCODE 0
|
||||
#define LV_USE_BARCODE 0
|
||||
#define LV_USE_IME_PINYIN 0
|
||||
#define LV_USE_GRIDNAV 0
|
||||
#define LV_USE_FRAGMENT 0
|
||||
|
||||
/* 裁剪未用控件,减小体积(menu/label/btn/img 等保留) */
|
||||
#define LV_USE_ANIMIMG 0
|
||||
#define LV_USE_ARC 0
|
||||
#define LV_USE_CHART 0
|
||||
#define LV_USE_CHECKBOX 0
|
||||
#define LV_USE_COLORWHEEL 0
|
||||
#define LV_USE_DROPDOWN 0
|
||||
#define LV_USE_IMGBTN 0
|
||||
#define LV_USE_KEYBOARD 0
|
||||
#define LV_USE_LED 0
|
||||
#define LV_USE_LIST 0
|
||||
#define LV_USE_METER 0
|
||||
#define LV_USE_MSGBOX 0
|
||||
#define LV_USE_ROLLER 0
|
||||
#define LV_USE_SCALE 0
|
||||
#define LV_USE_SLIDER 0
|
||||
#define LV_USE_SPAN 0
|
||||
#define LV_USE_SPINBOX 0
|
||||
#define LV_USE_SPINNER 0
|
||||
#define LV_USE_SWITCH 0
|
||||
#define LV_USE_TABVIEW 0
|
||||
#define LV_USE_TILEVIEW 0
|
||||
#define LV_USE_WIN 0
|
||||
#define LV_USE_TABLE 0
|
||||
#define LV_USE_CALENDAR 0
|
||||
#define LV_USE_CANVAS 0
|
||||
#define LV_USE_IMAGE 1 /* lv_menu 返回图标依赖 */
|
||||
#define LV_USE_TEXTLINE 0
|
||||
|
||||
#endif /* LV_CONF_H */
|
||||
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project (lv_emscripten)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -s USE_SDL=2")
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(lvgl)
|
||||
file(GLOB MY_SOURCES "./*.c")
|
||||
set(SOURCES ${MY_SOURCES})
|
||||
|
||||
add_executable(index ${SOURCES} ${INCLUDES})
|
||||
|
||||
if(NOT LVGL_CHOSEN_DEMO)
|
||||
set(LVGL_CHOSEN_DEMO lv_demo_widgets)
|
||||
endif()
|
||||
set_source_files_properties(main.c PROPERTIES COMPILE_FLAGS -DCHOSEN_DEMO=${LVGL_CHOSEN_DEMO})
|
||||
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".html")
|
||||
target_link_libraries(index
|
||||
lvgl
|
||||
lvgl_examples
|
||||
lvgl_demos
|
||||
lvgl_thorvg
|
||||
SDL2
|
||||
)
|
||||
set_target_properties(index PROPERTIES LINK_FLAGS "--shell-file ${PROJECT_SOURCE_DIR}/lvgl/.devcontainer/lvgl_shell.html -s SINGLE_FILE=1")
|
||||
@@ -0,0 +1,5 @@
|
||||
cd build
|
||||
emcmake cmake ..
|
||||
emmake make -j$(nproc)
|
||||
echo "Built succesfully, opening index.html"
|
||||
code index.html
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/local/emsdk/upstream/emscripten/cache/sysroot/include/"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "linux-clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
/**
|
||||
* @file main
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
|
||||
#include <SDL2/SDL.h>
|
||||
#include <emscripten.h>
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lvgl/demos/lv_demos.h"
|
||||
#include "lvgl/examples/lv_examples.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*On OSX SDL needs different handling*/
|
||||
#if defined(__APPLE__) && defined(TARGET_OS_MAC)
|
||||
# if __APPLE__ && TARGET_OS_MAC
|
||||
#define SDL_APPLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void hal_init(void);
|
||||
static int tick_thread(void * data);
|
||||
static void memory_monitor(lv_timer_t * param);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_display_t * disp1;
|
||||
|
||||
int monitor_hor_res, monitor_ver_res;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void do_loop(void *arg);
|
||||
|
||||
/* Allows disabling CHOSEN_DEMO */
|
||||
static void lv_example_noop(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
|
||||
monitor_hor_res = 800;
|
||||
monitor_ver_res = 480;
|
||||
printf("Starting with screen resolution of %dx%d px\n", monitor_hor_res, monitor_ver_res);
|
||||
|
||||
/*Initialize LittlevGL*/
|
||||
lv_init();
|
||||
|
||||
/*Initialize the HAL (display, input devices, tick) for LittlevGL*/
|
||||
hal_init();
|
||||
|
||||
lv_demo_widgets();
|
||||
|
||||
emscripten_set_main_loop_arg(do_loop, NULL, -1, true);
|
||||
}
|
||||
|
||||
void do_loop(void *arg)
|
||||
{
|
||||
/* Periodically call the lv_timer handler.
|
||||
* It could be done in a timer interrupt or an OS task too.*/
|
||||
lv_timer_handler();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the Hardware Abstraction Layer (HAL) for the Littlev graphics library
|
||||
*/
|
||||
static void hal_init(void)
|
||||
{
|
||||
lv_display_t * disp = lv_sdl_window_create(monitor_hor_res, monitor_ver_res);
|
||||
|
||||
lv_group_t * g = lv_group_create();
|
||||
lv_group_set_default(g);
|
||||
|
||||
lv_sdl_mouse_create();
|
||||
lv_indev_t * mousewheel = lv_sdl_mousewheel_create();
|
||||
lv_indev_set_group(mousewheel, lv_group_get_default());
|
||||
|
||||
lv_indev_t * keyboard = lv_sdl_keyboard_create();
|
||||
lv_indev_set_group(keyboard, lv_group_get_default());
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"sdl.h": "c"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"image": "mcr.microsoft.com/devcontainers/universal:2",
|
||||
"features": {
|
||||
"ghcr.io/ebaskoro/devcontainer-features/emscripten:1": {}
|
||||
},
|
||||
"postCreateCommand": "chmod +x /workspace/lvgl_app/lvgl/.devcontainer/setup.sh; /workspace/lvgl_app/lvgl/.devcontainer/setup.sh",
|
||||
"postStartCommand": ". /usr/local/emsdk/emsdk_env.sh;",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
//"searKing.preview-vscode"
|
||||
"analytic-signal.preview-html"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"hostRequirements": {
|
||||
"cpus": 4
|
||||
},
|
||||
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace/lvgl_app/lvgl,type=bind",
|
||||
"workspaceFolder": "/workspace/lvgl_app"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
LV_COLOR_DEPTH 32
|
||||
LV_MEM_SIZE (1024 * 1024)
|
||||
LV_DRAW_THREAD_STACK_SIZE (64 * 1024)
|
||||
LV_USE_MATRIX 1
|
||||
LV_USE_FLOAT 1
|
||||
LV_USE_LOTTIE 1
|
||||
|
||||
LV_USE_DRAW_SW_COMPLEX_GRADIENTS 1
|
||||
LV_OBJ_STYLE_CACHE 1
|
||||
LV_USE_LOG 1
|
||||
LV_LOG_PRINTF 1
|
||||
LV_USE_PERF_MONITOR 1
|
||||
LV_USE_SYSMON 1
|
||||
|
||||
LV_USE_ASSERT_MEM_INTEGRITY 1
|
||||
LV_USE_ASSERT_OBJ 1
|
||||
LV_USE_ASSERT_STYLE 1
|
||||
LV_FONT_MONTSERRAT_12 1
|
||||
LV_FONT_MONTSERRAT_14 1
|
||||
LV_FONT_MONTSERRAT_16 1
|
||||
LV_FONT_MONTSERRAT_18 1
|
||||
LV_FONT_MONTSERRAT_20 1
|
||||
LV_FONT_MONTSERRAT_22 1
|
||||
LV_FONT_MONTSERRAT_24 1
|
||||
LV_FONT_MONTSERRAT_26 1
|
||||
LV_FONT_MONTSERRAT_28 1
|
||||
LV_FONT_MONTSERRAT_30 1
|
||||
LV_FONT_MONTSERRAT_32 1
|
||||
LV_FONT_MONTSERRAT_34 1
|
||||
LV_FONT_MONTSERRAT_36 1
|
||||
LV_FONT_MONTSERRAT_38 1
|
||||
LV_FONT_MONTSERRAT_40 1
|
||||
LV_FONT_MONTSERRAT_42 1
|
||||
LV_FONT_MONTSERRAT_44 1
|
||||
LV_FONT_MONTSERRAT_46 1
|
||||
LV_FONT_MONTSERRAT_48 1
|
||||
LV_FONT_MONTSERRAT_28_COMPRESSED 1
|
||||
LV_FONT_DEJAVU_16_PERSIAN_HEBREW 1
|
||||
LV_FONT_SOURCE_HAN_SANS_SC_16_CJK 1
|
||||
LV_FONT_UNSCII_8 1
|
||||
|
||||
LV_USE_IMGFONT 1
|
||||
LV_USE_FS_STDIO 1
|
||||
LV_FS_STDIO_LETTER 'A'
|
||||
LV_USE_FS_MEMFS 1
|
||||
LV_FS_MEMFS_LETTER 'M'
|
||||
LV_USE_THORVG_INTERNAL 1
|
||||
LV_USE_LZ4_INTERNAL 1
|
||||
LV_USE_VECTOR_GRAPHIC 1
|
||||
LV_USE_TINY_TTF 1
|
||||
LV_USE_BARCODE 1
|
||||
LV_USE_QRCODE 1
|
||||
LV_USE_RLE 1
|
||||
LV_BIN_DECODER_RAM_LOAD 1
|
||||
LV_USE_TJPGD 1
|
||||
LV_USE_BMP 1
|
||||
LV_USE_LODEPNG 1
|
||||
LV_USE_SDL 1
|
||||
|
||||
LV_USE_DEMO_WIDGETS 1
|
||||
LV_USE_DEMO_KEYPAD_AND_ENCODER 1
|
||||
LV_USE_DEMO_BENCHMARK 1
|
||||
LV_USE_DEMO_RENDER 1
|
||||
LV_USE_DEMO_STRESS 1
|
||||
LV_USE_DEMO_MUSIC 1
|
||||
LV_USE_DEMO_FLEX_LAYOUT 1
|
||||
LV_USE_DEMO_MULTILANG 1
|
||||
LV_USE_DEMO_TRANSFORM 1
|
||||
LV_USE_DEMO_SCROLL 1
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no'/>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
margin: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.git-commit-info {
|
||||
font-family: Consolas, 'Courier New', Courier, monospace;
|
||||
background-color: #f1f1f1;
|
||||
padding: 2px;
|
||||
text-align: left;
|
||||
}
|
||||
#git-hash {
|
||||
text-align: center;
|
||||
}
|
||||
#output {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="git-hash"></div>
|
||||
<p id="output">
|
||||
<canvas id="canvas"></canvas>
|
||||
</p>
|
||||
<script src="gitrev.js"></script>
|
||||
<script>
|
||||
var siteURL = new URL(window.location.href);
|
||||
var w = siteURL.searchParams.get("w") || "800";
|
||||
var h = siteURL.searchParams.get("h") || "480";
|
||||
var canvas = document.getElementById('canvas');
|
||||
canvas.setAttribute("width", w);
|
||||
canvas.setAttribute("height", h);
|
||||
console.log("Requested " + w + "x" + h + " px");
|
||||
var Module = {
|
||||
print: function(text) {
|
||||
console.log(text);
|
||||
},
|
||||
printErr: function(text) {
|
||||
console.error(text);
|
||||
},
|
||||
canvas: (function() {
|
||||
return canvas;
|
||||
})(),
|
||||
arguments: [ siteURL.searchParams.get("w") || "800", siteURL.searchParams.get("h") || "480", siteURL.searchParams.get("example") ?? "default" ]
|
||||
};
|
||||
if(typeof window.git_hash != 'undefined') {
|
||||
var gitHashDiv = document.querySelector("#git-hash");
|
||||
var gitLink = document.createElement("div");
|
||||
var gitHashComponents = window.git_hash.split(" ").filter(component => component.trim().length > 0);
|
||||
for(var i = 0; i < gitHashComponents.length; i++) {
|
||||
console.log(gitHashComponents[i], gitHashComponents[i].length);
|
||||
/* This is an extremely lazy way of checking for a Git hash, but it works */
|
||||
if(gitHashComponents[i].length == 40) {
|
||||
gitHashComponents[i] = `<a href="https://github.com/lvgl/${gitHashComponents[i+1]}/commit/${gitHashComponents[i]}">${gitHashComponents[i]}</a>`;
|
||||
} else {
|
||||
/* Repository name */
|
||||
gitHashComponents[i] += "<br/>";
|
||||
}
|
||||
}
|
||||
gitLink.classList.add("git-commit-info");
|
||||
gitLink.innerHTML = gitHashComponents.join(" ");
|
||||
gitHashDiv.textContent = "LVGL compiled to Emscripten. Git commit information:";
|
||||
gitHashDiv.appendChild(gitLink);
|
||||
}
|
||||
window.addEventListener("click", () => window.focus());
|
||||
</script>
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo ". /usr/local/emsdk/emsdk_env.sh" >> /home/codespace/.bashrc
|
||||
|
||||
cd /workspace/lvgl_app
|
||||
sudo chmod 777 .
|
||||
mkdir build
|
||||
mkdir vscode
|
||||
|
||||
cd lvgl/.devcontainer
|
||||
cp __CMakeLists.txt__ ../../CMakeLists.txt
|
||||
cp __main.c__ ../../main.c
|
||||
cp __build_all.sh__ ../../build_all.sh
|
||||
cp __c_cpp_properties.json__ ../../.vscode/c_cpp_properties.json
|
||||
cp __settings.json__ ../../.vscode/settings.json
|
||||
touch ../../lv_conf.h
|
||||
../scripts/generate_lv_conf.py --template ../lv_conf_template.h --config ../../lv_conf.h
|
||||
|
||||
chmod +x ../../build_all.sh
|
||||
@@ -0,0 +1,22 @@
|
||||
**/*.o
|
||||
**/*bin
|
||||
**/*.swp
|
||||
**/*.swo
|
||||
**/*.gcda
|
||||
**/*.gcno
|
||||
tags
|
||||
scripts/cppcheck_res.txt
|
||||
scripts/built_in_font/lv_font_*
|
||||
__pycache__
|
||||
/emscripten_builder
|
||||
test_screenshot_error.h
|
||||
build/
|
||||
.DS_Store
|
||||
.vscode
|
||||
.idea
|
||||
*.bak
|
||||
.vs/
|
||||
.config*
|
||||
config.h
|
||||
defconfig
|
||||
env/*
|
||||
@@ -0,0 +1,42 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
# Run astyle over the staged files with c and h extension found in the directories
|
||||
# listed in the files regex pattern. Ignoring the files in the exclude pattern.
|
||||
- id: format-source
|
||||
name: Formatting source files
|
||||
entry: astyle --options=scripts/code-format.cfg --ignore-exclude-errors
|
||||
stages: [ commit ]
|
||||
language: system
|
||||
pass_filenames: true
|
||||
verbose: true
|
||||
files: |
|
||||
(?x)^(
|
||||
demos/ |
|
||||
examples/ |
|
||||
src/ |
|
||||
tests/
|
||||
)
|
||||
exclude: |
|
||||
(?x)^(
|
||||
demos/high_res/fonts/ |
|
||||
src/libs/ |
|
||||
src/lv_conf_internal.h |
|
||||
tests/test_images
|
||||
)
|
||||
types_or: ["c", "header"]
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.16.20
|
||||
hooks:
|
||||
- id: typos
|
||||
exclude: |
|
||||
(?x)^(
|
||||
src/libs/
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
[files]
|
||||
extend-exclude = [
|
||||
".git/",
|
||||
"docs/_static/css/fontawesome.min.css",
|
||||
"docs/README_*",
|
||||
"src/libs/",
|
||||
"docs/CHANGELOG.rst"
|
||||
]
|
||||
ignore-hidden = false
|
||||
|
||||
[default]
|
||||
extend-ignore-re = [
|
||||
"\\bser[^a-z]",
|
||||
"\\bfle[^a-z]",
|
||||
'"Lorem ipsum .*"',
|
||||
'ACI',
|
||||
"Nam consectetur",
|
||||
"U\\+[0-9A-F]{4}",
|
||||
'\{ "[a-z]+", "[^ -~]+" \},',
|
||||
"`[0-9a-f]{7} <https://\\S+>`__",
|
||||
"Rename lv_chart_clear_serie",
|
||||
"rename LV_ROLLER_MODE_INIFINITE",
|
||||
"CARD_INFO_SET\\(&img_multilang_avatar_.*\\)",
|
||||
"ACI\\)",
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6loca.html
|
||||
"loca" = "loca"
|
||||
@@ -0,0 +1,41 @@
|
||||
cmake_minimum_required(VERSION 3.12.4)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
project(lvgl LANGUAGES C HOMEPAGE_URL https://github.com/lvgl/lvgl)
|
||||
if(NOT (CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
|
||||
enable_language(CXX ASM)
|
||||
else()
|
||||
enable_language(CXX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LVGL_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/esp.cmake)
|
||||
elseif(ZEPHYR_BASE)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/zephyr.cmake)
|
||||
elseif(MICROPY_DIR)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/micropython.cmake)
|
||||
else()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/os_desktop.cmake)
|
||||
endif()
|
||||
|
||||
#[[
|
||||
unfortunately CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS does not work for global data.
|
||||
for global data we still need decl specs.
|
||||
Check out the docs to learn more about the limitations of CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
|
||||
https://cmake.org/cmake/help/latest/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.html#prop_tgt:WINDOWS_EXPORT_ALL_SYMBOLS
|
||||
|
||||
For all compiled sources within the library (i.e. basically all lvgl files) we need to use dllexport.
|
||||
For all compiled sources from outside the library (i.e. files which include lvgl headers) we need to use dllimport.
|
||||
We can do this by using CMakes INTERFACE and PRIVATE keyword.
|
||||
]]
|
||||
if (MSVC)
|
||||
target_compile_definitions(lvgl
|
||||
INTERFACE LV_ATTRIBUTE_EXTERN_DATA=__declspec\(dllimport\)
|
||||
PRIVATE LV_ATTRIBUTE_EXTERN_DATA=__declspec\(dllexport\)
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "_base",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-base",
|
||||
"inherits": "_base",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"installDir": "${sourceDir}/build/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "cl.exe",
|
||||
"CMAKE_CXX_COMPILER": "cl.exe",
|
||||
"BUILD_SHARED_LIBS": "ON"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-base",
|
||||
"inherits": "_base",
|
||||
"displayName": "Linux",
|
||||
"description": "Setup WSL or native linux",
|
||||
"generator": "Ninja Multi-Config",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"installDir": "${sourceDir}/build/${presetName}",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
|
||||
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
|
||||
}
|
||||
},
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-kconfig",
|
||||
"inherits": "linux-base",
|
||||
"displayName": "Linux/Kconfig",
|
||||
"description": "Setup WSL or native linux, using Kconfig",
|
||||
"generator": "Ninja Multi-Config",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"installDir": "${sourceDir}/build/${presetName}",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
|
||||
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
|
||||
}
|
||||
},
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": "ON",
|
||||
"BUILD_LV_USE_KCONFIG": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-kconfig",
|
||||
"inherits": "_base",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"installDir": "${sourceDir}/build/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "cl.exe",
|
||||
"CMAKE_CXX_COMPILER": "cl.exe",
|
||||
"BUILD_SHARED_LIBS": "ON",
|
||||
"LV_BUILD_USE_KCONFIG": "ON"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "_base",
|
||||
"hidden": true,
|
||||
"jobs": 12
|
||||
},
|
||||
{
|
||||
"name": "windows-base_dbg",
|
||||
"inherits": "_base",
|
||||
"displayName": "Debug",
|
||||
"configurePreset": "windows-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-base_rel",
|
||||
"inherits": "_base",
|
||||
"displayName": "Release",
|
||||
"configurePreset": "windows-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-base_dbg",
|
||||
"inherits": "_base",
|
||||
"displayName": "Debug",
|
||||
"configurePreset": "linux-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-base_rel",
|
||||
"inherits": "_base",
|
||||
"displayName": "Release",
|
||||
"configurePreset": "linux-base",
|
||||
"configuration": "Release"
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "windows-base_dbg",
|
||||
"displayName": "Debug",
|
||||
"configurePreset": "windows-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-base_rel",
|
||||
"displayName": "Release",
|
||||
"configurePreset": "windows-base",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-base_dbg",
|
||||
"displayName": "Debug",
|
||||
"configurePreset": "linux-base",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-base_rel",
|
||||
"displayName": "Release",
|
||||
"configurePreset": "linux-base",
|
||||
"configuration": "Release"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
LVGL uses the following third-party libraries.
|
||||
For the licenses, see the corresponding `LICENSE.txt` file in each library’s folder.
|
||||
|
||||
**Barcode (Barcode generator)**
|
||||
- Path: src/libs/barcode
|
||||
- Source: https://github.com/fhunleth/code128
|
||||
|
||||
**Expat (XML parser)**
|
||||
- Path: src/libs/expat
|
||||
- Source: https://github.com/libexpat/libexpat
|
||||
|
||||
**FreeType (Font rendering library)**
|
||||
- Path: src/libs/freetype
|
||||
- Source: https://github.com/freetype/freetype
|
||||
- Note: Only the interfaces are used; FreeType itself is not part of LVGL.
|
||||
|
||||
**GifDec (GIF decoder library)**
|
||||
- Path: src/libs/gifdec
|
||||
- Source: https://github.com/lecram/gifdec
|
||||
|
||||
**LodePNG (PNG decoder)**
|
||||
- Path: src/libs/lodepng
|
||||
- Source: https://github.com/lvandeve/lodepng
|
||||
|
||||
**LZ4 (Compression/Decompression)**
|
||||
- Path: src/libs/lz4
|
||||
- Source: https://github.com/lz4/lz4
|
||||
|
||||
**QR Code (QR code generator)**
|
||||
- Path: src/libs/qrcode
|
||||
- Source: https://github.com/nayuki/QR-Code-generator
|
||||
|
||||
**ThorVG (Vector graphics rendering)**
|
||||
- Path: src/libs/thorvg
|
||||
- Source: https://github.com/thorvg/thorvg
|
||||
|
||||
**TinyTTF**
|
||||
- Path: src/libs/tiny_ttf
|
||||
- Source:
|
||||
- https://github.com/nothings/stb (*Only parts are integrated*)
|
||||
- https://github.com/codewitch-honey-crisis/tiny_ttf (*Modified version of the original STB library*)
|
||||
|
||||
**TJPGD (JPEG decoder)**
|
||||
- Path: src/libs/tjpgd
|
||||
- Source: http://elm-chan.org/fsw/tjpgd/00index.html
|
||||
|
||||
**TLSF (Two-Level Segregate Fit memory allocator)**
|
||||
- Path: src/stdlib/builtin
|
||||
- Source: https://github.com/mattconte/tlsf
|
||||
|
||||
**Printf (Printf formatting library)**
|
||||
- Path: src/stdlib/builtin
|
||||
- Source: https://github.com/mpaland/printf
|
||||
|
||||
+2205
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
MIT licence
|
||||
Copyright (c) 2025 LVGL Kft
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,468 @@
|
||||
|
||||
<a href="https://github.com/sponsors/lvgl" target="_blank"><img align="left" src="https://lvgl.io/github-assets/sponsor.png" height="32px"></a>
|
||||
|
||||
<p align="right">
|
||||
<b>English</b> | <a href="./docs/README_zh.md">中文</a> | <a href="./docs/README_pt_BR.md">Português do Brasil</a> | <a href="./docs/README_jp.md">日本語</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://lvgl.io/github-assets/logo-colored.png" width=300px>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Light and Versatile Graphics Library</h1>
|
||||
<br>
|
||||
<div align="center">
|
||||
<img src="https://lvgl.io/github-assets/smartwatch-demo.gif">
|
||||
|
||||
<img border="1px" src="https://lvgl.io/github-assets/widgets-demo.gif">
|
||||
</div>
|
||||
<br>
|
||||
<p align="center">
|
||||
<a href="https://lvgl.io" title="Homepage of LVGL">Website </a> |
|
||||
<a href="https://docs.lvgl.io/" title="Detailed documentation with 100+ examples">Docs</a> |
|
||||
<a href="https://forum.lvgl.io" title="Get help and help others">Forum</a> |
|
||||
<a href="https://lvgl.io/demos" title="Demos running in your browser">Demos</a> |
|
||||
<a href="https://lvgl.io/services" title="Graphics design, UI implementation and consulting">Services</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
## :ledger: Overview
|
||||
|
||||
**Mature and Well-known**<br>
|
||||
LVGL is the most popular free and open source embedded graphics library to create beautiful UIs for any MCU, MPU and display type. It's supported by industry leading vendors and projects like Arm, STM32, NXP, Espressif, Nuvoton, Arduino, RT-Thread, Zephyr, NuttX, Adafruit and many more.
|
||||
|
||||
**Feature Rich**<br>
|
||||
It has all the features to create modern and beautiful GUIs: 30+ built-in widgets, a powerful style system, web inspired layout managers, and a typography system supporting many languages. To integrate LVGL into your platform, all you need is at least 32kB RAM and 128 kB Flash, a C compiler, a frame buffer, and at least an 1/10 screen sized buffer for rendering.
|
||||
|
||||
**Services**<br>
|
||||
Our team is ready to help you with graphics design, UI implementation and consulting services. Contact us if you need some support during the development of your next GUI project.
|
||||
|
||||
## :rocket: Features
|
||||
|
||||
**Free and Portable**
|
||||
- A fully portable C (C++ compatible) library with no external dependencies.
|
||||
- Can be compiled to any MCU or MPU, with any (RT)OS.
|
||||
- Supports monochrome, ePaper, OLED or TFT displays, or even monitors. [Displays](https://docs.lvgl.io/master/details/main-modules/display/index.html)
|
||||
- Distributed under the MIT license, so you can easily use it in commercial projects too.
|
||||
- Needs only 32kB RAM and 128 kB Flash, a frame buffer, and at least an 1/10 screen sized buffer for rendering.
|
||||
- OS, External memory and GPU are supported but not required.
|
||||
|
||||
**Widgets, Styles, Layouts and more**
|
||||
- 30+ built-in [Widgets](https://docs.lvgl.io/master/details/widgets/index.html): Button, Label, Slider, Chart, Keyboard, Meter, Arc, Table and many more.
|
||||
- Flexible [Style system](https://docs.lvgl.io/master/details/common-widget-features/styles/style.html) with ~100 style properties to customize any part of the widgets in any state.
|
||||
- [Flexbox](https://docs.lvgl.io/master/details/common-widget-features/layouts/flex.html) and [Grid](https://docs.lvgl.io/master/details/common-widget-features/layouts/grid.html)-like layouts engines to automatically size and position the widgets in a responsive way.
|
||||
- Texts are rendered with UTF-8 encoding supporting CJK, Thai, Hindi, Arabic, Persian writing systems.
|
||||
- Word wrapping, kerning, text scrolling, sub-pixel rendering, Pinyin-IME Chinese input, Emojis in texts.
|
||||
- Rendering engine supporting animations, anti-aliasing, opacity, smooth scrolling, shadows, image transformation, etc
|
||||
- Supports Mouse, Touchpad, Keypad, Keyboard, External buttons, Encoder [Input devices](https://docs.lvgl.io/master/details/main-modules/indev.html).
|
||||
- [Multiple display](https://docs.lvgl.io/master/details/main-modules/display/overview.html#how-many-displays-can-lvgl-use) support.
|
||||
|
||||
**Binding and Build Support**
|
||||
- [MicroPython Binding](https://blog.lvgl.io/2019-02-20/micropython-bindings) exposes LVGL API
|
||||
- [PikaScript Binding](https://blog.lvgl.io/2022-08-24/pikascript-and-lvgl) python on MCU lighter and easier.
|
||||
- No custom build system is used. You can build LVGL as you build the other files of your project.
|
||||
- Support for Make and [CMake](https://docs.lvgl.io/master/details/integration/building/cmake.html) is included out of the box.
|
||||
- [Develop on PC](https://docs.lvgl.io/master/details/integration/ide/pc-simulator.html) and use the same UI code on embedded hardware.
|
||||
- Convert the C UI code to HTML file with our [Emscripten port](https://github.com/lvgl/lv_web_emscripten).
|
||||
|
||||
**Docs, Tools, and Services**
|
||||
- Detailed [Documentation](https://docs.lvgl.io/) with [100+ simple examples](https://docs.lvgl.io/master/examples.html)
|
||||
- [Services](https://lvgl.io/services) such as User interface design, Implementation and Consulting to make UI development simpler and faster.
|
||||
|
||||
## :heart: Sponsor
|
||||
|
||||
If LVGL saved you a lot of time and money or you just had fun using it, consider [Supporting its Development](https://github.com/sponsors/lvgl).
|
||||
|
||||
**How do we spend the donations?**<br>
|
||||
Our goal is to provide financial compensation for people who do the most for LVGL. It means not only the maintainers but anyone who implements a great feature should get a payment from the accumulated money. We use the donations to cover our operational costs like servers and related services.
|
||||
|
||||
**How to donate?**<br>
|
||||
We use [GitHub Sponsors](https://github.com/sponsors/lvgl) where you can easily send one time or recurring donations. You can also see all of our expenses in a transparent way.
|
||||
|
||||
**How to get paid for your contribution?**<br>
|
||||
If someone implements or fixes an issue labeled as [Sponsored](https://github.com/lvgl/lvgl/labels/Sponsored) he or she will get a payment for that work. We estimate the required time, complexity and importance of the issue and set a price accordingly. To jump in just comment on a [Sponsored](https://github.com/lvgl/lvgl/labels/Sponsored) issue saying "Hi, I'd like to deal with it. This is how I'm planning to fix/implement it...". A work is considered ready when it's approved and merged by a maintainer. After that you can submit and expense at [opencollective.com](https://opencollective.com/lvgl) and you will receive the payment in a few days.
|
||||
|
||||
**Organizations supporting LVGL**<br>
|
||||
[](https://opencollective.com/lvgl)
|
||||
|
||||
**Individuals supporting LVGL**<br>
|
||||
[](https://opencollective.com/lvgl)
|
||||
|
||||
## :package: Packages
|
||||
LVGL is available as:
|
||||
- [Arduino library](https://docs.lvgl.io/master/details/integration/framework/arduino.html)
|
||||
- [PlatformIO package](https://registry.platformio.org/libraries/lvgl/lvgl)
|
||||
- [Zephyr library](https://docs.lvgl.io/master/details/integration/os/zephyr.html)
|
||||
- [ESP-IDF(ESP32) component](https://components.espressif.com/components/lvgl/lvgl)
|
||||
- [NXP MCUXpresso component](https://www.nxp.com/design/software/embedded-software/lvgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
|
||||
- [NuttX library](https://docs.lvgl.io/master/details/integration/os/nuttx.html)
|
||||
- [RT-Thread RTOS](https://docs.lvgl.io/master/details/integration/os/rt-thread.html)
|
||||
- CMSIS-Pack
|
||||
- [RIOT OS package](https://doc.riot-os.org/group__pkg__lvgl.html#details)
|
||||
|
||||
|
||||
## :robot: Examples
|
||||
|
||||
See some examples of creating widgets, using layouts and applying styles. You will find C and MicroPython code, and links to try out or edit the examples in an online MicroPython editor.
|
||||
|
||||
For more examples check out the [Examples](https://github.com/lvgl/lvgl/tree/master/examples) folder.
|
||||
|
||||
|
||||
### Hello world label
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
/*Change the active screen's background color*/
|
||||
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
|
||||
|
||||
/*Create a white label, set its text and align it to the center*/
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello world");
|
||||
lv_obj_set_style_text_color(label, lv_color_hex(0xffffff), LV_PART_MAIN);
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>MicroPython code | <a href="https://sim.lvgl.io/v8.3/micropython/ports/javascript/index.html?script_direct=4ab7c40c35b0dc349aa2f0c3b00938d7d8e8ac9f" target="_blank">Online Simulator</a></summary>
|
||||
|
||||
```python
|
||||
# Change the active screen's background color
|
||||
scr = lv.screen_active()
|
||||
scr.set_style_bg_color(lv.color_hex(0x003a57), lv.PART.MAIN)
|
||||
|
||||
# Create a white label, set its text and align it to the center
|
||||
label = lv.label(lv.screen_active())
|
||||
label.set_text("Hello world")
|
||||
label.set_style_text_color(lv.color_hex(0xffffff), lv.PART.MAIN)
|
||||
label.align(lv.ALIGN.CENTER, 0, 0)
|
||||
```
|
||||
</details>
|
||||
<br>
|
||||
|
||||
### Button with Click Event
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
lv_obj_t * button = lv_button_create(lv_screen_active()); /*Add a button to the current screen*/
|
||||
lv_obj_center(button); /*Set its position*/
|
||||
lv_obj_set_size(button, 100, 50); /*Set its size*/
|
||||
lv_obj_add_event_cb(button, button_event_cb, LV_EVENT_CLICKED, NULL); /*Assign a callback to the button*/
|
||||
|
||||
lv_obj_t * label = lv_label_create(button); /*Add a label to the button*/
|
||||
lv_label_set_text(label, "Button"); /*Set the labels text*/
|
||||
lv_obj_center(label); /*Align the label to the center*/
|
||||
...
|
||||
|
||||
void button_event_cb(lv_event_t * e)
|
||||
{
|
||||
printf("Clicked\n");
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>MicroPython code | <a href="https://sim.lvgl.io/v8.3/micropython/ports/javascript/index.html?script_startup=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/header.py&script=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/widgets/slider/lv_example_slider_2.py&script_direct=926bde43ec7af0146c486de470c53f11f167491e" target="_blank">Online Simulator</a></summary>
|
||||
|
||||
```python
|
||||
def button_event_cb(e):
|
||||
print("Clicked")
|
||||
|
||||
# Create a Button and a Label
|
||||
button = lv.button(lv.screen_active())
|
||||
button.center()
|
||||
button.set_size(100, 50)
|
||||
button.add_event_cb(button_event_cb, lv.EVENT.CLICKED, None)
|
||||
|
||||
label = lv.label(button)
|
||||
label.set_text("Button")
|
||||
label.center()
|
||||
```
|
||||
</details>
|
||||
<br>
|
||||
|
||||
### Checkboxes with Layout
|
||||

|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
|
||||
lv_obj_set_flex_flow(lv_screen_active(), LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(lv_screen_active(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lv_obj_t * cb;
|
||||
cb = lv_checkbox_create(lv_screen_active());
|
||||
lv_checkbox_set_text(cb, "Apple");
|
||||
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
|
||||
|
||||
cb = lv_checkbox_create(lv_screen_active());
|
||||
lv_checkbox_set_text(cb, "Banana");
|
||||
lv_obj_add_state(cb, LV_STATE_CHECKED);
|
||||
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
|
||||
|
||||
cb = lv_checkbox_create(lv_screen_active());
|
||||
lv_checkbox_set_text(cb, "Lemon");
|
||||
lv_obj_add_state(cb, LV_STATE_DISABLED);
|
||||
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
|
||||
|
||||
cb = lv_checkbox_create(lv_screen_active());
|
||||
lv_obj_add_state(cb, LV_STATE_CHECKED | LV_STATE_DISABLED);
|
||||
lv_checkbox_set_text(cb, "Melon\nand a new line");
|
||||
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>MicroPython code | <a href="https://sim.lvgl.io/v8.3/micropython/ports/javascript/index.html?script_startup=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/header.py&script=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/widgets/slider/lv_example_slider_2.py&script_direct=311d37e5f70daf1cb0d2cad24c7f72751b5f1792" target="_blank">Online Simulator</a></summary>
|
||||
|
||||
```python
|
||||
def event_handler(e):
|
||||
code = e.get_code()
|
||||
obj = e.get_target_obj()
|
||||
if code == lv.EVENT.VALUE_CHANGED:
|
||||
txt = obj.get_text()
|
||||
if obj.get_state() & lv.STATE.CHECKED:
|
||||
state = "Checked"
|
||||
else:
|
||||
state = "Unchecked"
|
||||
print(txt + ":" + state)
|
||||
|
||||
|
||||
lv.screen_active().set_flex_flow(lv.FLEX_FLOW.COLUMN)
|
||||
lv.screen_active().set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START, lv.FLEX_ALIGN.CENTER)
|
||||
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.set_text("Apple")
|
||||
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
|
||||
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.set_text("Banana")
|
||||
cb.add_state(lv.STATE.CHECKED)
|
||||
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
|
||||
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.set_text("Lemon")
|
||||
cb.add_state(lv.STATE.DISABLED)
|
||||
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
|
||||
|
||||
cb = lv.checkbox(lv.screen_active())
|
||||
cb.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
|
||||
cb.set_text("Melon")
|
||||
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
|
||||
```
|
||||
|
||||
</details>
|
||||
<br>
|
||||
|
||||
### Styling a Slider
|
||||

|
||||
|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
lv_obj_t * slider = lv_slider_create(lv_screen_active());
|
||||
lv_slider_set_value(slider, 70, LV_ANIM_OFF);
|
||||
lv_obj_set_size(slider, 300, 20);
|
||||
lv_obj_center(slider);
|
||||
|
||||
/*Add local styles to MAIN part (background rectangle)*/
|
||||
lv_obj_set_style_bg_color(slider, lv_color_hex(0x0F1215), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_color(slider, lv_color_hex(0x333943), LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(slider, 5, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_all(slider, 5, LV_PART_MAIN);
|
||||
|
||||
/*Create a reusable style sheet for the INDICATOR part*/
|
||||
static lv_style_t style_indicator;
|
||||
lv_style_init(&style_indicator);
|
||||
lv_style_set_bg_color(&style_indicator, lv_color_hex(0x37B9F5));
|
||||
lv_style_set_bg_grad_color(&style_indicator, lv_color_hex(0x1464F0));
|
||||
lv_style_set_bg_grad_dir(&style_indicator, LV_GRAD_DIR_HOR);
|
||||
lv_style_set_shadow_color(&style_indicator, lv_color_hex(0x37B9F5));
|
||||
lv_style_set_shadow_width(&style_indicator, 15);
|
||||
lv_style_set_shadow_spread(&style_indicator, 5);
|
||||
4
|
||||
/*Add the style sheet to the slider's INDICATOR part*/
|
||||
lv_obj_add_style(slider, &style_indicator, LV_PART_INDICATOR);
|
||||
|
||||
/*Add the same style to the KNOB part too and locally overwrite some properties*/
|
||||
lv_obj_add_style(slider, &style_indicator, LV_PART_KNOB);
|
||||
|
||||
lv_obj_set_style_outline_color(slider, lv_color_hex(0x0096FF), LV_PART_KNOB);
|
||||
lv_obj_set_style_outline_width(slider, 3, LV_PART_KNOB);
|
||||
lv_obj_set_style_outline_pad(slider, -5, LV_PART_KNOB);
|
||||
lv_obj_set_style_shadow_spread(slider, 2, LV_PART_KNOB);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>MicroPython code |
|
||||
<a href="https://sim.lvgl.io/v8.3/micropython/ports/javascript/index.html?script_startup=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/header.py&script=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/widgets/slider/lv_example_slider_2.py&script_direct=c431c7b4dfd2cc0dd9c392b74365d5af6ea986f0" target="_blank">Online Simulator</a>
|
||||
</summary>
|
||||
|
||||
|
||||
```python
|
||||
# Create a slider and add the style
|
||||
slider = lv.slider(lv.screen_active())
|
||||
slider.set_value(70, lv.ANIM.OFF)
|
||||
slider.set_size(300, 20)
|
||||
slider.center()
|
||||
|
||||
# Add local styles to MAIN part (background rectangle)
|
||||
slider.set_style_bg_color(lv.color_hex(0x0F1215), lv.PART.MAIN)
|
||||
slider.set_style_bg_opa(255, lv.PART.MAIN)
|
||||
slider.set_style_border_color(lv.color_hex(0x333943), lv.PART.MAIN)
|
||||
slider.set_style_border_width(5, lv.PART.MAIN)
|
||||
slider.set_style_pad_all(5, lv.PART.MAIN)
|
||||
|
||||
# Create a reusable style sheet for the INDICATOR part
|
||||
style_indicator = lv.style_t()
|
||||
style_indicator.init()
|
||||
style_indicator.set_bg_color(lv.color_hex(0x37B9F5))
|
||||
style_indicator.set_bg_grad_color(lv.color_hex(0x1464F0))
|
||||
style_indicator.set_bg_grad_dir(lv.GRAD_DIR.HOR)
|
||||
style_indicator.set_shadow_color(lv.color_hex(0x37B9F5))
|
||||
style_indicator.set_shadow_width(15)
|
||||
style_indicator.set_shadow_spread(5)
|
||||
|
||||
# Add the style sheet to the slider's INDICATOR part
|
||||
slider.add_style(style_indicator, lv.PART.INDICATOR)
|
||||
slider.add_style(style_indicator, lv.PART.KNOB)
|
||||
|
||||
# Add the same style to the KNOB part too and locally overwrite some properties
|
||||
slider.set_style_outline_color(lv.color_hex(0x0096FF), lv.PART.KNOB)
|
||||
slider.set_style_outline_width(3, lv.PART.KNOB)
|
||||
slider.set_style_outline_pad(-5, lv.PART.KNOB)
|
||||
slider.set_style_shadow_spread(2, lv.PART.KNOB)
|
||||
```
|
||||
</details>
|
||||
<br>
|
||||
|
||||
### English, Hebrew (mixed LTR-RTL) and Chinese texts
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary>C code</summary>
|
||||
|
||||
```c
|
||||
lv_obj_t * ltr_label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(ltr_label, "In modern terminology, a microcontroller is similar to a system on a chip (SoC).");
|
||||
lv_obj_set_style_text_font(ltr_label, &lv_font_montserrat_16, 0);
|
||||
lv_obj_set_width(ltr_label, 310);
|
||||
lv_obj_align(ltr_label, LV_ALIGN_TOP_LEFT, 5, 5);
|
||||
|
||||
lv_obj_t * rtl_label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(rtl_label,"מעבד, או בשמו המלא יחידת עיבוד מרכזית (באנגלית: CPU - Central Processing Unit).");
|
||||
lv_obj_set_style_base_dir(rtl_label, LV_BASE_DIR_RTL, 0);
|
||||
lv_obj_set_style_text_font(rtl_label, &lv_font_dejavu_16_persian_hebrew, 0);
|
||||
lv_obj_set_width(rtl_label, 310);
|
||||
lv_obj_align(rtl_label, LV_ALIGN_LEFT_MID, 5, 0);
|
||||
|
||||
lv_obj_t * cz_label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(cz_label,
|
||||
"嵌入式系统(Embedded System),\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。");
|
||||
lv_obj_set_style_text_font(cz_label, &lv_font_source_han_sans_sc_16_cjk, 0);
|
||||
lv_obj_set_width(cz_label, 310);
|
||||
lv_obj_align(cz_label, LV_ALIGN_BOTTOM_LEFT, 5, -5);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>MicroPython code | <a href="https://sim.lvgl.io/v8.3/micropython/ports/javascript/index.html?script_startup=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/header.py&script=https://raw.githubusercontent.com/lvgl/lvgl/0d9ab4ee0e591aad1970e3c9164fd7c544ecce70/examples/widgets/slider/lv_example_slider_2.py&script_direct=18bb38200a64e10ead1aa17a65c977fc18131842" target="_blank">Online Simulator</a></summary>
|
||||
|
||||
```python
|
||||
ltr_label = lv.label(lv.screen_active())
|
||||
ltr_label.set_text("In modern terminology, a microcontroller is similar to a system on a chip (SoC).")
|
||||
ltr_label.set_style_text_font(lv.font_montserrat_16, 0);
|
||||
|
||||
ltr_label.set_width(310)
|
||||
ltr_label.align(lv.ALIGN.TOP_LEFT, 5, 5)
|
||||
|
||||
rtl_label = lv.label(lv.screen_active())
|
||||
rtl_label.set_text("מעבד, או בשמו המלא יחידת עיבוד מרכזית (באנגלית: CPU - Central Processing Unit).")
|
||||
rtl_label.set_style_base_dir(lv.BASE_DIR.RTL, 0)
|
||||
rtl_label.set_style_text_font(lv.font_dejavu_16_persian_hebrew, 0)
|
||||
rtl_label.set_width(310)
|
||||
rtl_label.align(lv.ALIGN.LEFT_MID, 5, 0)
|
||||
|
||||
font_hans_sans_16_cjk = lv.font_load("S:../../assets/font/lv_font_source_han_sans_sc_16_cjk.fnt")
|
||||
|
||||
cz_label = lv.label(lv.screen_active())
|
||||
cz_label.set_style_text_font(font_hans_sans_16_cjk, 0)
|
||||
cz_label.set_text("嵌入式系统(Embedded System),\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。")
|
||||
cz_label.set_width(310)
|
||||
cz_label.align(lv.ALIGN.BOTTOM_LEFT, 5, -5)
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
## :arrow_forward: Get started
|
||||
This list will guide you to get started with LVGL step-by-step.
|
||||
|
||||
**Get Familiar with LVGL**
|
||||
|
||||
1. Check the [Online demos](https://lvgl.io/demos) to see LVGL in action (3 minutes).
|
||||
2. Read the [Introduction](https://docs.lvgl.io/master/intro/index.html) page of the documentation (5 minutes).
|
||||
3. Get familiar with the basics on the [Quick overview](https://docs.lvgl.io/master/intro/getting_started.html#lvgl-basics) page (15 minutes).
|
||||
|
||||
**Start to Use LVGL**
|
||||
|
||||
4. Set up a [Simulator](https://docs.lvgl.io/master/details/integration/ide/pc-simulator.html#simulator) (10 minutes).
|
||||
5. Try out some [Examples](https://github.com/lvgl/lvgl/tree/master/examples).
|
||||
6. Port LVGL to a board. See the [Porting](https://docs.lvgl.io/master/details/integration/adding-lvgl-to-your-project/index.html) guide or check out the ready-to-use [Projects](https://github.com/lvgl?q=lv_port_).
|
||||
|
||||
**Become a Pro**
|
||||
|
||||
7. Read the [Main-Modules](https://docs.lvgl.io/master/details/main-modules/index.html) page to get a better understanding of the library (2-3 hours)
|
||||
8. Check the documentation of the [Widgets](https://docs.lvgl.io/master/details/widgets/index.html) to see their features and usage
|
||||
|
||||
**Get Help and Help Others**
|
||||
|
||||
9. If you have questions go to the [Forum](http://forum.lvgl.io/)
|
||||
10. Read the [Contributing](https://docs.lvgl.io/master/contributing/index.html) guide to see how you can help to improve LVGL (15 minutes)
|
||||
|
||||
|
||||
## :handshake: Services
|
||||
LVGL LLC was established to provide a solid background for LVGL library and to offer several type of services to help you in UI development. With 15+ years of experience in the user interface and graphics industry we can help you the bring your UI to the next level.
|
||||
|
||||
- **Graphics design** Our in-house graphics designers are experts in creating beautiful modern designs which fit to your product and the resources of your hardware.
|
||||
- **UI implementation** We can also implement your UI based on the design you or we have created. You can be sure that we will make the most out of your hardware and LVGL. If a feature or widget is missing from LVGL, don't worry, we will implement it for you.
|
||||
- **Consulting and Support** We can support you with consulting as well to avoid pricey and time consuming mistakes during the UI development.
|
||||
- **Board certification** For companies who are offering development boards, or production ready kits we do board certification which shows how board can run LVGL.
|
||||
|
||||
|
||||
Check out our [Demos](https://lvgl.io/demos) as reference. For more information take look at the [Services page](https://lvgl.io/services).
|
||||
|
||||
[Contact us](https://lvgl.io/#contact) and tell how we can help.
|
||||
|
||||
|
||||
## :star2: Contributing
|
||||
LVGL is an open project and contribution is very welcome. There are many ways to contribute from simply speaking about your project, through writing examples, improving the documentation, fixing bugs or even hosting your own project under the LVGL organization.
|
||||
|
||||
For a detailed description of contribution opportunities visit the [Contributing](https://docs.lvgl.io/master/contributing/index.html) section of the documentation.
|
||||
|
||||
More than 300 people already left their fingerprint in LVGL. Be one them! See you here! :slightly_smiling_face:
|
||||
|
||||
<a href="https://github.com/lvgl/lvgl/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=lvgl/lvgl&max=48" />
|
||||
</a>
|
||||
|
||||
... and many other.
|
||||
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for bridge
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
objs = []
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
objs = objs + SConscript(cwd + '/env_support/rt-thread/SConscript')
|
||||
|
||||
Return('objs')
|
||||
@@ -0,0 +1,104 @@
|
||||
# ESP-IDF component file for make based commands
|
||||
|
||||
COMPONENT_SRCDIRS := . \
|
||||
src \
|
||||
src/core \
|
||||
src/extra \
|
||||
src/font \
|
||||
src/hal \
|
||||
src/tick \
|
||||
src/display \
|
||||
src/indev \
|
||||
src/osal \
|
||||
src/misc \
|
||||
src/misc/cache \
|
||||
src/misc/cache/class \
|
||||
src/misc/cache/instance \
|
||||
src/draw \
|
||||
src/draw/arm2d \
|
||||
src/draw/nxp \
|
||||
src/draw/sdl \
|
||||
src/draw/stm32_dma2d \
|
||||
src/draw/sw \
|
||||
src/draw/sw/blend \
|
||||
src/draw/swm342_dma2d \
|
||||
src/others \
|
||||
src/layouts \
|
||||
src/layouts/flex \
|
||||
src/layouts/grid \
|
||||
src/libs \
|
||||
src/libs/bin_decoder \
|
||||
src/libs/bmp \
|
||||
src/libs/ffmpeg \
|
||||
src/libs/freetype \
|
||||
src/libs/fsdrv \
|
||||
src/libs/gif \
|
||||
src/libs/libpng \
|
||||
src/libs/lodepng \
|
||||
src/libs/png \
|
||||
src/libs/qrcode \
|
||||
src/libs/rlottie \
|
||||
src/libs/rle \
|
||||
src/libs/sjgp \
|
||||
src/libs/tiny_ttf \
|
||||
src/libs/tjpgd \
|
||||
src/libs/libjpeg_turbo \
|
||||
src/others/fragment \
|
||||
src/others/gridnav \
|
||||
src/others/ime \
|
||||
src/others/imgfont \
|
||||
src/others/monkey \
|
||||
src/others/msg \
|
||||
src/others/observer \
|
||||
src/others/snapshot \
|
||||
src/others/sysmon \
|
||||
src/others/test \
|
||||
src/others/xml \
|
||||
src/others/xml/parsers \
|
||||
src/themes \
|
||||
src/themes/basic \
|
||||
src/themes/default \
|
||||
src/themes/mono \
|
||||
src/themes/simple \
|
||||
src/widgets \
|
||||
src/widgets/animimg \
|
||||
src/widgets/arc \
|
||||
src/widgets/bar \
|
||||
src/widgets/button \
|
||||
src/widgets/buttonmatrix \
|
||||
src/widgets/calendar \
|
||||
src/widgets/canvas \
|
||||
src/widgets/chart \
|
||||
src/widgets/checkbox \
|
||||
src/widgets/colorwheel \
|
||||
src/widgets/dropdown \
|
||||
src/widgets/image \
|
||||
src/widgets/imgbtn \
|
||||
src/widgets/keyboard \
|
||||
src/widgets/label \
|
||||
src/widgets/led \
|
||||
src/widgets/line \
|
||||
src/widgets/list \
|
||||
src/widgets/menu \
|
||||
src/widgets/meter \
|
||||
src/widgets/msgbox \
|
||||
src/widgets/roller \
|
||||
src/widgets/scale \
|
||||
src/widgets/slider \
|
||||
src/widgets/span \
|
||||
src/widgets/spinbox \
|
||||
src/widgets/spinner \
|
||||
src/widgets/switch \
|
||||
src/widgets/table \
|
||||
src/widgets/tabview \
|
||||
src/widgets/textarea \
|
||||
src/widgets/tileview \
|
||||
src/widgets/win \
|
||||
src/stdlib \
|
||||
src/stdlib/builtin
|
||||
|
||||
ifeq ($(CONFIG_LV_USE_THORVG_INTERNAL),y)
|
||||
COMPONENT_SRCDIRS += src/libs/thorvg
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := $(COMPONENT_SRCDIRS) .
|
||||
@@ -0,0 +1,5 @@
|
||||
description: LVGL - Light and Versatile Graphics Library
|
||||
url: https://lvgl.io/
|
||||
repository: https://github.com/lvgl/lvgl.git
|
||||
documentation: https://docs.lvgl.io/
|
||||
issues: https://github.com/lvgl/lvgl/issues
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "lvgl",
|
||||
"version": "9.3.0",
|
||||
"keywords": "graphics, gui, embedded, tft, lvgl",
|
||||
"description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lvgl/lvgl.git"
|
||||
},
|
||||
"build": {
|
||||
"includeDir": "."
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://lvgl.io",
|
||||
"frameworks": "*",
|
||||
"platforms": "*"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
name=lvgl
|
||||
version=9.3.0
|
||||
author=kisvegabor
|
||||
maintainer=kisvegabor,embeddedt,pete-pjb
|
||||
sentence=Full-featured Graphics Library for Embedded Systems
|
||||
paragraph=Powerful and easy-to-use embedded GUI with many widgets, advanced visual effects (opacity, antialiasing, animations) and low memory requirements (16K RAM, 64K Flash).
|
||||
category=Display
|
||||
url=https://lvgl.io
|
||||
architectures=*
|
||||
includes=lvgl.h
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file lv_version.h
|
||||
* The current version of LVGL
|
||||
*/
|
||||
|
||||
#ifndef LVGL_VERSION_H
|
||||
#define LVGL_VERSION_H
|
||||
|
||||
#define LVGL_VERSION_MAJOR 9
|
||||
#define LVGL_VERSION_MINOR 3
|
||||
#define LVGL_VERSION_PATCH 0
|
||||
#define LVGL_VERSION_INFO ""
|
||||
|
||||
#endif /* LVGL_VERSION_H */
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file version.h
|
||||
* The current version of LVGL
|
||||
*/
|
||||
|
||||
#ifndef LVGL_VERSION_H
|
||||
#define LVGL_VERSION_H
|
||||
|
||||
#define LVGL_VERSION_MAJOR @LVGL_VERSION_MAJOR@
|
||||
#define LVGL_VERSION_MINOR @LVGL_VERSION_MINOR@
|
||||
#define LVGL_VERSION_PATCH @LVGL_VERSION_PATCH@
|
||||
#define LVGL_VERSION_INFO "@LVGL_VERSION_INFO@"
|
||||
|
||||
#endif /*LVGL_VERSION_H*/
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* @file lvgl.h
|
||||
* Include all LVGL related headers
|
||||
*/
|
||||
|
||||
#ifndef LVGL_H
|
||||
#define LVGL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************
|
||||
* CURRENT VERSION OF LVGL
|
||||
***************************/
|
||||
#include "lv_version.h"
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "src/lv_init.h"
|
||||
|
||||
#include "src/stdlib/lv_mem.h"
|
||||
#include "src/stdlib/lv_string.h"
|
||||
#include "src/stdlib/lv_sprintf.h"
|
||||
|
||||
#include "src/misc/lv_log.h"
|
||||
#include "src/misc/lv_timer.h"
|
||||
#include "src/misc/lv_math.h"
|
||||
#include "src/misc/lv_array.h"
|
||||
#include "src/misc/lv_async.h"
|
||||
#include "src/misc/lv_anim_timeline.h"
|
||||
#include "src/misc/lv_profiler_builtin.h"
|
||||
#include "src/misc/lv_rb.h"
|
||||
#include "src/misc/lv_utils.h"
|
||||
#include "src/misc/lv_iter.h"
|
||||
#include "src/misc/lv_circle_buf.h"
|
||||
#include "src/misc/lv_tree.h"
|
||||
#include "src/misc/cache/lv_cache.h"
|
||||
|
||||
#include "src/tick/lv_tick.h"
|
||||
|
||||
#include "src/core/lv_obj.h"
|
||||
#include "src/core/lv_group.h"
|
||||
#include "src/indev/lv_indev.h"
|
||||
#include "src/indev/lv_indev_gesture.h"
|
||||
#include "src/core/lv_refr.h"
|
||||
#include "src/display/lv_display.h"
|
||||
|
||||
#include "src/font/lv_font.h"
|
||||
#include "src/font/lv_binfont_loader.h"
|
||||
#include "src/font/lv_font_fmt_txt.h"
|
||||
|
||||
#include "src/widgets/animimage/lv_animimage.h"
|
||||
#include "src/widgets/arc/lv_arc.h"
|
||||
#include "src/widgets/bar/lv_bar.h"
|
||||
#include "src/widgets/button/lv_button.h"
|
||||
#include "src/widgets/buttonmatrix/lv_buttonmatrix.h"
|
||||
#include "src/widgets/calendar/lv_calendar.h"
|
||||
#include "src/widgets/canvas/lv_canvas.h"
|
||||
#include "src/widgets/chart/lv_chart.h"
|
||||
#include "src/widgets/checkbox/lv_checkbox.h"
|
||||
#include "src/widgets/dropdown/lv_dropdown.h"
|
||||
#include "src/widgets/image/lv_image.h"
|
||||
#include "src/widgets/imagebutton/lv_imagebutton.h"
|
||||
#include "src/widgets/keyboard/lv_keyboard.h"
|
||||
#include "src/widgets/label/lv_label.h"
|
||||
#include "src/widgets/led/lv_led.h"
|
||||
#include "src/widgets/line/lv_line.h"
|
||||
#include "src/widgets/list/lv_list.h"
|
||||
#include "src/widgets/lottie/lv_lottie.h"
|
||||
#include "src/widgets/menu/lv_menu.h"
|
||||
#include "src/widgets/msgbox/lv_msgbox.h"
|
||||
#include "src/widgets/roller/lv_roller.h"
|
||||
#include "src/widgets/scale/lv_scale.h"
|
||||
#include "src/widgets/slider/lv_slider.h"
|
||||
#include "src/widgets/span/lv_span.h"
|
||||
#include "src/widgets/spinbox/lv_spinbox.h"
|
||||
#include "src/widgets/spinner/lv_spinner.h"
|
||||
#include "src/widgets/switch/lv_switch.h"
|
||||
#include "src/widgets/table/lv_table.h"
|
||||
#include "src/widgets/tabview/lv_tabview.h"
|
||||
#include "src/widgets/textarea/lv_textarea.h"
|
||||
#include "src/widgets/tileview/lv_tileview.h"
|
||||
#include "src/widgets/win/lv_win.h"
|
||||
#include "src/widgets/3dtexture/lv_3dtexture.h"
|
||||
|
||||
#include "src/others/snapshot/lv_snapshot.h"
|
||||
#include "src/others/sysmon/lv_sysmon.h"
|
||||
#include "src/others/monkey/lv_monkey.h"
|
||||
#include "src/others/gridnav/lv_gridnav.h"
|
||||
#include "src/others/fragment/lv_fragment.h"
|
||||
#include "src/others/imgfont/lv_imgfont.h"
|
||||
#include "src/others/observer/lv_observer.h"
|
||||
#include "src/others/ime/lv_ime_pinyin.h"
|
||||
#include "src/others/file_explorer/lv_file_explorer.h"
|
||||
#include "src/others/font_manager/lv_font_manager.h"
|
||||
#include "src/others/xml/lv_xml.h"
|
||||
#include "src/others/xml/lv_xml_component.h"
|
||||
#include "src/others/test/lv_test.h"
|
||||
|
||||
#include "src/libs/barcode/lv_barcode.h"
|
||||
#include "src/libs/bin_decoder/lv_bin_decoder.h"
|
||||
#include "src/libs/bmp/lv_bmp.h"
|
||||
#include "src/libs/rle/lv_rle.h"
|
||||
#include "src/libs/fsdrv/lv_fsdrv.h"
|
||||
#include "src/libs/lodepng/lv_lodepng.h"
|
||||
#include "src/libs/libpng/lv_libpng.h"
|
||||
#include "src/libs/gif/lv_gif.h"
|
||||
#include "src/libs/qrcode/lv_qrcode.h"
|
||||
#include "src/libs/tjpgd/lv_tjpgd.h"
|
||||
#include "src/libs/libjpeg_turbo/lv_libjpeg_turbo.h"
|
||||
#include "src/libs/freetype/lv_freetype.h"
|
||||
#include "src/libs/rlottie/lv_rlottie.h"
|
||||
#include "src/libs/ffmpeg/lv_ffmpeg.h"
|
||||
#include "src/libs/tiny_ttf/lv_tiny_ttf.h"
|
||||
#include "src/libs/svg/lv_svg.h"
|
||||
#include "src/libs/svg/lv_svg_render.h"
|
||||
|
||||
#include "src/layouts/lv_layout.h"
|
||||
|
||||
#include "src/draw/lv_draw_buf.h"
|
||||
#include "src/draw/lv_draw_vector.h"
|
||||
#include "src/draw/sw/lv_draw_sw_utils.h"
|
||||
|
||||
#include "src/themes/lv_theme.h"
|
||||
|
||||
#include "src/drivers/lv_drivers.h"
|
||||
|
||||
#include "src/lv_api_map_v8.h"
|
||||
#include "src/lv_api_map_v9_0.h"
|
||||
#include "src/lv_api_map_v9_1.h"
|
||||
|
||||
#if LV_USE_PRIVATE_API
|
||||
#include "src/lvgl_private.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/** Gives 1 if the x.y.z version is supported in the current version
|
||||
* Usage:
|
||||
*
|
||||
* - Require v6
|
||||
* #if LV_VERSION_CHECK(6,0,0)
|
||||
* new_func_in_v6();
|
||||
* #endif
|
||||
*
|
||||
*
|
||||
* - Require at least v5.3
|
||||
* #if LV_VERSION_CHECK(5,3,0)
|
||||
* new_feature_from_v5_3();
|
||||
* #endif
|
||||
*
|
||||
*
|
||||
* - Require v5.3.2 bugfixes
|
||||
* #if LV_VERSION_CHECK(5,3,2)
|
||||
* bugfix_in_v5_3_2();
|
||||
* #endif
|
||||
*
|
||||
*/
|
||||
#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH)))
|
||||
|
||||
/**
|
||||
* Wrapper functions for VERSION macros
|
||||
*/
|
||||
|
||||
static inline int lv_version_major(void)
|
||||
{
|
||||
return LVGL_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
static inline int lv_version_minor(void)
|
||||
{
|
||||
return LVGL_VERSION_MINOR;
|
||||
}
|
||||
|
||||
static inline int lv_version_patch(void)
|
||||
{
|
||||
return LVGL_VERSION_PATCH;
|
||||
}
|
||||
|
||||
static inline const char * lv_version_info(void)
|
||||
{
|
||||
return LVGL_VERSION_INFO;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LVGL_H*/
|
||||
@@ -0,0 +1,12 @@
|
||||
LVGL_PATH ?= ${shell pwd}/lvgl
|
||||
|
||||
ASRCS += $(shell find $(LVGL_PATH)/src -type f -name '*.S')
|
||||
CSRCS += $(shell find $(LVGL_PATH)/src -type f -name '*.c')
|
||||
CSRCS += $(shell find $(LVGL_PATH)/demos -type f -name '*.c')
|
||||
CSRCS += $(shell find $(LVGL_PATH)/examples -type f -name '*.c')
|
||||
CXXEXT := .cpp
|
||||
CXXSRCS += $(shell find $(LVGL_PATH)/src -type f -name '*${CXXEXT}')
|
||||
|
||||
AFLAGS += "-I$(LVGL_PATH)"
|
||||
CFLAGS += "-I$(LVGL_PATH)"
|
||||
CXXFLAGS += "-I$(LVGL_PATH)"
|
||||
@@ -0,0 +1,10 @@
|
||||
prefix="@CMAKE_INSTALL_PREFIX@"
|
||||
includedir="${prefix}/@INC_INSTALL_DIR@"
|
||||
libdir=${prefix}/lib
|
||||
|
||||
Name: lvgl
|
||||
Description: Light and Versatile Graphics Library
|
||||
URL: https://lvgl.io/
|
||||
Version: @LVGL_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -llvgl
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file lvgl_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LVGL_PRIVATE_H
|
||||
#define LVGL_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "src/core/lv_global.h"
|
||||
|
||||
#include "src/display/lv_display_private.h"
|
||||
#include "src/indev/lv_indev_private.h"
|
||||
#include "src/misc/lv_text_private.h"
|
||||
#include "src/misc/cache/lv_cache_entry_private.h"
|
||||
#include "src/misc/cache/lv_cache_private.h"
|
||||
#include "src/layouts/lv_layout_private.h"
|
||||
#include "src/stdlib/lv_mem_private.h"
|
||||
#include "src/others/file_explorer/lv_file_explorer_private.h"
|
||||
#include "src/others/sysmon/lv_sysmon_private.h"
|
||||
#include "src/others/monkey/lv_monkey_private.h"
|
||||
#include "src/others/ime/lv_ime_pinyin_private.h"
|
||||
#include "src/others/fragment/lv_fragment_private.h"
|
||||
#include "src/others/observer/lv_observer_private.h"
|
||||
#include "src/others/xml/lv_xml_private.h"
|
||||
#include "src/libs/qrcode/lv_qrcode_private.h"
|
||||
#include "src/libs/barcode/lv_barcode_private.h"
|
||||
#include "src/libs/gif/lv_gif_private.h"
|
||||
#include "src/draw/lv_draw_triangle_private.h"
|
||||
#include "src/draw/lv_draw_private.h"
|
||||
#include "src/draw/lv_draw_rect_private.h"
|
||||
#include "src/draw/lv_draw_image_private.h"
|
||||
#include "src/draw/lv_image_decoder_private.h"
|
||||
#include "src/draw/lv_draw_label_private.h"
|
||||
#include "src/draw/lv_draw_vector_private.h"
|
||||
#include "src/draw/lv_draw_buf_private.h"
|
||||
#include "src/draw/lv_draw_mask_private.h"
|
||||
#include "src/draw/sw/lv_draw_sw_private.h"
|
||||
#include "src/draw/sw/lv_draw_sw_mask_private.h"
|
||||
#include "src/draw/sw/blend/lv_draw_sw_blend_private.h"
|
||||
#include "src/drivers/libinput/lv_xkb_private.h"
|
||||
#include "src/drivers/libinput/lv_libinput_private.h"
|
||||
#include "src/drivers/evdev/lv_evdev_private.h"
|
||||
#include "src/font/lv_font_fmt_txt_private.h"
|
||||
#include "src/themes/lv_theme_private.h"
|
||||
#include "src/core/lv_refr_private.h"
|
||||
#include "src/core/lv_obj_style_private.h"
|
||||
#include "src/core/lv_obj_private.h"
|
||||
#include "src/core/lv_obj_scroll_private.h"
|
||||
#include "src/core/lv_obj_draw_private.h"
|
||||
#include "src/core/lv_obj_class_private.h"
|
||||
#include "src/core/lv_group_private.h"
|
||||
#include "src/core/lv_obj_event_private.h"
|
||||
#include "src/misc/lv_timer_private.h"
|
||||
#include "src/misc/lv_area_private.h"
|
||||
#include "src/misc/lv_fs_private.h"
|
||||
#include "src/misc/lv_profiler_builtin_private.h"
|
||||
#include "src/misc/lv_event_private.h"
|
||||
#include "src/misc/lv_bidi_private.h"
|
||||
#include "src/misc/lv_rb_private.h"
|
||||
#include "src/misc/lv_style_private.h"
|
||||
#include "src/misc/lv_color_op_private.h"
|
||||
#include "src/misc/lv_anim_private.h"
|
||||
#include "src/widgets/msgbox/lv_msgbox_private.h"
|
||||
#include "src/widgets/buttonmatrix/lv_buttonmatrix_private.h"
|
||||
#include "src/widgets/slider/lv_slider_private.h"
|
||||
#include "src/widgets/switch/lv_switch_private.h"
|
||||
#include "src/widgets/calendar/lv_calendar_private.h"
|
||||
#include "src/widgets/imagebutton/lv_imagebutton_private.h"
|
||||
#include "src/widgets/bar/lv_bar_private.h"
|
||||
#include "src/widgets/image/lv_image_private.h"
|
||||
#include "src/widgets/textarea/lv_textarea_private.h"
|
||||
#include "src/widgets/table/lv_table_private.h"
|
||||
#include "src/widgets/checkbox/lv_checkbox_private.h"
|
||||
#include "src/widgets/roller/lv_roller_private.h"
|
||||
#include "src/widgets/win/lv_win_private.h"
|
||||
#include "src/widgets/keyboard/lv_keyboard_private.h"
|
||||
#include "src/widgets/line/lv_line_private.h"
|
||||
#include "src/widgets/animimage/lv_animimage_private.h"
|
||||
#include "src/widgets/dropdown/lv_dropdown_private.h"
|
||||
#include "src/widgets/menu/lv_menu_private.h"
|
||||
#include "src/widgets/chart/lv_chart_private.h"
|
||||
#include "src/widgets/button/lv_button_private.h"
|
||||
#include "src/widgets/scale/lv_scale_private.h"
|
||||
#include "src/widgets/led/lv_led_private.h"
|
||||
#include "src/widgets/arc/lv_arc_private.h"
|
||||
#include "src/widgets/tileview/lv_tileview_private.h"
|
||||
#include "src/widgets/spinbox/lv_spinbox_private.h"
|
||||
#include "src/widgets/span/lv_span_private.h"
|
||||
#include "src/widgets/label/lv_label_private.h"
|
||||
#include "src/widgets/canvas/lv_canvas_private.h"
|
||||
#include "src/widgets/tabview/lv_tabview_private.h"
|
||||
#include "src/widgets/3dtexture/lv_3dtexture_private.h"
|
||||
#include "src/tick/lv_tick_private.h"
|
||||
#include "src/stdlib/builtin/lv_tlsf_private.h"
|
||||
#include "src/libs/rlottie/lv_rlottie_private.h"
|
||||
#include "src/libs/ffmpeg/lv_ffmpeg_private.h"
|
||||
#include "src/widgets/lottie/lv_lottie_private.h"
|
||||
#include "src/osal/lv_os_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LVGL_PRIVATE_H*/
|
||||
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* @file lv_global.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLOBAL_H
|
||||
#define LV_GLOBAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../draw/lv_draw.h"
|
||||
#if LV_USE_DRAW_SW
|
||||
#include "../draw/sw/lv_draw_sw.h"
|
||||
#endif
|
||||
#include "../misc/lv_anim.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_color_op.h"
|
||||
#include "../misc/lv_ll.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../misc/lv_timer.h"
|
||||
#include "../osal/lv_os.h"
|
||||
#include "../others/sysmon/lv_sysmon.h"
|
||||
#include "../stdlib/builtin/lv_tlsf.h"
|
||||
|
||||
#if LV_USE_FONT_COMPRESSED
|
||||
#include "../font/lv_font_fmt_txt_private.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS != LV_OS_NONE && defined(__linux__)
|
||||
#include "../osal/lv_linux_private.h"
|
||||
#endif
|
||||
|
||||
#include "../tick/lv_tick.h"
|
||||
#include "../layouts/lv_layout.h"
|
||||
|
||||
#include "../misc/lv_types.h"
|
||||
|
||||
#include "../misc/lv_timer_private.h"
|
||||
#include "../misc/lv_anim_private.h"
|
||||
#include "../tick/lv_tick_private.h"
|
||||
#include "../draw/lv_draw_buf_private.h"
|
||||
#include "../draw/lv_draw_private.h"
|
||||
#include "../draw/sw/lv_draw_sw_private.h"
|
||||
#include "../draw/sw/lv_draw_sw_mask_private.h"
|
||||
#include "../stdlib/builtin/lv_tlsf_private.h"
|
||||
#include "../others/sysmon/lv_sysmon_private.h"
|
||||
#include "../others/test/lv_test_private.h"
|
||||
#include "../layouts/lv_layout_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define ZERO_MEM_SENTINEL 0xa1b2c3d4
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_SPAN != 0
|
||||
struct _snippet_stack;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FREETYPE
|
||||
struct _lv_freetype_context_t;
|
||||
#endif
|
||||
|
||||
#if LV_USE_PROFILER && LV_USE_PROFILER_BUILTIN
|
||||
struct _lv_profiler_builtin_ctx_t;
|
||||
#endif
|
||||
|
||||
#if LV_USE_NUTTX
|
||||
struct _lv_nuttx_ctx_t;
|
||||
#endif
|
||||
|
||||
typedef struct _lv_global_t {
|
||||
bool inited;
|
||||
bool deinit_in_progress; /**< Can be used e.g. in the LV_EVENT_DELETE to deinit the drivers too */
|
||||
|
||||
lv_ll_t disp_ll;
|
||||
lv_display_t * disp_refresh;
|
||||
lv_display_t * disp_default;
|
||||
|
||||
lv_ll_t style_trans_ll;
|
||||
bool style_refresh;
|
||||
uint32_t style_custom_table_size;
|
||||
uint32_t style_last_custom_prop_id;
|
||||
uint8_t * style_custom_prop_flag_lookup_table;
|
||||
|
||||
lv_ll_t group_ll;
|
||||
lv_group_t * group_default;
|
||||
|
||||
lv_ll_t indev_ll;
|
||||
lv_indev_t * indev_active;
|
||||
lv_obj_t * indev_obj_active;
|
||||
|
||||
uint32_t layout_count;
|
||||
lv_layout_dsc_t * layout_list;
|
||||
bool layout_update_mutex;
|
||||
|
||||
uint32_t memory_zero;
|
||||
uint32_t math_rand_seed;
|
||||
|
||||
lv_event_t * event_header;
|
||||
uint32_t event_last_register_id;
|
||||
|
||||
lv_timer_state_t timer_state;
|
||||
lv_anim_state_t anim_state;
|
||||
lv_tick_state_t tick_state;
|
||||
|
||||
lv_draw_buf_handlers_t draw_buf_handlers;
|
||||
lv_draw_buf_handlers_t font_draw_buf_handlers;
|
||||
lv_draw_buf_handlers_t image_cache_draw_buf_handlers; /**< Ensure that all assigned draw buffers
|
||||
* can be managed by image cache. */
|
||||
|
||||
lv_ll_t img_decoder_ll;
|
||||
|
||||
lv_cache_t * img_cache;
|
||||
lv_cache_t * img_header_cache;
|
||||
|
||||
lv_draw_global_info_t draw_info;
|
||||
lv_ll_t draw_sw_blend_handler_ll;
|
||||
#if defined(LV_DRAW_SW_SHADOW_CACHE_SIZE) && LV_DRAW_SW_SHADOW_CACHE_SIZE > 0
|
||||
lv_draw_sw_shadow_cache_t sw_shadow_cache;
|
||||
#endif
|
||||
#if LV_DRAW_SW_COMPLEX
|
||||
lv_draw_sw_mask_radius_circle_dsc_arr_t sw_circle_cache;
|
||||
#endif
|
||||
|
||||
#if LV_USE_LOG
|
||||
lv_log_print_g_cb_t custom_log_print_cb;
|
||||
#endif
|
||||
|
||||
#if LV_USE_LOG && LV_LOG_USE_TIMESTAMP
|
||||
uint32_t log_last_log_time;
|
||||
#endif
|
||||
|
||||
#if LV_USE_THEME_SIMPLE
|
||||
void * theme_simple;
|
||||
#endif
|
||||
|
||||
#if LV_USE_THEME_DEFAULT
|
||||
void * theme_default;
|
||||
#endif
|
||||
|
||||
#if LV_USE_THEME_MONO
|
||||
void * theme_mono;
|
||||
#endif
|
||||
|
||||
#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN
|
||||
lv_tlsf_state_t tlsf_state;
|
||||
#endif
|
||||
|
||||
lv_ll_t fsdrv_ll;
|
||||
#if LV_USE_FS_STDIO != '\0'
|
||||
lv_fs_drv_t stdio_fs_drv;
|
||||
#endif
|
||||
#if LV_USE_FS_POSIX
|
||||
lv_fs_drv_t posix_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_FATFS
|
||||
lv_fs_drv_t fatfs_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_WIN32 != '\0'
|
||||
lv_fs_drv_t win32_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_UEFI
|
||||
lv_fs_drv_t uefi_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_LITTLEFS
|
||||
lv_fs_drv_t littlefs_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_ARDUINO_ESP_LITTLEFS
|
||||
lv_fs_drv_t arduino_esp_littlefs_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FS_ARDUINO_SD
|
||||
lv_fs_drv_t arduino_sd_fs_drv;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FREETYPE
|
||||
struct _lv_freetype_context_t * ft_context;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FONT_COMPRESSED
|
||||
lv_font_fmt_rle_t font_fmt_rle;
|
||||
#endif
|
||||
|
||||
#if LV_USE_SPAN != 0
|
||||
struct _snippet_stack * span_snippet_stack;
|
||||
#endif
|
||||
|
||||
#if LV_USE_PROFILER && LV_USE_PROFILER_BUILTIN
|
||||
struct _lv_profiler_builtin_ctx_t * profiler_context;
|
||||
#endif
|
||||
|
||||
#if LV_USE_FILE_EXPLORER != 0
|
||||
lv_style_t fe_list_button_style;
|
||||
#endif
|
||||
|
||||
#if LV_USE_MEM_MONITOR
|
||||
lv_sysmon_backend_data_t sysmon_mem;
|
||||
#endif
|
||||
|
||||
#if LV_USE_IME_PINYIN != 0
|
||||
size_t ime_cand_len;
|
||||
#endif
|
||||
|
||||
#if LV_USE_OBJ_ID_BUILTIN
|
||||
void * objid_array;
|
||||
uint32_t objid_count;
|
||||
#endif
|
||||
|
||||
#if LV_USE_TEST
|
||||
lv_test_state_t test_state;
|
||||
#endif
|
||||
|
||||
#if LV_USE_NUTTX
|
||||
struct _lv_nuttx_ctx_t * nuttx_ctx;
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS != LV_OS_NONE
|
||||
lv_mutex_t lv_general_mutex;
|
||||
#if defined(__linux__)
|
||||
lv_proc_stat_t linux_last_proc_stat;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS == LV_OS_FREERTOS
|
||||
uint32_t freertos_idle_time_sum;
|
||||
uint32_t freertos_non_idle_time_sum;
|
||||
uint32_t freertos_task_switch_timestamp;
|
||||
bool freertos_idle_task_running;
|
||||
#endif
|
||||
|
||||
#if LV_USE_EVDEV
|
||||
lv_evdev_discovery_t * evdev_discovery;
|
||||
#endif
|
||||
|
||||
void * user_data;
|
||||
} lv_global_t;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#if LV_ENABLE_GLOBAL_CUSTOM
|
||||
#include LV_GLOBAL_CUSTOM_INCLUDE
|
||||
|
||||
#ifndef LV_GLOBAL_CUSTOM
|
||||
#define LV_GLOBAL_CUSTOM() lv_global_default()
|
||||
#endif
|
||||
#define LV_GLOBAL_DEFAULT() LV_GLOBAL_CUSTOM()
|
||||
#else
|
||||
LV_ATTRIBUTE_EXTERN_DATA extern lv_global_t lv_global;
|
||||
#define LV_GLOBAL_DEFAULT() (&lv_global)
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
#if LV_ENABLE_GLOBAL_CUSTOM
|
||||
/**
|
||||
* Get the default global object for current thread
|
||||
* @return pointer to the default global object
|
||||
*/
|
||||
lv_global_t * lv_global_default(void);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLOBAL_H*/
|
||||
@@ -0,0 +1,530 @@
|
||||
/**
|
||||
* @file lv_group.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_group_private.h"
|
||||
#include "../core/lv_obj_private.h"
|
||||
#include "../core/lv_global.h"
|
||||
#include "../indev/lv_indev.h"
|
||||
#include "../misc/lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define default_group LV_GLOBAL_DEFAULT()->group_default
|
||||
#define group_ll_p &(LV_GLOBAL_DEFAULT()->group_ll)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *),
|
||||
void * (*move)(const lv_ll_t *, const void *));
|
||||
static void lv_group_refocus(lv_group_t * g);
|
||||
static lv_indev_t * get_indev(const lv_group_t * g);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_group_init(void)
|
||||
{
|
||||
lv_ll_init(group_ll_p, sizeof(lv_group_t));
|
||||
}
|
||||
|
||||
void lv_group_deinit(void)
|
||||
{
|
||||
lv_ll_clear(group_ll_p);
|
||||
}
|
||||
|
||||
lv_group_t * lv_group_create(void)
|
||||
{
|
||||
lv_group_t * group = lv_ll_ins_head(group_ll_p);
|
||||
LV_ASSERT_MALLOC(group);
|
||||
if(group == NULL) return NULL;
|
||||
lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));
|
||||
|
||||
group->obj_focus = NULL;
|
||||
group->frozen = 0;
|
||||
group->focus_cb = NULL;
|
||||
group->edge_cb = NULL;
|
||||
group->editing = 0;
|
||||
group->refocus_policy = LV_GROUP_REFOCUS_POLICY_PREV;
|
||||
group->wrap = 1;
|
||||
group->user_data = NULL;
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
void lv_group_delete(lv_group_t * group)
|
||||
{
|
||||
/*Defocus the currently focused object*/
|
||||
LV_ASSERT_NULL(group);
|
||||
if(group->obj_focus != NULL) {
|
||||
lv_obj_send_event(*group->obj_focus, LV_EVENT_DEFOCUSED, get_indev(group));
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
/*Remove the objects from the group*/
|
||||
lv_obj_t ** obj;
|
||||
LV_LL_READ(&group->obj_ll, obj) {
|
||||
if((*obj)->spec_attr)(*obj)->spec_attr->group_p = NULL;
|
||||
}
|
||||
|
||||
/*Remove the group from any indev devices */
|
||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||
while(indev) {
|
||||
if(lv_indev_get_group(indev) == group) {
|
||||
lv_indev_set_group(indev, NULL);
|
||||
}
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
|
||||
/*If the group is the default group, set the default group as NULL*/
|
||||
if(group == lv_group_get_default()) lv_group_set_default(NULL);
|
||||
|
||||
lv_ll_clear(&(group->obj_ll));
|
||||
lv_ll_remove(group_ll_p, group);
|
||||
lv_free(group);
|
||||
}
|
||||
|
||||
void lv_group_set_default(lv_group_t * group)
|
||||
{
|
||||
default_group = group;
|
||||
}
|
||||
|
||||
lv_group_t * lv_group_get_default(void)
|
||||
{
|
||||
return default_group;
|
||||
}
|
||||
|
||||
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)
|
||||
{
|
||||
if(group == NULL) return;
|
||||
|
||||
LV_LOG_TRACE("begin");
|
||||
|
||||
/*Be sure the object is removed from its current group*/
|
||||
lv_group_remove_obj(obj);
|
||||
|
||||
if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj);
|
||||
obj->spec_attr->group_p = group;
|
||||
|
||||
lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll);
|
||||
LV_ASSERT_MALLOC(next);
|
||||
if(next == NULL) return;
|
||||
*next = obj;
|
||||
|
||||
/*If the head and the tail is equal then there is only one object in the linked list.
|
||||
*In this case automatically activate it*/
|
||||
if(lv_ll_get_head(&group->obj_ll) == next) {
|
||||
lv_group_refocus(group);
|
||||
}
|
||||
|
||||
LV_LOG_TRACE("finished");
|
||||
}
|
||||
|
||||
void lv_group_swap_obj(lv_obj_t * obj1, lv_obj_t * obj2)
|
||||
{
|
||||
lv_group_t * g1 = lv_obj_get_group(obj1);
|
||||
lv_group_t * g2 = lv_obj_get_group(obj2);
|
||||
if(g1 != g2) return;
|
||||
if(g1 == NULL) return;
|
||||
|
||||
/*Do not add the object twice*/
|
||||
lv_obj_t ** obj_i;
|
||||
LV_LL_READ(&g1->obj_ll, obj_i) {
|
||||
if((*obj_i) == obj1)(*obj_i) = obj2;
|
||||
else if((*obj_i) == obj2)(*obj_i) = obj1;
|
||||
}
|
||||
|
||||
lv_obj_t * focused = lv_group_get_focused(g1);
|
||||
if(focused == obj1) lv_group_focus_obj(obj2);
|
||||
else if(focused == obj2) lv_group_focus_obj(obj1);
|
||||
|
||||
}
|
||||
|
||||
void lv_group_remove_obj(lv_obj_t * obj)
|
||||
{
|
||||
lv_group_t * g = lv_obj_get_group(obj);
|
||||
if(g == NULL) return;
|
||||
|
||||
LV_LOG_TRACE("begin");
|
||||
|
||||
/*Focus on the next object*/
|
||||
if(g->obj_focus && *g->obj_focus == obj) {
|
||||
if(g->frozen) g->frozen = 0;
|
||||
|
||||
/*If this is the only object in the group then focus to nothing.*/
|
||||
if(lv_ll_get_head(&g->obj_ll) == g->obj_focus && lv_ll_get_tail(&g->obj_ll) == g->obj_focus) {
|
||||
lv_obj_send_event(*g->obj_focus, LV_EVENT_DEFOCUSED, get_indev(g));
|
||||
}
|
||||
/*If there more objects in the group then focus to the next/prev object*/
|
||||
else {
|
||||
lv_group_refocus(g);
|
||||
}
|
||||
}
|
||||
|
||||
/*If the focuses object is still the same then it was the only object in the group but it will
|
||||
*be deleted. Set the `obj_focus` to NULL to get back to the initial state of the group with
|
||||
*zero objects*/
|
||||
if(g->obj_focus && *g->obj_focus == obj) {
|
||||
g->obj_focus = NULL;
|
||||
}
|
||||
|
||||
/*Search the object and remove it from its group*/
|
||||
lv_obj_t ** i;
|
||||
LV_LL_READ(&g->obj_ll, i) {
|
||||
if(*i == obj) {
|
||||
lv_ll_remove(&g->obj_ll, i);
|
||||
lv_free(i);
|
||||
if(obj->spec_attr) obj->spec_attr->group_p = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LV_LOG_TRACE("finished");
|
||||
}
|
||||
|
||||
void lv_group_remove_all_objs(lv_group_t * group)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
|
||||
/*Defocus the currently focused object*/
|
||||
if(group->obj_focus != NULL) {
|
||||
lv_obj_send_event(*group->obj_focus, LV_EVENT_DEFOCUSED, get_indev(group));
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
group->obj_focus = NULL;
|
||||
}
|
||||
|
||||
/*Remove the objects from the group*/
|
||||
lv_obj_t ** obj;
|
||||
LV_LL_READ(&group->obj_ll, obj) {
|
||||
if((*obj)->spec_attr)(*obj)->spec_attr->group_p = NULL;
|
||||
}
|
||||
|
||||
lv_ll_clear(&(group->obj_ll));
|
||||
}
|
||||
|
||||
void lv_group_focus_obj(lv_obj_t * obj)
|
||||
{
|
||||
if(obj == NULL) return;
|
||||
lv_group_t * g = lv_obj_get_group(obj);
|
||||
if(g == NULL) return;
|
||||
|
||||
if(g->frozen != 0) return;
|
||||
|
||||
/*On defocus edit mode must be leaved*/
|
||||
lv_group_set_editing(g, false);
|
||||
|
||||
lv_obj_t ** i;
|
||||
LV_LL_READ(&g->obj_ll, i) {
|
||||
if(*i == obj) {
|
||||
if(g->obj_focus != NULL && obj != *g->obj_focus) { /*Do not defocus if the same object needs to be focused again*/
|
||||
lv_result_t res = lv_obj_send_event(*g->obj_focus, LV_EVENT_DEFOCUSED, get_indev(g));
|
||||
if(res != LV_RESULT_OK) return;
|
||||
lv_obj_invalidate(*g->obj_focus);
|
||||
}
|
||||
|
||||
g->obj_focus = i;
|
||||
|
||||
if(g->obj_focus != NULL) {
|
||||
if(g->focus_cb) g->focus_cb(g);
|
||||
lv_result_t res = lv_obj_send_event(*g->obj_focus, LV_EVENT_FOCUSED, get_indev(g));
|
||||
if(res != LV_RESULT_OK) return;
|
||||
lv_obj_invalidate(*g->obj_focus);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lv_group_focus_next(lv_group_t * group)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
|
||||
bool focus_changed = focus_next_core(group, lv_ll_get_head, lv_ll_get_next);
|
||||
if(group->edge_cb) {
|
||||
if(!focus_changed)
|
||||
group->edge_cb(group, true);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_group_focus_prev(lv_group_t * group)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
|
||||
bool focus_changed = focus_next_core(group, lv_ll_get_tail, lv_ll_get_prev);
|
||||
if(group->edge_cb) {
|
||||
if(!focus_changed)
|
||||
group->edge_cb(group, false);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_group_focus_freeze(lv_group_t * group, bool en)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
|
||||
if(en == false) group->frozen = 0;
|
||||
else group->frozen = 1;
|
||||
}
|
||||
|
||||
lv_result_t lv_group_send_data(lv_group_t * group, uint32_t c)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
|
||||
lv_obj_t * act = lv_group_get_focused(group);
|
||||
if(act == NULL) return LV_RESULT_OK;
|
||||
|
||||
if(lv_obj_has_state(act, LV_STATE_DISABLED)) return LV_RESULT_OK;
|
||||
|
||||
return lv_obj_send_event(act, LV_EVENT_KEY, &c);
|
||||
}
|
||||
|
||||
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)
|
||||
{
|
||||
if(group == NULL) return;
|
||||
|
||||
group->focus_cb = focus_cb;
|
||||
}
|
||||
|
||||
void lv_group_set_edge_cb(lv_group_t * group, lv_group_edge_cb_t edge_cb)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
|
||||
group->edge_cb = edge_cb;
|
||||
}
|
||||
|
||||
void lv_group_set_editing(lv_group_t * group, bool edit)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
uint8_t en_val = edit ? 1 : 0;
|
||||
|
||||
if(en_val == group->editing) return; /*Do not set the same mode again*/
|
||||
|
||||
group->editing = en_val;
|
||||
lv_obj_t * focused = lv_group_get_focused(group);
|
||||
|
||||
if(focused) {
|
||||
lv_result_t res = lv_obj_send_event(*group->obj_focus, LV_EVENT_FOCUSED, get_indev(group));
|
||||
if(res != LV_RESULT_OK) return;
|
||||
|
||||
lv_obj_invalidate(focused);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
group->refocus_policy = policy & 0x01;
|
||||
}
|
||||
|
||||
void lv_group_set_wrap(lv_group_t * group, bool en)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
group->wrap = en ? 1 : 0;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_group_get_focused(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return NULL;
|
||||
if(group->obj_focus == NULL) return NULL;
|
||||
|
||||
return *group->obj_focus;
|
||||
}
|
||||
|
||||
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return NULL;
|
||||
return group->focus_cb;
|
||||
}
|
||||
|
||||
lv_group_edge_cb_t lv_group_get_edge_cb(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return NULL;
|
||||
return group->edge_cb;
|
||||
}
|
||||
|
||||
bool lv_group_get_editing(const lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->editing;
|
||||
}
|
||||
|
||||
bool lv_group_get_wrap(lv_group_t * group)
|
||||
{
|
||||
if(!group) return false;
|
||||
return group->wrap;
|
||||
}
|
||||
|
||||
uint32_t lv_group_get_obj_count(lv_group_t * group)
|
||||
{
|
||||
LV_ASSERT_NULL(group);
|
||||
return lv_ll_get_len(&group->obj_ll);
|
||||
}
|
||||
|
||||
lv_obj_t * lv_group_get_obj_by_index(lv_group_t * group, uint32_t index)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
lv_obj_t ** obj;
|
||||
|
||||
LV_LL_READ(&group->obj_ll, obj) {
|
||||
if(len == index) {
|
||||
return *obj;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t lv_group_get_count(void)
|
||||
{
|
||||
return lv_ll_get_len(group_ll_p);
|
||||
}
|
||||
|
||||
lv_group_t * lv_group_by_index(uint32_t index)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
lv_group_t * group;
|
||||
|
||||
LV_LL_READ_BACK(group_ll_p, group) {
|
||||
if(len == index) {
|
||||
return group;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_group_refocus(lv_group_t * g)
|
||||
{
|
||||
/*Refocus must temporarily allow wrapping to work correctly*/
|
||||
uint8_t temp_wrap = g->wrap;
|
||||
g->wrap = 1;
|
||||
|
||||
if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT)
|
||||
lv_group_focus_next(g);
|
||||
else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV)
|
||||
lv_group_focus_prev(g);
|
||||
/*Restore wrap property*/
|
||||
g->wrap = temp_wrap;
|
||||
}
|
||||
|
||||
static bool focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *),
|
||||
void * (*move)(const lv_ll_t *, const void *))
|
||||
{
|
||||
bool focus_changed = false;
|
||||
if(group->frozen) return focus_changed;
|
||||
|
||||
lv_obj_t ** obj_next = group->obj_focus;
|
||||
lv_obj_t ** obj_sentinel = NULL;
|
||||
bool can_move = true;
|
||||
bool can_begin = true;
|
||||
|
||||
for(;;) {
|
||||
if(obj_next == NULL) {
|
||||
if(group->wrap || obj_sentinel == NULL) {
|
||||
if(!can_begin) return focus_changed;
|
||||
obj_next = begin(&group->obj_ll);
|
||||
can_move = false;
|
||||
can_begin = false;
|
||||
}
|
||||
else {
|
||||
/*Currently focused object is the last/first in the group, keep it that way*/
|
||||
return focus_changed;
|
||||
}
|
||||
}
|
||||
|
||||
if(obj_sentinel == NULL) {
|
||||
obj_sentinel = obj_next;
|
||||
if(obj_sentinel == NULL) return focus_changed; /*Group is empty*/
|
||||
}
|
||||
|
||||
if(can_move) {
|
||||
obj_next = move(&group->obj_ll, obj_next);
|
||||
|
||||
/*Give up if we walked the entire list and haven't found another visible object*/
|
||||
if(obj_next == obj_sentinel) return focus_changed;
|
||||
}
|
||||
|
||||
can_move = true;
|
||||
|
||||
if(obj_next == NULL) continue;
|
||||
if(lv_obj_get_state(*obj_next) & LV_STATE_DISABLED) continue;
|
||||
|
||||
/*Hidden objects don't receive focus.
|
||||
*If any parent is hidden, the object is also hidden)*/
|
||||
lv_obj_t * parent = *obj_next;
|
||||
while(parent) {
|
||||
if(lv_obj_has_flag(parent, LV_OBJ_FLAG_HIDDEN)) break;
|
||||
parent = lv_obj_get_parent(parent);
|
||||
}
|
||||
|
||||
if(parent && lv_obj_has_flag(parent, LV_OBJ_FLAG_HIDDEN)) continue;
|
||||
|
||||
/*If we got her a good candidate is found*/
|
||||
break;
|
||||
}
|
||||
|
||||
if(obj_next == group->obj_focus) return focus_changed; /*There's only one visible object and it's already focused*/
|
||||
|
||||
if(group->obj_focus) {
|
||||
lv_result_t res = lv_obj_send_event(*group->obj_focus, LV_EVENT_DEFOCUSED, get_indev(group));
|
||||
if(res != LV_RESULT_OK) return focus_changed;
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
}
|
||||
|
||||
group->obj_focus = obj_next;
|
||||
|
||||
lv_result_t res = lv_obj_send_event(*group->obj_focus, LV_EVENT_FOCUSED, get_indev(group));
|
||||
if(res != LV_RESULT_OK) return focus_changed;
|
||||
|
||||
lv_obj_invalidate(*group->obj_focus);
|
||||
|
||||
if(group->focus_cb) group->focus_cb(group);
|
||||
focus_changed = true;
|
||||
return focus_changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an indev preferably with POINTER type (because it's the most generic) that uses the given group.
|
||||
* In other words, find an indev, that is related to the given group.
|
||||
* In the worst case simply return the latest indev
|
||||
* @param g a group the find in the indevs
|
||||
* @return the suggested indev
|
||||
*/
|
||||
static lv_indev_t * get_indev(const lv_group_t * g)
|
||||
{
|
||||
lv_indev_t * indev_guess = NULL;
|
||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||
|
||||
while(indev) {
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(indev);
|
||||
/*Prefer POINTER*/
|
||||
if(indev_type == LV_INDEV_TYPE_POINTER) return indev;
|
||||
if(lv_indev_get_group(indev) == g) {
|
||||
indev_guess = indev;
|
||||
}
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
|
||||
return indev_guess;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* @file lv_group.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GROUP_H
|
||||
#define LV_GROUP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_ll.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
/** Predefined keys to control which Widget has focus via lv_group_send(group, c) */
|
||||
typedef enum {
|
||||
LV_KEY_UP = 17, /*0x11*/
|
||||
LV_KEY_DOWN = 18, /*0x12*/
|
||||
LV_KEY_RIGHT = 19, /*0x13*/
|
||||
LV_KEY_LEFT = 20, /*0x14*/
|
||||
LV_KEY_ESC = 27, /*0x1B*/
|
||||
LV_KEY_DEL = 127, /*0x7F*/
|
||||
LV_KEY_BACKSPACE = 8, /*0x08*/
|
||||
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
|
||||
LV_KEY_NEXT = 9, /*0x09, '\t'*/
|
||||
LV_KEY_PREV = 11, /*0x0B, '*/
|
||||
LV_KEY_HOME = 2, /*0x02, STX*/
|
||||
LV_KEY_END = 3, /*0x03, ETX*/
|
||||
} lv_key_t;
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef void (*lv_group_focus_cb_t)(lv_group_t *);
|
||||
typedef void (*lv_group_edge_cb_t)(lv_group_t *, bool);
|
||||
|
||||
typedef enum {
|
||||
LV_GROUP_REFOCUS_POLICY_NEXT = 0,
|
||||
LV_GROUP_REFOCUS_POLICY_PREV = 1
|
||||
} lv_group_refocus_policy_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create new Widget group.
|
||||
* @return pointer to the new Widget group
|
||||
*/
|
||||
lv_group_t * lv_group_create(void);
|
||||
|
||||
/**
|
||||
* Delete group object.
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_delete(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Set default group. New Widgets will be added to this group if it's enabled in
|
||||
* their class with `add_to_def_group = true`.
|
||||
* @param group pointer to a group (can be `NULL`)
|
||||
*/
|
||||
void lv_group_set_default(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get default group.
|
||||
* @return pointer to the default group
|
||||
*/
|
||||
lv_group_t * lv_group_get_default(void);
|
||||
|
||||
/**
|
||||
* Add an Widget to group.
|
||||
* @param group pointer to a group
|
||||
* @param obj pointer to a Widget to add
|
||||
*/
|
||||
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Swap 2 Widgets in group. Widgets must be in the same group.
|
||||
* @param obj1 pointer to a Widget
|
||||
* @param obj2 pointer to another Widget
|
||||
*/
|
||||
void lv_group_swap_obj(lv_obj_t * obj1, lv_obj_t * obj2);
|
||||
|
||||
/**
|
||||
* Remove a Widget from its group.
|
||||
* @param obj pointer to Widget to remove
|
||||
*/
|
||||
void lv_group_remove_obj(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Remove all Widgets from a group.
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_remove_all_objs(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Focus on a Widget (defocus the current).
|
||||
* @param obj pointer to Widget to focus on
|
||||
*/
|
||||
void lv_group_focus_obj(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Focus on next Widget in a group (defocus the current).
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_focus_next(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Focus on previous Widget in a group (defocus the current).
|
||||
* @param group pointer to a group
|
||||
*/
|
||||
void lv_group_focus_prev(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Do not allow changing focus from current Widget.
|
||||
* @param group pointer to a group
|
||||
* @param en true: freeze, false: release freezing (normal mode)
|
||||
*/
|
||||
void lv_group_focus_freeze(lv_group_t * group, bool en);
|
||||
|
||||
/**
|
||||
* Send a control character to Widget that has focus in a group.
|
||||
* @param group pointer to a group
|
||||
* @param c a character (use LV_KEY_.. to navigate)
|
||||
* @return result of Widget with focus in group.
|
||||
*/
|
||||
lv_result_t lv_group_send_data(lv_group_t * group, uint32_t c);
|
||||
|
||||
/**
|
||||
* Set a function for a group which will be called when a new Widget has focus.
|
||||
* @param group pointer to a group
|
||||
* @param focus_cb the call back function or NULL if unused
|
||||
*/
|
||||
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb);
|
||||
|
||||
/**
|
||||
* Set a function for a group which will be called when a focus edge is reached
|
||||
* @param group pointer to a group
|
||||
* @param edge_cb the call back function or NULL if unused
|
||||
*/
|
||||
void lv_group_set_edge_cb(lv_group_t * group, lv_group_edge_cb_t edge_cb);
|
||||
|
||||
/**
|
||||
* Set whether the next or previous Widget in a group gets focus when Widget that has
|
||||
* focus is deleted.
|
||||
* @param group pointer to a group
|
||||
* @param policy new refocus policy enum
|
||||
*/
|
||||
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy);
|
||||
|
||||
/**
|
||||
* Manually set the current mode (edit or navigate).
|
||||
* @param group pointer to group
|
||||
* @param edit true: edit mode; false: navigate mode
|
||||
*/
|
||||
void lv_group_set_editing(lv_group_t * group, bool edit);
|
||||
|
||||
/**
|
||||
* Set whether moving focus to next/previous Widget will allow wrapping from
|
||||
* first->last or last->first Widget.
|
||||
* @param group pointer to group
|
||||
* @param en true: wrapping enabled; false: wrapping disabled
|
||||
*/
|
||||
void lv_group_set_wrap(lv_group_t * group, bool en);
|
||||
|
||||
/**
|
||||
* Get Widget that has focus, or NULL if there isn't one.
|
||||
* @param group pointer to a group
|
||||
* @return pointer to Widget with focus
|
||||
*/
|
||||
lv_obj_t * lv_group_get_focused(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get focus callback function of a group.
|
||||
* @param group pointer to a group
|
||||
* @return the call back function or NULL if not set
|
||||
*/
|
||||
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get edge callback function of a group.
|
||||
* @param group pointer to a group
|
||||
* @return the call back function or NULL if not set
|
||||
*/
|
||||
lv_group_edge_cb_t lv_group_get_edge_cb(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get current mode (edit or navigate).
|
||||
* @param group pointer to group
|
||||
* @return true: edit mode; false: navigate mode
|
||||
*/
|
||||
bool lv_group_get_editing(const lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get whether moving focus to next/previous Widget will allow wrapping from
|
||||
* first->last or last->first Widget.
|
||||
* @param group pointer to group
|
||||
*/
|
||||
bool lv_group_get_wrap(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get number of Widgets in group.
|
||||
* @param group pointer to a group
|
||||
* @return number of Widgets in the group
|
||||
*/
|
||||
uint32_t lv_group_get_obj_count(lv_group_t * group);
|
||||
|
||||
/**
|
||||
* Get nth Widget within group.
|
||||
* @param group pointer to a group
|
||||
* @param index index of Widget within the group
|
||||
* @return pointer to Widget
|
||||
*/
|
||||
lv_obj_t * lv_group_get_obj_by_index(lv_group_t * group, uint32_t index);
|
||||
|
||||
/**
|
||||
* Get the number of groups.
|
||||
* @return number of groups
|
||||
*/
|
||||
uint32_t lv_group_get_count(void);
|
||||
|
||||
/**
|
||||
* Get a group by its index.
|
||||
* @param index index of the group
|
||||
* @return pointer to the group
|
||||
*/
|
||||
lv_group_t * lv_group_by_index(uint32_t index);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GROUP_H*/
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file lv_group_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GROUP_PRIVATE_H
|
||||
#define LV_GROUP_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_group.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Groups can be used to logically hold objects so that they can be individually focused.
|
||||
* They are NOT for laying out objects on a screen (try layouts for that).
|
||||
*/
|
||||
struct _lv_group_t {
|
||||
lv_ll_t obj_ll; /**< Linked list to store the objects in the group*/
|
||||
lv_obj_t ** obj_focus; /**< The object in focus*/
|
||||
|
||||
lv_group_focus_cb_t focus_cb; /**< A function to call when a new object is focused (optional)*/
|
||||
lv_group_edge_cb_t edge_cb; /**< A function to call when an edge is reached, no more focus
|
||||
targets are available in this direction (to allow edge feedback
|
||||
like a sound or a scroll bounce) */
|
||||
|
||||
void * user_data;
|
||||
|
||||
uint8_t frozen : 1; /**< 1: can't focus to new object*/
|
||||
uint8_t editing : 1; /**< 1: Edit mode, 0: Navigate mode*/
|
||||
uint8_t refocus_policy : 1; /**< 1: Focus prev if focused on deletion. 0: Focus next if focused on
|
||||
deletion.*/
|
||||
uint8_t wrap : 1; /**< 1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end
|
||||
of list.*/
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Init the group module
|
||||
* @remarks Internal function, do not call directly.
|
||||
*/
|
||||
void lv_group_init(void);
|
||||
|
||||
/**
|
||||
* Deinit the group module
|
||||
* @remarks Internal function, do not call directly.
|
||||
*/
|
||||
void lv_group_deinit(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GROUP_PRIVATE_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,489 @@
|
||||
/**
|
||||
* @file lv_obj.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_H
|
||||
#define LV_OBJ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
|
||||
#include "lv_obj_tree.h"
|
||||
#include "lv_obj_pos.h"
|
||||
#include "lv_obj_scroll.h"
|
||||
#include "lv_obj_style.h"
|
||||
#include "lv_obj_draw.h"
|
||||
#include "lv_obj_class.h"
|
||||
#include "lv_obj_event.h"
|
||||
#include "lv_obj_property.h"
|
||||
#include "lv_group.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Possible states of a widget.
|
||||
* OR-ed values are possible
|
||||
*/
|
||||
enum {
|
||||
LV_STATE_DEFAULT = 0x0000,
|
||||
LV_STATE_CHECKED = 0x0001,
|
||||
LV_STATE_FOCUSED = 0x0002,
|
||||
LV_STATE_FOCUS_KEY = 0x0004,
|
||||
LV_STATE_EDITED = 0x0008,
|
||||
LV_STATE_HOVERED = 0x0010,
|
||||
LV_STATE_PRESSED = 0x0020,
|
||||
LV_STATE_SCROLLED = 0x0040,
|
||||
LV_STATE_DISABLED = 0x0080,
|
||||
LV_STATE_USER_1 = 0x1000,
|
||||
LV_STATE_USER_2 = 0x2000,
|
||||
LV_STATE_USER_3 = 0x4000,
|
||||
LV_STATE_USER_4 = 0x8000,
|
||||
|
||||
LV_STATE_ANY = 0xFFFF, /**< Special value can be used in some functions to target all states*/
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible parts of widgets.
|
||||
* The parts can be considered as the internal building block of the widgets.
|
||||
* E.g. slider = background + indicator + knob
|
||||
* Not all parts are used by every widget
|
||||
*/
|
||||
|
||||
enum {
|
||||
LV_PART_MAIN = 0x000000, /**< A background like rectangle*/
|
||||
LV_PART_SCROLLBAR = 0x010000, /**< The scrollbar(s)*/
|
||||
LV_PART_INDICATOR = 0x020000, /**< Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox*/
|
||||
LV_PART_KNOB = 0x030000, /**< Like handle to grab to adjust the value*/
|
||||
LV_PART_SELECTED = 0x040000, /**< Indicate the currently selected option or section*/
|
||||
LV_PART_ITEMS = 0x050000, /**< Used if the widget has multiple similar elements (e.g. table cells)*/
|
||||
LV_PART_CURSOR = 0x060000, /**< Mark a specific place e.g. for text area's cursor or on a chart*/
|
||||
|
||||
LV_PART_CUSTOM_FIRST = 0x080000, /**< Extension point for custom widgets*/
|
||||
|
||||
LV_PART_ANY = 0x0F0000, /**< Special value can be used in some functions to target all parts*/
|
||||
};
|
||||
|
||||
/**
|
||||
* On/Off features controlling the object's behavior.
|
||||
* OR-ed values are possible
|
||||
*
|
||||
* Note: update obj flags corresponding properties below
|
||||
* whenever add/remove flags or change bit definition of flags.
|
||||
*/
|
||||
typedef enum {
|
||||
LV_OBJ_FLAG_HIDDEN = (1L << 0), /**< Make the object hidden. (Like it wasn't there at all)*/
|
||||
LV_OBJ_FLAG_CLICKABLE = (1L << 1), /**< Make the object clickable by the input devices*/
|
||||
LV_OBJ_FLAG_CLICK_FOCUSABLE = (1L << 2), /**< Add focused state to the object when clicked*/
|
||||
LV_OBJ_FLAG_CHECKABLE = (1L << 3), /**< Toggle checked state when the object is clicked*/
|
||||
LV_OBJ_FLAG_SCROLLABLE = (1L << 4), /**< Make the object scrollable*/
|
||||
LV_OBJ_FLAG_SCROLL_ELASTIC = (1L << 5), /**< Allow scrolling inside but with slower speed*/
|
||||
LV_OBJ_FLAG_SCROLL_MOMENTUM = (1L << 6), /**< Make the object scroll further when "thrown"*/
|
||||
LV_OBJ_FLAG_SCROLL_ONE = (1L << 7), /**< Allow scrolling only one snappable children*/
|
||||
LV_OBJ_FLAG_SCROLL_CHAIN_HOR = (1L << 8), /**< Allow propagating the horizontal scroll to a parent*/
|
||||
LV_OBJ_FLAG_SCROLL_CHAIN_VER = (1L << 9), /**< Allow propagating the vertical scroll to a parent*/
|
||||
LV_OBJ_FLAG_SCROLL_CHAIN = (LV_OBJ_FLAG_SCROLL_CHAIN_HOR | LV_OBJ_FLAG_SCROLL_CHAIN_VER),
|
||||
LV_OBJ_FLAG_SCROLL_ON_FOCUS = (1L << 10), /**< Automatically scroll object to make it visible when focused*/
|
||||
LV_OBJ_FLAG_SCROLL_WITH_ARROW = (1L << 11), /**< Allow scrolling the focused object with arrow keys*/
|
||||
LV_OBJ_FLAG_SNAPPABLE = (1L << 12), /**< If scroll snap is enabled on the parent it can snap to this object*/
|
||||
LV_OBJ_FLAG_PRESS_LOCK = (1L << 13), /**< Keep the object pressed even if the press slid from the object*/
|
||||
LV_OBJ_FLAG_EVENT_BUBBLE = (1L << 14), /**< Propagate the events to the parent too*/
|
||||
LV_OBJ_FLAG_GESTURE_BUBBLE = (1L << 15), /**< Propagate the gestures to the parent*/
|
||||
LV_OBJ_FLAG_ADV_HITTEST = (1L << 16), /**< Allow performing more accurate hit (click) test. E.g. consider rounded corners.*/
|
||||
LV_OBJ_FLAG_IGNORE_LAYOUT = (1L << 17), /**< Make the object not positioned by the layouts*/
|
||||
LV_OBJ_FLAG_FLOATING = (1L << 18), /**< Do not scroll the object when the parent scrolls and ignore layout*/
|
||||
LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS = (1L << 19), /**< Send `LV_EVENT_DRAW_TASK_ADDED` events*/
|
||||
LV_OBJ_FLAG_OVERFLOW_VISIBLE = (1L << 20),/**< Do not clip the children to the parent's ext draw size*/
|
||||
#if LV_USE_FLEX
|
||||
LV_OBJ_FLAG_FLEX_IN_NEW_TRACK = (1L << 21), /**< Start a new flex track on this item*/
|
||||
#endif
|
||||
|
||||
LV_OBJ_FLAG_LAYOUT_1 = (1L << 23), /**< Custom flag, free to use by layouts*/
|
||||
LV_OBJ_FLAG_LAYOUT_2 = (1L << 24), /**< Custom flag, free to use by layouts*/
|
||||
|
||||
LV_OBJ_FLAG_WIDGET_1 = (1L << 25), /**< Custom flag, free to use by widget*/
|
||||
LV_OBJ_FLAG_WIDGET_2 = (1L << 26), /**< Custom flag, free to use by widget*/
|
||||
LV_OBJ_FLAG_USER_1 = (1L << 27), /**< Custom flag, free to use by user*/
|
||||
LV_OBJ_FLAG_USER_2 = (1L << 28), /**< Custom flag, free to use by user*/
|
||||
LV_OBJ_FLAG_USER_3 = (1L << 29), /**< Custom flag, free to use by user*/
|
||||
LV_OBJ_FLAG_USER_4 = (1L << 30), /**< Custom flag, free to use by user*/
|
||||
} lv_obj_flag_t;
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
enum {
|
||||
/*OBJ flag properties */
|
||||
LV_PROPERTY_ID(OBJ, FLAG_START, LV_PROPERTY_TYPE_INT, 0),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_HIDDEN, LV_PROPERTY_TYPE_INT, 0),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_CLICKABLE, LV_PROPERTY_TYPE_INT, 1),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_CLICK_FOCUSABLE, LV_PROPERTY_TYPE_INT, 2),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_CHECKABLE, LV_PROPERTY_TYPE_INT, 3),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLLABLE, LV_PROPERTY_TYPE_INT, 4),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_ELASTIC, LV_PROPERTY_TYPE_INT, 5),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_MOMENTUM, LV_PROPERTY_TYPE_INT, 6),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_ONE, LV_PROPERTY_TYPE_INT, 7),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_CHAIN_HOR, LV_PROPERTY_TYPE_INT, 8),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_CHAIN_VER, LV_PROPERTY_TYPE_INT, 9),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_ON_FOCUS, LV_PROPERTY_TYPE_INT, 10),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SCROLL_WITH_ARROW, LV_PROPERTY_TYPE_INT, 11),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SNAPPABLE, LV_PROPERTY_TYPE_INT, 12),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_PRESS_LOCK, LV_PROPERTY_TYPE_INT, 13),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_EVENT_BUBBLE, LV_PROPERTY_TYPE_INT, 14),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_GESTURE_BUBBLE, LV_PROPERTY_TYPE_INT, 15),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_ADV_HITTEST, LV_PROPERTY_TYPE_INT, 16),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_IGNORE_LAYOUT, LV_PROPERTY_TYPE_INT, 17),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_FLOATING, LV_PROPERTY_TYPE_INT, 18),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_SEND_DRAW_TASK_EVENTS, LV_PROPERTY_TYPE_INT, 19),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_OVERFLOW_VISIBLE, LV_PROPERTY_TYPE_INT, 20),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_FLEX_IN_NEW_TRACK, LV_PROPERTY_TYPE_INT, 21),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_LAYOUT_1, LV_PROPERTY_TYPE_INT, 23),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_LAYOUT_2, LV_PROPERTY_TYPE_INT, 24),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_WIDGET_1, LV_PROPERTY_TYPE_INT, 25),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_WIDGET_2, LV_PROPERTY_TYPE_INT, 26),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_1, LV_PROPERTY_TYPE_INT, 27),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_2, LV_PROPERTY_TYPE_INT, 28),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_3, LV_PROPERTY_TYPE_INT, 29),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_USER_4, LV_PROPERTY_TYPE_INT, 30),
|
||||
LV_PROPERTY_ID(OBJ, FLAG_END, LV_PROPERTY_TYPE_INT, 30),
|
||||
|
||||
LV_PROPERTY_ID(OBJ, STATE_START, LV_PROPERTY_TYPE_INT, 31),
|
||||
LV_PROPERTY_ID(OBJ, STATE_CHECKED, LV_PROPERTY_TYPE_INT, 31),
|
||||
LV_PROPERTY_ID(OBJ, STATE_FOCUSED, LV_PROPERTY_TYPE_INT, 32),
|
||||
LV_PROPERTY_ID(OBJ, STATE_FOCUS_KEY, LV_PROPERTY_TYPE_INT, 33),
|
||||
LV_PROPERTY_ID(OBJ, STATE_EDITED, LV_PROPERTY_TYPE_INT, 34),
|
||||
LV_PROPERTY_ID(OBJ, STATE_HOVERED, LV_PROPERTY_TYPE_INT, 35),
|
||||
LV_PROPERTY_ID(OBJ, STATE_PRESSED, LV_PROPERTY_TYPE_INT, 36),
|
||||
LV_PROPERTY_ID(OBJ, STATE_SCROLLED, LV_PROPERTY_TYPE_INT, 37),
|
||||
LV_PROPERTY_ID(OBJ, STATE_DISABLED, LV_PROPERTY_TYPE_INT, 38),
|
||||
/*not used bit8-bit11*/
|
||||
LV_PROPERTY_ID(OBJ, STATE_USER_1, LV_PROPERTY_TYPE_INT, 43),
|
||||
LV_PROPERTY_ID(OBJ, STATE_USER_2, LV_PROPERTY_TYPE_INT, 44),
|
||||
LV_PROPERTY_ID(OBJ, STATE_USER_3, LV_PROPERTY_TYPE_INT, 45),
|
||||
LV_PROPERTY_ID(OBJ, STATE_USER_4, LV_PROPERTY_TYPE_INT, 46),
|
||||
LV_PROPERTY_ID(OBJ, STATE_ANY, LV_PROPERTY_TYPE_INT, 47),
|
||||
LV_PROPERTY_ID(OBJ, STATE_END, LV_PROPERTY_TYPE_INT, 47),
|
||||
|
||||
/*OBJ normal properties*/
|
||||
LV_PROPERTY_ID(OBJ, PARENT, LV_PROPERTY_TYPE_OBJ, 48),
|
||||
LV_PROPERTY_ID(OBJ, X, LV_PROPERTY_TYPE_INT, 49),
|
||||
LV_PROPERTY_ID(OBJ, Y, LV_PROPERTY_TYPE_INT, 50),
|
||||
LV_PROPERTY_ID(OBJ, W, LV_PROPERTY_TYPE_INT, 51),
|
||||
LV_PROPERTY_ID(OBJ, H, LV_PROPERTY_TYPE_INT, 52),
|
||||
LV_PROPERTY_ID(OBJ, CONTENT_WIDTH, LV_PROPERTY_TYPE_INT, 53),
|
||||
LV_PROPERTY_ID(OBJ, CONTENT_HEIGHT, LV_PROPERTY_TYPE_INT, 54),
|
||||
LV_PROPERTY_ID(OBJ, LAYOUT, LV_PROPERTY_TYPE_INT, 55),
|
||||
LV_PROPERTY_ID(OBJ, ALIGN, LV_PROPERTY_TYPE_INT, 56),
|
||||
LV_PROPERTY_ID(OBJ, SCROLLBAR_MODE, LV_PROPERTY_TYPE_INT, 57),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_DIR, LV_PROPERTY_TYPE_INT, 58),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_SNAP_X, LV_PROPERTY_TYPE_INT, 59),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_SNAP_Y, LV_PROPERTY_TYPE_INT, 60),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_X, LV_PROPERTY_TYPE_INT, 61),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_Y, LV_PROPERTY_TYPE_INT, 62),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_TOP, LV_PROPERTY_TYPE_INT, 63),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_BOTTOM, LV_PROPERTY_TYPE_INT, 64),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_LEFT, LV_PROPERTY_TYPE_INT, 65),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_RIGHT, LV_PROPERTY_TYPE_INT, 66),
|
||||
LV_PROPERTY_ID(OBJ, SCROLL_END, LV_PROPERTY_TYPE_INT, 67),
|
||||
LV_PROPERTY_ID(OBJ, EXT_DRAW_SIZE, LV_PROPERTY_TYPE_INT, 68),
|
||||
LV_PROPERTY_ID(OBJ, EVENT_COUNT, LV_PROPERTY_TYPE_INT, 69),
|
||||
LV_PROPERTY_ID(OBJ, SCREEN, LV_PROPERTY_TYPE_OBJ, 70),
|
||||
LV_PROPERTY_ID(OBJ, DISPLAY, LV_PROPERTY_TYPE_POINTER, 71),
|
||||
LV_PROPERTY_ID(OBJ, CHILD_COUNT, LV_PROPERTY_TYPE_INT, 72),
|
||||
LV_PROPERTY_ID(OBJ, INDEX, LV_PROPERTY_TYPE_INT, 73),
|
||||
|
||||
LV_PROPERTY_OBJ_END,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Make the base object's class publicly available.
|
||||
*/
|
||||
LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_obj_class;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a base object (a rectangle)
|
||||
* @param parent pointer to a parent object. If NULL then a screen will be created.
|
||||
* @return pointer to the new object
|
||||
*/
|
||||
lv_obj_t * lv_obj_create(lv_obj_t * parent);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set one or more flags
|
||||
* @param obj pointer to an object
|
||||
* @param f OR-ed values from `lv_obj_flag_t` to set.
|
||||
*/
|
||||
void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f);
|
||||
|
||||
/**
|
||||
* Remove one or more flags
|
||||
* @param obj pointer to an object
|
||||
* @param f OR-ed values from `lv_obj_flag_t` to clear.
|
||||
*/
|
||||
void lv_obj_remove_flag(lv_obj_t * obj, lv_obj_flag_t f);
|
||||
|
||||
/**
|
||||
* Set add or remove one or more flags.
|
||||
* @param obj pointer to an object
|
||||
* @param f OR-ed values from `lv_obj_flag_t` to update.
|
||||
* @param v true: add the flags; false: remove the flags
|
||||
*/
|
||||
void lv_obj_set_flag(lv_obj_t * obj, lv_obj_flag_t f, bool v);
|
||||
|
||||
/**
|
||||
* Add one or more states to the object. The other state bits will remain unchanged.
|
||||
* If specified in the styles, transition animation will be started from the previous state to the current.
|
||||
* @param obj pointer to an object
|
||||
* @param state the states to add. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED`
|
||||
*/
|
||||
void lv_obj_add_state(lv_obj_t * obj, lv_state_t state);
|
||||
|
||||
/**
|
||||
* Remove one or more states to the object. The other state bits will remain unchanged.
|
||||
* If specified in the styles, transition animation will be started from the previous state to the current.
|
||||
* @param obj pointer to an object
|
||||
* @param state the states to add. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED`
|
||||
*/
|
||||
void lv_obj_remove_state(lv_obj_t * obj, lv_state_t state);
|
||||
|
||||
/**
|
||||
* Add or remove one or more states to the object. The other state bits will remain unchanged.
|
||||
* @param obj pointer to an object
|
||||
* @param state the states to add. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED`
|
||||
* @param v true: add the states; false: remove the states
|
||||
*/
|
||||
void lv_obj_set_state(lv_obj_t * obj, lv_state_t state, bool v);
|
||||
|
||||
/**
|
||||
* Set the user_data field of the object
|
||||
* @param obj pointer to an object
|
||||
* @param user_data pointer to the new user_data.
|
||||
*/
|
||||
void lv_obj_set_user_data(lv_obj_t * obj, void * user_data);
|
||||
|
||||
/*=======================
|
||||
* Getter functions
|
||||
*======================*/
|
||||
|
||||
/**
|
||||
* Check if a given flag or all the given flags are set on an object.
|
||||
* @param obj pointer to an object
|
||||
* @param f the flag(s) to check (OR-ed values can be used)
|
||||
* @return true: all flags are set; false: not all flags are set
|
||||
*/
|
||||
bool lv_obj_has_flag(const lv_obj_t * obj, lv_obj_flag_t f);
|
||||
|
||||
/**
|
||||
* Check if a given flag or any of the flags are set on an object.
|
||||
* @param obj pointer to an object
|
||||
* @param f the flag(s) to check (OR-ed values can be used)
|
||||
* @return true: at least one flag is set; false: none of the flags are set
|
||||
*/
|
||||
bool lv_obj_has_flag_any(const lv_obj_t * obj, lv_obj_flag_t f);
|
||||
|
||||
/**
|
||||
* Get the state of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the state (OR-ed values from `lv_state_t`)
|
||||
*/
|
||||
lv_state_t lv_obj_get_state(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Check if the object is in a given state or not.
|
||||
* @param obj pointer to an object
|
||||
* @param state a state or combination of states to check
|
||||
* @return true: `obj` is in `state`; false: `obj` is not in `state`
|
||||
*/
|
||||
bool lv_obj_has_state(const lv_obj_t * obj, lv_state_t state);
|
||||
|
||||
/**
|
||||
* Get the group of the object
|
||||
* @param obj pointer to an object
|
||||
* @return the pointer to group of the object
|
||||
*/
|
||||
lv_group_t * lv_obj_get_group(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the user_data field of the object
|
||||
* @param obj pointer to an object
|
||||
* @return the pointer to the user_data of the object
|
||||
*/
|
||||
void * lv_obj_get_user_data(lv_obj_t * obj);
|
||||
|
||||
/*=======================
|
||||
* Other functions
|
||||
*======================*/
|
||||
|
||||
/**
|
||||
* Allocate special data for an object if not allocated yet.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_allocate_spec_attr(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Check the type of obj.
|
||||
* @param obj pointer to an object
|
||||
* @param class_p a class to check (e.g. `lv_slider_class`)
|
||||
* @return true: `class_p` is the `obj` class.
|
||||
*/
|
||||
bool lv_obj_check_type(const lv_obj_t * obj, const lv_obj_class_t * class_p);
|
||||
|
||||
/**
|
||||
* Check if any object has a given class (type).
|
||||
* It checks the ancestor classes too.
|
||||
* @param obj pointer to an object
|
||||
* @param class_p a class to check (e.g. `lv_slider_class`)
|
||||
* @return true: `obj` has the given class
|
||||
*/
|
||||
bool lv_obj_has_class(const lv_obj_t * obj, const lv_obj_class_t * class_p);
|
||||
|
||||
/**
|
||||
* Get the class (type) of the object
|
||||
* @param obj pointer to an object
|
||||
* @return the class (type) of the object
|
||||
*/
|
||||
const lv_obj_class_t * lv_obj_get_class(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Check if any object is still "alive".
|
||||
* @param obj pointer to an object
|
||||
* @return true: valid
|
||||
*/
|
||||
bool lv_obj_is_valid(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Utility to set an object reference to NULL when it gets deleted.
|
||||
* The reference should be in a location that will not become invalid
|
||||
* during the object's lifetime, i.e. static or allocated.
|
||||
* @param obj_ptr a pointer to a pointer to an object
|
||||
*/
|
||||
void lv_obj_null_on_delete(lv_obj_t ** obj_ptr);
|
||||
|
||||
#if LV_USE_OBJ_ID
|
||||
/**
|
||||
* Set an id for an object.
|
||||
* @param obj pointer to an object
|
||||
* @param id the id of the object
|
||||
*/
|
||||
void lv_obj_set_id(lv_obj_t * obj, void * id);
|
||||
|
||||
/**
|
||||
* Get the id of an object.
|
||||
* @param obj pointer to an object
|
||||
* @return the id of the object
|
||||
*/
|
||||
void * lv_obj_get_id(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* DEPRECATED IDs are used only to print the widget trees.
|
||||
* To find a widget use `lv_obj_find_by_name`
|
||||
*
|
||||
* Get the child object by its id.
|
||||
* It will check children and grandchildren recursively.
|
||||
* Function `lv_obj_id_compare` is used to matched obj id with given id.
|
||||
*
|
||||
* @param obj pointer to an object
|
||||
* @param id the id of the child object
|
||||
* @return pointer to the child object or NULL if not found
|
||||
*/
|
||||
lv_obj_t * lv_obj_find_by_id(const lv_obj_t * obj, const void * id);
|
||||
|
||||
/**
|
||||
* Assign id to object if not previously assigned.
|
||||
* This function gets called automatically when LV_OBJ_ID_AUTO_ASSIGN is enabled.
|
||||
*
|
||||
* Set `LV_USE_OBJ_ID_BUILTIN` to use the builtin method to generate object ID.
|
||||
* Otherwise, these functions including `lv_obj_[set|assign|free|stringify]_id` and
|
||||
* `lv_obj_id_compare`should be implemented externally.
|
||||
*
|
||||
* @param class_p the class this obj belongs to. Note obj->class_p is the class currently being constructed.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Free resources allocated by `lv_obj_assign_id` or `lv_obj_set_id`.
|
||||
* This function is also called automatically when object is deleted.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_free_id(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Compare two obj id, return 0 if they are equal.
|
||||
*
|
||||
* Set `LV_USE_OBJ_ID_BUILTIN` to use the builtin method for compare.
|
||||
* Otherwise, it must be implemented externally.
|
||||
*
|
||||
* @param id1: the first id
|
||||
* @param id2: the second id
|
||||
* @return 0 if they are equal, non-zero otherwise.
|
||||
*/
|
||||
int lv_obj_id_compare(const void * id1, const void * id2);
|
||||
|
||||
/**
|
||||
* Format an object's id into a string.
|
||||
* @param obj pointer to an object
|
||||
* @param buf buffer to write the string into
|
||||
* @param len length of the buffer
|
||||
*/
|
||||
const char * lv_obj_stringify_id(lv_obj_t * obj, char * buf, uint32_t len);
|
||||
|
||||
#if LV_USE_OBJ_ID_BUILTIN
|
||||
/**
|
||||
* Free resources used by builtin ID generator.
|
||||
*/
|
||||
void lv_objid_builtin_destroy(void);
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_OBJ_ID*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_ASSERT_OBJ
|
||||
# define LV_ASSERT_OBJ(obj_p, obj_class) \
|
||||
do { \
|
||||
LV_ASSERT_MSG(obj_p != NULL, "The object is NULL"); \
|
||||
LV_ASSERT_MSG(lv_obj_has_class(obj_p, obj_class) == true, "Incompatible object type."); \
|
||||
LV_ASSERT_MSG(lv_obj_is_valid(obj_p) == true, "The object is invalid, deleted or corrupted?"); \
|
||||
} while(0)
|
||||
# else
|
||||
# define LV_ASSERT_OBJ(obj_p, obj_class) LV_ASSERT_NULL(obj_p)
|
||||
#endif
|
||||
|
||||
#if LV_USE_LOG && LV_LOG_TRACE_OBJ_CREATE
|
||||
# define LV_TRACE_OBJ_CREATE(...) LV_LOG_TRACE(__VA_ARGS__)
|
||||
#else
|
||||
# define LV_TRACE_OBJ_CREATE(...)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_H*/
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @file lv_obj_class.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj_class_private.h"
|
||||
#include "lv_obj_private.h"
|
||||
#include "../themes/lv_theme.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../display/lv_display_private.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS (&lv_obj_class)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void lv_obj_construct(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
static uint32_t get_instance_size(const lv_obj_class_t * class_p);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_obj_t * lv_obj_class_create_obj(const lv_obj_class_t * class_p, lv_obj_t * parent)
|
||||
{
|
||||
LV_TRACE_OBJ_CREATE("Creating object with %p class on %p parent", (void *)class_p, (void *)parent);
|
||||
uint32_t s = get_instance_size(class_p);
|
||||
lv_obj_t * obj = lv_malloc_zeroed(s);
|
||||
if(obj == NULL) return NULL;
|
||||
obj->class_p = class_p;
|
||||
obj->parent = parent;
|
||||
|
||||
/*Create a screen*/
|
||||
if(parent == NULL) {
|
||||
LV_TRACE_OBJ_CREATE("creating a screen");
|
||||
lv_display_t * disp = lv_display_get_default();
|
||||
if(!disp) {
|
||||
LV_LOG_WARN("No display created yet. No place to assign the new screen");
|
||||
lv_free(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(disp->screens == NULL) {
|
||||
disp->screen_cnt = 0;
|
||||
}
|
||||
|
||||
lv_obj_t ** screens = lv_realloc(disp->screens, sizeof(lv_obj_t *) * (disp->screen_cnt + 1));
|
||||
LV_ASSERT_MALLOC(screens);
|
||||
if(screens == NULL) {
|
||||
lv_free(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
disp->screen_cnt++;
|
||||
disp->screens = screens;
|
||||
disp->screens[disp->screen_cnt - 1] = obj;
|
||||
|
||||
/*Set coordinates to full screen size*/
|
||||
obj->coords.x1 = 0;
|
||||
obj->coords.y1 = 0;
|
||||
obj->coords.x2 = lv_display_get_horizontal_resolution(NULL) - 1;
|
||||
obj->coords.y2 = lv_display_get_vertical_resolution(NULL) - 1;
|
||||
}
|
||||
/*Create a normal object*/
|
||||
else {
|
||||
LV_TRACE_OBJ_CREATE("creating normal object");
|
||||
LV_ASSERT_OBJ(parent, MY_CLASS);
|
||||
if(parent->spec_attr == NULL) {
|
||||
lv_obj_allocate_spec_attr(parent);
|
||||
}
|
||||
|
||||
parent->spec_attr->child_cnt++;
|
||||
parent->spec_attr->children = lv_realloc(parent->spec_attr->children,
|
||||
sizeof(lv_obj_t *) * parent->spec_attr->child_cnt);
|
||||
parent->spec_attr->children[parent->spec_attr->child_cnt - 1] = obj;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void lv_obj_class_init_obj(lv_obj_t * obj)
|
||||
{
|
||||
if(obj == NULL) return;
|
||||
|
||||
lv_obj_mark_layout_as_dirty(obj);
|
||||
lv_obj_enable_style_refresh(false);
|
||||
|
||||
lv_theme_apply(obj);
|
||||
lv_obj_construct(obj->class_p, obj);
|
||||
|
||||
lv_obj_enable_style_refresh(true);
|
||||
lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY);
|
||||
|
||||
lv_obj_refresh_self_size(obj);
|
||||
|
||||
lv_group_t * def_group = lv_group_get_default();
|
||||
if(def_group && lv_obj_is_group_def(obj)) {
|
||||
lv_group_add_obj(def_group, obj);
|
||||
}
|
||||
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
if(parent) {
|
||||
/*Call the ancestor's event handler to the parent to notify it about the new child.
|
||||
*Also triggers layout update*/
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CHANGED, obj);
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CREATED, obj);
|
||||
|
||||
/*Invalidate the area if not screen created*/
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_destruct(lv_obj_t * obj)
|
||||
{
|
||||
if(obj->class_p->destructor_cb) obj->class_p->destructor_cb(obj->class_p, obj);
|
||||
|
||||
if(obj->class_p->base_class) {
|
||||
/*Don't let the descendant methods run during destructing the ancestor type*/
|
||||
obj->class_p = obj->class_p->base_class;
|
||||
|
||||
/*Call the base class's destructor too*/
|
||||
lv_obj_destruct(obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool lv_obj_is_editable(lv_obj_t * obj)
|
||||
{
|
||||
const lv_obj_class_t * class_p = obj->class_p;
|
||||
|
||||
/*Find a base in which editable is set*/
|
||||
while(class_p && class_p->editable == LV_OBJ_CLASS_EDITABLE_INHERIT) class_p = class_p->base_class;
|
||||
|
||||
if(class_p == NULL) return false;
|
||||
|
||||
return class_p->editable == LV_OBJ_CLASS_EDITABLE_TRUE;
|
||||
}
|
||||
|
||||
bool lv_obj_is_group_def(lv_obj_t * obj)
|
||||
{
|
||||
const lv_obj_class_t * class_p = obj->class_p;
|
||||
|
||||
/*Find a base in which group_def is set*/
|
||||
while(class_p && class_p->group_def == LV_OBJ_CLASS_GROUP_DEF_INHERIT) class_p = class_p->base_class;
|
||||
|
||||
if(class_p == NULL) return false;
|
||||
|
||||
return class_p->group_def == LV_OBJ_CLASS_GROUP_DEF_TRUE;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_obj_construct(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
{
|
||||
if(obj->class_p->base_class) {
|
||||
const lv_obj_class_t * original_class_p = obj->class_p;
|
||||
|
||||
/*Don't let the descendant methods run during constructing the ancestor type*/
|
||||
obj->class_p = obj->class_p->base_class;
|
||||
|
||||
/*Construct the base first*/
|
||||
lv_obj_construct(class_p, obj);
|
||||
|
||||
/*Restore the original class*/
|
||||
obj->class_p = original_class_p;
|
||||
}
|
||||
|
||||
if(obj->class_p->constructor_cb) obj->class_p->constructor_cb(class_p, obj);
|
||||
}
|
||||
|
||||
static uint32_t get_instance_size(const lv_obj_class_t * class_p)
|
||||
{
|
||||
/*Find a base in which instance size is set*/
|
||||
const lv_obj_class_t * base = class_p;
|
||||
while(base && base->instance_size == 0) base = base->base_class;
|
||||
|
||||
if(base == NULL) return 0; /*Never happens: set at least in `lv_obj` class*/
|
||||
|
||||
return base->instance_size;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file lv_obj_class.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_CLASS_H
|
||||
#define LV_OBJ_CLASS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "lv_obj_property.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_OBJ_CLASS_EDITABLE_INHERIT, /**< Check the base class. Must have 0 value to let zero initialized class inherit*/
|
||||
LV_OBJ_CLASS_EDITABLE_TRUE,
|
||||
LV_OBJ_CLASS_EDITABLE_FALSE,
|
||||
} lv_obj_class_editable_t;
|
||||
|
||||
typedef enum {
|
||||
LV_OBJ_CLASS_GROUP_DEF_INHERIT, /**< Check the base class. Must have 0 value to let zero initialized class inherit*/
|
||||
LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
LV_OBJ_CLASS_GROUP_DEF_FALSE,
|
||||
} lv_obj_class_group_def_t;
|
||||
|
||||
typedef enum {
|
||||
LV_OBJ_CLASS_THEME_INHERITABLE_FALSE, /**< Do not inherit theme from base class. */
|
||||
LV_OBJ_CLASS_THEME_INHERITABLE_TRUE,
|
||||
} lv_obj_class_theme_inheritable_t;
|
||||
|
||||
typedef void (*lv_obj_class_event_cb_t)(lv_obj_class_t * class_p, lv_event_t * e);
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create an object form a class descriptor
|
||||
* @param class_p pointer to a class
|
||||
* @param parent pointer to an object where the new object should be created
|
||||
* @return pointer to the created object
|
||||
*/
|
||||
lv_obj_t * lv_obj_class_create_obj(const lv_obj_class_t * class_p, lv_obj_t * parent);
|
||||
|
||||
void lv_obj_class_init_obj(lv_obj_t * obj);
|
||||
|
||||
bool lv_obj_is_editable(lv_obj_t * obj);
|
||||
|
||||
bool lv_obj_is_group_def(lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_CLASS_H*/
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file lv_obj_class_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_CLASS_PRIVATE_H
|
||||
#define LV_OBJ_CLASS_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_obj_class.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Describe the common methods of every object.
|
||||
* Similar to a C++ class.
|
||||
*/
|
||||
struct _lv_obj_class_t {
|
||||
const lv_obj_class_t * base_class;
|
||||
/** class_p is the final class while obj->class_p is the class currently being [de]constructed. */
|
||||
void (*constructor_cb)(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
void (*destructor_cb)(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
|
||||
/** class_p is the class in which event is being processed. */
|
||||
void (*event_cb)(const lv_obj_class_t * class_p, lv_event_t * e); /**< Widget type specific event function*/
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
uint32_t prop_index_start;
|
||||
uint32_t prop_index_end;
|
||||
const lv_property_ops_t * properties;
|
||||
uint32_t properties_count;
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY_NAME
|
||||
/* An array of property ID and name */
|
||||
const lv_property_name_t * property_names;
|
||||
uint32_t names_count;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void * user_data;
|
||||
const char * name;
|
||||
int32_t width_def;
|
||||
int32_t height_def;
|
||||
uint32_t editable : 2; /**< Value from ::lv_obj_class_editable_t*/
|
||||
uint32_t group_def : 2; /**< Value from ::lv_obj_class_group_def_t*/
|
||||
uint32_t instance_size : 16;
|
||||
uint32_t theme_inheritable : 1; /**< Value from ::lv_obj_class_theme_inheritable_t*/
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_obj_destruct(lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_CLASS_PRIVATE_H*/
|
||||
@@ -0,0 +1,454 @@
|
||||
/**
|
||||
* @file lv_obj_draw.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj_draw_private.h"
|
||||
#include "lv_obj_private.h"
|
||||
#include "lv_obj_style.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../indev/lv_indev.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../draw/lv_draw_arc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS (&lv_obj_class)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static inline lv_opa_t get_layer_opa(const lv_obj_t * obj, lv_part_t part, const lv_draw_dsc_base_t * base_dsc);
|
||||
static lv_color_t normal_apply_layer_recolor(const lv_obj_t * obj, lv_part_t part, const lv_draw_dsc_base_t * base_dsc,
|
||||
lv_color_t color);
|
||||
static lv_color32_t image_apply_layer_recolor(const lv_obj_t * obj, lv_part_t part,
|
||||
const lv_draw_dsc_base_t * base_dsc, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_rect_dsc_t * draw_dsc)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
draw_dsc->base.obj = obj;
|
||||
draw_dsc->base.part = part;
|
||||
|
||||
lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
|
||||
if(part != LV_PART_MAIN) {
|
||||
if(opa <= LV_OPA_MIN) {
|
||||
draw_dsc->bg_opa = LV_OPA_TRANSP;
|
||||
draw_dsc->bg_image_opa = LV_OPA_TRANSP;
|
||||
draw_dsc->border_opa = LV_OPA_TRANSP;
|
||||
draw_dsc->outline_opa = LV_OPA_TRANSP;
|
||||
draw_dsc->shadow_opa = LV_OPA_TRANSP;
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
draw_dsc->radius = lv_obj_get_style_radius(obj, part);
|
||||
|
||||
if(draw_dsc->bg_opa != LV_OPA_TRANSP) {
|
||||
draw_dsc->bg_opa = lv_obj_get_style_bg_opa(obj, part);
|
||||
if(draw_dsc->bg_opa > LV_OPA_MIN) {
|
||||
lv_color_t bg_color = lv_obj_get_style_bg_color_filtered(obj, part);
|
||||
draw_dsc->bg_color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, bg_color);
|
||||
const lv_grad_dsc_t * grad = lv_obj_get_style_bg_grad(obj, part);
|
||||
if(grad && grad->dir != LV_GRAD_DIR_NONE) {
|
||||
lv_memcpy(&draw_dsc->bg_grad, grad, sizeof(*grad));
|
||||
}
|
||||
else {
|
||||
draw_dsc->bg_grad.dir = lv_obj_get_style_bg_grad_dir(obj, part);
|
||||
if(draw_dsc->bg_grad.dir != LV_GRAD_DIR_NONE) {
|
||||
draw_dsc->bg_grad.stops[0].color = draw_dsc->bg_color;
|
||||
lv_color_t bg_grad_color = lv_obj_get_style_bg_grad_color_filtered(obj, part);
|
||||
draw_dsc->bg_grad.stops[1].color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, bg_grad_color);
|
||||
draw_dsc->bg_grad.stops[0].frac = lv_obj_get_style_bg_main_stop(obj, part);
|
||||
draw_dsc->bg_grad.stops[1].frac = lv_obj_get_style_bg_grad_stop(obj, part);
|
||||
draw_dsc->bg_grad.stops[0].opa = lv_obj_get_style_bg_main_opa(obj, part);
|
||||
draw_dsc->bg_grad.stops[1].opa = lv_obj_get_style_bg_grad_opa(obj, part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(draw_dsc->border_opa != LV_OPA_TRANSP) {
|
||||
draw_dsc->border_width = lv_obj_get_style_border_width(obj, part);
|
||||
if(draw_dsc->border_width) {
|
||||
draw_dsc->border_opa = lv_obj_get_style_border_opa(obj, part);
|
||||
if(draw_dsc->border_opa > LV_OPA_MIN) {
|
||||
draw_dsc->border_side = lv_obj_get_style_border_side(obj, part);
|
||||
lv_color_t border_color = lv_obj_get_style_border_color_filtered(obj, part);
|
||||
draw_dsc->border_color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, border_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(draw_dsc->outline_opa != LV_OPA_TRANSP) {
|
||||
draw_dsc->outline_width = lv_obj_get_style_outline_width(obj, part);
|
||||
if(draw_dsc->outline_width) {
|
||||
draw_dsc->outline_opa = lv_obj_get_style_outline_opa(obj, part);
|
||||
if(draw_dsc->outline_opa > LV_OPA_MIN) {
|
||||
draw_dsc->outline_pad = lv_obj_get_style_outline_pad(obj, part);
|
||||
lv_color_t outline_color = lv_obj_get_style_outline_color_filtered(obj, part);
|
||||
draw_dsc->outline_color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, outline_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(draw_dsc->bg_image_opa != LV_OPA_TRANSP) {
|
||||
draw_dsc->bg_image_src = lv_obj_get_style_bg_image_src(obj, part);
|
||||
if(draw_dsc->bg_image_src) {
|
||||
draw_dsc->bg_image_opa = lv_obj_get_style_bg_image_opa(obj, part);
|
||||
if(draw_dsc->bg_image_opa > LV_OPA_MIN) {
|
||||
if(lv_image_src_get_type(draw_dsc->bg_image_src) == LV_IMAGE_SRC_SYMBOL) {
|
||||
draw_dsc->bg_image_symbol_font = lv_obj_get_style_text_font(obj, part);
|
||||
lv_color_t text_color = lv_obj_get_style_text_color_filtered(obj, part);
|
||||
draw_dsc->bg_image_recolor = normal_apply_layer_recolor(obj, part, &draw_dsc->base, text_color);
|
||||
}
|
||||
else {
|
||||
lv_color_t bg_image_recolor = lv_obj_get_style_bg_image_recolor_filtered(obj, part);
|
||||
lv_opa_t bg_image_recolor_opa = lv_obj_get_style_bg_image_recolor_opa(obj, part);
|
||||
lv_color32_t result = image_apply_layer_recolor(obj, part, &draw_dsc->base, bg_image_recolor, bg_image_recolor_opa);
|
||||
draw_dsc->bg_image_recolor_opa = result.alpha;
|
||||
draw_dsc->bg_image_recolor = lv_color_make(result.red, result.green, result.blue);
|
||||
draw_dsc->bg_image_tiled = lv_obj_get_style_bg_image_tiled(obj, part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(draw_dsc->shadow_opa) {
|
||||
draw_dsc->shadow_width = lv_obj_get_style_shadow_width(obj, part);
|
||||
if(draw_dsc->shadow_width) {
|
||||
if(draw_dsc->shadow_opa > LV_OPA_MIN) {
|
||||
draw_dsc->shadow_opa = lv_obj_get_style_shadow_opa(obj, part);
|
||||
if(draw_dsc->shadow_opa > LV_OPA_MIN) {
|
||||
draw_dsc->shadow_offset_x = lv_obj_get_style_shadow_offset_x(obj, part);
|
||||
draw_dsc->shadow_offset_y = lv_obj_get_style_shadow_offset_y(obj, part);
|
||||
draw_dsc->shadow_spread = lv_obj_get_style_shadow_spread(obj, part);
|
||||
lv_color_t shadow_color = lv_obj_get_style_shadow_color_filtered(obj, part);
|
||||
draw_dsc->shadow_color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, shadow_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(opa < LV_OPA_MAX) {
|
||||
draw_dsc->bg_opa = LV_OPA_MIX2(draw_dsc->bg_opa, opa);
|
||||
draw_dsc->bg_image_opa = LV_OPA_MIX2(draw_dsc->bg_image_opa, opa);
|
||||
draw_dsc->border_opa = LV_OPA_MIX2(draw_dsc->border_opa, opa);
|
||||
draw_dsc->shadow_opa = LV_OPA_MIX2(draw_dsc->shadow_opa, opa);
|
||||
draw_dsc->outline_opa = LV_OPA_MIX2(draw_dsc->outline_opa, opa);
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_obj_init_draw_label_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_label_dsc_t * draw_dsc)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
draw_dsc->base.obj = obj;
|
||||
draw_dsc->base.part = part;
|
||||
|
||||
draw_dsc->opa = lv_obj_get_style_text_opa(obj, part);
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
|
||||
if(opa < LV_OPA_MAX) {
|
||||
draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
|
||||
}
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_color_t text_color = lv_obj_get_style_text_color_filtered(obj, part);
|
||||
draw_dsc->color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, text_color);
|
||||
draw_dsc->letter_space = lv_obj_get_style_text_letter_space(obj, part);
|
||||
draw_dsc->line_space = lv_obj_get_style_text_line_space(obj, part);
|
||||
draw_dsc->decor = lv_obj_get_style_text_decor(obj, part);
|
||||
|
||||
draw_dsc->font = lv_obj_get_style_text_font(obj, part);
|
||||
|
||||
#if LV_USE_BIDI
|
||||
draw_dsc->bidi_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
|
||||
#endif
|
||||
|
||||
draw_dsc->align = lv_obj_get_style_text_align(obj, part);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_obj_init_draw_image_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_image_dsc_t * draw_dsc)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
draw_dsc->base.obj = obj;
|
||||
draw_dsc->base.part = part;
|
||||
|
||||
draw_dsc->opa = lv_obj_get_style_image_opa(obj, part);
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
|
||||
if(opa < LV_OPA_MAX) {
|
||||
draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
|
||||
}
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
draw_dsc->rotation = 0;
|
||||
draw_dsc->scale_x = LV_SCALE_NONE;
|
||||
draw_dsc->scale_y = LV_SCALE_NONE;
|
||||
draw_dsc->pivot.x = lv_area_get_width(&obj->coords) / 2;
|
||||
draw_dsc->pivot.y = lv_area_get_height(&obj->coords) / 2;
|
||||
|
||||
lv_color_t recolor = lv_obj_get_style_image_recolor_filtered(obj, part);
|
||||
lv_opa_t recolor_opa = lv_obj_get_style_image_recolor_opa(obj, part);
|
||||
lv_color32_t result = image_apply_layer_recolor(obj, part, &draw_dsc->base, recolor, recolor_opa);
|
||||
draw_dsc->recolor_opa = result.alpha;
|
||||
draw_dsc->recolor = lv_color_make(result.red, result.green, result.blue);
|
||||
|
||||
if(part != LV_PART_MAIN) draw_dsc->blend_mode = lv_obj_get_style_blend_mode(obj, part);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_obj_init_draw_line_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_line_dsc_t * draw_dsc)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
draw_dsc->base.obj = obj;
|
||||
draw_dsc->base.part = part;
|
||||
|
||||
draw_dsc->opa = lv_obj_get_style_line_opa(obj, part);
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
|
||||
if(opa < LV_OPA_MAX) {
|
||||
draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
|
||||
}
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
draw_dsc->width = lv_obj_get_style_line_width(obj, part);
|
||||
if(draw_dsc->width == 0) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_color_t line_color = lv_obj_get_style_line_color_filtered(obj, part);
|
||||
draw_dsc->color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, line_color);
|
||||
|
||||
draw_dsc->dash_width = lv_obj_get_style_line_dash_width(obj, part);
|
||||
if(draw_dsc->dash_width) {
|
||||
draw_dsc->dash_gap = lv_obj_get_style_line_dash_gap(obj, part);
|
||||
}
|
||||
|
||||
draw_dsc->round_start = lv_obj_get_style_line_rounded(obj, part);
|
||||
draw_dsc->round_end = draw_dsc->round_start;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_obj_init_draw_arc_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_arc_dsc_t * draw_dsc)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
draw_dsc->base.obj = obj;
|
||||
draw_dsc->base.part = part;
|
||||
|
||||
draw_dsc->width = lv_obj_get_style_arc_width(obj, part);
|
||||
if(draw_dsc->width == 0) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
draw_dsc->opa = lv_obj_get_style_arc_opa(obj, part);
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_opa_t opa = get_layer_opa(obj, part, &draw_dsc->base);
|
||||
if(opa < LV_OPA_MAX) {
|
||||
draw_dsc->opa = LV_OPA_MIX2(draw_dsc->opa, opa);
|
||||
}
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_color_t arc_color = lv_obj_get_style_arc_color_filtered(obj, part);
|
||||
draw_dsc->color = normal_apply_layer_recolor(obj, part, &draw_dsc->base, arc_color);
|
||||
draw_dsc->img_src = lv_obj_get_style_arc_image_src(obj, part);
|
||||
|
||||
draw_dsc->rounded = lv_obj_get_style_arc_rounded(obj, part);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
int32_t lv_obj_calculate_ext_draw_size(lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
int32_t s = 0;
|
||||
|
||||
int32_t sh_width = lv_obj_get_style_shadow_width(obj, part);
|
||||
if(sh_width) {
|
||||
lv_opa_t sh_opa = lv_obj_get_style_shadow_opa(obj, part);
|
||||
if(sh_opa > LV_OPA_MIN) {
|
||||
sh_width = sh_width / 2 + 1; /*The blur adds only half width*/
|
||||
sh_width += lv_obj_get_style_shadow_spread(obj, part);
|
||||
int32_t sh_ofs_x = lv_obj_get_style_shadow_offset_x(obj, part);
|
||||
int32_t sh_ofs_y = lv_obj_get_style_shadow_offset_y(obj, part);
|
||||
sh_width += LV_MAX(LV_ABS(sh_ofs_x), LV_ABS(sh_ofs_y));
|
||||
s = LV_MAX(s, sh_width);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t outline_width = lv_obj_get_style_outline_width(obj, part);
|
||||
if(outline_width) {
|
||||
lv_opa_t outline_opa = lv_obj_get_style_outline_opa(obj, part);
|
||||
if(outline_opa > LV_OPA_MIN) {
|
||||
int32_t outline_pad = lv_obj_get_style_outline_pad(obj, part);
|
||||
s = LV_MAX(s, outline_pad + outline_width);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t w = lv_obj_get_style_transform_width(obj, part);
|
||||
int32_t h = lv_obj_get_style_transform_height(obj, part);
|
||||
int32_t wh = LV_MAX(w, h);
|
||||
if(wh > 0) s += wh;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return s;
|
||||
}
|
||||
|
||||
void lv_obj_refresh_ext_draw_size(lv_obj_t * obj)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
int32_t s_old = lv_obj_get_ext_draw_size(obj);
|
||||
int32_t s_new = 0;
|
||||
lv_obj_send_event(obj, LV_EVENT_REFR_EXT_DRAW_SIZE, &s_new);
|
||||
|
||||
/*Store the result if the special attrs already allocated*/
|
||||
if(obj->spec_attr) {
|
||||
obj->spec_attr->ext_draw_size = s_new;
|
||||
}
|
||||
/*Allocate spec. attrs. only if the result is not zero.
|
||||
*Zero is the default value if the spec. attr. are not defined.*/
|
||||
else if(s_new != 0) {
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
obj->spec_attr->ext_draw_size = s_new;
|
||||
}
|
||||
|
||||
if(s_new != s_old) lv_obj_invalidate(obj);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_ext_draw_size(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr) return obj->spec_attr->ext_draw_size;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
lv_layer_type_t lv_obj_get_layer_type(const lv_obj_t * obj)
|
||||
{
|
||||
|
||||
if(obj->spec_attr) return (lv_layer_type_t)obj->spec_attr->layer_type;
|
||||
else return LV_LAYER_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static inline lv_opa_t get_layer_opa(const lv_obj_t * obj, lv_part_t part, const lv_draw_dsc_base_t * base_dsc)
|
||||
{
|
||||
if(base_dsc->layer) {
|
||||
/* Accessing the layer opa directly is faster than using get style opa recursive */
|
||||
if(part == LV_PART_MAIN) {
|
||||
return base_dsc->layer->opa;
|
||||
}
|
||||
|
||||
return LV_OPA_MIX2(base_dsc->layer->opa, lv_obj_get_style_opa(obj, part));
|
||||
}
|
||||
|
||||
/* fallback to old recursive style opa */
|
||||
return lv_obj_get_style_opa_recursive(obj, part);
|
||||
}
|
||||
|
||||
|
||||
static lv_color_t normal_apply_layer_recolor(const lv_obj_t * obj, lv_part_t part, const lv_draw_dsc_base_t * base_dsc,
|
||||
lv_color_t color)
|
||||
{
|
||||
lv_color32_t recolor;
|
||||
|
||||
if(base_dsc->layer) {
|
||||
recolor = base_dsc->layer->recolor;
|
||||
if(part != LV_PART_MAIN) {
|
||||
recolor = lv_obj_style_apply_recolor(obj, part, recolor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
recolor = lv_obj_get_style_recolor_recursive(obj, part);
|
||||
}
|
||||
|
||||
return lv_color_mix(lv_color_make(recolor.red, recolor.green, recolor.blue), color, recolor.alpha);
|
||||
}
|
||||
|
||||
|
||||
static lv_color32_t image_apply_layer_recolor(const lv_obj_t * obj, lv_part_t part,
|
||||
const lv_draw_dsc_base_t * base_dsc, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
lv_color32_t recolor;
|
||||
|
||||
if(base_dsc->layer) {
|
||||
recolor = base_dsc->layer->recolor;
|
||||
if(part != LV_PART_MAIN) {
|
||||
recolor = lv_obj_style_apply_recolor(obj, part, recolor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
recolor = lv_obj_get_style_recolor_recursive(obj, part);
|
||||
}
|
||||
|
||||
if(opa > LV_OPA_TRANSP && recolor.alpha > LV_OPA_TRANSP) {
|
||||
return lv_color_over32(recolor, lv_color_to_32(color, opa));
|
||||
}
|
||||
else if(recolor.alpha > LV_OPA_TRANSP) {
|
||||
return recolor;
|
||||
}
|
||||
else {
|
||||
return lv_color_to_32(color, opa);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @file lv_obj_draw.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_DRAW_H
|
||||
#define LV_OBJ_DRAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../draw/lv_draw_rect.h"
|
||||
#include "../draw/lv_draw_label.h"
|
||||
#include "../draw/lv_draw_image.h"
|
||||
#include "../draw/lv_draw_line.h"
|
||||
#include "../draw/lv_draw_arc.h"
|
||||
#include "../draw/lv_draw_triangle.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/** Store the type of layer required to render a widget.*/
|
||||
typedef enum {
|
||||
/**No layer is needed. */
|
||||
LV_LAYER_TYPE_NONE,
|
||||
|
||||
/**Simple layer means that the layer can be rendered in chunks.
|
||||
* For example with opa_layered = 140 it's possible to render only 10 lines
|
||||
* from the layer. When it's ready go the the next 10 lines.
|
||||
* It avoids large memory allocations for the layer buffer.
|
||||
* The buffer size for a chunk can be set by `LV_DRAW_LAYER_SIMPLE_BUF_SIZE` in lv_conf.h.*/
|
||||
LV_LAYER_TYPE_SIMPLE,
|
||||
|
||||
/**The widget is transformed and cannot be rendered in chunks.
|
||||
* It's because - due to the transformations - pixel outside of
|
||||
* a given area will also contribute to the final image.
|
||||
* In this case there is no limitation on the buffer size.
|
||||
* LVGL will allocate as large buffer as needed to render the transformed area.*/
|
||||
LV_LAYER_TYPE_TRANSFORM,
|
||||
} lv_layer_type_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a rectangle draw descriptor from an object's styles in its current state
|
||||
* @param obj pointer to an object
|
||||
* @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
|
||||
* @param draw_dsc the descriptor to initialize.
|
||||
* If an `..._opa` field is set to `LV_OPA_TRANSP` the related properties won't be initialized.
|
||||
* Should be initialized with `lv_draw_rect_dsc_init(draw_dsc)`.
|
||||
* @note Only the relevant fields will be set.
|
||||
* E.g. if `border width == 0` the other border properties won't be evaluated.
|
||||
*/
|
||||
void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_rect_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Initialize a label draw descriptor from an object's styles in its current state
|
||||
* @param obj pointer to an object
|
||||
* @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
|
||||
* @param draw_dsc the descriptor to initialize.
|
||||
* If the `opa` field is set to or the property is equal to `LV_OPA_TRANSP` the rest won't be initialized.
|
||||
* Should be initialized with `lv_draw_label_dsc_init(draw_dsc)`.
|
||||
*/
|
||||
void lv_obj_init_draw_label_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_label_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Initialize an image draw descriptor from an object's styles in its current state
|
||||
* @param obj pointer to an object
|
||||
* @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
|
||||
* @param draw_dsc the descriptor to initialize.
|
||||
* Should be initialized with `lv_draw_image_dsc_init(draw_dsc)`.
|
||||
*/
|
||||
void lv_obj_init_draw_image_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_image_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Initialize a line draw descriptor from an object's styles in its current state
|
||||
* @param obj pointer to an object
|
||||
* @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
|
||||
* @param draw_dsc the descriptor to initialize.
|
||||
* Should be initialized with `lv_draw_line_dsc_init(draw_dsc)`.
|
||||
*/
|
||||
void lv_obj_init_draw_line_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_line_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Initialize an arc draw descriptor from an object's styles in its current state
|
||||
* @param obj pointer to an object
|
||||
* @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc
|
||||
* @param draw_dsc the descriptor to initialize.
|
||||
* Should be initialized with `lv_draw_arc_dsc_init(draw_dsc)`.
|
||||
*/
|
||||
void lv_obj_init_draw_arc_dsc(lv_obj_t * obj, lv_part_t part, lv_draw_arc_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Get the required extra size (around the object's part) to draw shadow, outline, value etc.
|
||||
* @param obj pointer to an object
|
||||
* @param part part of the object
|
||||
* @return the extra size required around the object
|
||||
*/
|
||||
int32_t lv_obj_calculate_ext_draw_size(lv_obj_t * obj, lv_part_t part);
|
||||
|
||||
/**
|
||||
* Send a 'LV_EVENT_REFR_EXT_DRAW_SIZE' Call the ancestor's event handler to the object to refresh the value of the extended draw size.
|
||||
* The result will be saved in `obj`.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_refresh_ext_draw_size(lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_DRAW_H*/
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file lv_obj_draw_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_DRAW_PRIVATE_H
|
||||
#define LV_OBJ_DRAW_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_obj_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get the extended draw area of an object.
|
||||
* @param obj pointer to an object
|
||||
* @return the size extended draw area around the real coordinates
|
||||
*/
|
||||
int32_t lv_obj_get_ext_draw_size(const lv_obj_t * obj);
|
||||
|
||||
lv_layer_type_t lv_obj_get_layer_type(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_DRAW_PRIVATE_H*/
|
||||
@@ -0,0 +1,423 @@
|
||||
/**
|
||||
* @file lv_obj_event.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_event_private.h"
|
||||
#include "lv_obj_event_private.h"
|
||||
#include "lv_obj_class_private.h"
|
||||
#include "lv_obj_private.h"
|
||||
#include "../indev/lv_indev.h"
|
||||
#include "../indev/lv_indev_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS (&lv_obj_class)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static lv_result_t event_send_core(lv_event_t * e);
|
||||
static bool event_is_bubbled(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#if LV_USE_LOG && LV_LOG_TRACE_EVENT
|
||||
#define LV_TRACE_EVENT(...) LV_LOG_TRACE(__VA_ARGS__)
|
||||
#else
|
||||
#define LV_TRACE_EVENT(...)
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_result_t lv_obj_send_event(lv_obj_t * obj, lv_event_code_t event_code, void * param)
|
||||
{
|
||||
if(obj == NULL) return LV_RESULT_OK;
|
||||
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_event_t e;
|
||||
e.current_target = obj;
|
||||
e.original_target = obj;
|
||||
e.code = event_code;
|
||||
e.user_data = NULL;
|
||||
e.param = param;
|
||||
e.deleted = 0;
|
||||
e.stop_bubbling = 0;
|
||||
e.stop_processing = 0;
|
||||
|
||||
lv_event_push(&e);
|
||||
|
||||
/*Send the event*/
|
||||
lv_result_t res = event_send_core(&e);
|
||||
|
||||
/*Remove this element from the list*/
|
||||
lv_event_pop(&e);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
lv_result_t lv_obj_event_base(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
{
|
||||
const lv_obj_class_t * base;
|
||||
if(class_p == NULL) base = ((lv_obj_t *)e->current_target)->class_p;
|
||||
else base = class_p->base_class;
|
||||
|
||||
/*Find a base in which call the ancestor's event handler_cb if set*/
|
||||
while(base && base->event_cb == NULL) base = base->base_class;
|
||||
|
||||
if(base == NULL) return LV_RESULT_OK;
|
||||
if(base->event_cb == NULL) return LV_RESULT_OK;
|
||||
|
||||
/*Call the actual event callback*/
|
||||
e->user_data = NULL;
|
||||
LV_PROFILER_EVENT_BEGIN_TAG(lv_event_code_get_name(e->code));
|
||||
base->event_cb(base, e);
|
||||
LV_PROFILER_EVENT_END_TAG(lv_event_code_get_name(e->code));
|
||||
|
||||
lv_result_t res = LV_RESULT_OK;
|
||||
/*Stop if the object is deleted*/
|
||||
if(e->deleted) res = LV_RESULT_INVALID;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
lv_event_dsc_t * lv_obj_add_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb, lv_event_code_t filter, void * user_data)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
|
||||
return lv_event_add(&obj->spec_attr->event_list, event_cb, filter, user_data);
|
||||
}
|
||||
|
||||
uint32_t lv_obj_get_event_count(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return lv_event_get_count(&obj->spec_attr->event_list);
|
||||
}
|
||||
|
||||
lv_event_dsc_t * lv_obj_get_event_dsc(lv_obj_t * obj, uint32_t index)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
if(obj->spec_attr == NULL) return NULL;
|
||||
return lv_event_get_dsc(&obj->spec_attr->event_list, index);
|
||||
}
|
||||
|
||||
bool lv_obj_remove_event(lv_obj_t * obj, uint32_t index)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
if(obj->spec_attr == NULL) return false;
|
||||
return lv_event_remove(&obj->spec_attr->event_list, index);
|
||||
}
|
||||
|
||||
bool lv_obj_remove_event_dsc(lv_obj_t * obj, lv_event_dsc_t * dsc)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
if(obj->spec_attr == NULL) return false;
|
||||
return lv_event_remove_dsc(&obj->spec_attr->event_list, dsc);
|
||||
}
|
||||
|
||||
uint32_t lv_obj_remove_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
|
||||
uint32_t event_cnt = lv_obj_get_event_count(obj);
|
||||
uint32_t removed_count = 0;
|
||||
uint32_t i;
|
||||
for(i = 0; i < event_cnt; i++) {
|
||||
lv_event_dsc_t * dsc = lv_obj_get_event_dsc(obj, i);
|
||||
if(dsc && dsc->cb == event_cb) {
|
||||
lv_obj_remove_event(obj, i);
|
||||
removed_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return removed_count;
|
||||
}
|
||||
|
||||
uint32_t lv_obj_remove_event_cb_with_user_data(lv_obj_t * obj, lv_event_cb_t event_cb, void * user_data)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
|
||||
uint32_t event_cnt = lv_obj_get_event_count(obj);
|
||||
uint32_t removed_count = 0;
|
||||
int32_t i;
|
||||
|
||||
if(event_cnt == 0) return 0;
|
||||
|
||||
for(i = event_cnt - 1; i >= 0; i--) {
|
||||
lv_event_dsc_t * dsc = lv_obj_get_event_dsc(obj, i);
|
||||
if(dsc && (event_cb == NULL || dsc->cb == event_cb) && dsc->user_data == user_data) {
|
||||
lv_obj_remove_event(obj, i);
|
||||
removed_count ++;
|
||||
}
|
||||
}
|
||||
|
||||
return removed_count;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_event_get_current_target_obj(lv_event_t * e)
|
||||
{
|
||||
return lv_event_get_current_target(e);
|
||||
}
|
||||
|
||||
lv_obj_t * lv_event_get_target_obj(lv_event_t * e)
|
||||
{
|
||||
return lv_event_get_target(e);
|
||||
}
|
||||
|
||||
lv_indev_t * lv_event_get_indev(lv_event_t * e)
|
||||
{
|
||||
|
||||
if(e->code == LV_EVENT_PRESSED ||
|
||||
e->code == LV_EVENT_PRESSING ||
|
||||
e->code == LV_EVENT_PRESS_LOST ||
|
||||
e->code == LV_EVENT_SHORT_CLICKED ||
|
||||
e->code == LV_EVENT_LONG_PRESSED ||
|
||||
e->code == LV_EVENT_LONG_PRESSED_REPEAT ||
|
||||
e->code == LV_EVENT_CLICKED ||
|
||||
e->code == LV_EVENT_RELEASED ||
|
||||
e->code == LV_EVENT_SCROLL_BEGIN ||
|
||||
e->code == LV_EVENT_SCROLL_END ||
|
||||
e->code == LV_EVENT_SCROLL ||
|
||||
e->code == LV_EVENT_GESTURE ||
|
||||
e->code == LV_EVENT_KEY ||
|
||||
e->code == LV_EVENT_FOCUSED ||
|
||||
e->code == LV_EVENT_DEFOCUSED ||
|
||||
e->code == LV_EVENT_LEAVE ||
|
||||
e->code == LV_EVENT_HOVER_OVER ||
|
||||
e->code == LV_EVENT_HOVER_LEAVE) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lv_layer_t * lv_event_get_layer(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_DRAW_MAIN ||
|
||||
e->code == LV_EVENT_DRAW_MAIN_BEGIN ||
|
||||
e->code == LV_EVENT_DRAW_MAIN_END ||
|
||||
e->code == LV_EVENT_DRAW_POST ||
|
||||
e->code == LV_EVENT_DRAW_POST_BEGIN ||
|
||||
e->code == LV_EVENT_DRAW_POST_END) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const lv_area_t * lv_event_get_old_size(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_SIZE_CHANGED) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lv_event_get_key(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_KEY) {
|
||||
uint32_t * k = lv_event_get_param(e);
|
||||
if(k) return *k;
|
||||
else return 0;
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t lv_event_get_rotary_diff(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_ROTARY) {
|
||||
int32_t * r = lv_event_get_param(e);
|
||||
if(r) return *r;
|
||||
else return 0;
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
lv_anim_t * lv_event_get_scroll_anim(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_SCROLL_BEGIN) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_event_set_ext_draw_size(lv_event_t * e, int32_t size)
|
||||
{
|
||||
if(e->code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
|
||||
int32_t * cur_size = lv_event_get_param(e);
|
||||
*cur_size = LV_MAX(*cur_size, size);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
}
|
||||
}
|
||||
|
||||
lv_point_t * lv_event_get_self_size_info(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_GET_SELF_SIZE) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
lv_hit_test_info_t * lv_event_get_hit_test_info(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_HIT_TEST) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const lv_area_t * lv_event_get_cover_area(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_COVER_CHECK) {
|
||||
lv_cover_check_info_t * p = lv_event_get_param(e);
|
||||
return p->area;
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_event_set_cover_res(lv_event_t * e, lv_cover_res_t res)
|
||||
{
|
||||
if(e->code == LV_EVENT_COVER_CHECK) {
|
||||
lv_cover_check_info_t * p = lv_event_get_param(e);
|
||||
if(res > p->res) p->res = res; /*Save only "stronger" results*/
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_event_get_draw_task(lv_event_t * e)
|
||||
{
|
||||
if(e->code == LV_EVENT_DRAW_TASK_ADDED) {
|
||||
return lv_event_get_param(e);
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("Not interpreted with this event code");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_result_t event_send_core(lv_event_t * e)
|
||||
{
|
||||
LV_TRACE_EVENT("Sending event %d to %p with %p param", e->code, (void *)e->original_target, e->param);
|
||||
|
||||
/*Call the input device's feedback callback if set*/
|
||||
lv_indev_t * indev_act = lv_indev_active();
|
||||
if(indev_act) {
|
||||
if(e->stop_processing) return LV_RESULT_OK;
|
||||
if(e->deleted) return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
lv_obj_t * target = e->current_target;
|
||||
lv_result_t res = LV_RESULT_OK;
|
||||
lv_event_list_t * list = target->spec_attr ? &target->spec_attr->event_list : NULL;
|
||||
|
||||
res = lv_event_send(list, e, true);
|
||||
if(res != LV_RESULT_OK || e->stop_processing) return res;
|
||||
|
||||
res = lv_obj_event_base(NULL, e);
|
||||
if(res != LV_RESULT_OK || e->stop_processing) return res;
|
||||
|
||||
res = lv_event_send(list, e, false);
|
||||
if(res != LV_RESULT_OK || e->stop_processing) return res;
|
||||
|
||||
lv_obj_t * parent = lv_obj_get_parent(e->current_target);
|
||||
if(parent && event_is_bubbled(e)) {
|
||||
e->current_target = parent;
|
||||
res = event_send_core(e);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool event_is_bubbled(lv_event_t * e)
|
||||
{
|
||||
if(e->stop_bubbling) return false;
|
||||
|
||||
/*Event codes that always bubble*/
|
||||
switch(e->code) {
|
||||
case LV_EVENT_CHILD_CREATED:
|
||||
case LV_EVENT_CHILD_DELETED:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*Check other codes only if bubbling is enabled*/
|
||||
if(lv_obj_has_flag(e->current_target, LV_OBJ_FLAG_EVENT_BUBBLE) == false) return false;
|
||||
|
||||
switch(e->code) {
|
||||
case LV_EVENT_HIT_TEST:
|
||||
case LV_EVENT_COVER_CHECK:
|
||||
case LV_EVENT_REFR_EXT_DRAW_SIZE:
|
||||
case LV_EVENT_DRAW_MAIN_BEGIN:
|
||||
case LV_EVENT_DRAW_MAIN:
|
||||
case LV_EVENT_DRAW_MAIN_END:
|
||||
case LV_EVENT_DRAW_POST_BEGIN:
|
||||
case LV_EVENT_DRAW_POST:
|
||||
case LV_EVENT_DRAW_POST_END:
|
||||
case LV_EVENT_DRAW_TASK_ADDED:
|
||||
case LV_EVENT_REFRESH:
|
||||
case LV_EVENT_DELETE:
|
||||
case LV_EVENT_CHILD_CREATED:
|
||||
case LV_EVENT_CHILD_DELETED:
|
||||
case LV_EVENT_CHILD_CHANGED:
|
||||
case LV_EVENT_SIZE_CHANGED:
|
||||
case LV_EVENT_STYLE_CHANGED:
|
||||
case LV_EVENT_GET_SELF_SIZE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @file lv_obj_event.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_EVENT_H
|
||||
#define LV_OBJ_EVENT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_event.h"
|
||||
#include "../indev/lv_indev.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/** Cover check results.*/
|
||||
typedef enum {
|
||||
LV_COVER_RES_COVER = 0,
|
||||
LV_COVER_RES_NOT_COVER = 1,
|
||||
LV_COVER_RES_MASKED = 2,
|
||||
} lv_cover_res_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Send an event to the object
|
||||
* @param obj pointer to an object
|
||||
* @param event_code the type of the event from `lv_event_t`
|
||||
* @param param arbitrary data depending on the widget type and the event. (Usually `NULL`)
|
||||
* @return LV_RESULT_OK: `obj` was not deleted in the event; LV_RESULT_INVALID: `obj` was deleted in the event_code
|
||||
*/
|
||||
lv_result_t lv_obj_send_event(lv_obj_t * obj, lv_event_code_t event_code, void * param);
|
||||
|
||||
/**
|
||||
* Used by the widgets internally to call the ancestor widget types's event handler
|
||||
* @param class_p pointer to the class of the widget (NOT the ancestor class)
|
||||
* @param e pointer to the event descriptor
|
||||
* @return LV_RESULT_OK: the target object was not deleted in the event; LV_RESULT_INVALID: it was deleted in the event_code
|
||||
*/
|
||||
lv_result_t lv_obj_event_base(const lv_obj_class_t * class_p, lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the current target of the event. It's the object which event handler being called.
|
||||
* If the event is not bubbled it's the same as "original" target.
|
||||
* @param e pointer to the event descriptor
|
||||
* @return the target of the event_code
|
||||
*/
|
||||
lv_obj_t * lv_event_get_current_target_obj(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the object originally targeted by the event. It's the same even if the event is bubbled.
|
||||
* @param e pointer to the event descriptor
|
||||
* @return pointer to the original target of the event_code
|
||||
*/
|
||||
lv_obj_t * lv_event_get_target_obj(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Add an event handler function for an object.
|
||||
* Used by the user to react on event which happens with the object.
|
||||
* An object can have multiple event handler. They will be called in the same order as they were added.
|
||||
* @param obj pointer to an object
|
||||
* @param filter an event code (e.g. `LV_EVENT_CLICKED`) on which the event should be called. `LV_EVENT_ALL` can be used to receive all the events.
|
||||
* @param event_cb the new event function
|
||||
* @param user_data custom data will be available in `event_cb`
|
||||
* @return handler to the event. It can be used in `lv_obj_remove_event_dsc`.
|
||||
*/
|
||||
lv_event_dsc_t * lv_obj_add_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb, lv_event_code_t filter, void * user_data);
|
||||
|
||||
uint32_t lv_obj_get_event_count(lv_obj_t * obj);
|
||||
|
||||
lv_event_dsc_t * lv_obj_get_event_dsc(lv_obj_t * obj, uint32_t index);
|
||||
|
||||
bool lv_obj_remove_event(lv_obj_t * obj, uint32_t index);
|
||||
|
||||
bool lv_obj_remove_event_dsc(lv_obj_t * obj, lv_event_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Remove an event_cb from an object
|
||||
* @param obj pointer to a obj
|
||||
* @param event_cb the event_cb of the event to remove
|
||||
* @return the count of the event removed
|
||||
*/
|
||||
uint32_t lv_obj_remove_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb);
|
||||
|
||||
/**
|
||||
* Remove an event_cb with user_data
|
||||
* @param obj pointer to a obj
|
||||
* @param event_cb the event_cb of the event to remove
|
||||
* @param user_data user_data
|
||||
* @return the count of the event removed
|
||||
*/
|
||||
uint32_t lv_obj_remove_event_cb_with_user_data(lv_obj_t * obj, lv_event_cb_t event_cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Get the input device passed as parameter to indev related events.
|
||||
* @param e pointer to an event
|
||||
* @return the indev that triggered the event or NULL if called on a not indev related event
|
||||
*/
|
||||
lv_indev_t * lv_event_get_indev(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the draw context which should be the first parameter of the draw functions.
|
||||
* Namely: `LV_EVENT_DRAW_MAIN/POST`, `LV_EVENT_DRAW_MAIN/POST_BEGIN`, `LV_EVENT_DRAW_MAIN/POST_END`
|
||||
* @param e pointer to an event
|
||||
* @return pointer to a draw context or NULL if called on an unrelated event
|
||||
*/
|
||||
lv_layer_t * lv_event_get_layer(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the old area of the object before its size was changed. Can be used in `LV_EVENT_SIZE_CHANGED`
|
||||
* @param e pointer to an event
|
||||
* @return the old absolute area of the object or NULL if called on an unrelated event
|
||||
*/
|
||||
const lv_area_t * lv_event_get_old_size(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the key passed as parameter to an event. Can be used in `LV_EVENT_KEY`
|
||||
* @param e pointer to an event
|
||||
* @return the triggering key or NULL if called on an unrelated event
|
||||
*/
|
||||
uint32_t lv_event_get_key(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the signed rotary encoder diff. passed as parameter to an event. Can be used in `LV_EVENT_ROTARY`
|
||||
* @param e pointer to an event
|
||||
* @return the triggering key or NULL if called on an unrelated event
|
||||
*/
|
||||
int32_t lv_event_get_rotary_diff(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get the animation descriptor of a scrolling. Can be used in `LV_EVENT_SCROLL_BEGIN`
|
||||
* @param e pointer to an event
|
||||
* @return the animation that will scroll the object. (can be modified as required)
|
||||
*/
|
||||
lv_anim_t * lv_event_get_scroll_anim(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Set the new extra draw size. Can be used in `LV_EVENT_REFR_EXT_DRAW_SIZE`
|
||||
* @param e pointer to an event
|
||||
* @param size The new extra draw size
|
||||
*/
|
||||
void lv_event_set_ext_draw_size(lv_event_t * e, int32_t size);
|
||||
|
||||
/**
|
||||
* Get a pointer to an `lv_point_t` variable in which the self size should be saved (width in `point->x` and height `point->y`).
|
||||
* Can be used in `LV_EVENT_GET_SELF_SIZE`
|
||||
* @param e pointer to an event
|
||||
* @return pointer to `lv_point_t` or NULL if called on an unrelated event
|
||||
*/
|
||||
lv_point_t * lv_event_get_self_size_info(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get a pointer to an `lv_hit_test_info_t` variable in which the hit test result should be saved. Can be used in `LV_EVENT_HIT_TEST`
|
||||
* @param e pointer to an event
|
||||
* @return pointer to `lv_hit_test_info_t` or NULL if called on an unrelated event
|
||||
*/
|
||||
lv_hit_test_info_t * lv_event_get_hit_test_info(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Get a pointer to an area which should be examined whether the object fully covers it or not.
|
||||
* Can be used in `LV_EVENT_HIT_TEST`
|
||||
* @param e pointer to an event
|
||||
* @return an area with absolute coordinates to check
|
||||
*/
|
||||
const lv_area_t * lv_event_get_cover_area(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Set the result of cover checking. Can be used in `LV_EVENT_COVER_CHECK`
|
||||
* @param e pointer to an event
|
||||
* @param res an element of ::lv_cover_check_info_t
|
||||
*/
|
||||
void lv_event_set_cover_res(lv_event_t * e, lv_cover_res_t res);
|
||||
|
||||
/**
|
||||
* Get the draw task which was just added.
|
||||
* Can be used in `LV_EVENT_DRAW_TASK_ADDED event`
|
||||
* @param e pointer to an event
|
||||
* @return the added draw task
|
||||
*/
|
||||
lv_draw_task_t * lv_event_get_draw_task(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_EVENT_H*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file lv_obj_event_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_EVENT_PRIVATE_H
|
||||
#define LV_OBJ_EVENT_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_obj_event.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Used as the event parameter of ::LV_EVENT_HIT_TEST to check if an `point` can click the object or not.
|
||||
* `res` should be set like this:
|
||||
* - If already set to `false` another event wants that point non clickable. If you want to respect it leave it as `false` or set `true` to overwrite it.
|
||||
* - If already set `true` and `point` shouldn't be clickable set to `false`
|
||||
* - If already set to `true` you agree that `point` can click the object leave it as `true`
|
||||
*/
|
||||
struct _lv_hit_test_info_t {
|
||||
const lv_point_t * point; /**< A point relative to screen to check if it can click the object or not*/
|
||||
bool res; /**< true: `point` can click the object; false: it cannot*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Used as the event parameter of ::LV_EVENT_COVER_CHECK to check if an area is covered by the object or not.
|
||||
* In the event use `const lv_area_t * area = lv_event_get_cover_area(e)` to get the area to check
|
||||
* and `lv_event_set_cover_res(e, res)` to set the result.
|
||||
*/
|
||||
struct _lv_cover_check_info_t {
|
||||
lv_cover_res_t res;
|
||||
const lv_area_t * area;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_EVENT_PRIVATE_H*/
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file lv_obj_id.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj_class_private.h"
|
||||
#include "lv_obj_private.h"
|
||||
#include "lv_global.h"
|
||||
#include "../osal/lv_os.h"
|
||||
#include "../stdlib/lv_sprintf.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
typedef struct _class_info_t {
|
||||
const lv_obj_class_t * class_p;
|
||||
uint32_t obj_count;
|
||||
} class_info_t;
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_OBJ_ID && LV_USE_OBJ_ID_BUILTIN
|
||||
|
||||
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT(obj && class_p);
|
||||
|
||||
uint32_t i;
|
||||
uint32_t id = 0;
|
||||
lv_global_t * global = LV_GLOBAL_DEFAULT();
|
||||
class_info_t * info = NULL;
|
||||
|
||||
if(obj == NULL || class_p == NULL) return;
|
||||
if(global == NULL) return;
|
||||
|
||||
obj->id = NULL;
|
||||
|
||||
for(i = 0; i < global->objid_count; i ++) {
|
||||
info = ((class_info_t *)global->objid_array) + i;
|
||||
if(class_p == info->class_p) break;
|
||||
}
|
||||
|
||||
/*Resize array*/
|
||||
if(i == global->objid_count) {
|
||||
void * array = lv_realloc(global->objid_array, sizeof(class_info_t) * (global->objid_count + 1));
|
||||
LV_ASSERT_MALLOC(array);
|
||||
if(array == NULL) return;
|
||||
global->objid_array = array;
|
||||
global->objid_count ++;
|
||||
info = ((class_info_t *)global->objid_array) + i;
|
||||
info->obj_count = 0;
|
||||
info->class_p = class_p;
|
||||
}
|
||||
|
||||
id = ++info->obj_count;
|
||||
|
||||
obj->id = (void *)(lv_uintptr_t)id;
|
||||
}
|
||||
|
||||
void lv_obj_set_id(lv_obj_t * obj, void * id)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
if(obj->id) lv_obj_free_id(obj);
|
||||
obj->id = id;
|
||||
}
|
||||
|
||||
void lv_obj_free_id(lv_obj_t * obj)
|
||||
{
|
||||
LV_UNUSED(obj);
|
||||
obj->id = NULL;
|
||||
}
|
||||
|
||||
const char * lv_obj_stringify_id(lv_obj_t * obj, char * buf, uint32_t len)
|
||||
{
|
||||
const char * name;
|
||||
if(obj == NULL || obj->class_p == NULL) return NULL;
|
||||
if(buf == NULL) return NULL;
|
||||
|
||||
name = obj->class_p->name;
|
||||
if(name == NULL) name = "nameless";
|
||||
|
||||
lv_snprintf(buf, len, "%s%" LV_PRIu32 "", name, (uint32_t)(lv_uintptr_t)obj->id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void lv_objid_builtin_destroy(void)
|
||||
{
|
||||
lv_global_t * global = LV_GLOBAL_DEFAULT();
|
||||
if(global == NULL) return;
|
||||
|
||||
lv_free(global->objid_array);
|
||||
global->objid_count = 0;
|
||||
}
|
||||
|
||||
int lv_obj_id_compare(const void * id1, const void * id2)
|
||||
{
|
||||
return id1 == id2 ? 0 : 1;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_OBJ_ID_BUILTIN*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,473 @@
|
||||
/**
|
||||
* @file lv_obj_pos.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_POS_H
|
||||
#define LV_OBJ_POS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
/** No flags */
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_NONE = 0x00,
|
||||
|
||||
/** Consider the transformation properties of the parents too */
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_RECURSIVE = 0x01,
|
||||
|
||||
/** Execute the inverse of the transformation (-angle and 1/zoom) */
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE = 0x02,
|
||||
|
||||
/** Both inverse and recursive*/
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE_RECURSIVE = 0x03,
|
||||
} lv_obj_point_transform_flag_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the position of an object relative to the set alignment.
|
||||
* @param obj pointer to an object
|
||||
* @param x new x coordinate
|
||||
* @param y new y coordinate
|
||||
* @note With default alignment it's the distance from the top left corner
|
||||
* @note E.g. LV_ALIGN_CENTER alignment it's the offset from the center of the parent
|
||||
* @note The position is interpreted on the content area of the parent
|
||||
* @note The values can be set in pixel or in percentage of parent size with `lv_pct(v)`
|
||||
*/
|
||||
void lv_obj_set_pos(lv_obj_t * obj, int32_t x, int32_t y);
|
||||
|
||||
/**
|
||||
* Set the x coordinate of an object
|
||||
* @param obj pointer to an object
|
||||
* @param x new x coordinate
|
||||
* @note With default alignment it's the distance from the top left corner
|
||||
* @note E.g. LV_ALIGN_CENTER alignment it's the offset from the center of the parent
|
||||
* @note The position is interpreted on the content area of the parent
|
||||
* @note The values can be set in pixel or in percentage of parent size with `lv_pct(v)`
|
||||
*/
|
||||
void lv_obj_set_x(lv_obj_t * obj, int32_t x);
|
||||
|
||||
/**
|
||||
* Set the y coordinate of an object
|
||||
* @param obj pointer to an object
|
||||
* @param y new y coordinate
|
||||
* @note With default alignment it's the distance from the top left corner
|
||||
* @note E.g. LV_ALIGN_CENTER alignment it's the offset from the center of the parent
|
||||
* @note The position is interpreted on the content area of the parent
|
||||
* @note The values can be set in pixel or in percentage of parent size with `lv_pct(v)`
|
||||
*/
|
||||
void lv_obj_set_y(lv_obj_t * obj, int32_t y);
|
||||
|
||||
/**
|
||||
* Set the size of an object.
|
||||
* @param obj pointer to an object
|
||||
* @param w the new width
|
||||
* @param h the new height
|
||||
* @note possible values are:
|
||||
* pixel simple set the size accordingly
|
||||
* LV_SIZE_CONTENT set the size to involve all children in the given direction
|
||||
* lv_pct(x) to set size in percentage of the parent's content area size (the size without paddings).
|
||||
* x should be in [0..1000]% range
|
||||
*/
|
||||
void lv_obj_set_size(lv_obj_t * obj, int32_t w, int32_t h);
|
||||
|
||||
/**
|
||||
* Recalculate the size of the object
|
||||
* @param obj pointer to an object
|
||||
* @return true: the size has been changed
|
||||
*/
|
||||
bool lv_obj_refr_size(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the width of an object
|
||||
* @param obj pointer to an object
|
||||
* @param w the new width
|
||||
* @note possible values are:
|
||||
* pixel simple set the size accordingly
|
||||
* LV_SIZE_CONTENT set the size to involve all children in the given direction
|
||||
* lv_pct(x) to set size in percentage of the parent's content area size (the size without paddings).
|
||||
* x should be in [0..1000]% range
|
||||
*/
|
||||
void lv_obj_set_width(lv_obj_t * obj, int32_t w);
|
||||
|
||||
/**
|
||||
* Set the height of an object
|
||||
* @param obj pointer to an object
|
||||
* @param h the new height
|
||||
* @note possible values are:
|
||||
* pixel simple set the size accordingly
|
||||
* LV_SIZE_CONTENT set the size to involve all children in the given direction
|
||||
* lv_pct(x) to set size in percentage of the parent's content area size (the size without paddings).
|
||||
* x should be in [0..1000]% range
|
||||
*/
|
||||
void lv_obj_set_height(lv_obj_t * obj, int32_t h);
|
||||
|
||||
/**
|
||||
* Set the width reduced by the left and right padding and the border width.
|
||||
* @param obj pointer to an object
|
||||
* @param w the width without paddings in pixels
|
||||
*/
|
||||
void lv_obj_set_content_width(lv_obj_t * obj, int32_t w);
|
||||
|
||||
/**
|
||||
* Set the height reduced by the top and bottom padding and the border width.
|
||||
* @param obj pointer to an object
|
||||
* @param h the height without paddings in pixels
|
||||
*/
|
||||
void lv_obj_set_content_height(lv_obj_t * obj, int32_t h);
|
||||
|
||||
/**
|
||||
* Set a layout for an object
|
||||
* @param obj pointer to an object
|
||||
* @param layout pointer to a layout descriptor to set
|
||||
*/
|
||||
void lv_obj_set_layout(lv_obj_t * obj, uint32_t layout);
|
||||
|
||||
/**
|
||||
* Test whether the and object is positioned by a layout or not
|
||||
* @param obj pointer to an object to test
|
||||
* @return true: positioned by a layout; false: not positioned by a layout
|
||||
*/
|
||||
bool lv_obj_is_layout_positioned(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Mark the object for layout update.
|
||||
* @param obj pointer to an object whose children need to be updated
|
||||
*/
|
||||
void lv_obj_mark_layout_as_dirty(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Update the layout of an object.
|
||||
* @param obj pointer to an object whose position and size needs to be updated
|
||||
*/
|
||||
void lv_obj_update_layout(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Change the alignment of an object.
|
||||
* @param obj pointer to an object to align
|
||||
* @param align type of alignment (see 'lv_align_t' enum) `LV_ALIGN_OUT_...` can't be used.
|
||||
*/
|
||||
void lv_obj_set_align(lv_obj_t * obj, lv_align_t align);
|
||||
|
||||
/**
|
||||
* Change the alignment of an object and set new coordinates.
|
||||
* Equivalent to:
|
||||
* lv_obj_set_align(obj, align);
|
||||
* lv_obj_set_pos(obj, x_ofs, y_ofs);
|
||||
* @param obj pointer to an object to align
|
||||
* @param align type of alignment (see 'lv_align_t' enum) `LV_ALIGN_OUT_...` can't be used.
|
||||
* @param x_ofs x coordinate offset after alignment
|
||||
* @param y_ofs y coordinate offset after alignment
|
||||
*/
|
||||
void lv_obj_align(lv_obj_t * obj, lv_align_t align, int32_t x_ofs, int32_t y_ofs);
|
||||
|
||||
/**
|
||||
* Align an object to another object.
|
||||
* @param obj pointer to an object to align
|
||||
* @param base pointer to another object (if NULL `obj`s parent is used). 'obj' will be aligned to it.
|
||||
* @param align type of alignment (see 'lv_align_t' enum)
|
||||
* @param x_ofs x coordinate offset after alignment
|
||||
* @param y_ofs y coordinate offset after alignment
|
||||
* @note if the position or size of `base` changes `obj` needs to be aligned manually again
|
||||
*/
|
||||
void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, int32_t x_ofs,
|
||||
int32_t y_ofs);
|
||||
|
||||
/**
|
||||
* Align an object to the center on its parent.
|
||||
* @param obj pointer to an object to align
|
||||
* @note if the parent size changes `obj` needs to be aligned manually again
|
||||
*/
|
||||
void lv_obj_center(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the transform matrix of an object
|
||||
* @param obj pointer to an object
|
||||
* @param matrix pointer to a matrix to set
|
||||
* @note `LV_DRAW_TRANSFORM_USE_MATRIX` needs to be enabled.
|
||||
*/
|
||||
void lv_obj_set_transform(lv_obj_t * obj, const lv_matrix_t * matrix);
|
||||
|
||||
/**
|
||||
* Reset the transform matrix of an object to identity matrix
|
||||
* @param obj pointer to an object
|
||||
* @note `LV_DRAW_TRANSFORM_USE_MATRIX` needs to be enabled.
|
||||
*/
|
||||
void lv_obj_reset_transform(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Copy the coordinates of an object to an area
|
||||
* @param obj pointer to an object
|
||||
* @param coords pointer to an area to store the coordinates
|
||||
*/
|
||||
void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Get the x coordinate of object.
|
||||
* @param obj pointer to an object
|
||||
* @return distance of `obj` from the left side of its parent plus the parent's left padding
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @note Zero return value means the object is on the left padding of the parent, and not on the left edge.
|
||||
* @note Scrolling of the parent doesn't change the returned value.
|
||||
* @note The returned value is always the distance from the parent even if `obj` is positioned by a layout.
|
||||
*/
|
||||
int32_t lv_obj_get_x(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the x2 coordinate of object.
|
||||
* @param obj pointer to an object
|
||||
* @return distance of `obj` from the right side of its parent plus the parent's right padding
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @note Zero return value means the object is on the right padding of the parent, and not on the right edge.
|
||||
* @note Scrolling of the parent doesn't change the returned value.
|
||||
* @note The returned value is always the distance from the parent even if `obj` is positioned by a layout.
|
||||
*/
|
||||
int32_t lv_obj_get_x2(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the y coordinate of object.
|
||||
* @param obj pointer to an object
|
||||
* @return distance of `obj` from the top side of its parent plus the parent's top padding
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @note Zero return value means the object is on the top padding of the parent, and not on the top edge.
|
||||
* @note Scrolling of the parent doesn't change the returned value.
|
||||
* @note The returned value is always the distance from the parent even if `obj` is positioned by a layout.
|
||||
*/
|
||||
int32_t lv_obj_get_y(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the y2 coordinate of object.
|
||||
* @param obj pointer to an object
|
||||
* @return distance of `obj` from the bottom side of its parent plus the parent's bottom padding
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @note Zero return value means the object is on the bottom padding of the parent, and not on the bottom edge.
|
||||
* @note Scrolling of the parent doesn't change the returned value.
|
||||
* @note The returned value is always the distance from the parent even if `obj` is positioned by a layout.
|
||||
*/
|
||||
int32_t lv_obj_get_y2(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the actually set x coordinate of object, i.e. the offset from the set alignment
|
||||
* @param obj pointer to an object
|
||||
* @return the set x coordinate
|
||||
*/
|
||||
int32_t lv_obj_get_x_aligned(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the actually set y coordinate of object, i.e. the offset from the set alignment
|
||||
* @param obj pointer to an object
|
||||
* @return the set y coordinate
|
||||
*/
|
||||
int32_t lv_obj_get_y_aligned(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the width of an object
|
||||
* @param obj pointer to an object
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @return the width in pixels
|
||||
*/
|
||||
int32_t lv_obj_get_width(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the height of an object
|
||||
* @param obj pointer to an object
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @return the height in pixels
|
||||
*/
|
||||
int32_t lv_obj_get_height(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the width reduced by the left and right padding and the border width.
|
||||
* @param obj pointer to an object
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @return the width which still fits into its parent without causing overflow (making the parent scrollable)
|
||||
*/
|
||||
int32_t lv_obj_get_content_width(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the height reduced by the top and bottom padding and the border width.
|
||||
* @param obj pointer to an object
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @return the height which still fits into the parent without causing overflow (making the parent scrollable)
|
||||
*/
|
||||
int32_t lv_obj_get_content_height(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the area reduced by the paddings and the border width.
|
||||
* @param obj pointer to an object
|
||||
* @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation
|
||||
* call `lv_obj_update_layout(obj)`.
|
||||
* @param area the area which still fits into the parent without causing overflow (making the parent scrollable)
|
||||
*/
|
||||
void lv_obj_get_content_coords(const lv_obj_t * obj, lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Get the width occupied by the "parts" of the widget. E.g. the width of all columns of a table.
|
||||
* @param obj pointer to an objects
|
||||
* @return the width of the virtually drawn content
|
||||
* @note This size independent from the real size of the widget.
|
||||
* It just tells how large the internal ("virtual") content is.
|
||||
*/
|
||||
int32_t lv_obj_get_self_width(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the height occupied by the "parts" of the widget. E.g. the height of all rows of a table.
|
||||
* @param obj pointer to an objects
|
||||
* @return the width of the virtually drawn content
|
||||
* @note This size independent from the real size of the widget.
|
||||
* It just tells how large the internal ("virtual") content is.
|
||||
*/
|
||||
int32_t lv_obj_get_self_height(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Handle if the size of the internal ("virtual") content of an object has changed.
|
||||
* @param obj pointer to an object
|
||||
* @return false: nothing happened; true: refresh happened
|
||||
*/
|
||||
bool lv_obj_refresh_self_size(lv_obj_t * obj);
|
||||
|
||||
void lv_obj_refr_pos(lv_obj_t * obj);
|
||||
|
||||
void lv_obj_move_to(lv_obj_t * obj, int32_t x, int32_t y);
|
||||
|
||||
void lv_obj_move_children_by(lv_obj_t * obj, int32_t x_diff, int32_t y_diff, bool ignore_floating);
|
||||
|
||||
/**
|
||||
* Get the transform matrix of an object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the transform matrix or NULL if not set
|
||||
*/
|
||||
const lv_matrix_t * lv_obj_get_transform(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Transform a point using the angle and zoom style properties of an object
|
||||
* @param obj pointer to an object whose style properties should be used
|
||||
* @param p a point to transform, the result will be written back here too
|
||||
* @param flags OR-ed valued of :cpp:enum:`lv_obj_point_transform_flag_t`
|
||||
*/
|
||||
void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, lv_obj_point_transform_flag_t flags);
|
||||
|
||||
/**
|
||||
* Transform an array of points using the angle and zoom style properties of an object
|
||||
* @param obj pointer to an object whose style properties should be used
|
||||
* @param points the array of points to transform, the result will be written back here too
|
||||
* @param count number of points in the array
|
||||
* @param flags OR-ed valued of :cpp:enum:`lv_obj_point_transform_flag_t`
|
||||
*/
|
||||
void lv_obj_transform_point_array(const lv_obj_t * obj, lv_point_t points[], size_t count,
|
||||
lv_obj_point_transform_flag_t flags);
|
||||
|
||||
/**
|
||||
* Transform an area using the angle and zoom style properties of an object
|
||||
* @param obj pointer to an object whose style properties should be used
|
||||
* @param area an area to transform, the result will be written back here too
|
||||
* @param flags OR-ed valued of :cpp:enum:`lv_obj_point_transform_flag_t`
|
||||
*/
|
||||
void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, lv_obj_point_transform_flag_t flags);
|
||||
|
||||
/**
|
||||
* Mark an area of an object as invalid.
|
||||
* The area will be truncated to the object's area and marked for redraw.
|
||||
* @param obj pointer to an object
|
||||
* @param area the area to redraw
|
||||
*/
|
||||
void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Mark the object as invalid to redrawn its area
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_invalidate(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Tell whether an area of an object is visible (even partially) now or not
|
||||
* @param obj pointer to an object
|
||||
* @param area the are to check. The visible part of the area will be written back here.
|
||||
* @return true visible; false not visible (hidden, out of parent, on other screen, etc)
|
||||
*/
|
||||
bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Tell whether an object is visible (even partially) now or not
|
||||
* @param obj pointer to an object
|
||||
* @return true: visible; false not visible (hidden, out of parent, on other screen, etc)
|
||||
*/
|
||||
bool lv_obj_is_visible(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the size of an extended clickable area
|
||||
* @param obj pointer to an object
|
||||
* @param size extended clickable area in all 4 directions [px]
|
||||
*/
|
||||
void lv_obj_set_ext_click_area(lv_obj_t * obj, int32_t size);
|
||||
|
||||
/**
|
||||
* Get the an area where to object can be clicked.
|
||||
* It's the object's normal area plus the extended click area.
|
||||
* @param obj pointer to an object
|
||||
* @param area store the result area here
|
||||
*/
|
||||
void lv_obj_get_click_area(const lv_obj_t * obj, lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Hit-test an object given a particular point in screen space.
|
||||
* @param obj object to hit-test
|
||||
* @param point screen-space point (absolute coordinate)
|
||||
* @return true: if the object is considered under the point
|
||||
*/
|
||||
bool lv_obj_hit_test(lv_obj_t * obj, const lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Clamp a width between min and max width. If the min/max width is in percentage value use the ref_width
|
||||
* @param width width to clamp
|
||||
* @param min_width the minimal width
|
||||
* @param max_width the maximal width
|
||||
* @param ref_width the reference width used when min/max width is in percentage
|
||||
* @return the clamped width
|
||||
*/
|
||||
int32_t lv_clamp_width(int32_t width, int32_t min_width, int32_t max_width, int32_t ref_width);
|
||||
|
||||
/**
|
||||
* Clamp a height between min and max height. If the min/max height is in percentage value use the ref_height
|
||||
* @param height height to clamp
|
||||
* @param min_height the minimal height
|
||||
* @param max_height the maximal height
|
||||
* @param ref_height the reference height used when min/max height is in percentage
|
||||
* @return the clamped height
|
||||
*/
|
||||
int32_t lv_clamp_height(int32_t height, int32_t min_height, int32_t max_height, int32_t ref_height);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_POS_H*/
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file lv_obj_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_PRIVATE_H
|
||||
#define LV_OBJ_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_obj.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Special, rarely used attributes.
|
||||
* They are allocated automatically if any elements is set.
|
||||
*/
|
||||
struct _lv_obj_spec_attr_t {
|
||||
lv_obj_t ** children; /**< Store the pointer of the children in an array.*/
|
||||
lv_group_t * group_p;
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
lv_matrix_t * matrix; /**< The transform matrix*/
|
||||
#endif
|
||||
lv_event_list_t event_list;
|
||||
#if LV_USE_OBJ_NAME
|
||||
const char * name; /**< Pointer to the name */
|
||||
#endif
|
||||
lv_point_t scroll; /**< The current X/Y scroll offset*/
|
||||
|
||||
int32_t ext_click_pad; /**< Extra click padding in all direction*/
|
||||
int32_t ext_draw_size; /**< EXTend the size in every direction for drawing.*/
|
||||
|
||||
uint16_t child_cnt; /**< Number of children*/
|
||||
uint16_t scrollbar_mode : 2; /**< How to display scrollbars, see `lv_scrollbar_mode_t`*/
|
||||
uint16_t scroll_snap_x : 2; /**< Where to align the snappable children horizontally, see `lv_scroll_snap_t`*/
|
||||
uint16_t scroll_snap_y : 2; /**< Where to align the snappable children vertically*/
|
||||
uint16_t scroll_dir : 4; /**< The allowed scroll direction(s), see `lv_dir_t`*/
|
||||
uint16_t layer_type : 2; /**< Cache the layer type here. Element of lv_intermediate_layer_type_t */
|
||||
uint16_t name_static : 1; /**< 1: `name` was not dynamically allocated */
|
||||
};
|
||||
|
||||
struct _lv_obj_t {
|
||||
const lv_obj_class_t * class_p;
|
||||
lv_obj_t * parent;
|
||||
lv_obj_spec_attr_t * spec_attr;
|
||||
lv_obj_style_t * styles;
|
||||
#if LV_OBJ_STYLE_CACHE
|
||||
uint32_t style_main_prop_is_set;
|
||||
uint32_t style_other_prop_is_set;
|
||||
#endif
|
||||
void * user_data;
|
||||
#if LV_USE_OBJ_ID
|
||||
void * id;
|
||||
#endif
|
||||
lv_area_t coords;
|
||||
lv_obj_flag_t flags;
|
||||
lv_state_t state;
|
||||
uint16_t layout_inv : 1;
|
||||
uint16_t readjust_scroll_after_layout : 1;
|
||||
uint16_t scr_layout_inv : 1;
|
||||
uint16_t skip_trans : 1;
|
||||
uint16_t style_cnt : 6;
|
||||
uint16_t h_layout : 1;
|
||||
uint16_t w_layout : 1;
|
||||
uint16_t is_deleting : 1;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_PRIVATE_H*/
|
||||
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* @file lv_obj_id.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../misc/lv_utils.h"
|
||||
#include "lv_obj_property.h"
|
||||
#include "lv_obj_class_private.h"
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define HANDLE_PROPERTY_TYPE(type, field) \
|
||||
if(!set) { \
|
||||
value->field = ((lv_property_get_##type##_t)(prop->getter))(obj); \
|
||||
} else { \
|
||||
switch(LV_PROPERTY_ID_TYPE2(prop->id)) { \
|
||||
case LV_PROPERTY_ID_INVALID: \
|
||||
((lv_property_set_##type##_t)(prop->setter))(obj, value->field); \
|
||||
break; \
|
||||
case LV_PROPERTY_TYPE_INT: \
|
||||
((lv_property_set_##type##_integer_t)(prop->setter))(obj, value->arg1.field, value->arg2.num); \
|
||||
break; \
|
||||
case LV_PROPERTY_TYPE_BOOL: \
|
||||
((lv_property_set_##type##_boolean_t)(prop->setter))(obj, value->arg1.field, value->arg2.enable); \
|
||||
break; \
|
||||
case LV_PROPERTY_TYPE_PRECISE: \
|
||||
((lv_property_set_##type##_precise_t)(prop->setter))(obj, value->arg1.field, value->arg2.precise); \
|
||||
break; \
|
||||
case LV_PROPERTY_TYPE_COLOR: \
|
||||
((lv_property_set_##type##_color_t)(prop->setter))(obj, value->arg1.field, value->arg2.color); \
|
||||
break; \
|
||||
case LV_PROPERTY_TYPE_POINTER: \
|
||||
case LV_PROPERTY_TYPE_IMGSRC: \
|
||||
case LV_PROPERTY_TYPE_TEXT: \
|
||||
case LV_PROPERTY_TYPE_OBJ: \
|
||||
case LV_PROPERTY_TYPE_DISPLAY: \
|
||||
case LV_PROPERTY_TYPE_FONT: \
|
||||
((lv_property_set_##type##_pointer_t)(prop->setter))(obj, value->arg1.field, value->arg2.ptr); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef int32_t integer;
|
||||
typedef bool boolean;
|
||||
typedef lv_value_precise_t precise;
|
||||
typedef lv_color_t color;
|
||||
typedef const void * pointer;
|
||||
|
||||
#define DEFINE_PROPERTY_SETTER_TYPES(type) \
|
||||
typedef void (*lv_property_set_##type##_t)(lv_obj_t *, type); \
|
||||
typedef void (*lv_property_set_##type##_integer_t)(lv_obj_t *, type, int32_t); \
|
||||
typedef void (*lv_property_set_##type##_boolean_t)(lv_obj_t *, type, bool); \
|
||||
typedef void (*lv_property_set_##type##_precise_t)(lv_obj_t *, type, lv_value_precise_t); \
|
||||
typedef void (*lv_property_set_##type##_color_t)(lv_obj_t *, type, lv_color_t); \
|
||||
typedef void (*lv_property_set_##type##_pointer_t)(lv_obj_t *, type, const void *)
|
||||
|
||||
DEFINE_PROPERTY_SETTER_TYPES(integer);
|
||||
DEFINE_PROPERTY_SETTER_TYPES(boolean);
|
||||
DEFINE_PROPERTY_SETTER_TYPES(precise);
|
||||
DEFINE_PROPERTY_SETTER_TYPES(color);
|
||||
DEFINE_PROPERTY_SETTER_TYPES(pointer);
|
||||
|
||||
typedef void (*lv_property_set_point_t)(lv_obj_t *, lv_point_t *);
|
||||
typedef lv_result_t (*lv_property_setter_t)(lv_obj_t *, lv_prop_id_t, const lv_property_t *);
|
||||
|
||||
typedef integer(*lv_property_get_integer_t)(const lv_obj_t *);
|
||||
typedef bool (*lv_property_get_boolean_t)(const lv_obj_t *);
|
||||
typedef lv_value_precise_t (*lv_property_get_precise_t)(const lv_obj_t *);
|
||||
typedef lv_color_t (*lv_property_get_color_t)(const lv_obj_t *);
|
||||
typedef void * (*lv_property_get_pointer_t)(const lv_obj_t *);
|
||||
typedef lv_point_t (*lv_property_get_point_t)(lv_obj_t *);
|
||||
|
||||
typedef lv_result_t (*lv_property_getter_t)(const lv_obj_t *, lv_prop_id_t, lv_property_t *);
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set);
|
||||
static int property_name_compare(const void * ref, const void * element);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_result_t lv_obj_set_property(lv_obj_t * obj, const lv_property_t * value)
|
||||
{
|
||||
LV_ASSERT(obj && value);
|
||||
|
||||
uint32_t index = LV_PROPERTY_ID_INDEX(value->id);
|
||||
if(value->id == LV_PROPERTY_ID_INVALID || index > LV_PROPERTY_ID_ANY) {
|
||||
LV_LOG_WARN("Invalid property id set to %p", obj);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
if(index < LV_PROPERTY_ID_START) {
|
||||
lv_obj_set_local_style_prop(obj, index, value->style, value->selector);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
return obj_property(obj, value->id, (lv_property_t *)value, true);
|
||||
}
|
||||
|
||||
lv_result_t lv_obj_set_properties(lv_obj_t * obj, const lv_property_t * value, uint32_t count)
|
||||
{
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
lv_result_t result = lv_obj_set_property(obj, &value[i]);
|
||||
if(result != LV_RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_property_t lv_obj_get_property(lv_obj_t * obj, lv_prop_id_t id)
|
||||
{
|
||||
lv_result_t result;
|
||||
lv_property_t value = { 0 };
|
||||
|
||||
uint32_t index = LV_PROPERTY_ID_INDEX(id);
|
||||
if(id == LV_PROPERTY_ID_INVALID || index > LV_PROPERTY_ID_ANY) {
|
||||
LV_LOG_WARN("Invalid property id to get from %p", obj);
|
||||
value.id = LV_PROPERTY_ID_INVALID;
|
||||
value.num = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
if(index < LV_PROPERTY_ID_START) {
|
||||
lv_obj_get_local_style_prop(obj, index, &value.style, 0);
|
||||
value.id = id;
|
||||
value.selector = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
result = obj_property(obj, id, &value, false);
|
||||
if(result != LV_RESULT_OK)
|
||||
value.id = LV_PROPERTY_ID_INVALID;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
lv_property_t lv_obj_get_style_property(lv_obj_t * obj, lv_prop_id_t id, uint32_t selector)
|
||||
{
|
||||
lv_property_t value;
|
||||
uint32_t index = LV_PROPERTY_ID_INDEX(id);
|
||||
|
||||
if(index == LV_PROPERTY_ID_INVALID || index >= LV_PROPERTY_ID_START) {
|
||||
LV_LOG_WARN("invalid style property id 0x%" LV_PRIx32, id);
|
||||
value.id = LV_PROPERTY_ID_INVALID;
|
||||
value.num = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
lv_obj_get_local_style_prop(obj, id, &value.style, selector);
|
||||
value.id = id;
|
||||
value.selector = selector;
|
||||
return value;
|
||||
}
|
||||
|
||||
lv_prop_id_t lv_style_property_get_id(const char * name)
|
||||
{
|
||||
#if LV_USE_OBJ_PROPERTY_NAME
|
||||
lv_property_name_t * found;
|
||||
/*Check style property*/
|
||||
found = lv_utils_bsearch(name, lv_style_property_names, sizeof(lv_style_property_names) / sizeof(lv_property_name_t),
|
||||
sizeof(lv_property_name_t), property_name_compare);
|
||||
if(found) return found->id;
|
||||
#else
|
||||
LV_UNUSED(name);
|
||||
#endif
|
||||
return LV_PROPERTY_ID_INVALID;
|
||||
}
|
||||
|
||||
lv_prop_id_t lv_obj_class_property_get_id(const lv_obj_class_t * clz, const char * name)
|
||||
{
|
||||
#if LV_USE_OBJ_PROPERTY_NAME
|
||||
const lv_property_name_t * names;
|
||||
lv_property_name_t * found;
|
||||
|
||||
names = clz->property_names;
|
||||
if(names == NULL) {
|
||||
/* try base class*/
|
||||
return LV_PROPERTY_ID_INVALID;
|
||||
}
|
||||
|
||||
found = lv_utils_bsearch(name, names, clz->names_count, sizeof(lv_property_name_t), property_name_compare);
|
||||
if(found) return found->id;
|
||||
#else
|
||||
LV_UNUSED(obj);
|
||||
LV_UNUSED(name);
|
||||
LV_UNUSED(property_name_compare);
|
||||
#endif
|
||||
return LV_PROPERTY_ID_INVALID;
|
||||
}
|
||||
|
||||
lv_prop_id_t lv_obj_property_get_id(const lv_obj_t * obj, const char * name)
|
||||
{
|
||||
#if LV_USE_OBJ_PROPERTY_NAME
|
||||
const lv_obj_class_t * clz;
|
||||
lv_prop_id_t id;
|
||||
|
||||
for(clz = obj->class_p; clz; clz = clz->base_class) {
|
||||
id = lv_obj_class_property_get_id(clz, name);
|
||||
if(id != LV_PROPERTY_ID_INVALID) return id;
|
||||
}
|
||||
|
||||
/*Check style property*/
|
||||
id = lv_style_property_get_id(name);
|
||||
if(id != LV_PROPERTY_ID_INVALID) return id;
|
||||
#else
|
||||
LV_UNUSED(obj);
|
||||
LV_UNUSED(name);
|
||||
LV_UNUSED(property_name_compare);
|
||||
#endif
|
||||
return LV_PROPERTY_ID_INVALID;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_result_t obj_property(lv_obj_t * obj, lv_prop_id_t id, lv_property_t * value, bool set)
|
||||
{
|
||||
const lv_property_ops_t * properties;
|
||||
const lv_property_ops_t * prop;
|
||||
|
||||
const lv_obj_class_t * clz;
|
||||
uint32_t index = LV_PROPERTY_ID_INDEX(id);
|
||||
|
||||
for(clz = obj->class_p ; clz; clz = clz->base_class) {
|
||||
properties = clz->properties;
|
||||
if(properties == NULL) {
|
||||
/* try base class*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if(id != LV_PROPERTY_ID_ANY && (index < clz->prop_index_start || index > clz->prop_index_end)) {
|
||||
/* try base class*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/*Check if there's setter available for this class*/
|
||||
for(uint32_t i = 0; i < clz->properties_count; i++) {
|
||||
prop = &properties[i];
|
||||
|
||||
/*pass id and value directly to widget's property method*/
|
||||
if(prop->id == LV_PROPERTY_ID_ANY) {
|
||||
value->id = prop->id;
|
||||
if(set) return ((lv_property_setter_t)prop->setter)(obj, id, value);
|
||||
else return ((lv_property_getter_t)prop->getter)(obj, id, value);
|
||||
}
|
||||
|
||||
/*Not this id, check next*/
|
||||
if(prop->id != id)
|
||||
continue;
|
||||
|
||||
/*id matched but we got null pointer to functions*/
|
||||
if(set ? prop->setter == NULL : prop->getter == NULL) {
|
||||
LV_LOG_WARN("NULL %s provided, id: 0x%" LV_PRIx32, set ? "setter" : "getter", id);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/*Update value id if it's a read*/
|
||||
if(!set) value->id = prop->id;
|
||||
|
||||
switch(LV_PROPERTY_ID_TYPE(prop->id)) {
|
||||
case LV_PROPERTY_TYPE_INT:
|
||||
HANDLE_PROPERTY_TYPE(integer, num);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_BOOL:
|
||||
HANDLE_PROPERTY_TYPE(boolean, enable);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_PRECISE:
|
||||
HANDLE_PROPERTY_TYPE(precise, precise);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_COLOR:
|
||||
HANDLE_PROPERTY_TYPE(color, color);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_POINTER:
|
||||
case LV_PROPERTY_TYPE_IMGSRC:
|
||||
case LV_PROPERTY_TYPE_TEXT:
|
||||
case LV_PROPERTY_TYPE_OBJ:
|
||||
case LV_PROPERTY_TYPE_DISPLAY:
|
||||
case LV_PROPERTY_TYPE_FONT:
|
||||
HANDLE_PROPERTY_TYPE(pointer, ptr);
|
||||
break;
|
||||
case LV_PROPERTY_TYPE_POINT: {
|
||||
lv_point_t * point = &value->point;
|
||||
if(set)((lv_property_set_point_t)(prop->setter))(obj, point);
|
||||
else *point = ((lv_property_get_point_t)(prop->getter))(obj);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LV_LOG_WARN("Unknown property id: 0x%08" LV_PRIx32, prop->id);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/*If no setter found, try base class then*/
|
||||
}
|
||||
|
||||
LV_LOG_WARN("Unknown property id: 0x%08" LV_PRIx32, id);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
static int property_name_compare(const void * ref, const void * element)
|
||||
{
|
||||
const lv_property_name_t * prop = element;
|
||||
return lv_strcmp(ref, prop->name);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_OBJ_PROPERTY*/
|
||||
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* @file lv_obj_property.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_PROPERTY_H
|
||||
#define LV_OBJ_PROPERTY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*All possible property value types*/
|
||||
#define LV_PROPERTY_TYPE_INVALID 0 /*Use default 0 as invalid to detect program outliers*/
|
||||
#define LV_PROPERTY_TYPE_INT 1 /*int32_t type*/
|
||||
#define LV_PROPERTY_TYPE_PRECISE 2 /*lv_value_precise_t, int32_t or float depending on LV_USE_FLOAT*/
|
||||
#define LV_PROPERTY_TYPE_COLOR 3 /*ARGB8888 type*/
|
||||
#define LV_PROPERTY_TYPE_POINT 4 /*lv_point_t */
|
||||
#define LV_PROPERTY_TYPE_POINTER 5 /*void * pointer*/
|
||||
#define LV_PROPERTY_TYPE_IMGSRC 6 /*Special pointer for image*/
|
||||
#define LV_PROPERTY_TYPE_TEXT 7 /*Special pointer of char* */
|
||||
#define LV_PROPERTY_TYPE_OBJ 8 /*Special pointer of lv_obj_t* */
|
||||
#define LV_PROPERTY_TYPE_DISPLAY 9 /*Special pointer of lv_display_t* */
|
||||
#define LV_PROPERTY_TYPE_FONT 10 /*Special pointer of lv_font_t* */
|
||||
#define LV_PROPERTY_TYPE_BOOL 11 /*int32_t type*/
|
||||
|
||||
#define LV_PROPERTY_TYPE_SHIFT 28
|
||||
#define LV_PROPERTY_TYPE2_SHIFT 24
|
||||
#define LV_PROPERTY_ID(clz, name, type, index) LV_PROPERTY_## clz ##_##name = (LV_PROPERTY_## clz ##_START + (index)) | ((type) << LV_PROPERTY_TYPE_SHIFT)
|
||||
#define LV_PROPERTY_ID2(clz, name, type, type2, index) LV_PROPERTY_ID(clz, name, type, index) | ((type2) << LV_PROPERTY_TYPE2_SHIFT)
|
||||
|
||||
#define LV_PROPERTY_ID_TYPE(id) ((id) >> LV_PROPERTY_TYPE_SHIFT)
|
||||
#define LV_PROPERTY_ID_TYPE2(id) ((id) >> LV_PROPERTY_TYPE_SHIFT)
|
||||
#define LV_PROPERTY_ID_INDEX(id) ((id) & 0xfffffff)
|
||||
|
||||
/*Set properties from an array of lv_property_t*/
|
||||
#define LV_OBJ_SET_PROPERTY_ARRAY(obj, array) lv_obj_set_properties(obj, array, sizeof(array)/sizeof(array[0]))
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Group of predefined widget ID start value.
|
||||
*/
|
||||
enum {
|
||||
LV_PROPERTY_ID_INVALID = 0,
|
||||
|
||||
/*ID 0x01 to 0xff are style ID, check lv_style_prop_t*/
|
||||
LV_PROPERTY_STYLE_START = 0x00,
|
||||
|
||||
LV_PROPERTY_ID_START = 0x0100, /*ID smaller than 0xff is style ID*/
|
||||
/*Define the property ID for every widget here. */
|
||||
LV_PROPERTY_OBJ_START = 0x0100, /* lv_obj.c */
|
||||
LV_PROPERTY_IMAGE_START = 0x0200, /* lv_image.c */
|
||||
LV_PROPERTY_LABEL_START = 0x0300, /* lv_label.c */
|
||||
LV_PROPERTY_KEYBOARD_START = 0x0400, /* lv_keyboard.c */
|
||||
LV_PROPERTY_TEXTAREA_START = 0x0500, /* lv_textarea.c */
|
||||
LV_PROPERTY_ROLLER_START = 0x0600, /* lv_roller.c */
|
||||
LV_PROPERTY_DROPDOWN_START = 0x0700, /* lv_dropdown.c */
|
||||
LV_PROPERTY_SLIDER_START = 0x0800, /* lv_slider.c */
|
||||
LV_PROPERTY_ANIMIMAGE_START = 0x0900, /* lv_animimage.c */
|
||||
|
||||
/*Special ID, use it to extend ID and make sure it's unique and compile time determinant*/
|
||||
LV_PROPERTY_ID_BUILTIN_LAST = 0xffff, /*ID of 0x10000 ~ 0xfffffff is reserved for user*/
|
||||
|
||||
LV_PROPERTY_ID_ANY = 0x7ffffffe, /*Special ID used by lvgl to intercept all setter/getter call.*/
|
||||
};
|
||||
|
||||
struct _lv_property_name_t {
|
||||
const char * name;
|
||||
lv_prop_id_t id;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
lv_prop_id_t id;
|
||||
union {
|
||||
int32_t num; /**< Signed integer number (enums or "normal" numbers)*/
|
||||
uint32_t num_u; /**< Unsigned integer number (opacity, Booleans) */
|
||||
bool enable; /**< Booleans */
|
||||
const void * ptr; /**< Constant pointers (font, cone text, etc.) */
|
||||
lv_color_t color; /**< Colors */
|
||||
lv_value_precise_t precise; /**< float or int for precise value */
|
||||
lv_point_t point; /**< Point, contains two int32_t */
|
||||
|
||||
struct {
|
||||
/**
|
||||
* Note that place struct member `style` at first place is intended.
|
||||
* `style` shares same memory with `num`, `ptr`, `color`.
|
||||
* So we set the style value directly without using `prop.style.num`.
|
||||
*
|
||||
* E.g.
|
||||
*
|
||||
* static const lv_property_t obj_pos_x = {
|
||||
* .id = LV_PROPERTY_STYLE_X,
|
||||
* .num = 123,
|
||||
* .selector = LV_STATE_PRESSED,
|
||||
* }
|
||||
*
|
||||
* instead of:
|
||||
* static const lv_property_t obj_pos_x = {
|
||||
* .id = LV_PROPERTY_STYLE_X,
|
||||
* .style.num = 123, // note this line.
|
||||
* .selector = LV_STATE_PRESSED,
|
||||
* }
|
||||
*/
|
||||
lv_style_value_t style; /**< Make sure it's the first element in struct. */
|
||||
uint32_t selector; /**< Style selector, lv_part_t | lv_state_t */
|
||||
};
|
||||
|
||||
/**
|
||||
* For some properties like slider range, it contains two simple (4-byte) values
|
||||
* so we can use `arg1.num` and `arg2.num` to set the argument.
|
||||
*/
|
||||
struct {
|
||||
union {
|
||||
int32_t num;
|
||||
uint32_t num_u;
|
||||
bool enable;
|
||||
const void * ptr;
|
||||
lv_color_t color;
|
||||
lv_value_precise_t precise;
|
||||
} arg1, arg2;
|
||||
};
|
||||
};
|
||||
} lv_property_t;
|
||||
|
||||
typedef struct {
|
||||
lv_prop_id_t id;
|
||||
|
||||
void * setter; /**< Callback used to set property. */
|
||||
void * getter; /**< Callback used to get property. */
|
||||
} lv_property_ops_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set Widget property.
|
||||
* @param obj pointer to Widget
|
||||
* @param value property value to set
|
||||
* @return return LV_RESULT_OK if call succeeded
|
||||
*/
|
||||
lv_result_t lv_obj_set_property(lv_obj_t * obj, const lv_property_t * value);
|
||||
|
||||
/**
|
||||
* Set multiple Widget properties. Helper `LV_OBJ_SET_PROPERTY_ARRAY` can be used for constant property array.
|
||||
* @param obj pointer to Widget
|
||||
* @param value property value array to set
|
||||
* @param count number of array elements
|
||||
* @return return LV_RESULT_OK if call succeeded
|
||||
*/
|
||||
lv_result_t lv_obj_set_properties(lv_obj_t * obj, const lv_property_t * value, uint32_t count);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Read property value from Widget.
|
||||
* If id is a style property. Style selector is 0 by default.
|
||||
* @param obj pointer to Widget
|
||||
* @param id ID of property to read
|
||||
* @return return property value read. The returned property ID is set to `LV_PROPERTY_ID_INVALID` if read failed.
|
||||
*/
|
||||
lv_property_t lv_obj_get_property(lv_obj_t * obj, lv_prop_id_t id);
|
||||
|
||||
/**
|
||||
* Read style property value from Widget
|
||||
* @param obj pointer to Widget
|
||||
* @param id ID of style property
|
||||
* @param selector selector for style property
|
||||
* @return return property value read. The returned property ID is set to `LV_PROPERTY_ID_INVALID` if read failed.
|
||||
*/
|
||||
lv_property_t lv_obj_get_style_property(lv_obj_t * obj, lv_prop_id_t id, uint32_t selector);
|
||||
|
||||
/**
|
||||
* Get property ID by recursively searching for name in Widget's class hierarchy, and
|
||||
* if still not found, then search style properties.
|
||||
* Requires to enabling `LV_USE_OBJ_PROPERTY_NAME`.
|
||||
* @param obj pointer to Widget whose class and base-class hierarchy are to be searched.
|
||||
* @param name property name
|
||||
* @return property ID found or `LV_PROPERTY_ID_INVALID` if not found.
|
||||
*/
|
||||
lv_prop_id_t lv_obj_property_get_id(const lv_obj_t * obj, const char * name);
|
||||
|
||||
/**
|
||||
* Get property ID by doing a non-recursive search for name directly in Widget class properties.
|
||||
* Requires enabling `LV_USE_OBJ_PROPERTY_NAME`.
|
||||
* @param clz pointer to Widget class that has specified property.
|
||||
* @param name property name
|
||||
* @return property ID found or `LV_PROPERTY_ID_INVALID` if not found.
|
||||
*/
|
||||
lv_prop_id_t lv_obj_class_property_get_id(const lv_obj_class_t * clz, const char * name);
|
||||
|
||||
/**
|
||||
* Get style property ID by name. Requires enabling `LV_USE_OBJ_PROPERTY_NAME`.
|
||||
* @param name property name
|
||||
* @return property ID found or `LV_PROPERTY_ID_INVALID` if not found.
|
||||
*/
|
||||
lv_prop_id_t lv_style_property_get_id(const char * name);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#include "../widgets/property/lv_obj_property_names.h"
|
||||
#include "../widgets/property/lv_style_properties.h"
|
||||
|
||||
#endif /*LV_USE_OBJ_PROPERTY*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_PROPERTY_H*/
|
||||
@@ -0,0 +1,813 @@
|
||||
/**
|
||||
* @file lv_obj_scroll.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj_scroll_private.h"
|
||||
#include "../misc/lv_anim_private.h"
|
||||
#include "lv_obj_private.h"
|
||||
#include "../indev/lv_indev.h"
|
||||
#include "../indev/lv_indev_scroll.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS (&lv_obj_class)
|
||||
#define SCROLL_ANIM_TIME_MIN 200 /*ms*/
|
||||
#define SCROLL_ANIM_TIME_MAX 400 /*ms*/
|
||||
#define SCROLLBAR_MIN_SIZE (LV_DPX(10))
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void scroll_x_anim(void * obj, int32_t v);
|
||||
static void scroll_y_anim(void * obj, int32_t v);
|
||||
static void scroll_end_cb(lv_anim_t * a);
|
||||
static void scroll_area_into_view(const lv_area_t * area, lv_obj_t * child, lv_point_t * scroll_value,
|
||||
lv_anim_enable_t anim_en);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
void lv_obj_set_scrollbar_mode(lv_obj_t * obj, lv_scrollbar_mode_t mode)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
|
||||
if(obj->spec_attr->scrollbar_mode == mode) return;
|
||||
obj->spec_attr->scrollbar_mode = mode;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
void lv_obj_set_scroll_dir(lv_obj_t * obj, lv_dir_t dir)
|
||||
{
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
|
||||
if(dir != obj->spec_attr->scroll_dir) {
|
||||
obj->spec_attr->scroll_dir = dir;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_set_scroll_snap_x(lv_obj_t * obj, lv_scroll_snap_t align)
|
||||
{
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
obj->spec_attr->scroll_snap_x = align;
|
||||
}
|
||||
|
||||
void lv_obj_set_scroll_snap_y(lv_obj_t * obj, lv_scroll_snap_t align)
|
||||
{
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
obj->spec_attr->scroll_snap_y = align;
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
lv_scrollbar_mode_t lv_obj_get_scrollbar_mode(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr) return (lv_scrollbar_mode_t) obj->spec_attr->scrollbar_mode;
|
||||
else return LV_SCROLLBAR_MODE_AUTO;
|
||||
}
|
||||
|
||||
lv_dir_t lv_obj_get_scroll_dir(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr) return (lv_dir_t) obj->spec_attr->scroll_dir;
|
||||
else return LV_DIR_ALL;
|
||||
}
|
||||
|
||||
lv_scroll_snap_t lv_obj_get_scroll_snap_x(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr) return (lv_scroll_snap_t) obj->spec_attr->scroll_snap_x;
|
||||
else return LV_SCROLL_SNAP_NONE;
|
||||
}
|
||||
|
||||
lv_scroll_snap_t lv_obj_get_scroll_snap_y(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr) return (lv_scroll_snap_t) obj->spec_attr->scroll_snap_y;
|
||||
else return LV_SCROLL_SNAP_NONE;
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_scroll_x(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return -obj->spec_attr->scroll.x;
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_scroll_y(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return -obj->spec_attr->scroll.y;
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_scroll_top(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return -obj->spec_attr->scroll.y;
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_scroll_bottom(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
int32_t child_res = LV_COORD_MIN;
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_count(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
const lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
|
||||
int32_t tmp_y = child->coords.y2 + lv_obj_get_style_margin_bottom(child, LV_PART_MAIN);
|
||||
child_res = LV_MAX(child_res, tmp_y);
|
||||
}
|
||||
|
||||
int32_t space_top = lv_obj_get_style_space_top(obj, LV_PART_MAIN);
|
||||
int32_t space_bottom = lv_obj_get_style_space_bottom(obj, LV_PART_MAIN);
|
||||
|
||||
if(child_res != LV_COORD_MIN) {
|
||||
child_res -= (obj->coords.y2 - space_bottom);
|
||||
}
|
||||
|
||||
int32_t self_h = lv_obj_get_self_height(obj);
|
||||
self_h = self_h - (lv_obj_get_height(obj) - space_top - space_bottom);
|
||||
self_h -= lv_obj_get_scroll_y(obj);
|
||||
return LV_MAX(child_res, self_h);
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_scroll_left(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
/*Normally can't scroll the object out on the left.
|
||||
*So simply use the current scroll position as "left size"*/
|
||||
if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) {
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return -obj->spec_attr->scroll.x;
|
||||
}
|
||||
|
||||
/*With RTL base direction scrolling the left is normal so find the left most coordinate*/
|
||||
int32_t space_right = lv_obj_get_style_space_right(obj, LV_PART_MAIN);
|
||||
int32_t space_left = lv_obj_get_style_space_left(obj, LV_PART_MAIN);
|
||||
|
||||
int32_t child_res = 0;
|
||||
|
||||
uint32_t i;
|
||||
int32_t x1 = LV_COORD_MAX;
|
||||
uint32_t child_cnt = lv_obj_get_child_count(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
const lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
|
||||
int32_t tmp_x = child->coords.x1 - lv_obj_get_style_margin_left(child, LV_PART_MAIN);
|
||||
x1 = LV_MIN(x1, tmp_x);
|
||||
}
|
||||
|
||||
if(x1 != LV_COORD_MAX) {
|
||||
child_res = x1;
|
||||
child_res = (obj->coords.x1 + space_left) - child_res;
|
||||
}
|
||||
else {
|
||||
child_res = LV_COORD_MIN;
|
||||
}
|
||||
|
||||
int32_t self_w = lv_obj_get_self_width(obj);
|
||||
self_w = self_w - (lv_obj_get_width(obj) - space_right - space_left);
|
||||
self_w += lv_obj_get_scroll_x(obj);
|
||||
|
||||
return LV_MAX(child_res, self_w);
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_scroll_right(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
/*With RTL base dir can't scroll to the object out on the right.
|
||||
*So simply use the current scroll position as "right size"*/
|
||||
if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) == LV_BASE_DIR_RTL) {
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return obj->spec_attr->scroll.x;
|
||||
}
|
||||
|
||||
/*With other base direction (LTR) scrolling to the right is normal so find the right most coordinate*/
|
||||
int32_t child_res = LV_COORD_MIN;
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_count(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
const lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
|
||||
int32_t tmp_x = child->coords.x2 + lv_obj_get_style_margin_right(child, LV_PART_MAIN);
|
||||
child_res = LV_MAX(child_res, tmp_x);
|
||||
}
|
||||
|
||||
int32_t space_right = lv_obj_get_style_space_right(obj, LV_PART_MAIN);
|
||||
int32_t space_left = lv_obj_get_style_space_left(obj, LV_PART_MAIN);
|
||||
|
||||
if(child_res != LV_COORD_MIN) {
|
||||
child_res -= (obj->coords.x2 - space_right);
|
||||
}
|
||||
|
||||
int32_t self_w;
|
||||
self_w = lv_obj_get_self_width(obj);
|
||||
self_w = self_w - (lv_obj_get_width(obj) - space_right - space_left);
|
||||
self_w -= lv_obj_get_scroll_x(obj);
|
||||
return LV_MAX(child_res, self_w);
|
||||
}
|
||||
|
||||
void lv_obj_get_scroll_end(lv_obj_t * obj, lv_point_t * end)
|
||||
{
|
||||
lv_anim_t * a;
|
||||
a = lv_anim_get(obj, scroll_x_anim);
|
||||
end->x = a ? -a->end_value : lv_obj_get_scroll_x(obj);
|
||||
|
||||
a = lv_anim_get(obj, scroll_y_anim);
|
||||
end->y = a ? -a->end_value : lv_obj_get_scroll_y(obj);
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
void lv_obj_scroll_by_bounded(lv_obj_t * obj, int32_t dx, int32_t dy, lv_anim_enable_t anim_en)
|
||||
{
|
||||
if(dx == 0 && dy == 0) return;
|
||||
|
||||
/*We need to know the final sizes for bound check*/
|
||||
lv_obj_update_layout(obj);
|
||||
|
||||
/*Don't let scroll more than naturally possible by the size of the content*/
|
||||
int32_t x_current = -lv_obj_get_scroll_x(obj);
|
||||
int32_t x_bounded = x_current + dx;
|
||||
|
||||
if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) {
|
||||
if(x_bounded > 0) x_bounded = 0;
|
||||
if(x_bounded < 0) {
|
||||
int32_t scroll_max = lv_obj_get_scroll_left(obj) + lv_obj_get_scroll_right(obj);
|
||||
if(scroll_max < 0) scroll_max = 0;
|
||||
|
||||
if(x_bounded < -scroll_max) x_bounded = -scroll_max;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(x_bounded < 0) x_bounded = 0;
|
||||
if(x_bounded > 0) {
|
||||
int32_t scroll_max = lv_obj_get_scroll_left(obj) + lv_obj_get_scroll_right(obj);
|
||||
if(scroll_max < 0) scroll_max = 0;
|
||||
|
||||
if(x_bounded > scroll_max) x_bounded = scroll_max;
|
||||
}
|
||||
}
|
||||
|
||||
/*Don't let scroll more than naturally possible by the size of the content*/
|
||||
int32_t y_current = -lv_obj_get_scroll_y(obj);
|
||||
int32_t y_bounded = y_current + dy;
|
||||
|
||||
if(y_bounded > 0) y_bounded = 0;
|
||||
if(y_bounded < 0) {
|
||||
int32_t scroll_max = lv_obj_get_scroll_top(obj) + lv_obj_get_scroll_bottom(obj);
|
||||
if(scroll_max < 0) scroll_max = 0;
|
||||
if(y_bounded < -scroll_max) y_bounded = -scroll_max;
|
||||
}
|
||||
|
||||
dx = x_bounded - x_current;
|
||||
dy = y_bounded - y_current;
|
||||
if(dx || dy) {
|
||||
lv_obj_scroll_by(obj, dx, dy, anim_en);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_scroll_by(lv_obj_t * obj, int32_t dx, int32_t dy, lv_anim_enable_t anim_en)
|
||||
{
|
||||
if(dx == 0 && dy == 0) return;
|
||||
if(anim_en) {
|
||||
lv_display_t * d = lv_obj_get_display(obj);
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_var(&a, obj);
|
||||
lv_anim_set_deleted_cb(&a, scroll_end_cb);
|
||||
|
||||
if(dx) {
|
||||
uint32_t t = lv_anim_speed_clamped((lv_display_get_horizontal_resolution(d)) >> 1, SCROLL_ANIM_TIME_MIN,
|
||||
SCROLL_ANIM_TIME_MAX);
|
||||
lv_anim_set_duration(&a, t);
|
||||
int32_t sx = lv_obj_get_scroll_x(obj);
|
||||
lv_anim_set_values(&a, -sx, -sx + dx);
|
||||
lv_anim_set_exec_cb(&a, scroll_x_anim);
|
||||
lv_anim_set_path_cb(&a, lv_anim_path_ease_out);
|
||||
|
||||
lv_result_t res;
|
||||
res = lv_obj_send_event(obj, LV_EVENT_SCROLL_BEGIN, &a);
|
||||
if(res != LV_RESULT_OK) return;
|
||||
lv_anim_start(&a);
|
||||
}
|
||||
|
||||
if(dy) {
|
||||
uint32_t t = lv_anim_speed_clamped((lv_display_get_vertical_resolution(d)) >> 1, SCROLL_ANIM_TIME_MIN,
|
||||
SCROLL_ANIM_TIME_MAX);
|
||||
lv_anim_set_duration(&a, t);
|
||||
int32_t sy = lv_obj_get_scroll_y(obj);
|
||||
lv_anim_set_values(&a, -sy, -sy + dy);
|
||||
lv_anim_set_exec_cb(&a, scroll_y_anim);
|
||||
lv_anim_set_path_cb(&a, lv_anim_path_ease_out);
|
||||
|
||||
lv_result_t res;
|
||||
res = lv_obj_send_event(obj, LV_EVENT_SCROLL_BEGIN, &a);
|
||||
if(res != LV_RESULT_OK) return;
|
||||
lv_anim_start(&a);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Remove pending animations*/
|
||||
lv_anim_delete(obj, scroll_y_anim);
|
||||
lv_anim_delete(obj, scroll_x_anim);
|
||||
|
||||
lv_result_t res;
|
||||
res = lv_obj_send_event(obj, LV_EVENT_SCROLL_BEGIN, NULL);
|
||||
if(res != LV_RESULT_OK) return;
|
||||
|
||||
res = lv_obj_scroll_by_raw(obj, dx, dy);
|
||||
if(res != LV_RESULT_OK) return;
|
||||
|
||||
res = lv_obj_send_event(obj, LV_EVENT_SCROLL_END, NULL);
|
||||
if(res != LV_RESULT_OK) return;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_scroll_to(lv_obj_t * obj, int32_t x, int32_t y, lv_anim_enable_t anim_en)
|
||||
{
|
||||
lv_obj_scroll_to_x(obj, x, anim_en);
|
||||
lv_obj_scroll_to_y(obj, y, anim_en);
|
||||
}
|
||||
|
||||
void lv_obj_scroll_to_x(lv_obj_t * obj, int32_t x, lv_anim_enable_t anim_en)
|
||||
{
|
||||
lv_anim_delete(obj, scroll_x_anim);
|
||||
|
||||
int32_t scroll_x = lv_obj_get_scroll_x(obj);
|
||||
int32_t diff = -x + scroll_x;
|
||||
|
||||
lv_obj_scroll_by_bounded(obj, diff, 0, anim_en);
|
||||
}
|
||||
|
||||
void lv_obj_scroll_to_y(lv_obj_t * obj, int32_t y, lv_anim_enable_t anim_en)
|
||||
{
|
||||
lv_anim_delete(obj, scroll_y_anim);
|
||||
|
||||
int32_t scroll_y = lv_obj_get_scroll_y(obj);
|
||||
int32_t diff = -y + scroll_y;
|
||||
|
||||
lv_obj_scroll_by_bounded(obj, 0, diff, anim_en);
|
||||
}
|
||||
|
||||
void lv_obj_scroll_to_view(lv_obj_t * obj, lv_anim_enable_t anim_en)
|
||||
{
|
||||
/*Be sure the screens layout is correct*/
|
||||
lv_obj_update_layout(obj);
|
||||
|
||||
lv_point_t p = {0, 0};
|
||||
scroll_area_into_view(&obj->coords, obj, &p, anim_en);
|
||||
}
|
||||
|
||||
void lv_obj_scroll_to_view_recursive(lv_obj_t * obj, lv_anim_enable_t anim_en)
|
||||
{
|
||||
/*Be sure the screens layout is correct*/
|
||||
lv_obj_update_layout(obj);
|
||||
|
||||
lv_point_t p = {0, 0};
|
||||
lv_obj_t * child = obj;
|
||||
lv_obj_t * parent = lv_obj_get_parent(child);
|
||||
while(parent) {
|
||||
scroll_area_into_view(&obj->coords, child, &p, anim_en);
|
||||
child = parent;
|
||||
parent = lv_obj_get_parent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
lv_result_t lv_obj_scroll_by_raw(lv_obj_t * obj, int32_t x, int32_t y)
|
||||
{
|
||||
if(x == 0 && y == 0) return LV_RESULT_OK;
|
||||
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
|
||||
obj->spec_attr->scroll.x += x;
|
||||
obj->spec_attr->scroll.y += y;
|
||||
|
||||
lv_obj_move_children_by(obj, x, y, true);
|
||||
lv_result_t res = lv_obj_send_event(obj, LV_EVENT_SCROLL, NULL);
|
||||
if(res != LV_RESULT_OK) return res;
|
||||
lv_obj_invalidate(obj);
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
bool lv_obj_is_scrolling(const lv_obj_t * obj)
|
||||
{
|
||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||
while(indev) {
|
||||
if(lv_indev_get_scroll_obj(indev) == obj) return true;
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
|
||||
if(lv_anim_get((lv_obj_t *)obj, scroll_x_anim) != NULL ||
|
||||
lv_anim_get((lv_obj_t *)obj, scroll_y_anim) != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void lv_obj_stop_scroll_anim(const lv_obj_t * obj)
|
||||
{
|
||||
lv_anim_delete((lv_obj_t *)obj, scroll_y_anim);
|
||||
lv_anim_delete((lv_obj_t *)obj, scroll_x_anim);
|
||||
}
|
||||
|
||||
void lv_obj_update_snap(lv_obj_t * obj, lv_anim_enable_t anim_en)
|
||||
{
|
||||
lv_obj_update_layout(obj);
|
||||
lv_point_t p;
|
||||
lv_indev_scroll_get_snap_dist(obj, &p);
|
||||
if(p.x == LV_COORD_MAX || p.x == LV_COORD_MIN) p.x = 0;
|
||||
if(p.y == LV_COORD_MAX || p.y == LV_COORD_MIN) p.y = 0;
|
||||
lv_obj_scroll_by(obj, p.x, p.y, anim_en);
|
||||
}
|
||||
|
||||
void lv_obj_get_scrollbar_area(lv_obj_t * obj, lv_area_t * hor_area, lv_area_t * ver_area)
|
||||
{
|
||||
lv_area_set(hor_area, 0, 0, -1, -1);
|
||||
lv_area_set(ver_area, 0, 0, -1, -1);
|
||||
|
||||
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLLABLE) == false) return;
|
||||
|
||||
lv_scrollbar_mode_t sm = lv_obj_get_scrollbar_mode(obj);
|
||||
if(sm == LV_SCROLLBAR_MODE_OFF) return;
|
||||
|
||||
/*If there is no indev scrolling this object but `mode==active` return*/
|
||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||
if(sm == LV_SCROLLBAR_MODE_ACTIVE) {
|
||||
while(indev) {
|
||||
if(lv_indev_get_scroll_obj(indev) == obj) break;
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
if(indev == NULL) return;
|
||||
}
|
||||
|
||||
int32_t st = lv_obj_get_scroll_top(obj);
|
||||
int32_t sb = lv_obj_get_scroll_bottom(obj);
|
||||
int32_t sl = lv_obj_get_scroll_left(obj);
|
||||
int32_t sr = lv_obj_get_scroll_right(obj);
|
||||
|
||||
lv_dir_t dir = lv_obj_get_scroll_dir(obj);
|
||||
|
||||
bool ver_draw = false;
|
||||
if((dir & LV_DIR_VER) &&
|
||||
((sm == LV_SCROLLBAR_MODE_ON) ||
|
||||
(sm == LV_SCROLLBAR_MODE_AUTO && (st > 0 || sb > 0)) ||
|
||||
(sm == LV_SCROLLBAR_MODE_ACTIVE && lv_indev_get_scroll_dir(indev) == LV_DIR_VER))) {
|
||||
ver_draw = true;
|
||||
}
|
||||
|
||||
bool hor_draw = false;
|
||||
if((dir & LV_DIR_HOR) &&
|
||||
((sm == LV_SCROLLBAR_MODE_ON) ||
|
||||
(sm == LV_SCROLLBAR_MODE_AUTO && (sl > 0 || sr > 0)) ||
|
||||
(sm == LV_SCROLLBAR_MODE_ACTIVE && lv_indev_get_scroll_dir(indev) == LV_DIR_HOR))) {
|
||||
hor_draw = true;
|
||||
}
|
||||
|
||||
if(!hor_draw && !ver_draw) return;
|
||||
|
||||
bool rtl = lv_obj_get_style_base_dir(obj, LV_PART_SCROLLBAR) == LV_BASE_DIR_RTL;
|
||||
|
||||
int32_t top_space = lv_obj_get_style_pad_top(obj, LV_PART_SCROLLBAR);
|
||||
int32_t bottom_space = lv_obj_get_style_pad_bottom(obj, LV_PART_SCROLLBAR);
|
||||
int32_t left_space = lv_obj_get_style_pad_left(obj, LV_PART_SCROLLBAR);
|
||||
int32_t right_space = lv_obj_get_style_pad_right(obj, LV_PART_SCROLLBAR);
|
||||
int32_t thickness = lv_obj_get_style_width(obj, LV_PART_SCROLLBAR);
|
||||
int32_t length = lv_obj_get_style_length(obj, LV_PART_SCROLLBAR);
|
||||
|
||||
int32_t obj_h = lv_obj_get_height(obj);
|
||||
int32_t obj_w = lv_obj_get_width(obj);
|
||||
|
||||
/*Space required for the vertical and horizontal scrollbars*/
|
||||
int32_t ver_reg_space = ver_draw ? thickness : 0;
|
||||
int32_t hor_req_space = hor_draw ? thickness : 0;
|
||||
int32_t rem;
|
||||
|
||||
if(lv_obj_get_style_bg_opa(obj, LV_PART_SCROLLBAR) <= LV_OPA_MIN &&
|
||||
lv_obj_get_style_border_opa(obj, LV_PART_SCROLLBAR) <= LV_OPA_MIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*Draw vertical scrollbar if the mode is ON or can be scrolled in this direction*/
|
||||
int32_t content_h = obj_h + st + sb;
|
||||
if(ver_draw && content_h) {
|
||||
ver_area->y1 = obj->coords.y1;
|
||||
ver_area->y2 = obj->coords.y2;
|
||||
if(rtl) {
|
||||
ver_area->x1 = obj->coords.x1 + left_space;
|
||||
ver_area->x2 = ver_area->x1 + thickness - 1;
|
||||
}
|
||||
else {
|
||||
ver_area->x2 = obj->coords.x2 - right_space;
|
||||
ver_area->x1 = ver_area->x2 - thickness + 1;
|
||||
}
|
||||
|
||||
int32_t sb_h = ((obj_h - top_space - bottom_space - hor_req_space) * obj_h) / content_h;
|
||||
sb_h = LV_MAX(length > 0 ? length : sb_h, SCROLLBAR_MIN_SIZE); /*Style-defined size, calculated size, or minimum size*/
|
||||
sb_h = LV_MIN(sb_h, obj_h); /*Limit scrollbar length to parent height*/
|
||||
rem = (obj_h - top_space - bottom_space - hor_req_space) -
|
||||
sb_h; /*Remaining size from the scrollbar track that is not the scrollbar itself*/
|
||||
int32_t scroll_h = content_h - obj_h; /*The size of the content which can be really scrolled*/
|
||||
if(scroll_h <= 0) {
|
||||
ver_area->y1 = obj->coords.y1 + top_space;
|
||||
ver_area->y2 = obj->coords.y2 - bottom_space - hor_req_space - 1;
|
||||
}
|
||||
else {
|
||||
int32_t sb_y = (rem * sb) / scroll_h;
|
||||
sb_y = rem - sb_y;
|
||||
|
||||
ver_area->y1 = obj->coords.y1 + sb_y + top_space;
|
||||
ver_area->y2 = ver_area->y1 + sb_h - 1;
|
||||
if(ver_area->y1 < obj->coords.y1 + top_space) {
|
||||
ver_area->y1 = obj->coords.y1 + top_space;
|
||||
if(ver_area->y1 + SCROLLBAR_MIN_SIZE > ver_area->y2) {
|
||||
ver_area->y2 = ver_area->y1 + SCROLLBAR_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
if(ver_area->y2 > obj->coords.y2 - hor_req_space - bottom_space) {
|
||||
ver_area->y2 = obj->coords.y2 - hor_req_space - bottom_space;
|
||||
if(ver_area->y2 - SCROLLBAR_MIN_SIZE < ver_area->y1) {
|
||||
ver_area->y1 = ver_area->y2 - SCROLLBAR_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Draw horizontal scrollbar if the mode is ON or can be scrolled in this direction*/
|
||||
int32_t content_w = obj_w + sl + sr;
|
||||
if(hor_draw && content_w) {
|
||||
hor_area->y2 = obj->coords.y2 - bottom_space;
|
||||
hor_area->y1 = hor_area->y2 - thickness + 1;
|
||||
hor_area->x1 = obj->coords.x1;
|
||||
hor_area->x2 = obj->coords.x2;
|
||||
|
||||
int32_t sb_w = ((obj_w - left_space - right_space - ver_reg_space) * obj_w) / content_w;
|
||||
sb_w = LV_MAX(length > 0 ? length : sb_w, SCROLLBAR_MIN_SIZE); /*Style-defined size, calculated size, or minimum size*/
|
||||
sb_w = LV_MIN(sb_w, obj_w); /*Limit scrollbar length to parent width*/
|
||||
rem = (obj_w - left_space - right_space - ver_reg_space) -
|
||||
sb_w; /*Remaining size from the scrollbar track that is not the scrollbar itself*/
|
||||
int32_t scroll_w = content_w - obj_w; /*The size of the content which can be really scrolled*/
|
||||
if(scroll_w <= 0) {
|
||||
if(rtl) {
|
||||
hor_area->x1 = obj->coords.x1 + left_space + ver_reg_space - 1;
|
||||
hor_area->x2 = obj->coords.x2 - right_space;
|
||||
}
|
||||
else {
|
||||
hor_area->x1 = obj->coords.x1 + left_space;
|
||||
hor_area->x2 = obj->coords.x2 - right_space - ver_reg_space - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int32_t sb_x = (rem * sr) / scroll_w;
|
||||
sb_x = rem - sb_x;
|
||||
|
||||
if(rtl) {
|
||||
hor_area->x1 = obj->coords.x1 + sb_x + left_space + ver_reg_space;
|
||||
hor_area->x2 = hor_area->x1 + sb_w - 1;
|
||||
if(hor_area->x1 < obj->coords.x1 + left_space + ver_reg_space) {
|
||||
hor_area->x1 = obj->coords.x1 + left_space + ver_reg_space;
|
||||
if(hor_area->x1 + SCROLLBAR_MIN_SIZE > hor_area->x2) {
|
||||
hor_area->x2 = hor_area->x1 + SCROLLBAR_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
if(hor_area->x2 > obj->coords.x2 - right_space) {
|
||||
hor_area->x2 = obj->coords.x2 - right_space;
|
||||
if(hor_area->x2 - SCROLLBAR_MIN_SIZE < hor_area->x1) {
|
||||
hor_area->x1 = hor_area->x2 - SCROLLBAR_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
hor_area->x1 = obj->coords.x1 + sb_x + left_space;
|
||||
hor_area->x2 = hor_area->x1 + sb_w - 1;
|
||||
if(hor_area->x1 < obj->coords.x1 + left_space) {
|
||||
hor_area->x1 = obj->coords.x1 + left_space;
|
||||
if(hor_area->x1 + SCROLLBAR_MIN_SIZE > hor_area->x2) {
|
||||
hor_area->x2 = hor_area->x1 + SCROLLBAR_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
if(hor_area->x2 > obj->coords.x2 - ver_reg_space - right_space) {
|
||||
hor_area->x2 = obj->coords.x2 - ver_reg_space - right_space;
|
||||
if(hor_area->x2 - SCROLLBAR_MIN_SIZE < hor_area->x1) {
|
||||
hor_area->x1 = hor_area->x2 - SCROLLBAR_MIN_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_scrollbar_invalidate(lv_obj_t * obj)
|
||||
{
|
||||
lv_area_t hor_area;
|
||||
lv_area_t ver_area;
|
||||
lv_obj_get_scrollbar_area(obj, &hor_area, &ver_area);
|
||||
|
||||
if(lv_area_get_size(&hor_area) <= 0 && lv_area_get_size(&ver_area) <= 0) return;
|
||||
|
||||
if(lv_area_get_size(&hor_area) > 0) lv_obj_invalidate_area(obj, &hor_area);
|
||||
if(lv_area_get_size(&ver_area) > 0) lv_obj_invalidate_area(obj, &ver_area);
|
||||
}
|
||||
|
||||
void lv_obj_readjust_scroll(lv_obj_t * obj, lv_anim_enable_t anim_en)
|
||||
{
|
||||
/*Be sure the bottom side is not remains scrolled in*/
|
||||
/*With snapping the content can't be scrolled in*/
|
||||
if(lv_obj_get_scroll_snap_y(obj) == LV_SCROLL_SNAP_NONE) {
|
||||
int32_t st = lv_obj_get_scroll_top(obj);
|
||||
int32_t sb = lv_obj_get_scroll_bottom(obj);
|
||||
if(sb < 0 && st > 0) {
|
||||
sb = LV_MIN(st, -sb);
|
||||
lv_obj_scroll_by(obj, 0, sb, anim_en);
|
||||
}
|
||||
}
|
||||
|
||||
if(lv_obj_get_scroll_snap_x(obj) == LV_SCROLL_SNAP_NONE) {
|
||||
int32_t sl = lv_obj_get_scroll_left(obj);
|
||||
int32_t sr = lv_obj_get_scroll_right(obj);
|
||||
if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) {
|
||||
/*Be sure the left side is not remains scrolled in*/
|
||||
if(sr < 0 && sl > 0) {
|
||||
sr = LV_MIN(sl, -sr);
|
||||
lv_obj_scroll_by(obj, sr, 0, anim_en);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Be sure the right side is not remains scrolled in*/
|
||||
if(sl < 0 && sr > 0) {
|
||||
sr = LV_MIN(sr, -sl);
|
||||
lv_obj_scroll_by(obj, sl, 0, anim_en);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void scroll_x_anim(void * obj, int32_t v)
|
||||
{
|
||||
lv_obj_scroll_by_raw(obj, v + lv_obj_get_scroll_x(obj), 0);
|
||||
}
|
||||
|
||||
static void scroll_y_anim(void * obj, int32_t v)
|
||||
{
|
||||
lv_obj_scroll_by_raw(obj, 0, v + lv_obj_get_scroll_y(obj));
|
||||
}
|
||||
|
||||
static void scroll_end_cb(lv_anim_t * a)
|
||||
{
|
||||
/*Do not sent END event if there wasn't a BEGIN*/
|
||||
if(a->start_cb_called) lv_obj_send_event(a->var, LV_EVENT_SCROLL_END, NULL);
|
||||
}
|
||||
|
||||
static void scroll_area_into_view(const lv_area_t * area, lv_obj_t * child, lv_point_t * scroll_value,
|
||||
lv_anim_enable_t anim_en)
|
||||
{
|
||||
lv_obj_t * parent = lv_obj_get_parent(child);
|
||||
if(!lv_obj_has_flag(parent, LV_OBJ_FLAG_SCROLLABLE)) return;
|
||||
|
||||
lv_dir_t scroll_dir = lv_obj_get_scroll_dir(parent);
|
||||
int32_t snap_goal = 0;
|
||||
int32_t act = 0;
|
||||
const lv_area_t * area_tmp;
|
||||
|
||||
int32_t y_scroll = 0;
|
||||
lv_scroll_snap_t snap_y = lv_obj_get_scroll_snap_y(parent);
|
||||
if(snap_y != LV_SCROLL_SNAP_NONE) area_tmp = &child->coords;
|
||||
else area_tmp = area;
|
||||
|
||||
int32_t stop = lv_obj_get_style_space_top(parent, LV_PART_MAIN);
|
||||
int32_t sbottom = lv_obj_get_style_space_bottom(parent, LV_PART_MAIN);
|
||||
int32_t top_diff = parent->coords.y1 + stop - area_tmp->y1 - scroll_value->y;
|
||||
int32_t bottom_diff = -(parent->coords.y2 - sbottom - area_tmp->y2 - scroll_value->y);
|
||||
int32_t parent_h = lv_obj_get_height(parent) - stop - sbottom;
|
||||
if((top_diff >= 0 && bottom_diff >= 0)) y_scroll = 0;
|
||||
else if(top_diff > 0) {
|
||||
y_scroll = top_diff;
|
||||
/*Do not let scrolling in*/
|
||||
int32_t st = lv_obj_get_scroll_top(parent);
|
||||
if(st - y_scroll < 0) y_scroll = 0;
|
||||
}
|
||||
else if(bottom_diff > 0) {
|
||||
y_scroll = -bottom_diff;
|
||||
/*Do not let scrolling in*/
|
||||
int32_t sb = lv_obj_get_scroll_bottom(parent);
|
||||
if(sb + y_scroll < 0) y_scroll = 0;
|
||||
}
|
||||
|
||||
switch(snap_y) {
|
||||
case LV_SCROLL_SNAP_START:
|
||||
snap_goal = parent->coords.y1 + stop;
|
||||
act = area_tmp->y1 + y_scroll;
|
||||
y_scroll += snap_goal - act;
|
||||
break;
|
||||
case LV_SCROLL_SNAP_END:
|
||||
snap_goal = parent->coords.y2 - sbottom;
|
||||
act = area_tmp->y2 + y_scroll;
|
||||
y_scroll += snap_goal - act;
|
||||
break;
|
||||
case LV_SCROLL_SNAP_CENTER:
|
||||
snap_goal = parent->coords.y1 + stop + parent_h / 2;
|
||||
act = lv_area_get_height(area_tmp) / 2 + area_tmp->y1 + y_scroll;
|
||||
y_scroll += snap_goal - act;
|
||||
break;
|
||||
case LV_SCROLL_SNAP_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t x_scroll = 0;
|
||||
lv_scroll_snap_t snap_x = lv_obj_get_scroll_snap_x(parent);
|
||||
if(snap_x != LV_SCROLL_SNAP_NONE) area_tmp = &child->coords;
|
||||
else area_tmp = area;
|
||||
|
||||
int32_t sleft = lv_obj_get_style_space_left(parent, LV_PART_MAIN);
|
||||
int32_t sright = lv_obj_get_style_space_right(parent, LV_PART_MAIN);
|
||||
int32_t left_diff = parent->coords.x1 + sleft - area_tmp->x1 - scroll_value->x;
|
||||
int32_t right_diff = -(parent->coords.x2 - sright - area_tmp->x2 - scroll_value->x);
|
||||
if((left_diff >= 0 && right_diff >= 0)) x_scroll = 0;
|
||||
else if(left_diff > 0) {
|
||||
x_scroll = left_diff;
|
||||
/*Do not let scrolling in*/
|
||||
int32_t sl = lv_obj_get_scroll_left(parent);
|
||||
if(sl - x_scroll < 0) x_scroll = 0;
|
||||
}
|
||||
else if(right_diff > 0) {
|
||||
x_scroll = -right_diff;
|
||||
/*Do not let scrolling in*/
|
||||
int32_t sr = lv_obj_get_scroll_right(parent);
|
||||
if(sr + x_scroll < 0) x_scroll = 0;
|
||||
}
|
||||
|
||||
int32_t parent_w = lv_obj_get_width(parent) - sleft - sright;
|
||||
switch(snap_x) {
|
||||
case LV_SCROLL_SNAP_START:
|
||||
snap_goal = parent->coords.x1 + sleft;
|
||||
act = area_tmp->x1 + x_scroll;
|
||||
x_scroll += snap_goal - act;
|
||||
break;
|
||||
case LV_SCROLL_SNAP_END:
|
||||
snap_goal = parent->coords.x2 - sright;
|
||||
act = area_tmp->x2 + x_scroll;
|
||||
x_scroll += snap_goal - act;
|
||||
break;
|
||||
case LV_SCROLL_SNAP_CENTER:
|
||||
snap_goal = parent->coords.x1 + sleft + parent_w / 2;
|
||||
act = lv_area_get_width(area_tmp) / 2 + area_tmp->x1 + x_scroll;
|
||||
x_scroll += snap_goal - act;
|
||||
break;
|
||||
case LV_SCROLL_SNAP_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
/*Remove any pending scroll animations.*/
|
||||
lv_anim_delete(parent, scroll_y_anim);
|
||||
lv_anim_delete(parent, scroll_x_anim);
|
||||
|
||||
if((scroll_dir & LV_DIR_LEFT) == 0 && x_scroll < 0) x_scroll = 0;
|
||||
if((scroll_dir & LV_DIR_RIGHT) == 0 && x_scroll > 0) x_scroll = 0;
|
||||
if((scroll_dir & LV_DIR_TOP) == 0 && y_scroll < 0) y_scroll = 0;
|
||||
if((scroll_dir & LV_DIR_BOTTOM) == 0 && y_scroll > 0) y_scroll = 0;
|
||||
|
||||
scroll_value->x += anim_en ? x_scroll : 0;
|
||||
scroll_value->y += anim_en ? y_scroll : 0;
|
||||
lv_obj_scroll_by(parent, x_scroll, y_scroll, anim_en);
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* @file lv_obj_scroll.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_SCROLL_H
|
||||
#define LV_OBJ_SCROLL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_anim.h"
|
||||
#include "../misc/lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/*Can't include lv_obj.h because it includes this header file*/
|
||||
|
||||
/** Scrollbar modes: shows when should the scrollbars be visible*/
|
||||
typedef enum {
|
||||
LV_SCROLLBAR_MODE_OFF, /**< Never show scrollbars*/
|
||||
LV_SCROLLBAR_MODE_ON, /**< Always show scrollbars*/
|
||||
LV_SCROLLBAR_MODE_ACTIVE, /**< Show scroll bars when Widget is being scrolled*/
|
||||
LV_SCROLLBAR_MODE_AUTO, /**< Show scroll bars when the content is large enough to be scrolled*/
|
||||
} lv_scrollbar_mode_t;
|
||||
|
||||
/** Scroll span align options. Tells where to align the snappable children when scroll stops.*/
|
||||
typedef enum {
|
||||
LV_SCROLL_SNAP_NONE, /**< Do not align, leave where it is*/
|
||||
LV_SCROLL_SNAP_START, /**< Align to the left/top*/
|
||||
LV_SCROLL_SNAP_END, /**< Align to the right/bottom*/
|
||||
LV_SCROLL_SNAP_CENTER /**< Align to the center*/
|
||||
} lv_scroll_snap_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Set how the scrollbars should behave.
|
||||
* @param obj pointer to Widget
|
||||
* @param mode LV_SCROLL_MODE_ON/OFF/AUTO/ACTIVE
|
||||
*/
|
||||
void lv_obj_set_scrollbar_mode(lv_obj_t * obj, lv_scrollbar_mode_t mode);
|
||||
|
||||
/**
|
||||
* Set direction Widget can be scrolled
|
||||
* @param obj pointer to Widget
|
||||
* @param dir one or more bit-wise OR-ed values of `lv_dir_t` enumeration
|
||||
*/
|
||||
void lv_obj_set_scroll_dir(lv_obj_t * obj, lv_dir_t dir);
|
||||
|
||||
/**
|
||||
* Set where to snap the children when scrolling ends horizontally
|
||||
* @param obj pointer to Widget
|
||||
* @param align value from `lv_scroll_snap_t` enumeration
|
||||
*/
|
||||
void lv_obj_set_scroll_snap_x(lv_obj_t * obj, lv_scroll_snap_t align);
|
||||
|
||||
/**
|
||||
* Set where to snap the children when scrolling ends vertically
|
||||
* @param obj pointer to Widget
|
||||
* @param align value from `lv_scroll_snap_t` enumeration
|
||||
*/
|
||||
void lv_obj_set_scroll_snap_y(lv_obj_t * obj, lv_scroll_snap_t align);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Get the current scroll mode (when to hide the scrollbars)
|
||||
* @param obj pointer to Widget
|
||||
* @return the current scroll mode from `lv_scrollbar_mode_t`
|
||||
*/
|
||||
lv_scrollbar_mode_t lv_obj_get_scrollbar_mode(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get directions Widget can be scrolled (set with `lv_obj_set_scroll_dir()`)
|
||||
* @param obj pointer to Widget
|
||||
* @return current scroll direction bit(s)
|
||||
*/
|
||||
lv_dir_t lv_obj_get_scroll_dir(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get where to snap child Widgets when horizontal scrolling ends.
|
||||
* @param obj pointer to Widget
|
||||
* @return current snap value from `lv_scroll_snap_t`
|
||||
*/
|
||||
lv_scroll_snap_t lv_obj_get_scroll_snap_x(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get where to snap child Widgets when vertical scrolling ends.
|
||||
* @param obj pointer to Widget
|
||||
* @return current snap value from `lv_scroll_snap_t`
|
||||
*/
|
||||
lv_scroll_snap_t lv_obj_get_scroll_snap_y(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get current X scroll position. Identical to `lv_obj_get_scroll_left()`.
|
||||
* @param obj pointer to scrollable container Widget
|
||||
* @return current scroll position from left edge
|
||||
* - If Widget is not scrolled return 0.
|
||||
* - If scrolled return > 0.
|
||||
* - If scrolled inside (elastic scroll) return < 0.
|
||||
*/
|
||||
int32_t lv_obj_get_scroll_x(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get current Y scroll position. Identical to `lv_obj_get_scroll_top()`.
|
||||
* @param obj pointer to scrollable container Widget
|
||||
* @return current scroll position from top edge
|
||||
* - If Widget is not scrolled return 0.
|
||||
* - If scrolled return > 0.
|
||||
* - If scrolled inside (elastic scroll) return < 0.
|
||||
*/
|
||||
int32_t lv_obj_get_scroll_y(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Number of pixels a scrollable container Widget can be scrolled down
|
||||
* before its top edge appears. When LV_OBJ_FLAG_SCROLL_ELASTIC flag
|
||||
* is set in Widget, this value can go negative while Widget is being
|
||||
* dragged below its normal top-edge boundary.
|
||||
* @param obj pointer to scrollable container Widget
|
||||
* @return pixels Widget can be scrolled down before its top edge appears
|
||||
*/
|
||||
int32_t lv_obj_get_scroll_top(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Number of pixels a scrollable container Widget can be scrolled up
|
||||
* before its bottom edge appears. When LV_OBJ_FLAG_SCROLL_ELASTIC flag
|
||||
* is set in Widget, this value can go negative while Widget is being
|
||||
* dragged above its normal bottom-edge boundary.
|
||||
* @param obj pointer to scrollable container Widget
|
||||
* @return pixels Widget can be scrolled up before its bottom edge appears
|
||||
*/
|
||||
int32_t lv_obj_get_scroll_bottom(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Number of pixels a scrollable container Widget can be scrolled right
|
||||
* before its left edge appears. When LV_OBJ_FLAG_SCROLL_ELASTIC flag
|
||||
* is set in Widget, this value can go negative while Widget is being
|
||||
* dragged farther right than its normal left-edge boundary.
|
||||
* @param obj pointer to scrollable container Widget
|
||||
* @return pixels Widget can be scrolled right before its left edge appears
|
||||
*/
|
||||
int32_t lv_obj_get_scroll_left(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Number of pixels a scrollable container Widget can be scrolled left
|
||||
* before its right edge appears. When LV_OBJ_FLAG_SCROLL_ELASTIC flag
|
||||
* is set in Widget, this value can go negative while Widget is being
|
||||
* dragged farther left than its normal right-edge boundary.
|
||||
* @param obj pointer to scrollable container Widget
|
||||
* @return pixels Widget can be scrolled left before its right edge appears
|
||||
*/
|
||||
int32_t lv_obj_get_scroll_right(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the X and Y coordinates where the scrolling will end for Widget if a scrolling animation is in progress.
|
||||
* If no scrolling animation, give the current `x` or `y` scroll position.
|
||||
* @param obj pointer to scrollable Widget
|
||||
* @param end pointer to `lv_point_t` object in which to store result
|
||||
*/
|
||||
void lv_obj_get_scroll_end(lv_obj_t * obj, lv_point_t * end);
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/**
|
||||
* Scroll by given amount of pixels.
|
||||
* @param obj pointer to scrollable Widget to scroll
|
||||
* @param dx pixels to scroll horizontally
|
||||
* @param dy pixels to scroll vertically
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
* @note > 0 value means scroll right/bottom (show the more content on the right/bottom)
|
||||
* @note e.g. dy = -20 means scroll down 20 px
|
||||
*/
|
||||
void lv_obj_scroll_by(lv_obj_t * obj, int32_t dx, int32_t dy, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Scroll by given amount of pixels.
|
||||
* `dx` and `dy` will be limited internally to allow scrolling only on the content area.
|
||||
* @param obj pointer to scrollable Widget to scroll
|
||||
* @param dx pixels to scroll horizontally
|
||||
* @param dy pixels to scroll vertically
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
* @note e.g. dy = -20 means scroll down 20 px
|
||||
*/
|
||||
void lv_obj_scroll_by_bounded(lv_obj_t * obj, int32_t dx, int32_t dy, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Scroll to given coordinate on Widget.
|
||||
* `x` and `y` will be limited internally to allow scrolling only on the content area.
|
||||
* @param obj pointer to scrollable Widget to scroll
|
||||
* @param x pixels to scroll horizontally
|
||||
* @param y pixels to scroll vertically
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
*/
|
||||
void lv_obj_scroll_to(lv_obj_t * obj, int32_t x, int32_t y, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Scroll to X coordinate on Widget.
|
||||
* `x` will be limited internally to allow scrolling only on the content area.
|
||||
* @param obj pointer to scrollable Widget to scroll
|
||||
* @param x pixels to scroll horizontally
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
*/
|
||||
void lv_obj_scroll_to_x(lv_obj_t * obj, int32_t x, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Scroll to Y coordinate on Widget.
|
||||
* `y` will be limited internally to allow scrolling only on the content area.
|
||||
* @param obj pointer to scrollable Widget to scroll
|
||||
* @param y pixels to scroll vertically
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
*/
|
||||
void lv_obj_scroll_to_y(lv_obj_t * obj, int32_t y, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Scroll `obj`'s parent Widget until `obj` becomes visible.
|
||||
* @param obj pointer to Widget to scroll into view
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
*/
|
||||
void lv_obj_scroll_to_view(lv_obj_t * obj, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Scroll `obj`'s parent Widgets recursively until `obj` becomes visible.
|
||||
* Widget will be scrolled into view even it has nested scrollable parents.
|
||||
* @param obj pointer to Widget to scroll into view
|
||||
* @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately
|
||||
*/
|
||||
void lv_obj_scroll_to_view_recursive(lv_obj_t * obj, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Tell whether Widget is being scrolled or not at this moment
|
||||
* @param obj pointer to Widget
|
||||
* @return true: `obj` is being scrolled
|
||||
*/
|
||||
bool lv_obj_is_scrolling(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Stop scrolling the current object
|
||||
*
|
||||
* @param obj The object being scrolled
|
||||
*/
|
||||
void lv_obj_stop_scroll_anim(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Check children of `obj` and scroll `obj` to fulfill scroll_snap settings.
|
||||
* @param obj Widget whose children need to be checked and snapped
|
||||
* @param anim_en LV_ANIM_ON/OFF
|
||||
*/
|
||||
void lv_obj_update_snap(lv_obj_t * obj, lv_anim_enable_t anim_en);
|
||||
|
||||
/**
|
||||
* Get the area of the scrollbars
|
||||
* @param obj pointer to Widget
|
||||
* @param hor pointer to store the area of the horizontal scrollbar
|
||||
* @param ver pointer to store the area of the vertical scrollbar
|
||||
*/
|
||||
void lv_obj_get_scrollbar_area(lv_obj_t * obj, lv_area_t * hor, lv_area_t * ver);
|
||||
|
||||
/**
|
||||
* Invalidate the area of the scrollbars
|
||||
* @param obj pointer to Widget
|
||||
*/
|
||||
void lv_obj_scrollbar_invalidate(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Checks if the content is scrolled "in" and adjusts it to a normal position.
|
||||
* @param obj pointer to Widget
|
||||
* @param anim_en LV_ANIM_ON/OFF
|
||||
*/
|
||||
void lv_obj_readjust_scroll(lv_obj_t * obj, lv_anim_enable_t anim_en);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_SCROLL_H*/
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @file lv_obj_scroll_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_SCROLL_PRIVATE_H
|
||||
#define LV_OBJ_SCROLL_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_obj_scroll.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Low level function to scroll by given x and y coordinates.
|
||||
* `LV_EVENT_SCROLL` is sent.
|
||||
* @param obj pointer to an object to scroll
|
||||
* @param x pixels to scroll horizontally
|
||||
* @param y pixels to scroll vertically
|
||||
* @return `LV_RESULT_INVALID`: to object was deleted in `LV_EVENT_SCROLL`;
|
||||
* `LV_RESULT_OK`: if the object is still valid
|
||||
*/
|
||||
lv_result_t lv_obj_scroll_by_raw(lv_obj_t * obj, int32_t x, int32_t y);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_SCROLL_PRIVATE_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* @file lv_obj_style.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_STYLE_H
|
||||
#define LV_OBJ_STYLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_bidi.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../misc/lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_STYLE_STATE_CMP_SAME, /**< The style properties in the 2 states are identical */
|
||||
LV_STYLE_STATE_CMP_DIFF_REDRAW, /**< The differences can be shown with a simple redraw */
|
||||
LV_STYLE_STATE_CMP_DIFF_DRAW_PAD, /**< The differences can be shown with a simple redraw */
|
||||
LV_STYLE_STATE_CMP_DIFF_LAYOUT, /**< The differences can be shown with a simple redraw */
|
||||
} lv_style_state_cmp_t;
|
||||
|
||||
typedef uint32_t lv_style_selector_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Add a style to an object.
|
||||
* @param obj pointer to an object
|
||||
* @param style pointer to a style to add
|
||||
* @param selector OR-ed value of parts and state to which the style should be added
|
||||
*
|
||||
* Examples:
|
||||
* @code
|
||||
* lv_obj_add_style(btn, &style_btn, 0); //Default button style
|
||||
*
|
||||
* lv_obj_add_style(btn, &btn_red, LV_STATE_PRESSED); //Overwrite only some colors to red when pressed
|
||||
* @endcode
|
||||
*/
|
||||
void lv_obj_add_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector);
|
||||
|
||||
/**
|
||||
* Replaces a style of an object, preserving the order of the style stack (local styles and transitions are ignored).
|
||||
* @param obj pointer to an object
|
||||
* @param old_style pointer to a style to replace.
|
||||
* @param new_style pointer to a style to replace the old style with.
|
||||
* @param selector OR-ed values of states and a part to replace only styles with matching selectors. LV_STATE_ANY and LV_PART_ANY can be used
|
||||
*
|
||||
* Examples:
|
||||
* @code
|
||||
* lv_obj_replace_style(obj, &yellow_style, &blue_style, LV_PART_ANY | LV_STATE_ANY); //Replace a specific style
|
||||
*
|
||||
* lv_obj_replace_style(obj, &yellow_style, &blue_style, LV_PART_MAIN | LV_STATE_PRESSED); //Replace a specific style assigned to the main part when it is pressed
|
||||
* @endcode
|
||||
*/
|
||||
bool lv_obj_replace_style(lv_obj_t * obj, const lv_style_t * old_style, const lv_style_t * new_style,
|
||||
lv_style_selector_t selector);
|
||||
|
||||
/**
|
||||
* Remove a style from an object.
|
||||
* @param obj pointer to an object
|
||||
* @param style pointer to a style to remove. Can be NULL to check only the selector
|
||||
* @param selector OR-ed values of states and a part to remove only styles with matching selectors. LV_STATE_ANY and LV_PART_ANY can be used
|
||||
*
|
||||
* Examples:
|
||||
* @code
|
||||
* lv_obj_remove_style(obj, &style, LV_PART_ANY | LV_STATE_ANY); //Remove a specific style
|
||||
*
|
||||
* lv_obj_remove_style(obj, NULL, LV_PART_MAIN | LV_STATE_ANY); //Remove all styles from the main part
|
||||
*
|
||||
* lv_obj_remove_style(obj, NULL, LV_PART_ANY | LV_STATE_ANY); //Remove all styles
|
||||
* @endcode
|
||||
*/
|
||||
void lv_obj_remove_style(lv_obj_t * obj, const lv_style_t * style, lv_style_selector_t selector);
|
||||
|
||||
/**
|
||||
* Remove all styles from an object
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_remove_style_all(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Notify all object if a style is modified
|
||||
* @param style pointer to a style. Only the objects with this style will be notified
|
||||
* (NULL to notify all objects)
|
||||
*/
|
||||
void lv_obj_report_style_change(lv_style_t * style);
|
||||
|
||||
/**
|
||||
* Notify an object and its children about its style is modified.
|
||||
* @param obj pointer to an object
|
||||
* @param part the part whose style was changed. E.g. `LV_PART_ANY`, `LV_PART_MAIN`
|
||||
* @param prop `LV_STYLE_PROP_ANY` or an `LV_STYLE_...` property.
|
||||
* It is used to optimize what needs to be refreshed.
|
||||
* `LV_STYLE_PROP_INV` to perform only a style cache update
|
||||
*/
|
||||
void lv_obj_refresh_style(lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop);
|
||||
|
||||
/**
|
||||
* Enable or disable automatic style refreshing when a new style is added/removed to/from an object
|
||||
* or any other style change happens.
|
||||
* @param en true: enable refreshing; false: disable refreshing
|
||||
*/
|
||||
void lv_obj_enable_style_refresh(bool en);
|
||||
|
||||
/**
|
||||
* Get the value of a style property. The current state of the object will be considered.
|
||||
* Inherited properties will be inherited.
|
||||
* If a property is not set a default value will be returned.
|
||||
* @param obj pointer to an object
|
||||
* @param part a part from which the property should be get
|
||||
* @param prop the property to get
|
||||
* @return the value of the property.
|
||||
* Should be read from the correct field of the `lv_style_value_t` according to the type of the property.
|
||||
*/
|
||||
lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop);
|
||||
|
||||
/**
|
||||
* Check if an object has a specified style property for a given style selector.
|
||||
* @param obj pointer to an object
|
||||
* @param selector the style selector to be checked, defining the scope of the style to be examined.
|
||||
* @param prop the property to be checked.
|
||||
* @return true if the object has the specified selector and property, false otherwise.
|
||||
*/
|
||||
bool lv_obj_has_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop);
|
||||
|
||||
/**
|
||||
* Set local style property on an object's part and state.
|
||||
* @param obj pointer to an object
|
||||
* @param prop the property
|
||||
* @param value value of the property. The correct element should be set according to the type of the property
|
||||
* @param selector OR-ed value of parts and state for which the style should be set
|
||||
*/
|
||||
void lv_obj_set_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value,
|
||||
lv_style_selector_t selector);
|
||||
|
||||
lv_style_res_t lv_obj_get_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value,
|
||||
lv_style_selector_t selector);
|
||||
|
||||
/**
|
||||
* Remove a local style property from a part of an object with a given state.
|
||||
* @param obj pointer to an object
|
||||
* @param prop a style property to remove.
|
||||
* @param selector OR-ed value of parts and state for which the style should be removed
|
||||
* @return true the property was found and removed; false: the property was not found
|
||||
*/
|
||||
bool lv_obj_remove_local_style_prop(lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector);
|
||||
|
||||
/**
|
||||
* Used internally for color filtering
|
||||
*/
|
||||
lv_style_value_t lv_obj_style_apply_color_filter(const lv_obj_t * obj, lv_part_t part, lv_style_value_t v);
|
||||
|
||||
/**
|
||||
* Fade in an an object and all its children.
|
||||
* @param obj the object to fade in
|
||||
* @param time time of fade
|
||||
* @param delay delay to start the animation
|
||||
*/
|
||||
void lv_obj_fade_in(lv_obj_t * obj, uint32_t time, uint32_t delay);
|
||||
|
||||
/**
|
||||
* Fade out an an object and all its children.
|
||||
* @param obj the object to fade out
|
||||
* @param time time of fade
|
||||
* @param delay delay to start the animation
|
||||
*/
|
||||
void lv_obj_fade_out(lv_obj_t * obj, uint32_t time, uint32_t delay);
|
||||
|
||||
static inline lv_state_t lv_obj_style_get_selector_state(lv_style_selector_t selector)
|
||||
{
|
||||
return selector & 0xFFFF;
|
||||
}
|
||||
|
||||
static inline lv_part_t lv_obj_style_get_selector_part(lv_style_selector_t selector)
|
||||
{
|
||||
return selector & 0xFF0000;
|
||||
}
|
||||
|
||||
#include "lv_obj_style_gen.h"
|
||||
|
||||
static inline void lv_obj_set_style_pad_all(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_pad_left(obj, value, selector);
|
||||
lv_obj_set_style_pad_right(obj, value, selector);
|
||||
lv_obj_set_style_pad_top(obj, value, selector);
|
||||
lv_obj_set_style_pad_bottom(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_pad_hor(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_pad_left(obj, value, selector);
|
||||
lv_obj_set_style_pad_right(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_pad_ver(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_pad_top(obj, value, selector);
|
||||
lv_obj_set_style_pad_bottom(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_margin_all(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_margin_left(obj, value, selector);
|
||||
lv_obj_set_style_margin_right(obj, value, selector);
|
||||
lv_obj_set_style_margin_top(obj, value, selector);
|
||||
lv_obj_set_style_margin_bottom(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_margin_hor(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_margin_left(obj, value, selector);
|
||||
lv_obj_set_style_margin_right(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_margin_ver(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_margin_top(obj, value, selector);
|
||||
lv_obj_set_style_margin_bottom(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_pad_gap(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_pad_row(obj, value, selector);
|
||||
lv_obj_set_style_pad_column(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_size(lv_obj_t * obj, int32_t width, int32_t height,
|
||||
lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_width(obj, width, selector);
|
||||
lv_obj_set_style_height(obj, height, selector);
|
||||
}
|
||||
|
||||
static inline void lv_obj_set_style_transform_scale(lv_obj_t * obj, int32_t value,
|
||||
lv_style_selector_t selector)
|
||||
{
|
||||
lv_obj_set_style_transform_scale_x(obj, value, selector);
|
||||
lv_obj_set_style_transform_scale_y(obj, value, selector);
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_space_left(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
int32_t padding = lv_obj_get_style_pad_left(obj, part);
|
||||
int32_t border_width = lv_obj_get_style_border_width(obj, part);
|
||||
lv_border_side_t border_side = lv_obj_get_style_border_side(obj, part);
|
||||
return (border_side & LV_BORDER_SIDE_LEFT) ? padding + border_width : padding;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_space_right(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
int32_t padding = lv_obj_get_style_pad_right(obj, part);
|
||||
int32_t border_width = lv_obj_get_style_border_width(obj, part);
|
||||
lv_border_side_t border_side = lv_obj_get_style_border_side(obj, part);
|
||||
return (border_side & LV_BORDER_SIDE_RIGHT) ? padding + border_width : padding;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_space_top(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
int32_t padding = lv_obj_get_style_pad_top(obj, part);
|
||||
int32_t border_width = lv_obj_get_style_border_width(obj, part);
|
||||
lv_border_side_t border_side = lv_obj_get_style_border_side(obj, part);
|
||||
return (border_side & LV_BORDER_SIDE_TOP) ? padding + border_width : padding;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_space_bottom(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
int32_t padding = lv_obj_get_style_pad_bottom(obj, part);
|
||||
int32_t border_width = lv_obj_get_style_border_width(obj, part);
|
||||
lv_border_side_t border_side = lv_obj_get_style_border_side(obj, part);
|
||||
return (border_side & LV_BORDER_SIDE_BOTTOM) ? padding + border_width : padding;
|
||||
}
|
||||
|
||||
lv_text_align_t lv_obj_calculate_style_text_align(const lv_obj_t * obj, lv_part_t part, const char * txt);
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_scale_x_safe(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
int32_t scale = lv_obj_get_style_transform_scale_x(obj, part);
|
||||
return scale > 0 ? scale : 1;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_scale_y_safe(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
int32_t scale = lv_obj_get_style_transform_scale_y(obj, part);
|
||||
return scale > 0 ? scale : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `opa` style property from all parents and multiply and `>> 8` them.
|
||||
* @param obj the object whose opacity should be get
|
||||
* @param part the part whose opacity should be get. Non-MAIN parts will consider the `opa` of the MAIN part too
|
||||
* @return the final opacity considering the parents' opacity too
|
||||
*/
|
||||
lv_opa_t lv_obj_get_style_opa_recursive(const lv_obj_t * obj, lv_part_t part);
|
||||
|
||||
|
||||
/**
|
||||
* Apply recolor effect to the input color based on the object's style properties.
|
||||
* @param obj the target object containing recolor style properties
|
||||
* @param part the part to retrieve recolor styles.
|
||||
* @param color the original color to be modified
|
||||
* @return the blended color after applying recolor and opacity
|
||||
*/
|
||||
lv_color32_t lv_obj_style_apply_recolor(const lv_obj_t * obj, lv_part_t part, lv_color32_t color);
|
||||
|
||||
/**
|
||||
* Get the `recolor` style property from all parents and blend them recursively.
|
||||
* @param obj the object whose recolor value should be retrieved
|
||||
* @param part the target part to check. Non-MAIN parts will also consider
|
||||
* the `recolor` value from the MAIN part during calculation
|
||||
* @return the final blended recolor value combining all parent's recolor values
|
||||
*/
|
||||
lv_color32_t lv_obj_get_style_recolor_recursive(const lv_obj_t * obj, lv_part_t part);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_STYLE_H*/
|
||||
@@ -0,0 +1,961 @@
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
* DO NOT EDIT
|
||||
* This file is automatically generated by "style_api_gen.py"
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#include "lv_obj.h"
|
||||
|
||||
|
||||
void lv_obj_set_style_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_min_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MIN_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_max_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MAX_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_HEIGHT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_min_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MIN_HEIGHT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_max_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MAX_HEIGHT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_length(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LENGTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_X, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_Y, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_align(lv_obj_t * obj, lv_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ALIGN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_HEIGHT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_translate_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSLATE_X, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_translate_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSLATE_Y, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_translate_radial(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSLATE_RADIAL, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_scale_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_SCALE_X, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_scale_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_SCALE_Y, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_rotation(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_ROTATION, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_pivot_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_PIVOT_X, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_pivot_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_PIVOT_Y, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_skew_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_SKEW_X, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transform_skew_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSFORM_SKEW_Y, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_top(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_TOP, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_bottom(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_BOTTOM, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_left(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_LEFT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_right(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_RIGHT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_row(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_ROW, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_column(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_COLUMN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_pad_radial(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_PAD_RADIAL, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_margin_top(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MARGIN_TOP, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_margin_bottom(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MARGIN_BOTTOM, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_margin_left(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MARGIN_LEFT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_margin_right(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_MARGIN_RIGHT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_grad_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_grad_dir(lv_obj_t * obj, lv_grad_dir_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD_DIR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_main_stop(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_MAIN_STOP, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_grad_stop(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD_STOP, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_main_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_MAIN_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_grad_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_grad(lv_obj_t * obj, const lv_grad_dsc_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_image_src(lv_obj_t * obj, const void * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_IMAGE_SRC, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_image_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_IMAGE_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_image_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_IMAGE_RECOLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_image_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_IMAGE_RECOLOR_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bg_image_tiled(lv_obj_t * obj, bool value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_IMAGE_TILED, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_border_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BORDER_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_border_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BORDER_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_border_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BORDER_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_border_side(lv_obj_t * obj, lv_border_side_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BORDER_SIDE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_border_post(lv_obj_t * obj, bool value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BORDER_POST, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_outline_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_OUTLINE_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_outline_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_OUTLINE_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_outline_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_OUTLINE_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_outline_pad(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_OUTLINE_PAD, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_shadow_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_SHADOW_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_shadow_offset_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_SHADOW_OFFSET_X, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_shadow_offset_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_SHADOW_OFFSET_Y, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_shadow_spread(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_SHADOW_SPREAD, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_shadow_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_SHADOW_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_shadow_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_SHADOW_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_image_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_IMAGE_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_image_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_IMAGE_RECOLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_image_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_IMAGE_RECOLOR_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_line_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LINE_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_line_dash_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LINE_DASH_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_line_dash_gap(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LINE_DASH_GAP, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_line_rounded(lv_obj_t * obj, bool value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LINE_ROUNDED, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_line_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LINE_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_line_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LINE_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_arc_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ARC_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_arc_rounded(lv_obj_t * obj, bool value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ARC_ROUNDED, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_arc_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ARC_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_arc_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ARC_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_arc_image_src(lv_obj_t * obj, const void * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ARC_IMAGE_SRC, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_font(lv_obj_t * obj, const lv_font_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_FONT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_letter_space(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_LETTER_SPACE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_line_space(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_LINE_SPACE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_decor(lv_obj_t * obj, lv_text_decor_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_DECOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_align(lv_obj_t * obj, lv_text_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_ALIGN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_outline_stroke_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_outline_stroke_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_text_outline_stroke_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TEXT_OUTLINE_STROKE_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_radius(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_RADIUS, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_radial_offset(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_RADIAL_OFFSET, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_clip_corner(lv_obj_t * obj, bool value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_CLIP_CORNER, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_opa_layered(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_OPA_LAYERED, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_COLOR_FILTER_DSC, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_color_filter_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_COLOR_FILTER_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.color = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_RECOLOR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_RECOLOR_OPA, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_anim(lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ANIM, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_anim_duration(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ANIM_DURATION, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_transition(lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_TRANSITION, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_blend_mode(lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BLEND_MODE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_layout(lv_obj_t * obj, uint16_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_LAYOUT, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_base_dir(lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BASE_DIR, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_bitmap_mask_src(lv_obj_t * obj, const void * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_BITMAP_MASK_SRC, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_rotary_sensitivity(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_ROTARY_SENSITIVITY, v, selector);
|
||||
}
|
||||
#if LV_USE_FLEX
|
||||
|
||||
void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_FLEX_FLOW, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_flex_main_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_FLEX_MAIN_PLACE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_flex_cross_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_FLEX_CROSS_PLACE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_flex_track_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_FLEX_TRACK_PLACE, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_flex_grow(lv_obj_t * obj, uint8_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_FLEX_GROW, v, selector);
|
||||
}
|
||||
#endif /*LV_USE_FLEX*/
|
||||
|
||||
#if LV_USE_GRID
|
||||
|
||||
void lv_obj_set_style_grid_column_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_COLUMN_DSC_ARRAY, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_column_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_COLUMN_ALIGN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_row_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.ptr = value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_ROW_DSC_ARRAY, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_row_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_ROW_ALIGN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_cell_column_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_CELL_COLUMN_POS, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_cell_x_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_CELL_X_ALIGN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_cell_column_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_CELL_COLUMN_SPAN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_cell_row_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_CELL_ROW_POS, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_cell_y_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_CELL_Y_ALIGN, v, selector);
|
||||
}
|
||||
|
||||
void lv_obj_set_style_grid_cell_row_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
|
||||
{
|
||||
lv_style_value_t v = {
|
||||
.num = (int32_t)value
|
||||
};
|
||||
lv_obj_set_local_style_prop(obj, LV_STYLE_GRID_CELL_ROW_SPAN, v, selector);
|
||||
}
|
||||
#endif /*LV_USE_GRID*/
|
||||
|
||||
@@ -0,0 +1,931 @@
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
* DO NOT EDIT
|
||||
* This file is automatically generated by "style_api_gen.py"
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LV_OBJ_STYLE_GEN_H
|
||||
#define LV_OBJ_STYLE_GEN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../core/lv_obj_style.h"
|
||||
#include "../misc/lv_types.h"
|
||||
|
||||
static inline int32_t lv_obj_get_style_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_min_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MIN_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_max_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MAX_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_height(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_HEIGHT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_min_height(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MIN_HEIGHT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_max_height(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MAX_HEIGHT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_length(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LENGTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_x(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_X);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_y(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_Y);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_align_t lv_obj_get_style_align(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ALIGN);
|
||||
return (lv_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_height(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_HEIGHT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_translate_x(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSLATE_X);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_translate_y(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSLATE_Y);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_translate_radial(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSLATE_RADIAL);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_scale_x(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_SCALE_X);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_scale_y(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_SCALE_Y);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_rotation(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_ROTATION);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_pivot_x(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_PIVOT_X);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_pivot_y(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_PIVOT_Y);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_skew_x(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_SKEW_X);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_transform_skew_y(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_SKEW_Y);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_top(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_TOP);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_bottom(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_BOTTOM);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_left(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_LEFT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_right(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_RIGHT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_row(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_ROW);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_column(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_COLUMN);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_pad_radial(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_RADIAL);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_margin_top(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MARGIN_TOP);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_margin_bottom(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MARGIN_BOTTOM);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_margin_left(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MARGIN_LEFT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_margin_right(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MARGIN_RIGHT);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_bg_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_bg_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_bg_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_bg_grad_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_bg_grad_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_grad_dir_t lv_obj_get_style_bg_grad_dir(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_DIR);
|
||||
return (lv_grad_dir_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_bg_main_stop(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_MAIN_STOP);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_bg_grad_stop(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_STOP);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_bg_main_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_MAIN_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_bg_grad_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline const lv_grad_dsc_t * lv_obj_get_style_bg_grad(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD);
|
||||
return (const lv_grad_dsc_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline const void * lv_obj_get_style_bg_image_src(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_SRC);
|
||||
return (const void *)v.ptr;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_bg_image_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_bg_image_recolor(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_RECOLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_bg_image_recolor_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_RECOLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_bg_image_recolor_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_RECOLOR_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline bool lv_obj_get_style_bg_image_tiled(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMAGE_TILED);
|
||||
return (bool)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_border_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_border_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_border_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_border_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_border_side_t lv_obj_get_style_border_side(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_SIDE);
|
||||
return (lv_border_side_t)v.num;
|
||||
}
|
||||
|
||||
static inline bool lv_obj_get_style_border_post(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_POST);
|
||||
return (bool)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_outline_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_outline_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_outline_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_outline_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_outline_pad(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_PAD);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_shadow_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_shadow_offset_x(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_OFFSET_X);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_shadow_offset_y(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_OFFSET_Y);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_shadow_spread(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_SPREAD);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_shadow_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_shadow_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_shadow_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_image_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_IMAGE_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_image_recolor(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_IMAGE_RECOLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_image_recolor_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_IMAGE_RECOLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_image_recolor_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_IMAGE_RECOLOR_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_line_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_line_dash_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_DASH_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_line_dash_gap(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_DASH_GAP);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline bool lv_obj_get_style_line_rounded(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_ROUNDED);
|
||||
return (bool)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_line_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_line_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_line_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_arc_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline bool lv_obj_get_style_arc_rounded(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_ROUNDED);
|
||||
return (bool)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_arc_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_arc_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_arc_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline const void * lv_obj_get_style_arc_image_src(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_IMAGE_SRC);
|
||||
return (const void *)v.ptr;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_text_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_text_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_text_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline const lv_font_t * lv_obj_get_style_text_font(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_FONT);
|
||||
return (const lv_font_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_text_letter_space(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_LETTER_SPACE);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_text_line_space(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_LINE_SPACE);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_text_decor_t lv_obj_get_style_text_decor(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_DECOR);
|
||||
return (lv_text_decor_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_text_align_t lv_obj_get_style_text_align(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_ALIGN);
|
||||
return (lv_text_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_text_outline_stroke_color(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_text_outline_stroke_color_filtered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_COLOR));
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_text_outline_stroke_width(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_text_outline_stroke_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OUTLINE_STROKE_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_radius(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_RADIUS);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_radial_offset(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_RADIAL_OFFSET);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline bool lv_obj_get_style_clip_corner(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_CLIP_CORNER);
|
||||
return (bool)v.num;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_opa_layered(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OPA_LAYERED);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_DSC);
|
||||
return (const lv_color_filter_dsc_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_color_filter_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_color_t lv_obj_get_style_recolor(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_RECOLOR);
|
||||
return v.color;
|
||||
}
|
||||
|
||||
static inline lv_opa_t lv_obj_get_style_recolor_opa(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_RECOLOR_OPA);
|
||||
return (lv_opa_t)v.num;
|
||||
}
|
||||
|
||||
static inline const lv_anim_t * lv_obj_get_style_anim(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM);
|
||||
return (const lv_anim_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline uint32_t lv_obj_get_style_anim_duration(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM_DURATION);
|
||||
return (uint32_t)v.num;
|
||||
}
|
||||
|
||||
static inline const lv_style_transition_dsc_t * lv_obj_get_style_transition(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSITION);
|
||||
return (const lv_style_transition_dsc_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline lv_blend_mode_t lv_obj_get_style_blend_mode(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BLEND_MODE);
|
||||
return (lv_blend_mode_t)v.num;
|
||||
}
|
||||
|
||||
static inline uint16_t lv_obj_get_style_layout(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LAYOUT);
|
||||
return (uint16_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_base_dir_t lv_obj_get_style_base_dir(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BASE_DIR);
|
||||
return (lv_base_dir_t)v.num;
|
||||
}
|
||||
|
||||
static inline const void * lv_obj_get_style_bitmap_mask_src(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BITMAP_MASK_SRC);
|
||||
return (const void *)v.ptr;
|
||||
}
|
||||
|
||||
static inline uint32_t lv_obj_get_style_rotary_sensitivity(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ROTARY_SENSITIVITY);
|
||||
return (uint32_t)v.num;
|
||||
}
|
||||
|
||||
#if LV_USE_FLEX
|
||||
static inline lv_flex_flow_t lv_obj_get_style_flex_flow(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_FLOW);
|
||||
return (lv_flex_flow_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_flex_align_t lv_obj_get_style_flex_main_place(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_MAIN_PLACE);
|
||||
return (lv_flex_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_flex_align_t lv_obj_get_style_flex_cross_place(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_CROSS_PLACE);
|
||||
return (lv_flex_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_flex_align_t lv_obj_get_style_flex_track_place(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_TRACK_PLACE);
|
||||
return (lv_flex_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline uint8_t lv_obj_get_style_flex_grow(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_GROW);
|
||||
return (uint8_t)v.num;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_FLEX*/
|
||||
|
||||
#if LV_USE_GRID
|
||||
static inline const int32_t * lv_obj_get_style_grid_column_dsc_array(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_COLUMN_DSC_ARRAY);
|
||||
return (const int32_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline lv_grid_align_t lv_obj_get_style_grid_column_align(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_COLUMN_ALIGN);
|
||||
return (lv_grid_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline const int32_t * lv_obj_get_style_grid_row_dsc_array(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_ROW_DSC_ARRAY);
|
||||
return (const int32_t *)v.ptr;
|
||||
}
|
||||
|
||||
static inline lv_grid_align_t lv_obj_get_style_grid_row_align(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_ROW_ALIGN);
|
||||
return (lv_grid_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_grid_cell_column_pos(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_COLUMN_POS);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_grid_align_t lv_obj_get_style_grid_cell_x_align(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_X_ALIGN);
|
||||
return (lv_grid_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_grid_cell_column_span(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_COLUMN_SPAN);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_grid_cell_row_pos(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_ROW_POS);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
static inline lv_grid_align_t lv_obj_get_style_grid_cell_y_align(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_Y_ALIGN);
|
||||
return (lv_grid_align_t)v.num;
|
||||
}
|
||||
|
||||
static inline int32_t lv_obj_get_style_grid_cell_row_span(const lv_obj_t * obj, lv_part_t part)
|
||||
{
|
||||
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_ROW_SPAN);
|
||||
return (int32_t)v.num;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GRID*/
|
||||
|
||||
void lv_obj_set_style_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_min_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_max_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_min_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_max_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_length(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_align(lv_obj_t * obj, lv_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_translate_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_translate_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_translate_radial(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_scale_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_scale_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_rotation(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_pivot_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_pivot_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_skew_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transform_skew_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_top(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_bottom(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_left(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_right(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_row(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_column(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_pad_radial(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_margin_top(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_margin_bottom(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_margin_left(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_margin_right(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_grad_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_grad_dir(lv_obj_t * obj, lv_grad_dir_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_main_stop(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_grad_stop(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_main_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_grad_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_grad(lv_obj_t * obj, const lv_grad_dsc_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_image_src(lv_obj_t * obj, const void * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_image_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_image_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_image_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bg_image_tiled(lv_obj_t * obj, bool value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_border_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_border_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_border_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_border_side(lv_obj_t * obj, lv_border_side_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_border_post(lv_obj_t * obj, bool value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_outline_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_outline_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_outline_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_outline_pad(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_shadow_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_shadow_offset_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_shadow_offset_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_shadow_spread(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_shadow_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_shadow_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_image_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_image_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_image_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_line_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_line_dash_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_line_dash_gap(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_line_rounded(lv_obj_t * obj, bool value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_line_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_line_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_arc_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_arc_rounded(lv_obj_t * obj, bool value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_arc_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_arc_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_arc_image_src(lv_obj_t * obj, const void * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_font(lv_obj_t * obj, const lv_font_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_letter_space(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_line_space(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_decor(lv_obj_t * obj, lv_text_decor_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_align(lv_obj_t * obj, lv_text_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_outline_stroke_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_outline_stroke_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_text_outline_stroke_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_radius(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_radial_offset(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_clip_corner(lv_obj_t * obj, bool value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_opa_layered(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_color_filter_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_anim(lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_anim_duration(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_transition(lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_blend_mode(lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_layout(lv_obj_t * obj, uint16_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_base_dir(lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_bitmap_mask_src(lv_obj_t * obj, const void * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_rotary_sensitivity(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
|
||||
#if LV_USE_FLEX
|
||||
void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_flex_main_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_flex_cross_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_flex_track_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_flex_grow(lv_obj_t * obj, uint8_t value, lv_style_selector_t selector);
|
||||
#endif /*LV_USE_FLEX*/
|
||||
|
||||
#if LV_USE_GRID
|
||||
void lv_obj_set_style_grid_column_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_column_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_row_dsc_array(lv_obj_t * obj, const int32_t * value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_row_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_cell_column_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_cell_x_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_cell_column_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_cell_row_pos(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_cell_y_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector);
|
||||
void lv_obj_set_style_grid_cell_row_span(lv_obj_t * obj, int32_t value, lv_style_selector_t selector);
|
||||
#endif /*LV_USE_GRID*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV_OBJ_STYLE_GEN_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file lv_obj_style_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_STYLE_PRIVATE_H
|
||||
#define LV_OBJ_STYLE_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_obj_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_obj_style_t {
|
||||
const lv_style_t * style;
|
||||
uint32_t selector : 24;
|
||||
uint32_t is_local : 1;
|
||||
uint32_t is_trans : 1;
|
||||
};
|
||||
|
||||
struct _lv_obj_style_transition_dsc_t {
|
||||
uint16_t time;
|
||||
uint16_t delay;
|
||||
lv_style_selector_t selector;
|
||||
lv_style_prop_t prop;
|
||||
lv_anim_path_cb_t path_cb;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the object related style manager module.
|
||||
* Called by LVGL in `lv_init()`
|
||||
*/
|
||||
void lv_obj_style_init(void);
|
||||
|
||||
/**
|
||||
* Deinitialize the object related style manager module.
|
||||
* Called by LVGL in `lv_deinit()`
|
||||
*/
|
||||
void lv_obj_style_deinit(void);
|
||||
|
||||
/**
|
||||
* Used internally to create a style transition
|
||||
* @param obj
|
||||
* @param part
|
||||
* @param prev_state
|
||||
* @param new_state
|
||||
* @param tr
|
||||
*/
|
||||
void lv_obj_style_create_transition(lv_obj_t * obj, lv_part_t part, lv_state_t prev_state,
|
||||
lv_state_t new_state, const lv_obj_style_transition_dsc_t * tr);
|
||||
|
||||
/**
|
||||
* Used internally to compare the appearance of an object in 2 states
|
||||
* @param obj
|
||||
* @param state1
|
||||
* @param state2
|
||||
* @return
|
||||
*/
|
||||
lv_style_state_cmp_t lv_obj_style_state_compare(lv_obj_t * obj, lv_state_t state1, lv_state_t state2);
|
||||
|
||||
/**
|
||||
* Update the layer type of a widget bayed on its current styles.
|
||||
* The result will be stored in `obj->spec_attr->layer_type`
|
||||
* @param obj the object whose layer should be updated
|
||||
*/
|
||||
void lv_obj_update_layer_type(lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_STYLE_PRIVATE_H*/
|
||||
@@ -0,0 +1,845 @@
|
||||
/**
|
||||
* @file lv_obj_tree.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj_private.h"
|
||||
#include "lv_obj_class_private.h"
|
||||
#include "../indev/lv_indev.h"
|
||||
#include "../indev/lv_indev_private.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../display/lv_display_private.h"
|
||||
#include "../misc/lv_anim_private.h"
|
||||
#include "../misc/lv_async.h"
|
||||
#include "../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define MY_CLASS (&lv_obj_class)
|
||||
#define disp_ll_p &(LV_GLOBAL_DEFAULT()->disp_ll)
|
||||
|
||||
#define OBJ_DUMP_STRING_LEN 128
|
||||
#define LV_OBJ_NAME_MAX_LEN 128
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void lv_obj_delete_async_cb(void * obj);
|
||||
static void obj_delete_core(lv_obj_t * obj);
|
||||
static lv_obj_tree_walk_res_t walk_core(lv_obj_t * obj, lv_obj_tree_walk_cb_t cb, void * user_data);
|
||||
static void dump_tree_core(lv_obj_t * obj, int32_t depth);
|
||||
static lv_obj_t * lv_obj_get_first_not_deleting_child(lv_obj_t * obj);
|
||||
#if LV_USE_OBJ_NAME
|
||||
static lv_obj_t * find_by_name_direct(const lv_obj_t * parent, const char * name, size_t len);
|
||||
#endif /*LV_USE_OBJ_NAME*/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_obj_delete(lv_obj_t * obj)
|
||||
{
|
||||
if(obj->is_deleting)
|
||||
return;
|
||||
|
||||
LV_LOG_TRACE("begin (delete %p)", (void *)obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
lv_obj_t * par = lv_obj_get_parent(obj);
|
||||
|
||||
lv_display_t * disp = NULL;
|
||||
bool act_screen_del = false;
|
||||
if(par == NULL) {
|
||||
disp = lv_obj_get_display(obj);
|
||||
if(!disp) return; /*Shouldn't happen*/
|
||||
if(disp->act_scr == obj) act_screen_del = true;
|
||||
}
|
||||
|
||||
obj_delete_core(obj);
|
||||
|
||||
/*Call the ancestor's event handler to the parent to notify it about the child delete*/
|
||||
if(par && !par->is_deleting) {
|
||||
lv_obj_scrollbar_invalidate(par);
|
||||
lv_obj_send_event(par, LV_EVENT_CHILD_CHANGED, NULL);
|
||||
lv_obj_send_event(par, LV_EVENT_CHILD_DELETED, NULL);
|
||||
}
|
||||
|
||||
/*Handle if the active screen was deleted*/
|
||||
if(act_screen_del) {
|
||||
LV_LOG_WARN("the active screen was deleted");
|
||||
disp->act_scr = NULL;
|
||||
}
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
LV_LOG_TRACE("finished (delete %p)", (void *)obj);
|
||||
}
|
||||
|
||||
void lv_obj_clean(lv_obj_t * obj)
|
||||
{
|
||||
LV_LOG_TRACE("begin (clean %p)", (void *)obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
uint32_t cnt = lv_obj_get_child_count(obj);
|
||||
lv_obj_t * child = lv_obj_get_first_not_deleting_child(obj);
|
||||
while(child) {
|
||||
obj_delete_core(child);
|
||||
child = lv_obj_get_first_not_deleting_child(obj);
|
||||
}
|
||||
/*Just to remove scroll animations if any*/
|
||||
lv_obj_scroll_to(obj, 0, 0, LV_ANIM_OFF);
|
||||
if(obj->spec_attr) {
|
||||
obj->spec_attr->scroll.x = 0;
|
||||
obj->spec_attr->scroll.y = 0;
|
||||
}
|
||||
|
||||
if(lv_obj_get_child_count(obj) < cnt) {
|
||||
lv_obj_send_event(obj, LV_EVENT_CHILD_CHANGED, NULL);
|
||||
lv_obj_send_event(obj, LV_EVENT_CHILD_DELETED, NULL);
|
||||
}
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
|
||||
LV_LOG_TRACE("finished (clean %p)", (void *)obj);
|
||||
}
|
||||
|
||||
void lv_obj_delete_delayed(lv_obj_t * obj, uint32_t delay_ms)
|
||||
{
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_var(&a, obj);
|
||||
lv_anim_set_exec_cb(&a, NULL);
|
||||
lv_anim_set_duration(&a, 1);
|
||||
lv_anim_set_delay(&a, delay_ms);
|
||||
lv_anim_set_completed_cb(&a, lv_obj_delete_anim_completed_cb);
|
||||
lv_anim_start(&a);
|
||||
}
|
||||
|
||||
void lv_obj_delete_anim_completed_cb(lv_anim_t * a)
|
||||
{
|
||||
lv_obj_delete(a->var);
|
||||
}
|
||||
|
||||
void lv_obj_delete_async(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_async_call(lv_obj_delete_async_cb, obj);
|
||||
}
|
||||
|
||||
void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
LV_ASSERT_OBJ(parent, MY_CLASS);
|
||||
|
||||
if(obj->parent == NULL) {
|
||||
LV_LOG_WARN("Can't set the parent of a screen");
|
||||
return;
|
||||
}
|
||||
|
||||
if(parent == NULL) {
|
||||
LV_LOG_WARN("Can't set parent == NULL to an object");
|
||||
return;
|
||||
}
|
||||
|
||||
if(parent == obj->parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
lv_obj_allocate_spec_attr(parent);
|
||||
|
||||
lv_obj_t * old_parent = obj->parent;
|
||||
/*Remove the object from the old parent's child list*/
|
||||
int32_t i;
|
||||
for(i = lv_obj_get_index(obj); i <= (int32_t)lv_obj_get_child_count(old_parent) - 2; i++) {
|
||||
old_parent->spec_attr->children[i] = old_parent->spec_attr->children[i + 1];
|
||||
}
|
||||
old_parent->spec_attr->child_cnt--;
|
||||
if(old_parent->spec_attr->child_cnt) {
|
||||
old_parent->spec_attr->children = lv_realloc(old_parent->spec_attr->children,
|
||||
old_parent->spec_attr->child_cnt * (sizeof(lv_obj_t *)));
|
||||
}
|
||||
else {
|
||||
lv_free(old_parent->spec_attr->children);
|
||||
old_parent->spec_attr->children = NULL;
|
||||
}
|
||||
|
||||
/*Add the child to the new parent as the last (newest child)*/
|
||||
parent->spec_attr->child_cnt++;
|
||||
parent->spec_attr->children = lv_realloc(parent->spec_attr->children,
|
||||
parent->spec_attr->child_cnt * (sizeof(lv_obj_t *)));
|
||||
parent->spec_attr->children[lv_obj_get_child_count(parent) - 1] = obj;
|
||||
|
||||
obj->parent = parent;
|
||||
|
||||
/*Notify the original parent because one of its children is lost*/
|
||||
lv_obj_scrollbar_invalidate(old_parent);
|
||||
lv_obj_send_event(old_parent, LV_EVENT_CHILD_CHANGED, obj);
|
||||
lv_obj_send_event(old_parent, LV_EVENT_CHILD_DELETED, NULL);
|
||||
|
||||
/*Notify the new parent about the child*/
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CHANGED, obj);
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CREATED, NULL);
|
||||
|
||||
lv_obj_mark_layout_as_dirty(obj);
|
||||
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
void lv_obj_move_to_index(lv_obj_t * obj, int32_t index)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
/* Check parent validity */
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
if(!parent) {
|
||||
LV_LOG_WARN("parent is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t parent_child_count = lv_obj_get_child_count(parent);
|
||||
/* old_index only can be 0 or greater, this point cannot be reached if the parent is not null */
|
||||
const int32_t old_index = lv_obj_get_index(obj);
|
||||
LV_ASSERT(0 <= old_index);
|
||||
|
||||
if(index < 0) {
|
||||
index += parent_child_count;
|
||||
}
|
||||
|
||||
/* Index was negative and the absolute value is greater than parent child count */
|
||||
if((index < 0)
|
||||
/* Index is same or bigger than parent child count */
|
||||
|| (index >= (int32_t) parent_child_count)
|
||||
/* If both previous and new index are the same */
|
||||
|| (index == old_index)) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t i = old_index;
|
||||
if(index < old_index) {
|
||||
while(i > index) {
|
||||
parent->spec_attr->children[i] = parent->spec_attr->children[i - 1];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(i < index) {
|
||||
parent->spec_attr->children[i] = parent->spec_attr->children[i + 1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
parent->spec_attr->children[index] = obj;
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CHANGED, NULL);
|
||||
lv_obj_invalidate(parent);
|
||||
}
|
||||
|
||||
void lv_obj_swap(lv_obj_t * obj1, lv_obj_t * obj2)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj1, MY_CLASS);
|
||||
LV_ASSERT_OBJ(obj2, MY_CLASS);
|
||||
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj1);
|
||||
lv_obj_t * parent2 = lv_obj_get_parent(obj2);
|
||||
|
||||
uint_fast32_t index1 = lv_obj_get_index(obj1);
|
||||
uint_fast32_t index2 = lv_obj_get_index(obj2);
|
||||
|
||||
lv_obj_send_event(parent2, LV_EVENT_CHILD_DELETED, obj2);
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_DELETED, obj1);
|
||||
|
||||
parent->spec_attr->children[index1] = obj2;
|
||||
obj2->parent = parent;
|
||||
|
||||
parent2->spec_attr->children[index2] = obj1;
|
||||
obj1->parent = parent2;
|
||||
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CHANGED, obj2);
|
||||
lv_obj_send_event(parent, LV_EVENT_CHILD_CREATED, obj2);
|
||||
lv_obj_send_event(parent2, LV_EVENT_CHILD_CHANGED, obj1);
|
||||
lv_obj_send_event(parent2, LV_EVENT_CHILD_CREATED, obj1);
|
||||
|
||||
lv_obj_invalidate(parent);
|
||||
|
||||
if(parent != parent2) {
|
||||
lv_obj_invalidate(parent2);
|
||||
}
|
||||
lv_group_swap_obj(obj1, obj2);
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
const lv_obj_t * par = obj;
|
||||
const lv_obj_t * act_par;
|
||||
|
||||
do {
|
||||
act_par = par;
|
||||
par = lv_obj_get_parent(act_par);
|
||||
} while(par != NULL);
|
||||
|
||||
return (lv_obj_t *)act_par;
|
||||
}
|
||||
|
||||
lv_display_t * lv_obj_get_display(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
const lv_obj_t * scr;
|
||||
|
||||
if(obj->parent == NULL) scr = obj; /*`obj` is a screen*/
|
||||
else scr = lv_obj_get_screen(obj); /*get the screen of `obj`*/
|
||||
|
||||
lv_display_t * d;
|
||||
lv_ll_t * disp_head = disp_ll_p;
|
||||
LV_LL_READ(disp_head, d) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < d->screen_cnt; i++) {
|
||||
if(d->screens[i] == scr) return d;
|
||||
}
|
||||
}
|
||||
|
||||
LV_LOG_WARN("No screen found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj == NULL) return NULL;
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
return obj->parent;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, int32_t idx)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(obj->spec_attr == NULL) return NULL;
|
||||
|
||||
uint32_t idu;
|
||||
if(idx < 0) {
|
||||
idx = obj->spec_attr->child_cnt + idx;
|
||||
if(idx < 0) return NULL;
|
||||
idu = (uint32_t) idx;
|
||||
}
|
||||
else {
|
||||
idu = idx;
|
||||
}
|
||||
|
||||
if(idu >= obj->spec_attr->child_cnt) return NULL;
|
||||
else return obj->spec_attr->children[idx];
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_child_by_type(const lv_obj_t * obj, int32_t idx, const lv_obj_class_t * class_p)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(obj->spec_attr == NULL) return NULL;
|
||||
|
||||
int32_t i;
|
||||
int32_t cnt = (int32_t)obj->spec_attr->child_cnt;
|
||||
if(idx >= 0) {
|
||||
for(i = 0; i < cnt; i++) {
|
||||
if(obj->spec_attr->children[i]->class_p == class_p) {
|
||||
if(idx == 0) return obj->spec_attr->children[i];
|
||||
else idx--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx++; /*-1 means the first child*/
|
||||
for(i = cnt - 1; i >= 0; i--) {
|
||||
if(obj->spec_attr->children[i]->class_p == class_p) {
|
||||
if(idx == 0) return obj->spec_attr->children[i];
|
||||
else idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_sibling(const lv_obj_t * obj, int32_t idx)
|
||||
{
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
int32_t sibling_idx = (int32_t)lv_obj_get_index(obj) + idx;
|
||||
if(sibling_idx < 0) return NULL;
|
||||
|
||||
return lv_obj_get_child(parent, sibling_idx);
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_sibling_by_type(const lv_obj_t * obj, int32_t idx, const lv_obj_class_t * class_p)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
int32_t sibling_idx = (int32_t)lv_obj_get_index_by_type(obj, class_p) + idx;
|
||||
if(sibling_idx < 0) return NULL;
|
||||
|
||||
return lv_obj_get_child_by_type(parent, sibling_idx, class_p);
|
||||
}
|
||||
|
||||
uint32_t lv_obj_get_child_count(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
return obj->spec_attr->child_cnt;
|
||||
}
|
||||
|
||||
uint32_t lv_obj_get_child_count_by_type(const lv_obj_t * obj, const lv_obj_class_t * class_p)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
if(obj->spec_attr == NULL) return 0;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t cnt = 0;
|
||||
for(i = 0; i < obj->spec_attr->child_cnt; i++) {
|
||||
if(obj->spec_attr->children[i]->class_p == class_p) cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
|
||||
void lv_obj_set_name(lv_obj_t * obj, const char * name)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
|
||||
if(!obj->spec_attr->name_static && obj->spec_attr->name) lv_free((void *)obj->spec_attr->name);
|
||||
|
||||
if(name == NULL) {
|
||||
obj->spec_attr->name = NULL;
|
||||
obj->spec_attr->name_static = 1;
|
||||
}
|
||||
else {
|
||||
obj->spec_attr->name = lv_strdup(name);
|
||||
obj->spec_attr->name_static = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_set_name_static(lv_obj_t * obj, const char * name)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
|
||||
if(!obj->spec_attr->name_static && obj->spec_attr->name) lv_free((void *)obj->spec_attr->name);
|
||||
|
||||
obj->spec_attr->name = name;
|
||||
obj->spec_attr->name_static = 1;
|
||||
}
|
||||
|
||||
const char * lv_obj_get_name(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(obj->spec_attr == NULL) return NULL;
|
||||
else return obj->spec_attr->name;
|
||||
}
|
||||
|
||||
void lv_obj_get_name_resolved(const lv_obj_t * obj, char buf[], size_t buf_size)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
const char * name = lv_obj_get_name(obj);
|
||||
/*Use a default name which auto-indexing*/
|
||||
char name_buf[LV_OBJ_NAME_MAX_LEN];
|
||||
if(name == NULL) {
|
||||
lv_snprintf(name_buf, sizeof(name_buf), "%s_#", obj->class_p->name);
|
||||
name = name_buf;
|
||||
}
|
||||
|
||||
size_t name_len = lv_strlen(name);
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
|
||||
/*If the last character is # automatically index the children with the same name start*/
|
||||
if(parent && name_len > 0 && name[name_len - 1] == '#') {
|
||||
uint32_t child_cnt = lv_obj_get_child_count(parent);
|
||||
uint32_t cnt = 0;
|
||||
uint32_t i;
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(parent, i);
|
||||
/*All siblings older siblings are checked, craft the name of this widget*/
|
||||
if(child == obj) {
|
||||
char num_buf[8];
|
||||
size_t num_len;
|
||||
num_len = lv_snprintf(num_buf, sizeof(num_buf), "%d", cnt);
|
||||
/*Is there enough space for the name and the index?*/
|
||||
if(buf_size > name_len + num_len) {
|
||||
/*E.g. buf = "some_name_", so trim the # from the end*/
|
||||
lv_strncpy(buf, name, name_len - 1);
|
||||
lv_strcpy(&buf[name_len - 1], num_buf);
|
||||
}
|
||||
else {
|
||||
/*Use the name as it is as a fallback*/
|
||||
lv_strlcpy(buf, obj->spec_attr->name, buf_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*Check the older siblings. IF they start with the same name count them*/
|
||||
else {
|
||||
const char * child_name = lv_obj_get_name(child);
|
||||
if(child_name == NULL) {
|
||||
/*If the name we are looking for start with the child's class name
|
||||
*increment the index. E.g. <class_name>_#*/
|
||||
size_t class_name_len = lv_strlen(child->class_p->name);
|
||||
if(name_len > 3 && class_name_len == name_len - 2 &&
|
||||
lv_strncmp(child->class_p->name, name, class_name_len) == 0) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
/*The name is set, check if it's e.g. <some_name>#*/
|
||||
else {
|
||||
if(lv_strcmp(child->spec_attr->name, name) == 0) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Just use the set name*/
|
||||
lv_strlcpy(buf, obj->spec_attr->name, buf_size);
|
||||
}
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_get_child_by_name(const lv_obj_t * parent, const char * path)
|
||||
{
|
||||
LV_ASSERT_OBJ(parent, MY_CLASS);
|
||||
|
||||
if(parent == NULL || parent->spec_attr == NULL || path == NULL) return NULL;
|
||||
|
||||
while(*path) {
|
||||
const char * segment = path;
|
||||
uint32_t len = 0;
|
||||
|
||||
/* Calculate the length of the current segment */
|
||||
while(path[len] && path[len] != '/')
|
||||
len++;
|
||||
|
||||
/* Look for a child whose resolved name exactly matches the segment */
|
||||
lv_obj_t * child = find_by_name_direct(parent, segment, len);
|
||||
if(!child) return NULL; /*Segment not found*/
|
||||
|
||||
/* Advance to the next segment */
|
||||
path += len;
|
||||
if(*path == '/') path++; /* Skip the '/' */
|
||||
|
||||
/* If there is no further segment, we've found the target child */
|
||||
if(*path == '\0') return child;
|
||||
|
||||
parent = child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
lv_obj_t * lv_obj_find_by_name(const lv_obj_t * parent, const char * name)
|
||||
{
|
||||
if(parent == NULL) parent = lv_display_get_screen_active(NULL);
|
||||
if(parent == NULL) return NULL;
|
||||
|
||||
lv_obj_t * child = find_by_name_direct(parent, name, UINT16_MAX);
|
||||
if(child) return child;
|
||||
|
||||
/*Search children recursively*/
|
||||
uint32_t child_cnt = lv_obj_get_child_count(parent);
|
||||
uint32_t i;
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
child = parent->spec_attr->children[i];
|
||||
lv_obj_t * found = lv_obj_find_by_name(child, name);
|
||||
if(found != NULL) return found;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_OBJ_NAME*/
|
||||
|
||||
int32_t lv_obj_get_index(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
if(parent == NULL) return -1;
|
||||
|
||||
int32_t i = 0;
|
||||
for(i = 0; i < parent->spec_attr->child_cnt; i++) {
|
||||
if(parent->spec_attr->children[i] == obj) return i;
|
||||
}
|
||||
|
||||
/*Shouldn't reach this point*/
|
||||
LV_ASSERT(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t lv_obj_get_index_by_type(const lv_obj_t * obj, const lv_obj_class_t * class_p)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
if(parent == NULL) return 0xFFFFFFFF;
|
||||
|
||||
uint32_t i = 0;
|
||||
uint32_t idx = 0;
|
||||
for(i = 0; i < parent->spec_attr->child_cnt; i++) {
|
||||
lv_obj_t * child = parent->spec_attr->children[i];
|
||||
if(child->class_p == class_p) {
|
||||
if(child == obj) return idx;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/*Can happen if there was no children with the given type*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
void lv_obj_tree_walk(lv_obj_t * start_obj, lv_obj_tree_walk_cb_t cb, void * user_data)
|
||||
{
|
||||
walk_core(start_obj, cb, user_data);
|
||||
}
|
||||
|
||||
void lv_obj_dump_tree(lv_obj_t * start_obj)
|
||||
{
|
||||
if(start_obj == NULL) {
|
||||
lv_display_t * disp = lv_display_get_next(NULL);
|
||||
while(disp) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < disp->screen_cnt; i++) {
|
||||
dump_tree_core(disp->screens[i], 0);
|
||||
}
|
||||
disp = lv_display_get_next(disp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
dump_tree_core(start_obj, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_obj_delete_async_cb(void * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
lv_obj_delete(obj);
|
||||
}
|
||||
|
||||
static void obj_indev_reset(lv_indev_t * indev, lv_obj_t * obj)
|
||||
{
|
||||
/* If the input device is already in the release state,
|
||||
* there is no need to wait for the input device to be released
|
||||
*/
|
||||
if(lv_indev_get_state(indev) != LV_INDEV_STATE_RELEASED) {
|
||||
/*Wait for release to avoid accidentally triggering other obj to be clicked*/
|
||||
lv_indev_wait_release(indev);
|
||||
}
|
||||
|
||||
/*Reset the input device*/
|
||||
lv_indev_reset(indev, obj);
|
||||
}
|
||||
|
||||
static void obj_delete_core(lv_obj_t * obj)
|
||||
{
|
||||
if(obj->is_deleting)
|
||||
return;
|
||||
|
||||
obj->is_deleting = true;
|
||||
|
||||
/*Let the user free the resources used in `LV_EVENT_DELETE`*/
|
||||
lv_result_t res = lv_obj_send_event(obj, LV_EVENT_DELETE, NULL);
|
||||
if(res == LV_RESULT_INVALID) {
|
||||
obj->is_deleting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/*Clean registered event_cb*/
|
||||
if(obj->spec_attr) lv_event_remove_all(&(obj->spec_attr->event_list));
|
||||
|
||||
/*Recursively delete the children*/
|
||||
lv_obj_t * child = lv_obj_get_child(obj, 0);
|
||||
while(child) {
|
||||
obj_delete_core(child);
|
||||
child = lv_obj_get_child(obj, 0);
|
||||
}
|
||||
|
||||
lv_group_t * group = lv_obj_get_group(obj);
|
||||
|
||||
/*Reset all input devices if the object to delete is used*/
|
||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||
while(indev) {
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(indev);
|
||||
if(indev_type == LV_INDEV_TYPE_POINTER || indev_type == LV_INDEV_TYPE_BUTTON) {
|
||||
if(indev->pointer.act_obj == obj || indev->pointer.last_obj == obj || indev->pointer.scroll_obj == obj) {
|
||||
obj_indev_reset(indev, obj);
|
||||
}
|
||||
if(indev->pointer.last_pressed == obj) {
|
||||
indev->pointer.last_pressed = NULL;
|
||||
}
|
||||
if(indev->pointer.last_hovered == obj) {
|
||||
indev->pointer.last_hovered = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(indev->group == group && obj == lv_indev_get_active_obj()) {
|
||||
obj_indev_reset(indev, obj);
|
||||
}
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
|
||||
/*Delete all pending async del-s*/
|
||||
lv_result_t async_cancel_res = LV_RESULT_OK;
|
||||
while(async_cancel_res == LV_RESULT_OK) {
|
||||
async_cancel_res = lv_async_call_cancel(lv_obj_delete_async_cb, obj);
|
||||
}
|
||||
|
||||
/*All children deleted. Now clean up the object specific data*/
|
||||
lv_obj_destruct(obj);
|
||||
|
||||
/*Remove the screen for the screen list*/
|
||||
if(obj->parent == NULL) {
|
||||
lv_display_t * disp = lv_obj_get_display(obj);
|
||||
uint32_t i;
|
||||
/*Find the screen in the list*/
|
||||
for(i = 0; i < disp->screen_cnt; i++) {
|
||||
if(disp->screens[i] == obj) break;
|
||||
}
|
||||
|
||||
uint32_t id = i;
|
||||
for(i = id; i < disp->screen_cnt - 1; i++) {
|
||||
disp->screens[i] = disp->screens[i + 1];
|
||||
}
|
||||
disp->screen_cnt--;
|
||||
disp->screens = lv_realloc(disp->screens, disp->screen_cnt * sizeof(lv_obj_t *));
|
||||
}
|
||||
/*Remove the object from the child list of its parent*/
|
||||
else {
|
||||
int32_t id = lv_obj_get_index(obj);
|
||||
uint16_t i;
|
||||
for(i = id; i < obj->parent->spec_attr->child_cnt - 1; i++) {
|
||||
obj->parent->spec_attr->children[i] = obj->parent->spec_attr->children[i + 1];
|
||||
}
|
||||
obj->parent->spec_attr->child_cnt--;
|
||||
obj->parent->spec_attr->children = lv_realloc(obj->parent->spec_attr->children,
|
||||
obj->parent->spec_attr->child_cnt * sizeof(lv_obj_t *));
|
||||
}
|
||||
|
||||
/*Free the object itself*/
|
||||
lv_free(obj);
|
||||
}
|
||||
|
||||
static lv_obj_tree_walk_res_t walk_core(lv_obj_t * obj, lv_obj_tree_walk_cb_t cb, void * user_data)
|
||||
{
|
||||
lv_obj_tree_walk_res_t res = LV_OBJ_TREE_WALK_NEXT;
|
||||
|
||||
if(obj == NULL) {
|
||||
lv_display_t * disp = lv_display_get_next(NULL);
|
||||
while(disp) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < disp->screen_cnt; i++) {
|
||||
walk_core(disp->screens[i], cb, user_data);
|
||||
}
|
||||
disp = lv_display_get_next(disp);
|
||||
}
|
||||
return LV_OBJ_TREE_WALK_END; /*The value doesn't matter as it wasn't called recursively*/
|
||||
}
|
||||
|
||||
res = cb(obj, user_data);
|
||||
|
||||
if(res == LV_OBJ_TREE_WALK_END) return LV_OBJ_TREE_WALK_END;
|
||||
|
||||
if(res != LV_OBJ_TREE_WALK_SKIP_CHILDREN) {
|
||||
uint32_t i;
|
||||
for(i = 0; i < lv_obj_get_child_count(obj); i++) {
|
||||
res = walk_core(lv_obj_get_child(obj, i), cb, user_data);
|
||||
if(res == LV_OBJ_TREE_WALK_END) return LV_OBJ_TREE_WALK_END;
|
||||
}
|
||||
}
|
||||
return LV_OBJ_TREE_WALK_NEXT;
|
||||
}
|
||||
|
||||
static void dump_tree_core(lv_obj_t * obj, int32_t depth)
|
||||
{
|
||||
#if LV_USE_LOG
|
||||
const char * id;
|
||||
|
||||
#if LV_USE_OBJ_ID
|
||||
char buf[OBJ_DUMP_STRING_LEN];
|
||||
id = lv_obj_stringify_id(obj, buf, sizeof(buf));
|
||||
if(id == NULL) id = "obj0";
|
||||
#else
|
||||
id = "obj0";
|
||||
#endif
|
||||
|
||||
/*id of `obj0` is an invalid id for builtin id*/
|
||||
LV_LOG_USER("%*sobj:%p, id:%s;", (int)(2 * depth), "", (void *)obj, id);
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
if(obj && obj->spec_attr && obj->spec_attr->child_cnt) {
|
||||
for(uint32_t i = 0; i < obj->spec_attr->child_cnt; i++) {
|
||||
dump_tree_core(lv_obj_get_child(obj, i), depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static lv_obj_t * lv_obj_get_first_not_deleting_child(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(obj->spec_attr == NULL) return NULL;
|
||||
|
||||
int32_t i;
|
||||
int32_t cnt = (int32_t)obj->spec_attr->child_cnt;
|
||||
for(i = 0; i < cnt; i++) {
|
||||
if(!obj->spec_attr->children[i]->is_deleting) {
|
||||
return obj->spec_attr->children[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
|
||||
static lv_obj_t * find_by_name_direct(const lv_obj_t * parent, const char * name, size_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_count(parent);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = parent->spec_attr->children[i];
|
||||
|
||||
char child_name_resolved[LV_OBJ_NAME_MAX_LEN];
|
||||
lv_obj_get_name_resolved(child, child_name_resolved, sizeof(child_name_resolved));
|
||||
if(lv_strncmp(child_name_resolved, name, len) == 0) return child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_OBJ_NAME*/
|
||||
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* @file lv_obj_tree.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OBJ_TREE_H
|
||||
#define LV_OBJ_TREE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_anim.h"
|
||||
#include "../display/lv_display.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_OBJ_TREE_WALK_NEXT,
|
||||
LV_OBJ_TREE_WALK_SKIP_CHILDREN,
|
||||
LV_OBJ_TREE_WALK_END,
|
||||
} lv_obj_tree_walk_res_t;
|
||||
|
||||
typedef lv_obj_tree_walk_res_t (*lv_obj_tree_walk_cb_t)(lv_obj_t *, void *);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Delete an object and all of its children.
|
||||
* Also remove the objects from their group and remove all animations (if any).
|
||||
* Send `LV_EVENT_DELETED` to deleted objects.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_delete(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Delete all children of an object.
|
||||
* Also remove the objects from their group and remove all animations (if any).
|
||||
* Send `LV_EVENT_DELETED` to deleted objects.
|
||||
* @param obj pointer to an object
|
||||
*/
|
||||
void lv_obj_clean(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Delete an object after some delay
|
||||
* @param obj pointer to an object
|
||||
* @param delay_ms time to wait before delete in milliseconds
|
||||
*/
|
||||
void lv_obj_delete_delayed(lv_obj_t * obj, uint32_t delay_ms);
|
||||
|
||||
/**
|
||||
* A function to be easily used in animation ready callback to delete an object when the animation is ready
|
||||
* @param a pointer to the animation
|
||||
*/
|
||||
void lv_obj_delete_anim_completed_cb(lv_anim_t * a);
|
||||
|
||||
/**
|
||||
* Helper function for asynchronously deleting objects.
|
||||
* Useful for cases where you can't delete an object directly in an `LV_EVENT_DELETE` handler (i.e. parent).
|
||||
* @param obj object to delete
|
||||
* @see lv_async_call
|
||||
*/
|
||||
void lv_obj_delete_async(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Move the parent of an object. The relative coordinates will be kept.
|
||||
*
|
||||
* @param obj pointer to an object whose parent needs to be changed
|
||||
* @param parent pointer to the new parent
|
||||
*/
|
||||
void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent);
|
||||
|
||||
/**
|
||||
* Swap the positions of two objects.
|
||||
* When used in listboxes, it can be used to sort the listbox items.
|
||||
* @param obj1 pointer to the first object
|
||||
* @param obj2 pointer to the second object
|
||||
*/
|
||||
void lv_obj_swap(lv_obj_t * obj1, lv_obj_t * obj2);
|
||||
|
||||
/**
|
||||
* moves the object to the given index in its parent.
|
||||
* When used in listboxes, it can be used to sort the listbox items.
|
||||
* @param obj pointer to the object to be moved.
|
||||
* @param index new index in parent. -1 to count from the back
|
||||
* @note to move to the background: lv_obj_move_to_index(obj, 0)
|
||||
* @note to move forward (up): lv_obj_move_to_index(obj, lv_obj_get_index(obj) - 1)
|
||||
*/
|
||||
void lv_obj_move_to_index(lv_obj_t * obj, int32_t index);
|
||||
|
||||
/**
|
||||
* Get the screen of an object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the object's screen
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the display of the object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the object's display
|
||||
*/
|
||||
lv_display_t * lv_obj_get_display(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the parent of an object
|
||||
* @param obj pointer to an object
|
||||
* @return the parent of the object. (NULL if `obj` was a screen)
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the child of an object by the child's index.
|
||||
* @param obj pointer to an object whose child should be get
|
||||
* @param idx the index of the child.
|
||||
* 0: the oldest (firstly created) child
|
||||
* 1: the second oldest
|
||||
* child count-1: the youngest
|
||||
* -1: the youngest
|
||||
* -2: the second youngest
|
||||
* @return pointer to the child or NULL if the index was invalid
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, int32_t idx);
|
||||
|
||||
/**
|
||||
* Get the child of an object by the child's index. Consider the children only with a given type.
|
||||
* @param obj pointer to an object whose child should be get
|
||||
* @param idx the index of the child.
|
||||
* 0: the oldest (firstly created) child
|
||||
* 1: the second oldest
|
||||
* child count-1: the youngest
|
||||
* -1: the youngest
|
||||
* -2: the second youngest
|
||||
* @param class_p the type of the children to check
|
||||
* @return pointer to the child or NULL if the index was invalid
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_child_by_type(const lv_obj_t * obj, int32_t idx,
|
||||
const lv_obj_class_t * class_p);
|
||||
|
||||
/**
|
||||
* Return a sibling of an object
|
||||
* @param obj pointer to an object whose sibling should be get
|
||||
* @param idx 0: `obj` itself
|
||||
* -1: the first older sibling
|
||||
* -2: the next older sibling
|
||||
* 1: the first younger sibling
|
||||
* 2: the next younger sibling
|
||||
* etc
|
||||
* @return pointer to the requested sibling or NULL if there is no such sibling
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_sibling(const lv_obj_t * obj, int32_t idx);
|
||||
|
||||
/**
|
||||
* Return a sibling of an object. Consider the siblings only with a given type.
|
||||
* @param obj pointer to an object whose sibling should be get
|
||||
* @param idx 0: `obj` itself
|
||||
* -1: the first older sibling
|
||||
* -2: the next older sibling
|
||||
* 1: the first younger sibling
|
||||
* 2: the next younger sibling
|
||||
* etc
|
||||
* @param class_p the type of the children to check
|
||||
* @return pointer to the requested sibling or NULL if there is no such sibling
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_sibling_by_type(const lv_obj_t * obj, int32_t idx,
|
||||
const lv_obj_class_t * class_p);
|
||||
|
||||
/**
|
||||
* Get the number of children
|
||||
* @param obj pointer to an object
|
||||
* @return the number of children
|
||||
*/
|
||||
uint32_t lv_obj_get_child_count(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the number of children having a given type.
|
||||
* @param obj pointer to an object
|
||||
* @param class_p the type of the children to check
|
||||
* @return the number of children
|
||||
*/
|
||||
|
||||
uint32_t lv_obj_get_child_count_by_type(const lv_obj_t * obj, const lv_obj_class_t * class_p);
|
||||
|
||||
#if LV_USE_OBJ_NAME
|
||||
|
||||
/**
|
||||
* Set a name for a widget. The name will be allocated and freed when the
|
||||
* widget is deleted or a new name is set.
|
||||
* @param obj pointer to an object
|
||||
* @param name the name to set. If set to `NULL` the default "<widget_type>_#"
|
||||
* name will be used.
|
||||
* @note If the name ends with a `#`, older siblings with the same name
|
||||
* will be counted, and the `#` will be replaced by the index of the
|
||||
* given widget. For example, creating multiple widgets with the name
|
||||
* "mybtn_#" will result in resolved names like "mybtn_0", "mybtn_1",
|
||||
* "mybtn_2", etc. The name is resolved when `lv_obj_get_name_resolved`
|
||||
* is called, so the result reflects the currently existing widgets at
|
||||
* that time.
|
||||
*/
|
||||
void lv_obj_set_name(lv_obj_t * obj, const char * name);
|
||||
|
||||
/**
|
||||
* Set a name for a widget. Only a pointer will be saved.
|
||||
* @param obj pointer to an object
|
||||
* @param name the name to set. If set to `NULL` the default "<widget_type>_#"
|
||||
* name will be used.
|
||||
* @note If the name ends with a `#`, older siblings with the same name
|
||||
* will be counted, and the `#` will be replaced by the index of the
|
||||
* given widget. For example, creating multiple widgets with the name
|
||||
* "mybtn_#" will result in resolved names like "mybtn_0", "mybtn_1",
|
||||
* "mybtn_2", etc. The name is resolved when `lv_obj_get_name_resolved`
|
||||
* is called, so the result reflects the currently existing widgets at
|
||||
* that time.
|
||||
*/
|
||||
void lv_obj_set_name_static(lv_obj_t * obj, const char * name);
|
||||
|
||||
/**
|
||||
* Get the set name as it was set.
|
||||
* @param obj pointer to an object
|
||||
* @return get the set name or NULL if it wasn't set yet
|
||||
*/
|
||||
const char * lv_obj_get_name(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the set name or craft a name automatically.
|
||||
* @param obj pointer to an object
|
||||
* @param buf buffer to store the name
|
||||
* @param buf_size the size of the buffer in bytes
|
||||
* @note If the name ends with a `#`, older siblings with the same name
|
||||
* will be counted, and the `#` will be replaced by the index of the
|
||||
* given widget. For example, creating multiple widgets with the name
|
||||
* "mybtn_#" will result in resolved names like "mybtn_0", "mybtn_1",
|
||||
* "mybtn_2", etc. The name is resolved when `lv_obj_get_name_resolved`
|
||||
* is called, so the result reflects the currently existing widgets at
|
||||
* that time.
|
||||
*/
|
||||
void lv_obj_get_name_resolved(const lv_obj_t * obj, char buf[], size_t buf_size);
|
||||
|
||||
/**
|
||||
* Find a child with a given name on a parent. This child doesn't have to be the
|
||||
* direct child of the parent. First direct children of the parent will be checked,
|
||||
* and the direct children of the first child, etc. (Breadth-first search).
|
||||
*
|
||||
* If the name of a widget was not set a name like "lv_button_1" will
|
||||
* be created for it using `lv_obj_get_name_resolved`.
|
||||
*
|
||||
* @param parent the widget where the search should start
|
||||
* @return the found widget or NULL if not found.
|
||||
*/
|
||||
lv_obj_t * lv_obj_find_by_name(const lv_obj_t * parent, const char * name);
|
||||
|
||||
/**
|
||||
* Get an object by name. The name can be a path too, for example
|
||||
* "main_container/lv_button_1/label".
|
||||
* In this case the first part of the name-path should be the direct child of the parent,
|
||||
* the second part, should the direct child of first one, etc.
|
||||
*
|
||||
* If the name of a widget was not set a name like "lv_button_1" will
|
||||
* be created for it using `lv_obj_get_name_resolved`.
|
||||
*
|
||||
* @param parent the widget where the search should start
|
||||
* @return the found widget or NULL if not found.
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_child_by_name(const lv_obj_t * parent, const char * name_path);
|
||||
|
||||
#endif /*LV_USE_OBJ_NAME*/
|
||||
|
||||
/**
|
||||
* Get the index of a child.
|
||||
* @param obj pointer to an object
|
||||
* @return the child index of the object.
|
||||
* E.g. 0: the oldest (firstly created child).
|
||||
* (-1 if child could not be found or no parent exists)
|
||||
*/
|
||||
int32_t lv_obj_get_index(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the index of a child. Consider the children only with a given type.
|
||||
* @param obj pointer to an object
|
||||
* @param class_p the type of the children to check
|
||||
* @return the child index of the object.
|
||||
* E.g. 0: the oldest (firstly created child with the given class).
|
||||
* (-1 if child could not be found or no parent exists)
|
||||
*/
|
||||
int32_t lv_obj_get_index_by_type(const lv_obj_t * obj, const lv_obj_class_t * class_p);
|
||||
|
||||
/**
|
||||
* Iterate through all children of any object.
|
||||
* @param start_obj start integrating from this object
|
||||
* @param cb call this callback on the objects
|
||||
* @param user_data pointer to any user related data (will be passed to `cb`)
|
||||
*/
|
||||
void lv_obj_tree_walk(lv_obj_t * start_obj, lv_obj_tree_walk_cb_t cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Iterate through all children of any object and print their ID.
|
||||
* @param start_obj start integrating from this object
|
||||
*/
|
||||
void lv_obj_dump_tree(lv_obj_t * start_obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_OBJ_TREE_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file lv_refr.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_REFR_H
|
||||
#define LV_REFR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_obj.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../misc/lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Redraw the invalidated areas now.
|
||||
* Normally the redrawing is periodically executed in `lv_timer_handler` but a long blocking process
|
||||
* can prevent the call of `lv_timer_handler`. In this case if the GUI is updated in the process
|
||||
* (e.g. progress bar) this function can be called when the screen should be updated.
|
||||
* @param disp pointer to display to refresh. NULL to refresh all displays.
|
||||
*/
|
||||
void lv_refr_now(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Redrawn on object and all its children using the passed draw context
|
||||
* @param layer pointer to a layer where to draw.
|
||||
* @param obj the start object from the redraw should start
|
||||
*/
|
||||
void lv_obj_redraw(lv_layer_t * layer, lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Called periodically to handle the refreshing
|
||||
* @param timer pointer to the timer itself, or `NULL`
|
||||
*/
|
||||
void lv_display_refr_timer(lv_timer_t * timer);
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_REFR_H*/
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file lv_refr_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_REFR_PRIVATE_H
|
||||
#define LV_REFR_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_refr.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the screen refresh subsystem
|
||||
*/
|
||||
void lv_refr_init(void);
|
||||
|
||||
/**
|
||||
* Deinitialize the screen refresh subsystem
|
||||
*/
|
||||
void lv_refr_deinit(void);
|
||||
|
||||
/**
|
||||
* Invalidate an area on display to redraw it
|
||||
* @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas)
|
||||
* @param disp pointer to display where the area should be invalidated (NULL can be used if there is
|
||||
* only one display)
|
||||
*/
|
||||
void lv_inv_area(lv_display_t * disp, const lv_area_t * area_p);
|
||||
|
||||
/**
|
||||
* Get the display which is being refreshed
|
||||
* @return the display being refreshed
|
||||
*/
|
||||
lv_display_t * lv_refr_get_disp_refreshing(void);
|
||||
|
||||
/**
|
||||
* Set the display which is being refreshed
|
||||
* @param disp the display being refreshed
|
||||
*/
|
||||
void lv_refr_set_disp_refreshing(lv_display_t * disp);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_REFR_PRIVATE_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,710 @@
|
||||
/**
|
||||
* @file lv_display.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DISPLAY_H
|
||||
#define LV_DISPLAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_timer.h"
|
||||
#include "../misc/lv_event.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#ifndef LV_ATTRIBUTE_FLUSH_READY
|
||||
#define LV_ATTRIBUTE_FLUSH_READY
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_DISPLAY_ROTATION_0 = 0,
|
||||
LV_DISPLAY_ROTATION_90,
|
||||
LV_DISPLAY_ROTATION_180,
|
||||
LV_DISPLAY_ROTATION_270
|
||||
} lv_display_rotation_t;
|
||||
|
||||
typedef enum {
|
||||
/**
|
||||
* Use the buffer(s) to render the screen is smaller parts.
|
||||
* This way the buffers can be smaller then the display to save RAM. At least 1/10 screen size buffer(s) are recommended.
|
||||
*/
|
||||
LV_DISPLAY_RENDER_MODE_PARTIAL,
|
||||
|
||||
/**
|
||||
* The buffer(s) has to be screen sized and LVGL will render into the correct location of the buffer.
|
||||
* This way the buffer always contain the whole image. Only the changed ares will be updated.
|
||||
* With 2 buffers the buffers' content are kept in sync automatically and in flush_cb only address change is required.
|
||||
*/
|
||||
LV_DISPLAY_RENDER_MODE_DIRECT,
|
||||
|
||||
/**
|
||||
* Always redraw the whole screen even if only one pixel has been changed.
|
||||
* With 2 buffers in flush_cb only an address change is required.
|
||||
*/
|
||||
LV_DISPLAY_RENDER_MODE_FULL,
|
||||
} lv_display_render_mode_t;
|
||||
|
||||
typedef enum {
|
||||
LV_SCR_LOAD_ANIM_NONE,
|
||||
LV_SCR_LOAD_ANIM_OVER_LEFT,
|
||||
LV_SCR_LOAD_ANIM_OVER_RIGHT,
|
||||
LV_SCR_LOAD_ANIM_OVER_TOP,
|
||||
LV_SCR_LOAD_ANIM_OVER_BOTTOM,
|
||||
LV_SCR_LOAD_ANIM_MOVE_LEFT,
|
||||
LV_SCR_LOAD_ANIM_MOVE_RIGHT,
|
||||
LV_SCR_LOAD_ANIM_MOVE_TOP,
|
||||
LV_SCR_LOAD_ANIM_MOVE_BOTTOM,
|
||||
LV_SCR_LOAD_ANIM_FADE_IN,
|
||||
LV_SCR_LOAD_ANIM_FADE_ON = LV_SCR_LOAD_ANIM_FADE_IN, /*For backward compatibility*/
|
||||
LV_SCR_LOAD_ANIM_FADE_OUT,
|
||||
LV_SCR_LOAD_ANIM_OUT_LEFT,
|
||||
LV_SCR_LOAD_ANIM_OUT_RIGHT,
|
||||
LV_SCR_LOAD_ANIM_OUT_TOP,
|
||||
LV_SCR_LOAD_ANIM_OUT_BOTTOM,
|
||||
} lv_screen_load_anim_t;
|
||||
|
||||
typedef void (*lv_display_flush_cb_t)(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
|
||||
typedef void (*lv_display_flush_wait_cb_t)(lv_display_t * disp);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a new display with the given resolution
|
||||
* @param hor_res horizontal resolution in pixels
|
||||
* @param ver_res vertical resolution in pixels
|
||||
* @return pointer to a display object or `NULL` on error
|
||||
*/
|
||||
lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res);
|
||||
|
||||
/**
|
||||
* Remove a display
|
||||
* @param disp pointer to display
|
||||
*/
|
||||
void lv_display_delete(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Set a default display. The new screens will be created on it by default.
|
||||
* @param disp pointer to a display
|
||||
*/
|
||||
void lv_display_set_default(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the default display
|
||||
* @return pointer to the default display
|
||||
*/
|
||||
lv_display_t * lv_display_get_default(void);
|
||||
|
||||
/**
|
||||
* Get the next display.
|
||||
* @param disp pointer to the current display. NULL to initialize.
|
||||
* @return the next display or NULL if no more. Gives the first display when the parameter is NULL.
|
||||
*/
|
||||
lv_display_t * lv_display_get_next(lv_display_t * disp);
|
||||
|
||||
/*---------------------
|
||||
* RESOLUTION
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Sets the resolution of a display. `LV_EVENT_RESOLUTION_CHANGED` event will be sent.
|
||||
* Here the native resolution of the device should be set. If the display will be rotated later with
|
||||
* `lv_display_set_rotation` LVGL will swap the hor. and ver. resolution automatically.
|
||||
* @param disp pointer to a display
|
||||
* @param hor_res the new horizontal resolution
|
||||
* @param ver_res the new vertical resolution
|
||||
*/
|
||||
void lv_display_set_resolution(lv_display_t * disp, int32_t hor_res, int32_t ver_res);
|
||||
|
||||
/**
|
||||
* It's not mandatory to use the whole display for LVGL, however in some cases physical resolution is important.
|
||||
* For example the touchpad still sees whole resolution and the values needs to be converted
|
||||
* to the active LVGL display area.
|
||||
* @param disp pointer to a display
|
||||
* @param hor_res the new physical horizontal resolution, or -1 to assume it's the same as the normal hor. res.
|
||||
* @param ver_res the new physical vertical resolution, or -1 to assume it's the same as the normal hor. res.
|
||||
*/
|
||||
void lv_display_set_physical_resolution(lv_display_t * disp, int32_t hor_res, int32_t ver_res);
|
||||
|
||||
/**
|
||||
* If physical resolution is not the same as the normal resolution
|
||||
* the offset of the active display area can be set here.
|
||||
* @param disp pointer to a display
|
||||
* @param x X offset
|
||||
* @param y Y offset
|
||||
*/
|
||||
void lv_display_set_offset(lv_display_t * disp, int32_t x, int32_t y);
|
||||
|
||||
/**
|
||||
* Set the rotation of this display. LVGL will swap the horizontal and vertical resolutions internally.
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @param rotation `LV_DISPLAY_ROTATION_0/90/180/270`
|
||||
*/
|
||||
void lv_display_set_rotation(lv_display_t * disp, lv_display_rotation_t rotation);
|
||||
|
||||
/**
|
||||
* Use matrix rotation for the display. This function is depended on `LV_DRAW_TRANSFORM_USE_MATRIX`
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @param enable true: enable matrix rotation, false: disable
|
||||
*/
|
||||
void lv_display_set_matrix_rotation(lv_display_t * disp, bool enable);
|
||||
|
||||
/**
|
||||
* Set the DPI (dot per inch) of the display.
|
||||
* dpi = sqrt(hor_res^2 + ver_res^2) / diagonal"
|
||||
* @param disp pointer to a display
|
||||
* @param dpi the new DPI
|
||||
*/
|
||||
void lv_display_set_dpi(lv_display_t * disp, int32_t dpi);
|
||||
|
||||
/**
|
||||
* Get the horizontal resolution of a display.
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal resolution of the display.
|
||||
*/
|
||||
int32_t lv_display_get_horizontal_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the vertical resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the vertical resolution of the display
|
||||
*/
|
||||
int32_t lv_display_get_vertical_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the original horizontal resolution of a display without considering rotation
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal resolution of the display.
|
||||
*/
|
||||
int32_t lv_display_get_original_horizontal_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the original vertical resolution of a display without considering rotation
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the vertical resolution of the display
|
||||
*/
|
||||
int32_t lv_display_get_original_vertical_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the physical horizontal resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the physical horizontal resolution of the display
|
||||
*/
|
||||
int32_t lv_display_get_physical_horizontal_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the physical vertical resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the physical vertical resolution of the display
|
||||
*/
|
||||
int32_t lv_display_get_physical_vertical_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the horizontal offset from the full / physical display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal offset from the physical display
|
||||
*/
|
||||
int32_t lv_display_get_offset_x(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the vertical offset from the full / physical display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal offset from the physical display
|
||||
*/
|
||||
int32_t lv_display_get_offset_y(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the current rotation of this display.
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the current rotation
|
||||
*/
|
||||
lv_display_rotation_t lv_display_get_rotation(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get if matrix rotation is enabled for a display or not
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return true: matrix rotation is enabled; false: disabled
|
||||
*/
|
||||
bool lv_display_get_matrix_rotation(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the DPI of the display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return dpi of the display
|
||||
*/
|
||||
int32_t lv_display_get_dpi(const lv_display_t * disp);
|
||||
|
||||
/*---------------------
|
||||
* BUFFERING
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Set the buffers for a display, similarly to `lv_display_set_draw_buffers`, but accept the raw buffer pointers.
|
||||
* For DIRECT/FULL rending modes, the buffer size must be at least
|
||||
* `hor_res * ver_res * lv_color_format_get_size(lv_display_get_color_format(disp))`
|
||||
* @param disp pointer to a display
|
||||
* @param buf1 first buffer
|
||||
* @param buf2 second buffer (can be `NULL`)
|
||||
* @param buf_size buffer size in byte
|
||||
* @param render_mode LV_DISPLAY_RENDER_MODE_PARTIAL/DIRECT/FULL
|
||||
*/
|
||||
void lv_display_set_buffers(lv_display_t * disp, void * buf1, void * buf2, uint32_t buf_size,
|
||||
lv_display_render_mode_t render_mode);
|
||||
|
||||
/**
|
||||
* Set the frame buffers for a display, similarly to `lv_display_set_buffers`, but allow
|
||||
* for a custom stride as required by a display controller.
|
||||
* This allows the frame buffers to have a stride alignment different from the rest of
|
||||
* the buffers`
|
||||
* @param disp pointer to a display
|
||||
* @param buf1 first buffer
|
||||
* @param buf2 second buffer (can be `NULL`)
|
||||
* @param buf_size buffer size in byte
|
||||
* @param stride buffer stride in bytes
|
||||
* @param render_mode LV_DISPLAY_RENDER_MODE_PARTIAL/DIRECT/FULL
|
||||
*/
|
||||
void lv_display_set_buffers_with_stride(lv_display_t * disp, void * buf1, void * buf2, uint32_t buf_size,
|
||||
uint32_t stride, lv_display_render_mode_t render_mode);
|
||||
|
||||
/**
|
||||
* Set the buffers for a display, accept a draw buffer pointer.
|
||||
* Normally use `lv_display_set_buffers` is enough for most cases.
|
||||
* Use this function when an existing lv_draw_buf_t is available.
|
||||
* @param disp pointer to a display
|
||||
* @param buf1 first buffer
|
||||
* @param buf2 second buffer (can be `NULL`)
|
||||
*/
|
||||
void lv_display_set_draw_buffers(lv_display_t * disp, lv_draw_buf_t * buf1, lv_draw_buf_t * buf2);
|
||||
|
||||
/**
|
||||
* Set the third draw buffer for a display.
|
||||
* @param disp pointer to a display
|
||||
* @param buf3 third buffer
|
||||
*/
|
||||
void lv_display_set_3rd_draw_buffer(lv_display_t * disp, lv_draw_buf_t * buf3);
|
||||
|
||||
/**
|
||||
* Set display render mode
|
||||
* @param disp pointer to a display
|
||||
* @param render_mode LV_DISPLAY_RENDER_MODE_PARTIAL/DIRECT/FULL
|
||||
*/
|
||||
void lv_display_set_render_mode(lv_display_t * disp, lv_display_render_mode_t render_mode);
|
||||
|
||||
/**
|
||||
* Set the flush callback which will be called to copy the rendered image to the display.
|
||||
* @param disp pointer to a display
|
||||
* @param flush_cb the flush callback (`px_map` contains the rendered image as raw pixel map and it should be copied to `area` on the display)
|
||||
*/
|
||||
void lv_display_set_flush_cb(lv_display_t * disp, lv_display_flush_cb_t flush_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to be used while LVGL is waiting flushing to be finished.
|
||||
* It can do any complex logic to wait, including semaphores, mutexes, polling flags, etc.
|
||||
* If not set the `disp->flushing` flag is used which can be cleared with `lv_display_flush_ready()`
|
||||
* @param disp pointer to a display
|
||||
* @param wait_cb a callback to call while LVGL is waiting for flush ready.
|
||||
* If NULL `lv_display_flush_ready()` can be used to signal that flushing is ready.
|
||||
*/
|
||||
void lv_display_set_flush_wait_cb(lv_display_t * disp, lv_display_flush_wait_cb_t wait_cb);
|
||||
|
||||
/**
|
||||
* Set the color format of the display.
|
||||
* @param disp pointer to a display
|
||||
* @param color_format Possible values are
|
||||
* - LV_COLOR_FORMAT_RGB565
|
||||
* - LV_COLOR_FORMAT_RGB888
|
||||
* - LV_COLOR_FORMAT_XRGB888
|
||||
* - LV_COLOR_FORMAT_ARGB888
|
||||
*@note To change the endianness of the rendered image in case of RGB565 format
|
||||
* (i.e. swap the 2 bytes) call `lv_draw_sw_rgb565_swap` in the flush_cb
|
||||
*/
|
||||
void lv_display_set_color_format(lv_display_t * disp, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Get the color format of the display
|
||||
* @param disp pointer to a display
|
||||
* @return the color format
|
||||
*/
|
||||
lv_color_format_t lv_display_get_color_format(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Set the number of tiles for parallel rendering.
|
||||
* @param disp pointer to a display
|
||||
* @param tile_cnt number of tiles (1 =< tile_cnt < 256)
|
||||
*/
|
||||
void lv_display_set_tile_cnt(lv_display_t * disp, uint32_t tile_cnt);
|
||||
|
||||
/**
|
||||
* Get the number of tiles used for parallel rendering
|
||||
* @param disp pointer to a display
|
||||
* @return number of tiles
|
||||
*/
|
||||
uint32_t lv_display_get_tile_cnt(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Enable anti-aliasing for the render engine
|
||||
* @param disp pointer to a display
|
||||
* @param en true/false
|
||||
*/
|
||||
void lv_display_set_antialiasing(lv_display_t * disp, bool en);
|
||||
|
||||
/**
|
||||
* Get if anti-aliasing is enabled for a display or not
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return true/false
|
||||
*/
|
||||
bool lv_display_get_antialiasing(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Call from the display driver when the flushing is finished
|
||||
* @param disp pointer to display whose `flush_cb` was called
|
||||
*/
|
||||
LV_ATTRIBUTE_FLUSH_READY void lv_display_flush_ready(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Tell if it's the last area of the refreshing process.
|
||||
* Can be called from `flush_cb` to execute some special display refreshing if needed when all areas area flushed.
|
||||
* @param disp pointer to display
|
||||
* @return true: it's the last area to flush;
|
||||
* false: there are other areas too which will be refreshed soon
|
||||
*/
|
||||
LV_ATTRIBUTE_FLUSH_READY bool lv_display_flush_is_last(lv_display_t * disp);
|
||||
|
||||
bool lv_display_is_double_buffered(lv_display_t * disp);
|
||||
|
||||
/*---------------------
|
||||
* SCREENS
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Return a pointer to the active screen on a display
|
||||
* @param disp pointer to display which active screen should be get.
|
||||
* (NULL to use the default screen)
|
||||
* @return pointer to the active screen object (loaded by 'lv_screen_load()')
|
||||
*/
|
||||
lv_obj_t * lv_display_get_screen_active(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Return with a pointer to the previous screen. Only used during screen transitions.
|
||||
* @param disp pointer to display which previous screen should be get.
|
||||
* (NULL to use the default screen)
|
||||
* @return pointer to the previous screen object or NULL if not used now
|
||||
*/
|
||||
lv_obj_t * lv_display_get_screen_prev(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Return the top layer. The top layer is the same on all screens and it is above the normal screen layer.
|
||||
* @param disp pointer to display which top layer should be get. (NULL to use the default screen)
|
||||
* @return pointer to the top layer object
|
||||
*/
|
||||
lv_obj_t * lv_display_get_layer_top(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Return the sys. layer. The system layer is the same on all screen and it is above the normal screen and the top layer.
|
||||
* @param disp pointer to display which sys. layer should be retrieved. (NULL to use the default screen)
|
||||
* @return pointer to the sys layer object
|
||||
*/
|
||||
lv_obj_t * lv_display_get_layer_sys(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Return the bottom layer. The bottom layer is the same on all screen and it is under the normal screen layer.
|
||||
* It's visible only if the screen is transparent.
|
||||
* @param disp pointer to display (NULL to use the default screen)
|
||||
* @return pointer to the bottom layer object
|
||||
*/
|
||||
lv_obj_t * lv_display_get_layer_bottom(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Load a screen on the default display
|
||||
* @param scr pointer to a screen
|
||||
*/
|
||||
void lv_screen_load(struct _lv_obj_t * scr);
|
||||
|
||||
/**
|
||||
* Switch screen with animation
|
||||
* @param scr pointer to the new screen to load
|
||||
* @param anim_type type of the animation from `lv_screen_load_anim_t`, e.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT`
|
||||
* @param time time of the animation
|
||||
* @param delay delay before the transition
|
||||
* @param auto_del true: automatically delete the old screen
|
||||
*/
|
||||
void lv_screen_load_anim(lv_obj_t * scr, lv_screen_load_anim_t anim_type, uint32_t time, uint32_t delay,
|
||||
bool auto_del);
|
||||
|
||||
/**
|
||||
* Get the active screen of the default display
|
||||
* @return pointer to the active screen
|
||||
*/
|
||||
lv_obj_t * lv_screen_active(void);
|
||||
|
||||
/**
|
||||
* Get the top layer of the default display
|
||||
* @return pointer to the top layer
|
||||
*/
|
||||
lv_obj_t * lv_layer_top(void);
|
||||
|
||||
/**
|
||||
* Get the system layer of the default display
|
||||
* @return pointer to the sys layer
|
||||
*/
|
||||
lv_obj_t * lv_layer_sys(void);
|
||||
|
||||
/**
|
||||
* Get the bottom layer of the default display
|
||||
* @return pointer to the bottom layer
|
||||
*/
|
||||
lv_obj_t * lv_layer_bottom(void);
|
||||
|
||||
/*---------------------
|
||||
* OTHERS
|
||||
*--------------------*/
|
||||
|
||||
/**
|
||||
* Add an event handler to the display
|
||||
* @param disp pointer to a display
|
||||
* @param event_cb an event callback
|
||||
* @param filter event code to react or `LV_EVENT_ALL`
|
||||
* @param user_data optional user_data
|
||||
*/
|
||||
void lv_display_add_event_cb(lv_display_t * disp, lv_event_cb_t event_cb, lv_event_code_t filter, void * user_data);
|
||||
|
||||
/**
|
||||
* Get the number of event attached to a display
|
||||
* @param disp pointer to a display
|
||||
* @return number of events
|
||||
*/
|
||||
uint32_t lv_display_get_event_count(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get an event descriptor for an event
|
||||
* @param disp pointer to a display
|
||||
* @param index the index of the event
|
||||
* @return the event descriptor
|
||||
*/
|
||||
lv_event_dsc_t * lv_display_get_event_dsc(lv_display_t * disp, uint32_t index);
|
||||
|
||||
/**
|
||||
* Remove an event
|
||||
* @param disp pointer to a display
|
||||
* @param index the index of the event to remove
|
||||
* @return true: and event was removed; false: no event was removed
|
||||
*/
|
||||
bool lv_display_delete_event(lv_display_t * disp, uint32_t index);
|
||||
|
||||
/**
|
||||
* Remove an event_cb with user_data
|
||||
* @param disp pointer to a display
|
||||
* @param event_cb the event_cb of the event to remove
|
||||
* @param user_data user_data
|
||||
* @return the count of the event removed
|
||||
*/
|
||||
uint32_t lv_display_remove_event_cb_with_user_data(lv_display_t * disp, lv_event_cb_t event_cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Send an event to a display
|
||||
* @param disp pointer to a display
|
||||
* @param code an event code. LV_EVENT_...
|
||||
* @param param optional param
|
||||
* @return LV_RESULT_OK: disp wasn't deleted in the event.
|
||||
*/
|
||||
lv_result_t lv_display_send_event(lv_display_t * disp, lv_event_code_t code, void * param);
|
||||
|
||||
/**
|
||||
* Get the area to be invalidated. Can be used in `LV_EVENT_INVALIDATE_AREA`
|
||||
* @param e pointer to an event
|
||||
* @return the area to invalidated (can be modified as required)
|
||||
*/
|
||||
lv_area_t * lv_event_get_invalidated_area(lv_event_t * e);
|
||||
|
||||
/**
|
||||
* Set the theme of a display. If there are no user created widgets yet the screens' theme will be updated
|
||||
* @param disp pointer to a display
|
||||
* @param th pointer to a theme
|
||||
*/
|
||||
void lv_display_set_theme(lv_display_t * disp, lv_theme_t * th);
|
||||
|
||||
/**
|
||||
* Get the theme of a display
|
||||
* @param disp pointer to a display
|
||||
* @return the display's theme (can be NULL)
|
||||
*/
|
||||
lv_theme_t * lv_display_get_theme(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get elapsed time since last user activity on a display (e.g. click)
|
||||
* @param disp pointer to a display (NULL to get the overall smallest inactivity)
|
||||
* @return elapsed ticks (milliseconds) since the last activity
|
||||
*/
|
||||
uint32_t lv_display_get_inactive_time(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Manually trigger an activity on a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
*/
|
||||
void lv_display_trigger_activity(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Temporarily enable and disable the invalidation of the display.
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @param en true: enable invalidation; false: invalidation
|
||||
*/
|
||||
void lv_display_enable_invalidation(lv_display_t * disp, bool en);
|
||||
|
||||
/**
|
||||
* Get display invalidation is enabled.
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return return true if invalidation is enabled
|
||||
*/
|
||||
bool lv_display_is_invalidation_enabled(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get a pointer to the screen refresher timer to
|
||||
* modify its parameters with `lv_timer_...` functions.
|
||||
* @param disp pointer to a display
|
||||
* @return pointer to the display refresher timer. (NULL on error)
|
||||
*/
|
||||
lv_timer_t * lv_display_get_refr_timer(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Delete screen refresher timer
|
||||
* @param disp pointer to a display
|
||||
*/
|
||||
void lv_display_delete_refr_timer(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Register vsync event of a display. `LV_EVENT_VSYNC` event will be sent periodically.
|
||||
* Please don't use it in display event listeners, as it may cause memory leaks and illegal access issues.
|
||||
*
|
||||
* @param disp pointer to a display
|
||||
* @param event_cb an event callback
|
||||
* @param user_data optional user_data
|
||||
*/
|
||||
bool lv_display_register_vsync_event(lv_display_t * disp, lv_event_cb_t event_cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Unregister vsync event of a display. `LV_EVENT_VSYNC` event won't be sent periodically.
|
||||
* Please don't use it in display event listeners, as it may cause memory leaks and illegal access issues.
|
||||
* @param disp pointer to a display
|
||||
* @param event_cb an event callback
|
||||
* @param user_data optional user_data
|
||||
*/
|
||||
bool lv_display_unregister_vsync_event(lv_display_t * disp, lv_event_cb_t event_cb, void * user_data);
|
||||
|
||||
/**
|
||||
* Send an vsync event to a display
|
||||
* @param disp pointer to a display
|
||||
* @param param optional param
|
||||
* @return LV_RESULT_OK: disp wasn't deleted in the event.
|
||||
*/
|
||||
lv_result_t lv_display_send_vsync_event(lv_display_t * disp, void * param);
|
||||
|
||||
void lv_display_set_user_data(lv_display_t * disp, void * user_data);
|
||||
void lv_display_set_driver_data(lv_display_t * disp, void * driver_data);
|
||||
void * lv_display_get_user_data(lv_display_t * disp);
|
||||
void * lv_display_get_driver_data(lv_display_t * disp);
|
||||
lv_draw_buf_t * lv_display_get_buf_active(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Rotate an area in-place according to the display's rotation
|
||||
* @param disp pointer to a display
|
||||
* @param area pointer to an area to rotate
|
||||
*/
|
||||
void lv_display_rotate_area(lv_display_t * disp, lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Get the size of the draw buffers
|
||||
* @param disp pointer to a display
|
||||
* @return the size of the draw buffer in bytes for valid display, 0 otherwise
|
||||
*/
|
||||
uint32_t lv_display_get_draw_buf_size(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the size of the invalidated draw buffer. Can be used in the flush callback
|
||||
* to get the number of bytes used in the current render buffer.
|
||||
* @param disp pointer to a display
|
||||
* @param width the width of the invalidated area
|
||||
* @param height the height of the invalidated area
|
||||
* @return the size of the invalidated draw buffer in bytes, not accounting for
|
||||
* any preceding palette information for a valid display, 0 otherwise
|
||||
*/
|
||||
uint32_t lv_display_get_invalidated_draw_buf_size(lv_display_t * disp, uint32_t width, uint32_t height);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/*------------------------------------------------
|
||||
* To improve backward compatibility
|
||||
* Recommended only if you have one display
|
||||
*------------------------------------------------*/
|
||||
|
||||
#ifndef LV_HOR_RES
|
||||
/**
|
||||
* The horizontal resolution of the currently active display.
|
||||
*/
|
||||
#define LV_HOR_RES lv_display_get_horizontal_resolution(lv_display_get_default())
|
||||
#endif
|
||||
|
||||
#ifndef LV_VER_RES
|
||||
/**
|
||||
* The vertical resolution of the currently active display.
|
||||
*/
|
||||
#define LV_VER_RES lv_display_get_vertical_resolution(lv_display_get_default())
|
||||
#endif
|
||||
|
||||
/**
|
||||
* See `lv_dpx()` and `lv_display_dpx()`.
|
||||
* Same as Android's DIP. (Different name is chosen to avoid mistype between LV_DPI and LV_DIP)
|
||||
*
|
||||
* - 40 dip is 40 px on a 160 DPI screen (distance = 1/4 inch).
|
||||
* - 40 dip is 80 px on a 320 DPI screen (distance still = 1/4 inch).
|
||||
*
|
||||
* @sa https://stackoverflow.com/questions/2025282/what-is-the-difference-between-px-dip-dp-and-sp
|
||||
*/
|
||||
#define LV_DPX_CALC(dpi, n) ((n) == 0 ? 0 :LV_MAX((( (dpi) * (n) + 80) / 160), 1)) /*+80 for rounding*/
|
||||
#define LV_DPX(n) LV_DPX_CALC(lv_display_get_dpi(NULL), n)
|
||||
|
||||
/**
|
||||
* For default display, computes the number of pixels (a distance or size) as if the
|
||||
* display had 160 DPI. This allows you to specify 1/160-th fractions of an inch to
|
||||
* get real distance on the display that will be consistent regardless of its current
|
||||
* DPI. It ensures `lv_dpx(100)`, for example, will have the same physical size
|
||||
* regardless to the DPI of the display.
|
||||
* @param n number of 1/160-th-inch units to compute with
|
||||
* @return number of pixels to use to make that distance
|
||||
*/
|
||||
int32_t lv_dpx(int32_t n);
|
||||
|
||||
/**
|
||||
* For specified display, computes the number of pixels (a distance or size) as if the
|
||||
* display had 160 DPI. This allows you to specify 1/160-th fractions of an inch to
|
||||
* get real distance on the display that will be consistent regardless of its current
|
||||
* DPI. It ensures `lv_dpx(100)`, for example, will have the same physical size
|
||||
* regardless to the DPI of the display.
|
||||
* @param disp pointer to display whose dpi should be considered
|
||||
* @param n number of 1/160-th-inch units to compute with
|
||||
* @return number of pixels to use to make that distance
|
||||
*/
|
||||
int32_t lv_display_dpx(const lv_display_t * disp, int32_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DISPLAY_H*/
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file lv_display_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DISPLAY_PRIVATE_H
|
||||
#define LV_DISPLAY_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../draw/lv_draw.h"
|
||||
#include "lv_display.h"
|
||||
|
||||
#if LV_USE_SYSMON
|
||||
#include "../others/sysmon/lv_sysmon_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifndef LV_INV_BUF_SIZE
|
||||
#define LV_INV_BUF_SIZE 32 /**< Buffer size for invalid areas */
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_display_t {
|
||||
|
||||
/*---------------------
|
||||
* Resolution
|
||||
*--------------------*/
|
||||
|
||||
/** Horizontal resolution.*/
|
||||
int32_t hor_res;
|
||||
|
||||
/** Vertical resolution.*/
|
||||
int32_t ver_res;
|
||||
|
||||
/** Horizontal resolution of the full / physical display. Set to -1 for fullscreen mode.*/
|
||||
int32_t physical_hor_res;
|
||||
|
||||
/** Vertical resolution of the full / physical display. Set to -1 for fullscreen mode.*/
|
||||
int32_t physical_ver_res;
|
||||
|
||||
/** Horizontal offset from the full / physical display. Set to 0 for fullscreen mode.*/
|
||||
int32_t offset_x;
|
||||
|
||||
/** Vertical offset from the full / physical display. Set to 0 for fullscreen mode.*/
|
||||
int32_t offset_y;
|
||||
|
||||
/** DPI (dot per inch) of the display. Default value is `LV_DPI_DEF`.*/
|
||||
uint32_t dpi;
|
||||
|
||||
/*---------------------
|
||||
* Buffering
|
||||
*--------------------*/
|
||||
lv_draw_buf_t * buf_1;
|
||||
lv_draw_buf_t * buf_2;
|
||||
lv_draw_buf_t * buf_3;
|
||||
|
||||
/** Internal, used by the library*/
|
||||
lv_draw_buf_t * buf_act;
|
||||
|
||||
/** MANDATORY: Write the internal buffer (draw_buf) to the display. 'lv_display_flush_ready()' has to be
|
||||
* called when finished*/
|
||||
lv_display_flush_cb_t flush_cb;
|
||||
|
||||
/**
|
||||
* Used to wait while flushing is ready.
|
||||
* It can do any complex logic to wait, including semaphores, mutexes, polling flags, etc.
|
||||
* If not set `flushing` flag is used which can be cleared with `lv_display_flush_ready()` */
|
||||
lv_display_flush_wait_cb_t flush_wait_cb;
|
||||
|
||||
/** 1: flushing is in progress. (It can't be a bit field because when it's cleared from IRQ
|
||||
* Read-Modify-Write issue might occur) */
|
||||
volatile int flushing;
|
||||
|
||||
/** 1: It was the last chunk to flush. (It can't be a bit field because when it's cleared
|
||||
* from IRQ Read-Modify-Write issue might occur) */
|
||||
volatile int flushing_last;
|
||||
volatile uint32_t last_area : 1; /**< 1: last area is being rendered */
|
||||
volatile uint32_t last_part : 1; /**< 1: last part of the current area is being rendered */
|
||||
|
||||
lv_display_render_mode_t render_mode;
|
||||
uint32_t antialiasing : 1; /**< 1: anti-aliasing is enabled on this display.*/
|
||||
uint32_t tile_cnt : 8; /**< Divide the display buffer into these number of tiles */
|
||||
uint32_t stride_is_auto : 1; /**< 1: The stride of the buffers was not set explicitly. */
|
||||
|
||||
|
||||
/** 1: The current screen rendering is in progress*/
|
||||
uint32_t rendering_in_progress : 1;
|
||||
|
||||
lv_color_format_t color_format;
|
||||
|
||||
/** Invalidated (marked to redraw) areas*/
|
||||
lv_area_t inv_areas[LV_INV_BUF_SIZE];
|
||||
uint8_t inv_area_joined[LV_INV_BUF_SIZE];
|
||||
uint32_t inv_p;
|
||||
int32_t inv_en_cnt;
|
||||
|
||||
/** Double buffer sync areas (redrawn during last refresh) */
|
||||
lv_ll_t sync_areas;
|
||||
|
||||
lv_draw_buf_t _static_buf1; /**< Used when user pass in a raw buffer as display draw buffer */
|
||||
lv_draw_buf_t _static_buf2;
|
||||
/*---------------------
|
||||
* Layer
|
||||
*--------------------*/
|
||||
lv_layer_t * layer_head;
|
||||
void (*layer_init)(lv_display_t * disp, lv_layer_t * layer);
|
||||
void (*layer_deinit)(lv_display_t * disp, lv_layer_t * layer);
|
||||
|
||||
/*---------------------
|
||||
* Screens
|
||||
*--------------------*/
|
||||
|
||||
/** Screens of the display*/
|
||||
lv_obj_t ** screens; /**< Array of screen objects.*/
|
||||
lv_obj_t * sys_layer; /**< @see lv_display_get_layer_sys*/
|
||||
lv_obj_t * top_layer; /**< @see lv_display_get_layer_top*/
|
||||
lv_obj_t * act_scr; /**< Currently active screen on this display*/
|
||||
lv_obj_t * bottom_layer;/**< @see lv_display_get_layer_bottom*/
|
||||
lv_obj_t * prev_scr; /**< Previous screen. Used during screen animations*/
|
||||
lv_obj_t * scr_to_load; /**< The screen prepared to load in lv_screen_load_anim*/
|
||||
uint32_t screen_cnt;
|
||||
uint8_t draw_prev_over_act : 1;/** 1: Draw previous screen over active screen*/
|
||||
uint8_t del_prev : 1; /** 1: Automatically delete the previous screen when the screen load animation is ready*/
|
||||
|
||||
/*---------------------
|
||||
* Others
|
||||
*--------------------*/
|
||||
|
||||
void * driver_data; /**< Custom user data*/
|
||||
|
||||
void * user_data; /**< Custom user data*/
|
||||
|
||||
lv_event_list_t event_list;
|
||||
|
||||
uint32_t rotation : 3; /**< Element of lv_display_rotation_t*/
|
||||
|
||||
uint32_t matrix_rotation : 1; /**< 1: Use matrix for display rotation*/
|
||||
|
||||
lv_theme_t * theme; /**< The theme assigned to the screen*/
|
||||
|
||||
/** A timer which periodically checks the dirty areas and refreshes them*/
|
||||
lv_timer_t * refr_timer;
|
||||
|
||||
/*Miscellaneous data*/
|
||||
uint32_t last_activity_time; /**< Last time when there was activity on this display*/
|
||||
|
||||
/** The area being refreshed*/
|
||||
lv_area_t refreshed_area;
|
||||
uint32_t vsync_count;
|
||||
|
||||
#if LV_USE_PERF_MONITOR
|
||||
lv_obj_t * perf_label;
|
||||
lv_sysmon_backend_data_t perf_sysmon_backend;
|
||||
lv_sysmon_perf_info_t perf_sysmon_info;
|
||||
#endif
|
||||
|
||||
#if LV_USE_MEM_MONITOR
|
||||
lv_obj_t * mem_label;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DISPLAY_PRIVATE_H*/
|
||||
@@ -0,0 +1,472 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d_private.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
#include "../sw/lv_draw_sw.h"
|
||||
#include "../../misc/lv_area_private.h"
|
||||
|
||||
#if !LV_DRAW_DMA2D_ASYNC && LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
#warning LV_USE_DRAW_DMA2D_INTERRUPT is 1 but has no effect because LV_USE_OS is LV_OS_NONE
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_DMA2D 5
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static int32_t evaluate_cb(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
static int32_t dispatch_cb(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
static int32_t delete_cb(lv_draw_unit_t * draw_unit);
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
static void thread_cb(void * arg);
|
||||
#endif
|
||||
#if !LV_DRAW_DMA2D_ASYNC
|
||||
static bool check_transfer_completion(void);
|
||||
#endif
|
||||
static void post_transfer_tasks(lv_draw_dma2d_unit_t * u);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
static lv_draw_dma2d_unit_t * g_unit;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_init(void)
|
||||
{
|
||||
lv_draw_dma2d_unit_t * draw_dma2d_unit = lv_draw_create_unit(sizeof(lv_draw_dma2d_unit_t));
|
||||
draw_dma2d_unit->base_unit.evaluate_cb = evaluate_cb;
|
||||
draw_dma2d_unit->base_unit.dispatch_cb = dispatch_cb;
|
||||
draw_dma2d_unit->base_unit.delete_cb = delete_cb;
|
||||
draw_dma2d_unit->base_unit.name = "DMA2D";
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
g_unit = draw_dma2d_unit;
|
||||
|
||||
lv_result_t res = lv_thread_init(&draw_dma2d_unit->thread, "dma2d", LV_DRAW_THREAD_PRIO, thread_cb, 2 * 1024,
|
||||
draw_dma2d_unit);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
#endif
|
||||
|
||||
/* enable the DMA2D clock */
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32U5)
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
|
||||
#elif defined(STM32H7)
|
||||
RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN;
|
||||
#elif defined(STM32H7RS)
|
||||
RCC->AHB5ENR |= RCC_AHB5ENR_DMA2DEN;
|
||||
#else
|
||||
#warning "LVGL can't enable the clock for DMA2D"
|
||||
#endif
|
||||
|
||||
/* disable dead time */
|
||||
DMA2D->AMTCR = 0;
|
||||
|
||||
/* enable the interrupt */
|
||||
NVIC_EnableIRQ(DMA2D_IRQn);
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_deinit(void)
|
||||
{
|
||||
/* disable the interrupt */
|
||||
NVIC_DisableIRQ(DMA2D_IRQn);
|
||||
|
||||
/* disable the DMA2D clock */
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32U5) || defined(STM32L4)
|
||||
RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA2DEN;
|
||||
#elif defined(STM32H7)
|
||||
RCC->AHB3ENR &= ~RCC_AHB3ENR_DMA2DEN;
|
||||
#elif defined(STM32H7RS)
|
||||
RCC->AHB5ENR &= ~RCC_AHB5ENR_DMA2DEN;
|
||||
#endif
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
lv_result_t res = lv_thread_delete(&g_unit->thread);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
|
||||
res = lv_thread_sync_delete(&g_unit->interrupt_signal);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
|
||||
g_unit = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
void lv_draw_dma2d_transfer_complete_interrupt_handler(void)
|
||||
{
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
lv_thread_sync_signal_isr(&g_unit->interrupt_signal);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_draw_dma2d_output_cf_t lv_draw_dma2d_cf_to_dma2d_output_cf(lv_color_format_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_ARGB8888;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_RGB888;
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_RGB565;
|
||||
case LV_COLOR_FORMAT_ARGB1555:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_ARGB1555;
|
||||
default:
|
||||
LV_ASSERT_MSG(false, "unsupported output color format");
|
||||
}
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_RGB565;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_dma2d_color_to_dma2d_color(lv_draw_dma2d_output_cf_t cf, lv_color_t color)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_DRAW_DMA2D_OUTPUT_CF_ARGB8888:
|
||||
case LV_DRAW_DMA2D_OUTPUT_CF_RGB888:
|
||||
return lv_color_to_u32(color);
|
||||
case LV_DRAW_DMA2D_OUTPUT_CF_RGB565:
|
||||
return lv_color_to_u16(color);
|
||||
default:
|
||||
LV_ASSERT_MSG(false, "unsupported output color format");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_configure_and_start_transfer(const lv_draw_dma2d_configuration_t * conf)
|
||||
{
|
||||
/* number of lines register */
|
||||
DMA2D->NLR = (conf->w << DMA2D_NLR_PL_Pos) | (conf->h << DMA2D_NLR_NL_Pos);
|
||||
|
||||
/* output */
|
||||
|
||||
/* output memory address register */
|
||||
DMA2D->OMAR = (uint32_t)(uintptr_t) conf->output_address;
|
||||
/* output offset register */
|
||||
DMA2D->OOR = conf->output_offset;
|
||||
/* output pixel format converter control register */
|
||||
DMA2D->OPFCCR = ((uint32_t) conf->output_cf) << DMA2D_OPFCCR_CM_Pos;
|
||||
|
||||
/* Fill color. Only for mode LV_DRAW_DMA2D_MODE_REGISTER_TO_MEMORY */
|
||||
DMA2D->OCOLR = conf->reg_to_mem_mode_color;
|
||||
|
||||
/* foreground */
|
||||
|
||||
/* foreground memory address register */
|
||||
DMA2D->FGMAR = (uint32_t)(uintptr_t) conf->fg_address;
|
||||
/* foreground offset register */
|
||||
DMA2D->FGOR = conf->fg_offset;
|
||||
/* foreground color. only for mem-to-mem with blending and fixed-color foreground */
|
||||
DMA2D->FGCOLR = conf->fg_color;
|
||||
/* foreground pixel format converter control register */
|
||||
DMA2D->FGPFCCR = (((uint32_t) conf->fg_cf) << DMA2D_FGPFCCR_CM_Pos)
|
||||
| (conf->fg_alpha << DMA2D_FGPFCCR_ALPHA_Pos)
|
||||
| (conf->fg_alpha_mode << DMA2D_FGPFCCR_AM_Pos);
|
||||
|
||||
/* background */
|
||||
|
||||
DMA2D->BGMAR = (uint32_t)(uintptr_t) conf->bg_address;
|
||||
DMA2D->BGOR = conf->bg_offset;
|
||||
DMA2D->BGCOLR = conf->bg_color;
|
||||
DMA2D->BGPFCCR = (((uint32_t) conf->bg_cf) << DMA2D_BGPFCCR_CM_Pos)
|
||||
| (conf->bg_alpha << DMA2D_BGPFCCR_ALPHA_Pos)
|
||||
| (conf->bg_alpha_mode << DMA2D_BGPFCCR_AM_Pos);
|
||||
|
||||
/* ensure the DMA2D register values are observed before the start transfer bit is set */
|
||||
__DSB();
|
||||
|
||||
/* start the transfer (also set mode and enable transfer complete interrupt) */
|
||||
DMA2D->CR = DMA2D_CR_START | (((uint32_t) conf->mode) << DMA2D_CR_MODE_Pos)
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
| DMA2D_CR_TCIE
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
void lv_draw_dma2d_invalidate_cache(const lv_draw_dma2d_cache_area_t * mem_area)
|
||||
{
|
||||
if((SCB->CCR & SCB_CCR_DC_Msk) == 0) return; /* data cache is disabled */
|
||||
|
||||
uint32_t rows_remaining = mem_area->height;
|
||||
uint32_t row_addr = (uint32_t)(uintptr_t) mem_area->first_byte;
|
||||
uint32_t row_end_addr = 0;
|
||||
|
||||
__DSB();
|
||||
|
||||
while(rows_remaining) {
|
||||
uint32_t addr = row_addr & ~(__SCB_DCACHE_LINE_SIZE - 1U);
|
||||
uint32_t cache_lines = ((((row_addr + mem_area->width_bytes - 1) & ~(__SCB_DCACHE_LINE_SIZE - 1U)) - addr) /
|
||||
__SCB_DCACHE_LINE_SIZE) + 1;
|
||||
|
||||
if(addr == row_end_addr) {
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
while(cache_lines) {
|
||||
SCB->DCIMVAC = addr;
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
row_end_addr = addr - __SCB_DCACHE_LINE_SIZE;
|
||||
row_addr += mem_area->stride;
|
||||
rows_remaining--;
|
||||
};
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_clean_cache(const lv_draw_dma2d_cache_area_t * mem_area)
|
||||
{
|
||||
if((SCB->CCR & SCB_CCR_DC_Msk) == 0) return; /* data cache is disabled */
|
||||
|
||||
uint32_t rows_remaining = mem_area->height;
|
||||
uint32_t row_addr = (uint32_t)(uintptr_t) mem_area->first_byte;
|
||||
uint32_t row_end_addr = 0;
|
||||
|
||||
__DSB();
|
||||
|
||||
while(rows_remaining) {
|
||||
uint32_t addr = row_addr & ~(__SCB_DCACHE_LINE_SIZE - 1U);
|
||||
uint32_t cache_lines = ((((row_addr + mem_area->width_bytes - 1) & ~(__SCB_DCACHE_LINE_SIZE - 1U)) - addr) /
|
||||
__SCB_DCACHE_LINE_SIZE) + 1;
|
||||
|
||||
if(addr == row_end_addr) {
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
while(cache_lines) {
|
||||
SCB->DCCMVAC = addr;
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
row_end_addr = addr - __SCB_DCACHE_LINE_SIZE;
|
||||
row_addr += mem_area->stride;
|
||||
rows_remaining--;
|
||||
};
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static int32_t evaluate_cb(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
|
||||
{
|
||||
switch(task->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
lv_draw_fill_dsc_t * dsc = task->draw_dsc;
|
||||
if(!(dsc->radius == 0
|
||||
&& dsc->grad.dir == LV_GRAD_DIR_NONE
|
||||
&& (dsc->base.layer->color_format == LV_COLOR_FORMAT_ARGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_XRGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB565))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t * dsc = task->draw_dsc;
|
||||
if(!(dsc->header.cf < LV_COLOR_FORMAT_PROPRIETARY_START
|
||||
&& dsc->clip_radius == 0
|
||||
&& dsc->bitmap_mask_src == NULL
|
||||
&& dsc->sup == NULL
|
||||
&& dsc->tile == 0
|
||||
&& dsc->blend_mode == LV_BLEND_MODE_NORMAL
|
||||
&& dsc->recolor_opa <= LV_OPA_MIN
|
||||
&& dsc->skew_y == 0
|
||||
&& dsc->skew_x == 0
|
||||
&& dsc->scale_x == 256
|
||||
&& dsc->scale_y == 256
|
||||
&& dsc->rotation == 0
|
||||
&& lv_image_src_get_type(dsc->src) == LV_IMAGE_SRC_VARIABLE
|
||||
&& (dsc->header.cf == LV_COLOR_FORMAT_ARGB8888
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_XRGB8888
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_RGB888
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_RGB565
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_ARGB1555)
|
||||
&& (dsc->base.layer->color_format == LV_COLOR_FORMAT_ARGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_XRGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB565))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_DMA2D;
|
||||
task->preference_score = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t dispatch_cb(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_dma2d_unit_t * draw_dma2d_unit = (lv_draw_dma2d_unit_t *) draw_unit;
|
||||
|
||||
if(draw_dma2d_unit->task_act) {
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
/*Return immediately if it's busy with draw task*/
|
||||
return 0;
|
||||
#else
|
||||
if(!check_transfer_completion()) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
post_transfer_tasks(draw_dma2d_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DMA2D);
|
||||
if(t == NULL) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
void * buf = lv_draw_layer_alloc_buf(layer);
|
||||
if(buf == NULL) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
t->draw_unit = draw_unit;
|
||||
draw_dma2d_unit->task_act = t;
|
||||
|
||||
if(t->type == LV_DRAW_TASK_TYPE_FILL) {
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
const lv_area_t * coords = &t->area;
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, coords, &t->clip_area)) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
void * dest = lv_draw_layer_go_to_xy(layer,
|
||||
clipped_coords.x1 - layer->buf_area.x1,
|
||||
clipped_coords.y1 - layer->buf_area.y1);
|
||||
|
||||
if(dsc->opa >= LV_OPA_MAX) {
|
||||
lv_draw_dma2d_opaque_fill(t,
|
||||
dest,
|
||||
lv_area_get_width(&clipped_coords),
|
||||
lv_area_get_height(&clipped_coords),
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
else {
|
||||
lv_draw_dma2d_fill(t,
|
||||
dest,
|
||||
lv_area_get_width(&clipped_coords),
|
||||
lv_area_get_height(&clipped_coords),
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
}
|
||||
else if(t->type == LV_DRAW_TASK_TYPE_IMAGE) {
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
const lv_area_t * coords = &t->area;
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, coords, &t->clip_area)) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
void * dest = lv_draw_layer_go_to_xy(layer,
|
||||
clipped_coords.x1 - layer->buf_area.x1,
|
||||
clipped_coords.y1 - layer->buf_area.y1);
|
||||
|
||||
if(dsc->opa >= LV_OPA_MAX) {
|
||||
lv_draw_dma2d_opaque_image(
|
||||
t,
|
||||
dest,
|
||||
&clipped_coords,
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
else {
|
||||
lv_draw_dma2d_image(
|
||||
t,
|
||||
dest,
|
||||
&clipped_coords,
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
}
|
||||
|
||||
#if !LV_DRAW_DMA2D_ASYNC
|
||||
lv_draw_dispatch_request();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t delete_cb(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
static void thread_cb(void * arg)
|
||||
{
|
||||
lv_draw_dma2d_unit_t * u = arg;
|
||||
|
||||
lv_thread_sync_init(&u->interrupt_signal);
|
||||
|
||||
while(1) {
|
||||
|
||||
do {
|
||||
lv_thread_sync_wait(&u->interrupt_signal);
|
||||
} while(u->task_act != NULL);
|
||||
|
||||
post_transfer_tasks(u);
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !LV_DRAW_DMA2D_ASYNC
|
||||
static bool check_transfer_completion(void)
|
||||
{
|
||||
return !(DMA2D->CR & DMA2D_CR_START);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void post_transfer_tasks(lv_draw_dma2d_unit_t * u)
|
||||
{
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_invalidate_cache(&u->writing_area);
|
||||
#endif
|
||||
u->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
u->task_act = NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_DMA2D_H
|
||||
#define LV_DRAW_DMA2D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_init(void);
|
||||
void lv_draw_dma2d_deinit(void);
|
||||
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
void lv_draw_dma2d_transfer_complete_interrupt_handler(void);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_DMA2D_H*/
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d_private.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_opaque_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride)
|
||||
{
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_format_t cf = dsc->base.layer->color_format;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf = lv_draw_dma2d_cf_to_dma2d_output_cf(cf);
|
||||
uint32_t cf_size = LV_COLOR_FORMAT_GET_SIZE(cf);
|
||||
uint32_t reg_to_mem_color = lv_draw_dma2d_color_to_dma2d_color(output_cf, dsc->color);
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t cache_area = {
|
||||
.first_byte = first_pixel,
|
||||
.width_bytes = w * cf_size,
|
||||
.height = h,
|
||||
.stride = stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &cache_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
#endif
|
||||
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_REGISTER_TO_MEMORY,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = first_pixel,
|
||||
.output_offset = (stride / cf_size) - w,
|
||||
.output_cf = output_cf,
|
||||
|
||||
.reg_to_mem_mode_color = reg_to_mem_color
|
||||
};
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride)
|
||||
{
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_t color = dsc->color;
|
||||
lv_color_format_t cf = dsc->base.layer->color_format;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf = lv_draw_dma2d_cf_to_dma2d_output_cf(cf);
|
||||
uint32_t cf_size = LV_COLOR_FORMAT_GET_SIZE(cf);
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t cache_area = {
|
||||
.first_byte = first_pixel,
|
||||
.width_bytes = w * cf_size,
|
||||
.height = h,
|
||||
.stride = stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &cache_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
|
||||
/* make sure the background area DMA2D is blending is up-to-date in main memory */
|
||||
lv_draw_dma2d_clean_cache(&cache_area);
|
||||
#endif
|
||||
|
||||
uint32_t output_offset = (stride / cf_size) - w;
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING_AND_FIXED_COLOR_FG,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = first_pixel,
|
||||
.output_offset = output_offset,
|
||||
.output_cf = output_cf,
|
||||
|
||||
.fg_color = lv_color_to_u32(color),
|
||||
.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL,
|
||||
.fg_alpha = opa,
|
||||
|
||||
.bg_address = first_pixel,
|
||||
.bg_offset = output_offset,
|
||||
.bg_cf = (lv_draw_dma2d_fgbg_cf_t) output_cf
|
||||
};
|
||||
|
||||
/* Background alpha channel should be treated as 0xFF if the cf is XRGB */
|
||||
if(cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.bg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.bg_alpha = 0xff;
|
||||
}
|
||||
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d_image.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d_private.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_opaque_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride)
|
||||
{
|
||||
int32_t w = lv_area_get_width(clipped_coords);
|
||||
int32_t h = lv_area_get_height(clipped_coords);
|
||||
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_format_t output_cf = dsc->base.layer->color_format;
|
||||
lv_color_format_t image_cf = dsc->header.cf;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf_dma2d = lv_draw_dma2d_cf_to_dma2d_output_cf(output_cf);
|
||||
uint32_t output_cf_size = LV_COLOR_FORMAT_GET_SIZE(output_cf);
|
||||
|
||||
lv_draw_dma2d_fgbg_cf_t image_cf_dma2d = (lv_draw_dma2d_fgbg_cf_t) lv_draw_dma2d_cf_to_dma2d_output_cf(image_cf);
|
||||
uint32_t image_cf_size = LV_COLOR_FORMAT_GET_SIZE(image_cf);
|
||||
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
uint32_t image_stride = img_dsc->header.stride;
|
||||
if(image_stride == 0) image_stride = image_cf_size * img_dsc->header.w;
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t dest_area = {
|
||||
.first_byte = dest_first_pixel,
|
||||
.width_bytes = w * output_cf_size,
|
||||
.height = h,
|
||||
.stride = dest_stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &dest_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
if(lv_color_format_has_alpha(image_cf)) {
|
||||
/* make sure the background area DMA2D is blending is up-to-date in main memory */
|
||||
lv_draw_dma2d_clean_cache(&dest_area);
|
||||
}
|
||||
#endif
|
||||
|
||||
const void * image_first_byte = img_dsc->data
|
||||
+ (image_stride * (clipped_coords->y1 - dsc->image_area.y1))
|
||||
+ (image_cf_size * (clipped_coords->x1 - dsc->image_area.x1));
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t src_area = {
|
||||
.first_byte = image_first_byte,
|
||||
.width_bytes = w * image_cf_size,
|
||||
.height = h,
|
||||
.stride = image_stride
|
||||
};
|
||||
/* make sure the image area is up-to-date in main memory for DMA2D */
|
||||
lv_draw_dma2d_clean_cache(&src_area);
|
||||
#endif
|
||||
|
||||
uint32_t output_offset = (dest_stride / output_cf_size) - w;
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_PFC,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = dest_first_pixel,
|
||||
.output_offset = output_offset,
|
||||
.output_cf = output_cf_dma2d,
|
||||
|
||||
.fg_address = image_first_byte,
|
||||
.fg_offset = (image_stride / image_cf_size) - w,
|
||||
.fg_cf = image_cf_dma2d
|
||||
};
|
||||
|
||||
/* only process the background if the image might be transparent */
|
||||
if(lv_color_format_has_alpha(image_cf)) {
|
||||
conf.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING;
|
||||
|
||||
conf.bg_address = dest_first_pixel;
|
||||
conf.bg_offset = output_offset;
|
||||
conf.bg_cf = output_cf_dma2d;
|
||||
}
|
||||
|
||||
/* Alpha channel should be treated as 0xFF if the cf is XRGB */
|
||||
if(image_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.fg_alpha = 0xff;
|
||||
}
|
||||
if(output_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.bg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.bg_alpha = 0xff;
|
||||
}
|
||||
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride)
|
||||
{
|
||||
int32_t w = lv_area_get_width(clipped_coords);
|
||||
int32_t h = lv_area_get_height(clipped_coords);
|
||||
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_format_t output_cf = dsc->base.layer->color_format;
|
||||
lv_color_format_t image_cf = dsc->header.cf;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf_dma2d = lv_draw_dma2d_cf_to_dma2d_output_cf(output_cf);
|
||||
uint32_t output_cf_size = LV_COLOR_FORMAT_GET_SIZE(output_cf);
|
||||
|
||||
lv_draw_dma2d_fgbg_cf_t image_cf_dma2d = (lv_draw_dma2d_fgbg_cf_t) lv_draw_dma2d_cf_to_dma2d_output_cf(image_cf);
|
||||
uint32_t image_cf_size = LV_COLOR_FORMAT_GET_SIZE(image_cf);
|
||||
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
uint32_t image_stride = img_dsc->header.stride;
|
||||
if(image_stride == 0) image_stride = image_cf_size * img_dsc->header.w;
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t dest_area = {
|
||||
.first_byte = dest_first_pixel,
|
||||
.width_bytes = w * output_cf_size,
|
||||
.height = h,
|
||||
.stride = dest_stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &dest_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
/* make sure the background area DMA2D is blending is up-to-date in main memory */
|
||||
lv_draw_dma2d_clean_cache(&dest_area);
|
||||
#endif
|
||||
|
||||
const void * image_first_byte = img_dsc->data
|
||||
+ (image_stride * (clipped_coords->y1 - dsc->image_area.y1))
|
||||
+ (image_cf_size * (clipped_coords->x1 - dsc->image_area.x1));
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t src_area = {
|
||||
.first_byte = image_first_byte,
|
||||
.width_bytes = w * image_cf_size,
|
||||
.height = h,
|
||||
.stride = image_stride
|
||||
};
|
||||
/* make sure the image area is up-to-date in main memory for DMA2D */
|
||||
lv_draw_dma2d_clean_cache(&src_area);
|
||||
#endif
|
||||
|
||||
uint32_t output_offset = (dest_stride / output_cf_size) - w;
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = dest_first_pixel,
|
||||
.output_offset = output_offset,
|
||||
.output_cf = output_cf_dma2d,
|
||||
|
||||
.fg_address = image_first_byte,
|
||||
.fg_offset = (image_stride / image_cf_size) - w,
|
||||
.fg_cf = image_cf_dma2d,
|
||||
.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_MULTIPLY_IMAGE_ALPHA_CHANNEL,
|
||||
.fg_alpha = opa,
|
||||
|
||||
.bg_address = dest_first_pixel,
|
||||
.bg_offset = output_offset,
|
||||
.bg_cf = output_cf_dma2d,
|
||||
};
|
||||
|
||||
/* Alpha channel should be treated as 0xFF if the cf is XRGB */
|
||||
if(image_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
}
|
||||
if(output_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.bg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.bg_alpha = 0xff;
|
||||
}
|
||||
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_DMA2D_PRIVATE_H
|
||||
#define LV_DRAW_DMA2D_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
#include "../lv_draw_private.h"
|
||||
#include "../sw/lv_draw_sw.h"
|
||||
#include LV_DRAW_DMA2D_HAL_INCLUDE
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT && LV_USE_OS
|
||||
#define LV_DRAW_DMA2D_ASYNC 1
|
||||
#else
|
||||
#define LV_DRAW_DMA2D_ASYNC 0
|
||||
#endif
|
||||
|
||||
#if defined(__CORTEX_M) && (__CORTEX_M == 7)
|
||||
#define LV_DRAW_DMA2D_CACHE 1
|
||||
#else
|
||||
#define LV_DRAW_DMA2D_CACHE 0
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_ARGB8888 = 0,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_RGB888,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_RGB565,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_ARGB1555,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_ARGB4444
|
||||
} lv_draw_dma2d_output_cf_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_FGBG_CF_ARGB8888 = 0,
|
||||
LV_DRAW_DMA2D_FGBG_CF_RGB888,
|
||||
LV_DRAW_DMA2D_FGBG_CF_RGB565,
|
||||
LV_DRAW_DMA2D_FGBG_CF_ARGB1555,
|
||||
LV_DRAW_DMA2D_FGBG_CF_ARGB4444,
|
||||
LV_DRAW_DMA2D_FGBG_CF_L8,
|
||||
LV_DRAW_DMA2D_FGBG_CF_AL44,
|
||||
LV_DRAW_DMA2D_FGBG_CF_AL88,
|
||||
LV_DRAW_DMA2D_FGBG_CF_L4,
|
||||
LV_DRAW_DMA2D_FGBG_CF_A8,
|
||||
LV_DRAW_DMA2D_FGBG_CF_A4,
|
||||
LV_DRAW_DMA2D_FGBG_CF_YCBCR
|
||||
} lv_draw_dma2d_fgbg_cf_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY = 0,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_PFC,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING,
|
||||
LV_DRAW_DMA2D_MODE_REGISTER_TO_MEMORY,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING_AND_FIXED_COLOR_FG,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING_AND_FIXED_COLOR_BG
|
||||
} lv_draw_dma2d_mode_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_ALPHA_MODE_NO_MODIFY_IMAGE_ALPHA_CHANNEL = 0,
|
||||
LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL,
|
||||
LV_DRAW_DMA2D_ALPHA_MODE_MULTIPLY_IMAGE_ALPHA_CHANNEL
|
||||
} lv_draw_dma2d_alpha_mode_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dma2d_mode_t mode;
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
|
||||
void * output_address;
|
||||
uint32_t output_offset;
|
||||
lv_draw_dma2d_output_cf_t output_cf;
|
||||
|
||||
uint32_t reg_to_mem_mode_color;
|
||||
|
||||
const void * fg_address;
|
||||
uint32_t fg_offset;
|
||||
lv_draw_dma2d_fgbg_cf_t fg_cf;
|
||||
uint32_t fg_color;
|
||||
uint32_t fg_alpha_mode;
|
||||
uint32_t fg_alpha;
|
||||
|
||||
const void * bg_address;
|
||||
uint32_t bg_offset;
|
||||
lv_draw_dma2d_fgbg_cf_t bg_cf;
|
||||
uint32_t bg_color;
|
||||
uint32_t bg_alpha_mode;
|
||||
uint32_t bg_alpha;
|
||||
|
||||
} lv_draw_dma2d_configuration_t;
|
||||
|
||||
typedef struct {
|
||||
const void * first_byte;
|
||||
uint32_t width_bytes;
|
||||
uint32_t height;
|
||||
uint32_t stride;
|
||||
} lv_draw_dma2d_cache_area_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_unit_t base_unit;
|
||||
lv_draw_task_t * volatile task_act;
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t writing_area;
|
||||
#endif
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
lv_thread_t thread;
|
||||
lv_thread_sync_t interrupt_signal;
|
||||
#endif
|
||||
} lv_draw_dma2d_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_opaque_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride);
|
||||
void lv_draw_dma2d_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride);
|
||||
void lv_draw_dma2d_opaque_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride);
|
||||
void lv_draw_dma2d_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride);
|
||||
lv_draw_dma2d_output_cf_t lv_draw_dma2d_cf_to_dma2d_output_cf(lv_color_format_t cf);
|
||||
uint32_t lv_draw_dma2d_color_to_dma2d_color(lv_draw_dma2d_output_cf_t cf, lv_color_t color);
|
||||
void lv_draw_dma2d_configure_and_start_transfer(const lv_draw_dma2d_configuration_t * conf);
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
void lv_draw_dma2d_invalidate_cache(const lv_draw_dma2d_cache_area_t * mem_area);
|
||||
void lv_draw_dma2d_clean_cache(const lv_draw_dma2d_cache_area_t * mem_area);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_DMA2D_PRIVATE_H*/
|
||||
@@ -0,0 +1,683 @@
|
||||
/**
|
||||
* @file lv_draw.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modified by NXP in 2024
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "lv_draw_mask_private.h"
|
||||
#include "lv_draw_vector_private.h"
|
||||
#include "lv_draw_3d.h"
|
||||
#include "sw/lv_draw_sw.h"
|
||||
#include "../display/lv_display_private.h"
|
||||
#include "../core/lv_global.h"
|
||||
#include "../core/lv_refr_private.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define _draw_info LV_GLOBAL_DEFAULT()->draw_info
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool is_independent(lv_layer_t * layer, lv_draw_task_t * t_check);
|
||||
static void cleanup_task(lv_draw_task_t * t, lv_display_t * disp);
|
||||
static inline size_t get_draw_dsc_size(lv_draw_task_type_t type);
|
||||
static lv_draw_task_t * get_first_available_task(lv_layer_t * layer);
|
||||
|
||||
#if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO
|
||||
static inline uint32_t get_layer_size_kb(uint32_t size_byte)
|
||||
{
|
||||
return (size_byte + 1023) >> 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_init(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_init(&_draw_info.sync);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_deinit(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_delete(&_draw_info.sync);
|
||||
#endif
|
||||
|
||||
lv_draw_unit_t * u = _draw_info.unit_head;
|
||||
while(u) {
|
||||
lv_draw_unit_t * cur_unit = u;
|
||||
u = u->next;
|
||||
|
||||
if(cur_unit->delete_cb) cur_unit->delete_cb(cur_unit);
|
||||
lv_free(cur_unit);
|
||||
}
|
||||
_draw_info.unit_head = NULL;
|
||||
}
|
||||
|
||||
void * lv_draw_create_unit(size_t size)
|
||||
{
|
||||
lv_draw_unit_t * new_unit = lv_malloc_zeroed(size);
|
||||
LV_ASSERT_MALLOC(new_unit);
|
||||
new_unit->next = _draw_info.unit_head;
|
||||
|
||||
_draw_info.unit_head = new_unit;
|
||||
_draw_info.unit_cnt++;
|
||||
|
||||
new_unit->idx = _draw_info.unit_cnt;
|
||||
|
||||
return new_unit;
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords, lv_draw_task_type_t type)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
size_t dsc_size = get_draw_dsc_size(type);
|
||||
LV_ASSERT_FORMAT_MSG(dsc_size > 0, "Draw task size is 0 for type %d", type);
|
||||
lv_draw_task_t * new_task = lv_malloc_zeroed(LV_ALIGN_UP(sizeof(lv_draw_task_t), 8) + dsc_size);
|
||||
LV_ASSERT_MALLOC(new_task);
|
||||
new_task->area = *coords;
|
||||
new_task->_real_area = *coords;
|
||||
new_task->target_layer = layer;
|
||||
new_task->clip_area = layer->_clip_area;
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
new_task->matrix = layer->matrix;
|
||||
#endif
|
||||
new_task->type = type;
|
||||
new_task->draw_dsc = (uint8_t *)new_task + LV_ALIGN_UP(sizeof(lv_draw_task_t), 8);
|
||||
new_task->state = LV_DRAW_TASK_STATE_QUEUED;
|
||||
|
||||
/*Find the tail*/
|
||||
if(layer->draw_task_head == NULL) {
|
||||
layer->draw_task_head = new_task;
|
||||
}
|
||||
else {
|
||||
lv_draw_task_t * tail = layer->draw_task_head;
|
||||
while(tail->next) tail = tail->next;
|
||||
|
||||
tail->next = new_task;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return new_task;
|
||||
}
|
||||
|
||||
void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_dsc_base_t * base_dsc = t->draw_dsc;
|
||||
base_dsc->layer = layer;
|
||||
|
||||
lv_draw_global_info_t * info = &_draw_info;
|
||||
|
||||
/*Send LV_EVENT_DRAW_TASK_ADDED and dispatch only on the "main" draw_task
|
||||
*and not on the draw tasks added in the event.
|
||||
*Sending LV_EVENT_DRAW_TASK_ADDED events might cause recursive event sends and besides
|
||||
*dispatching might remove the "main" draw task while it's still being used in the event*/
|
||||
|
||||
if(info->task_running == false) {
|
||||
if(base_dsc->obj && lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) {
|
||||
info->task_running = true;
|
||||
lv_obj_send_event(base_dsc->obj, LV_EVENT_DRAW_TASK_ADDED, t);
|
||||
info->task_running = false;
|
||||
}
|
||||
|
||||
/*Let the draw units set their preference score*/
|
||||
t->preference_score = 100;
|
||||
t->preferred_draw_unit_id = 0;
|
||||
lv_draw_unit_t * u = info->unit_head;
|
||||
while(u) {
|
||||
if(u->evaluate_cb) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("evaluate_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
u->evaluate_cb(u, t);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("evaluate_cb");
|
||||
}
|
||||
u = u->next;
|
||||
}
|
||||
if(t->preferred_draw_unit_id == LV_DRAW_UNIT_NONE) {
|
||||
LV_LOG_WARN("the draw task was not taken by any units");
|
||||
t->state = LV_DRAW_TASK_STATE_READY;
|
||||
}
|
||||
else {
|
||||
lv_draw_dispatch();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Let the draw units set their preference score*/
|
||||
t->preference_score = 100;
|
||||
t->preferred_draw_unit_id = 0;
|
||||
lv_draw_unit_t * u = info->unit_head;
|
||||
while(u) {
|
||||
if(u->evaluate_cb) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("evaluate_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
u->evaluate_cb(u, t);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("evaluate_cb");
|
||||
}
|
||||
u = u->next;
|
||||
}
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_wait_for_finish(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_unit_t * u = _draw_info.unit_head;
|
||||
while(u) {
|
||||
if(u->wait_for_finish_cb) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("wait_for_finish_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
u->wait_for_finish_cb(u);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("wait_for_finish_cb");
|
||||
}
|
||||
u = u->next;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_dispatch(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool task_dispatched = false;
|
||||
lv_display_t * disp = lv_display_get_next(NULL);
|
||||
while(disp) {
|
||||
lv_layer_t * layer = disp->layer_head;
|
||||
while(layer) {
|
||||
if(lv_draw_dispatch_layer(disp, layer))
|
||||
task_dispatched = true;
|
||||
layer = layer->next;
|
||||
}
|
||||
if(!task_dispatched) {
|
||||
lv_draw_wait_for_finish();
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
disp = lv_display_get_next(disp);
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
bool lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/*Remove the finished tasks first*/
|
||||
lv_draw_task_t * t_prev = NULL;
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
lv_draw_task_t * t_next;
|
||||
bool remove_task = false;
|
||||
while(t) {
|
||||
t_next = t->next;
|
||||
if(t->state == LV_DRAW_TASK_STATE_READY) {
|
||||
cleanup_task(t, disp);
|
||||
remove_task = true;
|
||||
if(t_prev != NULL)
|
||||
t_prev->next = t_next;
|
||||
else
|
||||
layer->draw_task_head = t_next;
|
||||
}
|
||||
else {
|
||||
t_prev = t;
|
||||
}
|
||||
t = t_next;
|
||||
}
|
||||
|
||||
bool task_dispatched = false;
|
||||
|
||||
/*This layer is ready, enable blending its buffer*/
|
||||
if(layer->parent && layer->all_tasks_added && layer->draw_task_head == NULL) {
|
||||
/*Find a draw task with TYPE_LAYER in the layer where the src is this layer*/
|
||||
lv_draw_task_t * t_src = layer->parent->draw_task_head;
|
||||
while(t_src) {
|
||||
if(t_src->type == LV_DRAW_TASK_TYPE_LAYER && t_src->state == LV_DRAW_TASK_STATE_WAITING) {
|
||||
lv_draw_image_dsc_t * draw_dsc = t_src->draw_dsc;
|
||||
if(draw_dsc->src == layer) {
|
||||
t_src->state = LV_DRAW_TASK_STATE_QUEUED;
|
||||
lv_draw_dispatch_request();
|
||||
break;
|
||||
}
|
||||
}
|
||||
t_src = t_src->next;
|
||||
}
|
||||
}
|
||||
/*Assign draw tasks to the draw_units*/
|
||||
else if(remove_task || layer->draw_task_head) {
|
||||
/*Find a draw unit which is not busy and can take at least one task*/
|
||||
/*Let all draw units to pick draw tasks*/
|
||||
lv_draw_unit_t * u = _draw_info.unit_head;
|
||||
while(u) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("dispatch_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
int32_t taken_cnt = u->dispatch_cb(u, layer);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("dispatch_cb");
|
||||
if(taken_cnt != LV_DRAW_UNIT_IDLE) task_dispatched = true;
|
||||
u = u->next;
|
||||
}
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return task_dispatched;
|
||||
}
|
||||
|
||||
void lv_draw_dispatch_wait_for_request(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_wait(&_draw_info.sync);
|
||||
#else
|
||||
while(!_draw_info.dispatch_req);
|
||||
_draw_info.dispatch_req = 0;
|
||||
#endif
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_dispatch_request(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_signal(&_draw_info.sync);
|
||||
#else
|
||||
_draw_info.dispatch_req = 1;
|
||||
#endif
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_get_unit_count(void)
|
||||
{
|
||||
return _draw_info.unit_cnt;
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id)
|
||||
{
|
||||
if(_draw_info.unit_cnt == 1) {
|
||||
return get_first_available_task(layer);
|
||||
}
|
||||
else {
|
||||
return lv_draw_get_next_available_task(layer, t_prev, draw_unit_id);
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
/*If the first task is screen sized, there cannot be independent areas*/
|
||||
if(layer->draw_task_head) {
|
||||
int32_t hor_res = lv_display_get_horizontal_resolution(lv_refr_get_disp_refreshing());
|
||||
int32_t ver_res = lv_display_get_vertical_resolution(lv_refr_get_disp_refreshing());
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
if(t->state != LV_DRAW_TASK_STATE_QUEUED &&
|
||||
t->area.x1 <= 0 && t->area.x2 >= hor_res - 1 &&
|
||||
t->area.y1 <= 0 && t->area.y2 >= ver_res - 1) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_task_t * t = t_prev ? t_prev->next : layer->draw_task_head;
|
||||
while(t) {
|
||||
/*Find a queued and independent task*/
|
||||
if(t->state == LV_DRAW_TASK_STATE_QUEUED &&
|
||||
(t->preferred_draw_unit_id == LV_DRAW_UNIT_NONE || t->preferred_draw_unit_id == draw_unit_id) &&
|
||||
is_independent(layer, t)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return t;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_get_dependent_count(lv_draw_task_t * t_check)
|
||||
{
|
||||
if(t_check == NULL) return 0;
|
||||
if(t_check->next == NULL) return 0;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
uint32_t cnt = 0;
|
||||
|
||||
lv_draw_task_t * t = t_check->next;
|
||||
while(t) {
|
||||
if((t->state == LV_DRAW_TASK_STATE_QUEUED || t->state == LV_DRAW_TASK_STATE_WAITING) &&
|
||||
lv_area_is_on(&t_check->area, &t->area)) {
|
||||
cnt++;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void lv_layer_init(lv_layer_t * layer)
|
||||
{
|
||||
LV_ASSERT_NULL(layer);
|
||||
lv_memzero(layer, sizeof(lv_layer_t));
|
||||
lv_layer_reset(layer);
|
||||
}
|
||||
|
||||
void lv_layer_reset(lv_layer_t * layer)
|
||||
{
|
||||
LV_ASSERT_NULL(layer);
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
lv_matrix_identity(&layer->matrix);
|
||||
#endif
|
||||
layer->opa = LV_OPA_COVER;
|
||||
layer->recolor = lv_color32_make(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
lv_layer_t * lv_draw_layer_create(lv_layer_t * parent_layer, lv_color_format_t color_format, const lv_area_t * area)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_layer_t * new_layer = lv_malloc_zeroed(sizeof(lv_layer_t));
|
||||
LV_ASSERT_MALLOC(new_layer);
|
||||
if(new_layer == NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_draw_layer_init(new_layer, parent_layer, color_format, area);
|
||||
|
||||
/*Inherits transparency from parent*/
|
||||
if(parent_layer) {
|
||||
new_layer->opa = parent_layer->opa;
|
||||
new_layer->recolor = parent_layer->recolor;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return new_layer;
|
||||
}
|
||||
|
||||
void lv_draw_layer_init(lv_layer_t * layer, lv_layer_t * parent_layer, lv_color_format_t color_format,
|
||||
const lv_area_t * area)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_layer_init(layer);
|
||||
lv_display_t * disp = lv_refr_get_disp_refreshing();
|
||||
|
||||
layer->parent = parent_layer;
|
||||
layer->_clip_area = *area;
|
||||
layer->buf_area = *area;
|
||||
layer->phy_clip_area = *area;
|
||||
layer->color_format = color_format;
|
||||
|
||||
if(disp->layer_init) disp->layer_init(disp, layer);
|
||||
|
||||
if(disp->layer_head) {
|
||||
lv_layer_t * tail = disp->layer_head;
|
||||
while(tail->next) tail = tail->next;
|
||||
tail->next = layer;
|
||||
}
|
||||
else {
|
||||
disp->layer_head = layer;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void * lv_draw_layer_alloc_buf(lv_layer_t * layer)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/*If the buffer of the layer is already allocated return it*/
|
||||
if(layer->draw_buf != NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return layer->draw_buf->data;
|
||||
}
|
||||
|
||||
/*If the buffer of the layer is not allocated yet, allocate it now*/
|
||||
int32_t w = lv_area_get_width(&layer->buf_area);
|
||||
int32_t h = lv_area_get_height(&layer->buf_area);
|
||||
uint32_t layer_size_byte = h * lv_draw_buf_width_to_stride(w, layer->color_format);
|
||||
|
||||
#if LV_DRAW_LAYER_MAX_MEMORY > 0
|
||||
/* Do not allocate the layer if the sum of allocated layer sizes
|
||||
* will exceed `LV_DRAW_LAYER_MAX_MEMORY` */
|
||||
if((_draw_info.used_memory_for_layers + layer_size_byte) > LV_DRAW_LAYER_MAX_MEMORY) {
|
||||
LV_LOG_WARN("LV_DRAW_LAYER_MAX_MEMORY was reached when allocating the layer.");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
layer->draw_buf = lv_draw_buf_create(w, h, layer->color_format, 0);
|
||||
|
||||
if(layer->draw_buf == NULL) {
|
||||
LV_LOG_WARN("Allocating layer buffer failed. Try later");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_draw_info.used_memory_for_layers += layer_size_byte;
|
||||
LV_LOG_INFO("Layer memory used: %" LV_PRIu32 " kB", get_layer_size_kb(_draw_info.used_memory_for_layers));
|
||||
|
||||
if(lv_color_format_has_alpha(layer->color_format)) {
|
||||
lv_draw_buf_clear(layer->draw_buf, NULL);
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return layer->draw_buf->data;
|
||||
}
|
||||
|
||||
void * lv_draw_layer_go_to_xy(lv_layer_t * layer, int32_t x, int32_t y)
|
||||
{
|
||||
return lv_draw_buf_goto_xy(layer->draw_buf, x, y);
|
||||
}
|
||||
|
||||
lv_draw_task_type_t lv_draw_task_get_type(const lv_draw_task_t * t)
|
||||
{
|
||||
return t->type;
|
||||
}
|
||||
|
||||
void * lv_draw_task_get_draw_dsc(const lv_draw_task_t * t)
|
||||
{
|
||||
return t->draw_dsc;
|
||||
}
|
||||
|
||||
void lv_draw_task_get_area(const lv_draw_task_t * t, lv_area_t * area)
|
||||
{
|
||||
*area = t->area;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Check if there are older draw task overlapping the area of `t_check`
|
||||
* @param layer the draw ctx to search in
|
||||
* @param t_check check this task if it overlaps with the older ones
|
||||
* @return true: `t_check` is not overlapping with older tasks so it's independent
|
||||
*/
|
||||
static bool is_independent(lv_layer_t * layer, lv_draw_task_t * t_check)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
|
||||
/*If t_check is outside of the older tasks then it's independent*/
|
||||
while(t && t != t_check) {
|
||||
if(t->state != LV_DRAW_TASK_STATE_READY) {
|
||||
lv_area_t a;
|
||||
if(lv_area_intersect(&a, &t->_real_area, &t_check->_real_area)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the draw descriptor of a draw task
|
||||
* @param type type of the draw task
|
||||
* @return size of the draw descriptor in bytes
|
||||
*/
|
||||
static inline size_t get_draw_dsc_size(lv_draw_task_type_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case LV_DRAW_TASK_TYPE_NONE:
|
||||
return 0;
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
return sizeof(lv_draw_fill_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
return sizeof(lv_draw_border_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
||||
return sizeof(lv_draw_box_shadow_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LETTER:
|
||||
return sizeof(lv_draw_letter_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
return sizeof(lv_draw_label_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
return sizeof(lv_draw_image_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
return sizeof(lv_draw_image_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
return sizeof(lv_draw_line_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
return sizeof(lv_draw_arc_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
return sizeof(lv_draw_triangle_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
||||
return sizeof(lv_draw_mask_rect_dsc_t);
|
||||
|
||||
/* no struct match for LV_DRAW_TASK_TYPE_MASK_BITMAP, set it to zero now */
|
||||
case LV_DRAW_TASK_TYPE_MASK_BITMAP:
|
||||
return 0;
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
case LV_DRAW_TASK_TYPE_VECTOR:
|
||||
return sizeof(lv_draw_vector_task_dsc_t);
|
||||
#endif
|
||||
#if LV_USE_3DTEXTURE
|
||||
case LV_DRAW_TASK_TYPE_3D:
|
||||
return sizeof(lv_draw_3d_dsc_t);
|
||||
#endif
|
||||
/* Note that default is not added here because when adding new draw task type,
|
||||
* if forget to add case, the compiler will automatically report a warning.
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean-up resources allocated by a finished task
|
||||
* @param t pointer to a draw task
|
||||
* @param disp pointer to a display on which the task was drawn
|
||||
*/
|
||||
static void cleanup_task(lv_draw_task_t * t, lv_display_t * disp)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/*If it was layer drawing free the layer too*/
|
||||
if(t->type == LV_DRAW_TASK_TYPE_LAYER) {
|
||||
lv_draw_image_dsc_t * draw_image_dsc = t->draw_dsc;
|
||||
lv_layer_t * layer_drawn = (lv_layer_t *)draw_image_dsc->src;
|
||||
|
||||
if(layer_drawn->draw_buf) {
|
||||
int32_t h = lv_area_get_height(&layer_drawn->buf_area);
|
||||
uint32_t layer_size_byte = h * layer_drawn->draw_buf->header.stride;
|
||||
|
||||
if(_draw_info.used_memory_for_layers >= layer_size_byte) {
|
||||
_draw_info.used_memory_for_layers -= layer_size_byte;
|
||||
}
|
||||
else {
|
||||
_draw_info.used_memory_for_layers = 0;
|
||||
LV_LOG_WARN("More layers were freed than allocated");
|
||||
}
|
||||
LV_LOG_INFO("Layer memory used: %" LV_PRIu32 " kB", get_layer_size_kb(_draw_info.used_memory_for_layers));
|
||||
lv_draw_buf_destroy(layer_drawn->draw_buf);
|
||||
layer_drawn->draw_buf = NULL;
|
||||
}
|
||||
|
||||
/*Remove the layer from the display's*/
|
||||
if(disp) {
|
||||
lv_layer_t * l2 = disp->layer_head;
|
||||
while(l2) {
|
||||
if(l2->next == layer_drawn) {
|
||||
l2->next = layer_drawn->next;
|
||||
break;
|
||||
}
|
||||
l2 = l2->next;
|
||||
}
|
||||
|
||||
if(disp->layer_deinit) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("layer_deinit");
|
||||
disp->layer_deinit(disp, layer_drawn);
|
||||
LV_PROFILER_DRAW_END_TAG("layer_deinit");
|
||||
}
|
||||
lv_free(layer_drawn);
|
||||
}
|
||||
}
|
||||
lv_draw_label_dsc_t * draw_label_dsc = lv_draw_task_get_label_dsc(t);
|
||||
if(draw_label_dsc && draw_label_dsc->text_local) {
|
||||
lv_free((void *)draw_label_dsc->text);
|
||||
draw_label_dsc->text = NULL;
|
||||
}
|
||||
|
||||
lv_free(t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
static lv_draw_task_t * get_first_available_task(lv_layer_t * layer)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/* If there is only 1 draw unit the task can be consumed linearly as
|
||||
* they are added in the correct order. However, it can happen that
|
||||
* there is a `LV_DRAW_TASK_TYPE_LAYER` which can be blended only when
|
||||
* all its tasks are ready. As other areas might be on top of that
|
||||
* layer-to-blend don't skip it. Instead stop there, so that the
|
||||
* draw tasks of that layer can be consumed and can be finished.
|
||||
* After that this layer-to-blenf will have `LV_DRAW_TASK_STATE_QUEUED`
|
||||
* so it can be blended normally.*/
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
while(t) {
|
||||
/*Not queued yet, leave this layer while the first task is queued*/
|
||||
if(t->state != LV_DRAW_TASK_STATE_QUEUED) {
|
||||
t = NULL;
|
||||
break;
|
||||
}
|
||||
/*It's a supported and queued task, process it*/
|
||||
else {
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return t;
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* @file lv_draw.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modified by NXP in 2024
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_H
|
||||
#define LV_DRAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../misc/lv_text.h"
|
||||
#include "../misc/lv_profiler.h"
|
||||
#include "../misc/lv_matrix.h"
|
||||
#include "lv_image_decoder.h"
|
||||
#include "lv_draw_buf.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_DRAW_UNIT_NONE 0
|
||||
#define LV_DRAW_UNIT_IDLE -1 /**< The draw unit is idle, new dispatching might be requested to try again */
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
#if !LV_USE_MATRIX
|
||||
#error "LV_DRAW_TRANSFORM_USE_MATRIX requires LV_USE_MATRIX = 1"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_TASK_TYPE_NONE = 0,
|
||||
LV_DRAW_TASK_TYPE_FILL,
|
||||
LV_DRAW_TASK_TYPE_BORDER,
|
||||
LV_DRAW_TASK_TYPE_BOX_SHADOW,
|
||||
LV_DRAW_TASK_TYPE_LETTER,
|
||||
LV_DRAW_TASK_TYPE_LABEL,
|
||||
LV_DRAW_TASK_TYPE_IMAGE,
|
||||
LV_DRAW_TASK_TYPE_LAYER,
|
||||
LV_DRAW_TASK_TYPE_LINE,
|
||||
LV_DRAW_TASK_TYPE_ARC,
|
||||
LV_DRAW_TASK_TYPE_TRIANGLE,
|
||||
LV_DRAW_TASK_TYPE_MASK_RECTANGLE,
|
||||
LV_DRAW_TASK_TYPE_MASK_BITMAP,
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
LV_DRAW_TASK_TYPE_VECTOR,
|
||||
#endif
|
||||
#if LV_USE_3DTEXTURE
|
||||
LV_DRAW_TASK_TYPE_3D,
|
||||
#endif
|
||||
} lv_draw_task_type_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_TASK_STATE_WAITING, /*Waiting for something to be finished. E.g. rendering a layer*/
|
||||
LV_DRAW_TASK_STATE_QUEUED,
|
||||
LV_DRAW_TASK_STATE_IN_PROGRESS,
|
||||
LV_DRAW_TASK_STATE_READY,
|
||||
} lv_draw_task_state_t;
|
||||
|
||||
struct _lv_layer_t {
|
||||
|
||||
/** Target draw buffer of the layer*/
|
||||
lv_draw_buf_t * draw_buf;
|
||||
|
||||
/** The absolute coordinates of the buffer */
|
||||
lv_area_t buf_area;
|
||||
|
||||
/** The color format of the layer. LV_COLOR_FORMAT_... */
|
||||
lv_color_format_t color_format;
|
||||
|
||||
/**
|
||||
* NEVER USE IT DRAW UNITS. USED INTERNALLY DURING DRAW TASK CREATION.
|
||||
* The current clip area with absolute coordinates, always the same or smaller than `buf_area`
|
||||
* Can be set before new draw tasks are added to indicate the clip area of the draw tasks.
|
||||
* Therefore `lv_draw_add_task()` always saves it in the new draw task to know the clip area when the draw task was added.
|
||||
* During drawing the draw units also sees the saved clip_area and should use it during drawing.
|
||||
* During drawing the layer's clip area shouldn't be used as it might be already changed for other draw tasks.
|
||||
*/
|
||||
lv_area_t _clip_area;
|
||||
|
||||
/**
|
||||
* The physical clipping area relative to the display.
|
||||
*/
|
||||
lv_area_t phy_clip_area;
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
/** Transform matrix to be applied when rendering the layer */
|
||||
lv_matrix_t matrix;
|
||||
#endif
|
||||
|
||||
/** Opacity of the layer */
|
||||
lv_opa_t opa;
|
||||
|
||||
/*Recolor of the layer*/
|
||||
lv_color32_t recolor;
|
||||
|
||||
/** Partial y offset */
|
||||
int32_t partial_y_offset;
|
||||
|
||||
/** Linked list of draw tasks */
|
||||
lv_draw_task_t * draw_task_head;
|
||||
|
||||
lv_layer_t * parent;
|
||||
lv_layer_t * next;
|
||||
bool all_tasks_added;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/**The widget for which draw descriptor was created */
|
||||
lv_obj_t * obj;
|
||||
|
||||
/**The widget part for which draw descriptor was created */
|
||||
lv_part_t part;
|
||||
|
||||
/**A widget type specific ID (e.g. table row index). See the docs of the given widget.*/
|
||||
uint32_t id1;
|
||||
|
||||
/**A widget type specific ID (e.g. table column index). See the docs of the given widget.*/
|
||||
uint32_t id2;
|
||||
|
||||
/**The target layer */
|
||||
lv_layer_t * layer;
|
||||
|
||||
/**Size of the specific draw descriptor into which this base descriptor is embedded*/
|
||||
size_t dsc_size;
|
||||
|
||||
/**Any custom user data*/
|
||||
void * user_data;
|
||||
} lv_draw_dsc_base_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Used internally to initialize the drawing module
|
||||
*/
|
||||
void lv_draw_init(void);
|
||||
|
||||
/**
|
||||
* Deinitialize the drawing module
|
||||
*/
|
||||
void lv_draw_deinit(void);
|
||||
|
||||
/**
|
||||
* Allocate a new draw unit with the given size and appends it to the list of draw units
|
||||
* @param size the size to allocate. E.g. `sizeof(my_draw_unit_t)`,
|
||||
* where the first element of `my_draw_unit_t` is `lv_draw_unit_t`.
|
||||
*/
|
||||
void * lv_draw_create_unit(size_t size);
|
||||
|
||||
/**
|
||||
* Add an empty draw task to the draw task list of a layer.
|
||||
* @param layer pointer to a layer
|
||||
* @param coords the coordinates of the draw task
|
||||
* @return the created draw task which needs to be
|
||||
* further configured e.g. by added a draw descriptor
|
||||
*/
|
||||
lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords, lv_draw_task_type_t type);
|
||||
|
||||
/**
|
||||
* Needs to be called when a draw task is created and configured.
|
||||
* It will send an event about the new draw task to the widget
|
||||
* and assign it to a draw unit.
|
||||
* @param layer pointer to a layer
|
||||
* @param t pointer to a draw task
|
||||
*/
|
||||
void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t);
|
||||
|
||||
/**
|
||||
* Try dispatching draw tasks to draw units
|
||||
*/
|
||||
void lv_draw_dispatch(void);
|
||||
|
||||
/**
|
||||
* Used internally to try dispatching draw tasks of a specific layer
|
||||
* @param disp pointer to a display on which the dispatching was requested
|
||||
* @param layer pointer to a layer
|
||||
* @return at least one draw task is being rendered (maybe it was taken earlier)
|
||||
*/
|
||||
bool lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Wait for a new dispatch request.
|
||||
* It's blocking if `LV_USE_OS == 0` else it yields
|
||||
*/
|
||||
void lv_draw_dispatch_wait_for_request(void);
|
||||
|
||||
/**
|
||||
* Wait for draw finish in case of asynchronous task execution.
|
||||
* If `LV_USE_OS == 0` it just return.
|
||||
*/
|
||||
void lv_draw_wait_for_finish(void);
|
||||
|
||||
/**
|
||||
* When a draw unit finished a draw task it needs to request dispatching
|
||||
* to let LVGL assign a new draw task to it
|
||||
*/
|
||||
void lv_draw_dispatch_request(void);
|
||||
|
||||
/**
|
||||
* Get the total number of draw units.
|
||||
*/
|
||||
uint32_t lv_draw_get_unit_count(void);
|
||||
|
||||
/**
|
||||
* If there is only one draw unit check the first draw task if it's available.
|
||||
* If there are multiple draw units call `lv_draw_get_next_available_task` to find a task.
|
||||
* @param layer the draw layer to search in
|
||||
* @param t_prev continue searching from this task
|
||||
* @param draw_unit_id check the task where `preferred_draw_unit_id` equals this value or `LV_DRAW_UNIT_NONE`
|
||||
* @return an available draw task or NULL if there is not any
|
||||
*/
|
||||
lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id);
|
||||
|
||||
/**
|
||||
* Find and available draw task
|
||||
* @param layer the draw layer to search in
|
||||
* @param t_prev continue searching from this task
|
||||
* @param draw_unit_id check the task where `preferred_draw_unit_id` equals this value or `LV_DRAW_UNIT_NONE`
|
||||
* @return an available draw task or NULL if there is not any
|
||||
*/
|
||||
lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id);
|
||||
|
||||
/**
|
||||
* Tell how many draw task are waiting to be drawn on the area of `t_check`.
|
||||
* It can be used to determine if a GPU shall combine many draw tasks into one or not.
|
||||
* If a lot of tasks are waiting for the current ones it makes sense to draw them one-by-one
|
||||
* to not block the dependent tasks' rendering
|
||||
* @param t_check the task whose dependent tasks shall be counted
|
||||
* @return number of tasks depending on `t_check`
|
||||
*/
|
||||
uint32_t lv_draw_get_dependent_count(lv_draw_task_t * t_check);
|
||||
|
||||
/**
|
||||
* Initialize a layer
|
||||
* @param layer pointer to a layer to initialize
|
||||
*/
|
||||
void lv_layer_init(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Reset the layer to a drawable state
|
||||
* @param layer pointer to a layer to reset
|
||||
*/
|
||||
void lv_layer_reset(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Create (allocate) a new layer on a parent layer
|
||||
* @param parent_layer the parent layer to which the layer will be merged when it's rendered
|
||||
* @param color_format the color format of the layer
|
||||
* @param area the areas of the layer (absolute coordinates)
|
||||
* @return the new target_layer or NULL on error
|
||||
*/
|
||||
lv_layer_t * lv_draw_layer_create(lv_layer_t * parent_layer, lv_color_format_t color_format, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Initialize a layer which is allocated by the user
|
||||
* @param layer pointer the layer to initialize (its lifetime needs to be managed by the user)
|
||||
* @param parent_layer the parent layer to which the layer will be merged when it's rendered
|
||||
* @param color_format the color format of the layer
|
||||
* @param area the areas of the layer (absolute coordinates)
|
||||
* @return the new target_layer or NULL on error
|
||||
*/
|
||||
void lv_draw_layer_init(lv_layer_t * layer, lv_layer_t * parent_layer, lv_color_format_t color_format,
|
||||
const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Try to allocate a buffer for the layer.
|
||||
* @param layer pointer to a layer
|
||||
* @return pointer to the allocated aligned buffer or NULL on failure
|
||||
*/
|
||||
void * lv_draw_layer_alloc_buf(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Got to a pixel at X and Y coordinate on a layer
|
||||
* @param layer pointer to a layer
|
||||
* @param x the target X coordinate
|
||||
* @param y the target X coordinate
|
||||
* @return `buf` offset to point to the given X and Y coordinate
|
||||
*/
|
||||
void * lv_draw_layer_go_to_xy(lv_layer_t * layer, int32_t x, int32_t y);
|
||||
|
||||
/**
|
||||
* Get the type of a draw task
|
||||
* @param t the draw task to get the type of
|
||||
* @return the draw task type
|
||||
*/
|
||||
lv_draw_task_type_t lv_draw_task_get_type(const lv_draw_task_t * t);
|
||||
|
||||
/**
|
||||
* Get the draw descriptor of a draw task
|
||||
* @param t the draw task to get the draw descriptor of
|
||||
* @return a void pointer to the draw descriptor
|
||||
*/
|
||||
void * lv_draw_task_get_draw_dsc(const lv_draw_task_t * t);
|
||||
|
||||
/**
|
||||
* Get the draw area of a draw task
|
||||
* @param t the draw task to get the draw area of
|
||||
* @param area the destination where the draw area will be stored
|
||||
*/
|
||||
void lv_draw_task_get_area(const lv_draw_task_t * t, lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_H*/
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file lv_draw_3d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_3d.h"
|
||||
#if LV_USE_3DTEXTURE
|
||||
|
||||
#include "lv_draw_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_3d_dsc_t));
|
||||
dsc->base.dsc_size = sizeof(lv_draw_3d_dsc_t);
|
||||
dsc->tex_id = LV_3DTEXTURE_ID_NULL;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
}
|
||||
|
||||
lv_draw_3d_dsc_t * lv_draw_task_get_3d_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_3D ? (lv_draw_3d_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_3d(lv_layer_t * layer, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_3D);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_3DTEXTURE*/
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file lv_draw_3d.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_3D_H
|
||||
#define LV_DRAW_3D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../lv_conf_internal.h"
|
||||
#if LV_USE_3DTEXTURE
|
||||
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
lv_3dtexture_id_t tex_id;
|
||||
lv_opa_t opa;
|
||||
} lv_draw_3d_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a 3D draw descriptor
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a 3D draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_3D
|
||||
*/
|
||||
lv_draw_3d_dsc_t * lv_draw_task_get_3d_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a 3D draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized `lv_draw_3d_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_3d(lv_layer_t * layer, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_3DTEXTURE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_3D_H*/
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* @file lv_draw_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "lv_draw_arc.h"
|
||||
#include "../core/lv_obj_event.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_arc_dsc_t));
|
||||
dsc->width = 1;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->base.dsc_size = sizeof(lv_draw_arc_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_arc_dsc_t * lv_draw_task_get_arc_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_ARC ? (lv_draw_arc_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_arc(lv_layer_t * layer, const lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->start_angle == dsc->end_angle) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_area_t a;
|
||||
a.x1 = dsc->center.x - dsc->radius;
|
||||
a.y1 = dsc->center.y - dsc->radius;
|
||||
a.x2 = dsc->center.x + dsc->radius - 1;
|
||||
a.y2 = dsc->center.y + dsc->radius - 1;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_ARC);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_arc_get_area(int32_t x, int32_t y, uint16_t radius, lv_value_precise_t start_angle,
|
||||
lv_value_precise_t end_angle,
|
||||
int32_t w, bool rounded, lv_area_t * area)
|
||||
{
|
||||
int32_t rout = radius;
|
||||
int32_t start_angle_int = (int32_t) start_angle;
|
||||
int32_t end_angle_int = (int32_t) end_angle;
|
||||
|
||||
/*Special case: full arc invalidation */
|
||||
if(end_angle_int == start_angle_int + 360) {
|
||||
area->x1 = x - rout;
|
||||
area->y1 = y - rout;
|
||||
area->x2 = x + rout;
|
||||
area->y2 = y + rout;
|
||||
return;
|
||||
}
|
||||
|
||||
if(start_angle_int > 360) start_angle_int -= 360;
|
||||
if(end_angle_int > 360) end_angle_int -= 360;
|
||||
|
||||
int32_t rin = radius - w;
|
||||
int32_t extra_area = rounded ? w / 2 + 1 : 0;
|
||||
uint8_t start_quarter = start_angle_int / 90;
|
||||
uint8_t end_quarter = end_angle_int / 90;
|
||||
|
||||
/*360 deg still counts as quarter 3 (360 / 90 would be 4)*/
|
||||
if(start_quarter == 4) start_quarter = 3;
|
||||
if(end_quarter == 4) end_quarter = 3;
|
||||
|
||||
if(start_quarter == end_quarter && start_angle_int <= end_angle_int) {
|
||||
if(start_quarter == 0) {
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle_int) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
}
|
||||
else if(start_quarter == 1) {
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle_int) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
}
|
||||
else if(start_quarter == 2) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle_int) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 3) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle_int) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
}
|
||||
else if(start_quarter == 0 && end_quarter == 1) {
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((LV_MIN(lv_trigo_sin(end_angle_int),
|
||||
lv_trigo_sin(start_angle_int)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + rout + extra_area;
|
||||
}
|
||||
else if(start_quarter == 1 && end_quarter == 2) {
|
||||
area->x1 = x - rout - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((LV_MAX(lv_trigo_sin(start_angle_int + 90),
|
||||
lv_trigo_sin(end_angle_int + 90)) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 2 && end_quarter == 3) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y - rout - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + (LV_MAX(lv_trigo_sin(end_angle_int) * rin,
|
||||
lv_trigo_sin(start_angle_int) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 3 && end_quarter == 0) {
|
||||
area->x1 = x + ((LV_MIN(lv_trigo_sin(end_angle_int + 90),
|
||||
lv_trigo_sin(start_angle_int + 90)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + rout + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
}
|
||||
else {
|
||||
area->x1 = x - rout;
|
||||
area->y1 = y - rout;
|
||||
area->x2 = x + rout;
|
||||
area->y2 = y + rout;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file lv_draw_arc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_ARC_H
|
||||
#define LV_DRAW_ARC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The color of the arc*/
|
||||
lv_color_t color;
|
||||
|
||||
/**The width (thickness) of the arc */
|
||||
int32_t width;
|
||||
|
||||
/**The start angle in 1 degree units (if `LV_USE_FLOAT` is enabled a float number can be also used)
|
||||
* 0° is the 3 o'clock position, 90° is the 6 o'clock, etc. */
|
||||
lv_value_precise_t start_angle;
|
||||
|
||||
/**The end angle, similarly to start_angle. */
|
||||
lv_value_precise_t end_angle;
|
||||
|
||||
/**The center point of the arc. */
|
||||
lv_point_t center;
|
||||
|
||||
/**The outer radius of the arc*/
|
||||
uint16_t radius;
|
||||
|
||||
/**An image source to be used instead of `color`. `NULL` if unused*/
|
||||
const void * img_src;
|
||||
|
||||
/**Opacity of the arc in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**1: Make the arc ends rounded*/
|
||||
uint8_t rounded : 1;
|
||||
} lv_draw_arc_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an arc draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get an arc draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_ARC
|
||||
*/
|
||||
lv_draw_arc_dsc_t * lv_draw_task_get_arc_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create an arc draw task.
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor variable
|
||||
*/
|
||||
void lv_draw_arc(lv_layer_t * layer, const lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get an area the should be invalidated when the arcs angle changed between start_angle and end_ange
|
||||
* @param x the x coordinate of the center of the arc
|
||||
* @param y the y coordinate of the center of the arc
|
||||
* @param radius the radius of the arc
|
||||
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
|
||||
* @param end_angle the end angle of the arc
|
||||
* @param w width of the arc
|
||||
* @param rounded true: the arc is rounded
|
||||
* @param area store the area to invalidate here
|
||||
*/
|
||||
void lv_draw_arc_get_area(int32_t x, int32_t y, uint16_t radius, lv_value_precise_t start_angle,
|
||||
lv_value_precise_t end_angle,
|
||||
int32_t w, bool rounded, lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_ARC_H*/
|
||||
@@ -0,0 +1,725 @@
|
||||
/**
|
||||
* @file lv_draw_buf.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_buf_private.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../core/lv_global.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define default_handlers LV_GLOBAL_DEFAULT()->draw_buf_handlers
|
||||
#define font_draw_buf_handlers LV_GLOBAL_DEFAULT()->font_draw_buf_handlers
|
||||
#define image_cache_draw_buf_handlers LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void * buf_malloc(size_t size, lv_color_format_t color_format);
|
||||
static void buf_free(void * buf);
|
||||
static void * buf_align(void * buf, lv_color_format_t color_format);
|
||||
static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handler, size_t size_bytes,
|
||||
lv_color_format_t color_format);
|
||||
static void draw_buf_free(const lv_draw_buf_handlers_t * handler, void * buf);
|
||||
static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format);
|
||||
static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride);
|
||||
static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_buf_init_handlers(void)
|
||||
{
|
||||
lv_draw_buf_init_with_default_handlers(&default_handlers);
|
||||
lv_draw_buf_init_with_default_handlers(&font_draw_buf_handlers);
|
||||
lv_draw_buf_init_with_default_handlers(&image_cache_draw_buf_handlers);
|
||||
}
|
||||
|
||||
void lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers)
|
||||
{
|
||||
lv_draw_buf_handlers_init(handlers, buf_malloc, buf_free, buf_align, NULL, NULL, width_to_stride);
|
||||
}
|
||||
|
||||
void lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,
|
||||
lv_draw_buf_malloc_cb buf_malloc_cb,
|
||||
lv_draw_buf_free_cb buf_free_cb,
|
||||
lv_draw_buf_align_cb align_pointer_cb,
|
||||
lv_draw_buf_cache_operation_cb invalidate_cache_cb,
|
||||
lv_draw_buf_cache_operation_cb flush_cache_cb,
|
||||
lv_draw_buf_width_to_stride_cb width_to_stride_cb)
|
||||
{
|
||||
lv_memzero(handlers, sizeof(lv_draw_buf_handlers_t));
|
||||
handlers->buf_malloc_cb = buf_malloc_cb;
|
||||
handlers->buf_free_cb = buf_free_cb;
|
||||
handlers->align_pointer_cb = align_pointer_cb;
|
||||
handlers->invalidate_cache_cb = invalidate_cache_cb;
|
||||
handlers->flush_cache_cb = flush_cache_cb;
|
||||
handlers->width_to_stride_cb = width_to_stride_cb;
|
||||
}
|
||||
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_handlers(void)
|
||||
{
|
||||
return &default_handlers;
|
||||
}
|
||||
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_font_handlers(void)
|
||||
{
|
||||
return &font_draw_buf_handlers;
|
||||
}
|
||||
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_image_handlers(void)
|
||||
{
|
||||
return &image_cache_draw_buf_handlers;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_buf_width_to_stride(uint32_t w, lv_color_format_t color_format)
|
||||
{
|
||||
return lv_draw_buf_width_to_stride_ex(&default_handlers, w, color_format);
|
||||
}
|
||||
|
||||
uint32_t lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w,
|
||||
lv_color_format_t color_format)
|
||||
{
|
||||
if(handlers->width_to_stride_cb) return handlers->width_to_stride_cb(w, color_format);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void * lv_draw_buf_align(void * data, lv_color_format_t color_format)
|
||||
{
|
||||
return lv_draw_buf_align_ex(&default_handlers, data, color_format);
|
||||
}
|
||||
|
||||
void * lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers, void * data, lv_color_format_t color_format)
|
||||
{
|
||||
if(handlers->align_pointer_cb) return handlers->align_pointer_cb(data, color_format);
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
void lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
LV_ASSERT_NULL(draw_buf->handlers);
|
||||
|
||||
const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
|
||||
if(!handlers->invalidate_cache_cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t full;
|
||||
if(area == NULL) {
|
||||
draw_buf_get_full_area(draw_buf, &full);
|
||||
area = &full;
|
||||
}
|
||||
|
||||
handlers->invalidate_cache_cb(draw_buf, area);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
LV_ASSERT_NULL(draw_buf->handlers);
|
||||
|
||||
const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
|
||||
if(!handlers->flush_cache_cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t full;
|
||||
if(area == NULL) {
|
||||
draw_buf_get_full_area(draw_buf, &full);
|
||||
area = &full;
|
||||
}
|
||||
|
||||
handlers->flush_cache_cb(draw_buf, area);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * a)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
uint32_t stride = header->stride;
|
||||
|
||||
if(a == NULL) {
|
||||
uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, 0, 0);
|
||||
lv_memzero(buf, header->h * stride);
|
||||
lv_draw_buf_flush_cache(draw_buf, a);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t a_draw_buf;
|
||||
a_draw_buf.x1 = 0;
|
||||
a_draw_buf.y1 = 0;
|
||||
a_draw_buf.x2 = draw_buf->header.w - 1;
|
||||
a_draw_buf.y2 = draw_buf->header.h - 1;
|
||||
|
||||
lv_area_t a_clipped;
|
||||
if(!lv_area_intersect(&a_clipped, a, &a_draw_buf)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_area_get_width(&a_clipped) <= 0) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_area_get_height(&a_clipped) <= 0) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, a_clipped.x1, a_clipped.y1);
|
||||
uint8_t bpp = lv_color_format_get_bpp(header->cf);
|
||||
uint32_t line_length = (lv_area_get_width(&a_clipped) * bpp + 7) >> 3;
|
||||
int32_t y;
|
||||
for(y = a_clipped.y1; y <= a_clipped.y2; y++) {
|
||||
lv_memzero(buf, line_length);
|
||||
buf += stride;
|
||||
}
|
||||
lv_draw_buf_flush_cache(draw_buf, a);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_buf_copy(lv_draw_buf_t * dest, const lv_area_t * dest_area,
|
||||
const lv_draw_buf_t * src, const lv_area_t * src_area)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
uint8_t * dest_bufc;
|
||||
uint8_t * src_bufc;
|
||||
int32_t line_width;
|
||||
|
||||
/*Source and dest color format must be same. Color conversion is not supported yet.*/
|
||||
LV_ASSERT_FORMAT_MSG(dest->header.cf == src->header.cf, "Color format mismatch: %d != %d",
|
||||
dest->header.cf, src->header.cf);
|
||||
|
||||
if(dest_area == NULL) line_width = dest->header.w;
|
||||
else line_width = lv_area_get_width(dest_area);
|
||||
|
||||
/* For indexed image, copy the palette if we are copying full image area*/
|
||||
if(dest_area == NULL || src_area == NULL) {
|
||||
if(LV_COLOR_FORMAT_IS_INDEXED(dest->header.cf)) {
|
||||
lv_memcpy(dest->data, src->data, LV_COLOR_INDEXED_PALETTE_SIZE(dest->header.cf) * sizeof(lv_color32_t));
|
||||
}
|
||||
}
|
||||
|
||||
/*Check source and dest area have same width*/
|
||||
if((src_area == NULL && line_width != src->header.w) || \
|
||||
(src_area != NULL && line_width != lv_area_get_width(src_area))) {
|
||||
LV_ASSERT_MSG(0, "Source and destination areas have different width");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(src_area) src_bufc = lv_draw_buf_goto_xy(src, src_area->x1, src_area->y1);
|
||||
else src_bufc = lv_draw_buf_goto_xy(src, 0, 0);
|
||||
|
||||
if(dest_area) dest_bufc = lv_draw_buf_goto_xy(dest, dest_area->x1, dest_area->y1);
|
||||
else dest_bufc = lv_draw_buf_goto_xy(dest, 0, 0);
|
||||
|
||||
int32_t start_y, end_y;
|
||||
if(dest_area) {
|
||||
start_y = dest_area->y1;
|
||||
end_y = dest_area->y2;
|
||||
}
|
||||
else {
|
||||
start_y = 0;
|
||||
end_y = dest->header.h - 1;
|
||||
}
|
||||
|
||||
uint32_t dest_stride = dest->header.stride;
|
||||
uint32_t src_stride = src->header.stride;
|
||||
uint32_t line_bytes = (line_width * lv_color_format_get_bpp(dest->header.cf) + 7) >> 3;
|
||||
|
||||
for(; start_y <= end_y; start_y++) {
|
||||
lv_memcpy(dest_bufc, src_bufc, line_bytes);
|
||||
dest_bufc += dest_stride;
|
||||
src_bufc += src_stride;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_init(lv_draw_buf_t * draw_buf, uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride,
|
||||
void * data, uint32_t data_size)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return LV_RESULT_INVALID;
|
||||
|
||||
lv_memzero(draw_buf, sizeof(lv_draw_buf_t));
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
if(stride * h > data_size) {
|
||||
LV_LOG_WARN("Data size too small, required: %" LV_PRId32 ", provided: %" LV_PRId32, stride * h,
|
||||
data_size);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
lv_image_header_t * header = &draw_buf->header;
|
||||
header->w = w;
|
||||
header->h = h;
|
||||
header->cf = cf;
|
||||
header->stride = stride;
|
||||
header->flags = 0;
|
||||
header->magic = LV_IMAGE_HEADER_MAGIC;
|
||||
|
||||
draw_buf->data = data;
|
||||
draw_buf->unaligned_data = data;
|
||||
draw_buf->handlers = &default_handlers;
|
||||
draw_buf->data_size = data_size;
|
||||
if(lv_draw_buf_align(data, cf) != draw_buf->unaligned_data) {
|
||||
LV_LOG_WARN("Data is not aligned, ignored");
|
||||
}
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_create(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
|
||||
{
|
||||
return lv_draw_buf_create_ex(&default_handlers, w, h, cf, stride);
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w, uint32_t h,
|
||||
lv_color_format_t cf, uint32_t stride)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_buf_t * draw_buf = lv_malloc_zeroed(sizeof(lv_draw_buf_t));
|
||||
LV_ASSERT_MALLOC(draw_buf);
|
||||
if(draw_buf == NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
|
||||
uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
|
||||
|
||||
void * buf = draw_buf_malloc(handlers, size, cf);
|
||||
/*Do not assert here as LVGL or the app might just want to try creating a draw_buf*/
|
||||
if(buf == NULL) {
|
||||
LV_LOG_WARN("No memory: %"LV_PRIu32"x%"LV_PRIu32", cf: %d, stride: %"LV_PRIu32", %"LV_PRIu32"Byte, ",
|
||||
w, h, cf, stride, size);
|
||||
lv_free(draw_buf);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
draw_buf->header.w = w;
|
||||
draw_buf->header.h = h;
|
||||
draw_buf->header.cf = cf;
|
||||
draw_buf->header.flags = LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
|
||||
draw_buf->header.stride = stride;
|
||||
draw_buf->header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
draw_buf->data = lv_draw_buf_align(buf, cf);
|
||||
draw_buf->unaligned_data = buf;
|
||||
draw_buf->data_size = size;
|
||||
draw_buf->handlers = handlers;
|
||||
LV_PROFILER_DRAW_END;
|
||||
return draw_buf;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_dup(const lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
return lv_draw_buf_dup_ex(&default_handlers, draw_buf);
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers, const lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
lv_draw_buf_t * new_buf = lv_draw_buf_create_ex(handlers, header->w, header->h, header->cf, header->stride);
|
||||
if(new_buf == NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_buf->header.flags = draw_buf->header.flags;
|
||||
new_buf->header.flags |= LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
|
||||
|
||||
/*Choose the smaller size to copy*/
|
||||
uint32_t size = LV_MIN(draw_buf->data_size, new_buf->data_size);
|
||||
|
||||
/*Copy image data*/
|
||||
lv_memcpy(new_buf->data, draw_buf->data, size);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return new_buf;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_reshape(lv_draw_buf_t * draw_buf, lv_color_format_t cf, uint32_t w, uint32_t h,
|
||||
uint32_t stride)
|
||||
{
|
||||
if(draw_buf == NULL) return NULL;
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
/*If color format is unknown, keep using the original color format.*/
|
||||
if(cf == LV_COLOR_FORMAT_UNKNOWN) cf = draw_buf->header.cf;
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
|
||||
uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
|
||||
|
||||
if(size > draw_buf->data_size) {
|
||||
LV_LOG_TRACE("Draw buf too small for new shape");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
draw_buf->header.cf = cf;
|
||||
draw_buf->header.w = w;
|
||||
draw_buf->header.h = h;
|
||||
draw_buf->header.stride = stride;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return draw_buf;
|
||||
}
|
||||
|
||||
void lv_draw_buf_destroy(lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return;
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
if(draw_buf->header.flags & LV_IMAGE_FLAGS_ALLOCATED) {
|
||||
LV_ASSERT_NULL(draw_buf->handlers);
|
||||
|
||||
const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
|
||||
draw_buf_free(handlers, draw_buf->unaligned_data);
|
||||
lv_free(draw_buf);
|
||||
}
|
||||
else {
|
||||
LV_LOG_ERROR("draw buffer is not allocated, ignored");
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y)
|
||||
{
|
||||
LV_ASSERT_NULL(buf);
|
||||
if(buf == NULL) return NULL;
|
||||
|
||||
uint8_t * data = buf->data;
|
||||
|
||||
/*Skip palette*/
|
||||
data += LV_COLOR_INDEXED_PALETTE_SIZE(buf->header.cf) * sizeof(lv_color32_t);
|
||||
data += buf->header.stride * y;
|
||||
|
||||
if(x == 0) return data;
|
||||
|
||||
return data + x * lv_color_format_get_bpp(buf->header.cf) / 8;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride)
|
||||
{
|
||||
LV_ASSERT_NULL(src);
|
||||
LV_ASSERT_NULL(src->data);
|
||||
if(src == NULL) return LV_RESULT_INVALID;
|
||||
if(src->data == NULL) return LV_RESULT_INVALID;
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
const lv_image_header_t * header = &src->header;
|
||||
uint32_t w = header->w;
|
||||
uint32_t h = header->h;
|
||||
|
||||
if(!lv_draw_buf_has_flag(src, LV_IMAGE_FLAGS_MODIFIABLE)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/*Use global stride*/
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, header->cf);
|
||||
|
||||
/*Check if stride already match*/
|
||||
if(header->stride == stride) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/*Calculate the minimal stride allowed from bpp*/
|
||||
uint32_t bpp = lv_color_format_get_bpp(header->cf);
|
||||
uint32_t min_stride = (w * bpp + 7) >> 3;
|
||||
if(stride < min_stride) {
|
||||
LV_LOG_WARN("New stride is too small. min: %" LV_PRId32, min_stride);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/*Check if buffer has enough space. */
|
||||
uint32_t new_size = _calculate_draw_buf_size(w, h, header->cf, stride);
|
||||
if(new_size > src->data_size) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
uint32_t offset = LV_COLOR_INDEXED_PALETTE_SIZE(header->cf) * 4;
|
||||
|
||||
if(stride > header->stride) {
|
||||
/*Copy from the last line to the first*/
|
||||
uint8_t * src_data = src->data + offset + header->stride * (h - 1);
|
||||
uint8_t * dst_data = src->data + offset + stride * (h - 1);
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_memmove(dst_data, src_data, min_stride);
|
||||
src_data -= header->stride;
|
||||
dst_data -= stride;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Copy from the first line to the last*/
|
||||
uint8_t * src_data = src->data + offset;
|
||||
uint8_t * dst_data = src->data + offset;
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_memmove(dst_data, src_data, min_stride);
|
||||
src_data += header->stride;
|
||||
dst_data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
src->header.stride = stride;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return LV_RESULT_INVALID;
|
||||
|
||||
if(draw_buf->header.flags & LV_IMAGE_FLAGS_PREMULTIPLIED) return LV_RESULT_INVALID;
|
||||
if((draw_buf->header.flags & LV_IMAGE_FLAGS_MODIFIABLE) == 0) {
|
||||
LV_LOG_WARN("draw buf is not modifiable: 0x%04x", draw_buf->header.flags);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
/*Premultiply color with alpha, do case by case by judging color format*/
|
||||
lv_color_format_t cf = draw_buf->header.cf;
|
||||
if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
|
||||
int size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
|
||||
lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
|
||||
for(int i = 0; i < size; i++) {
|
||||
lv_color_premultiply(&palette[i]);
|
||||
}
|
||||
}
|
||||
else if(cf == LV_COLOR_FORMAT_ARGB8888) {
|
||||
uint32_t h = draw_buf->header.h;
|
||||
uint32_t w = draw_buf->header.w;
|
||||
uint32_t stride = draw_buf->header.stride;
|
||||
uint8_t * line = (uint8_t *)draw_buf->data;
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_color32_t * pixel = (lv_color32_t *)line;
|
||||
for(uint32_t x = 0; x < w; x++) {
|
||||
lv_color_premultiply(pixel);
|
||||
pixel++;
|
||||
}
|
||||
line += stride;
|
||||
}
|
||||
}
|
||||
else if(cf == LV_COLOR_FORMAT_RGB565A8) {
|
||||
uint32_t h = draw_buf->header.h;
|
||||
uint32_t w = draw_buf->header.w;
|
||||
uint32_t stride = draw_buf->header.stride;
|
||||
uint32_t alpha_stride = stride / 2;
|
||||
uint8_t * line = (uint8_t *)draw_buf->data;
|
||||
lv_opa_t * alpha = (lv_opa_t *)(line + stride * h);
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_color16_t * pixel = (lv_color16_t *)line;
|
||||
for(uint32_t x = 0; x < w; x++) {
|
||||
lv_color16_premultiply(pixel, alpha[x]);
|
||||
pixel++;
|
||||
}
|
||||
line += stride;
|
||||
alpha += alpha_stride;
|
||||
}
|
||||
}
|
||||
else if(cf == LV_COLOR_FORMAT_ARGB8565) {
|
||||
uint32_t h = draw_buf->header.h;
|
||||
uint32_t w = draw_buf->header.w;
|
||||
uint32_t stride = draw_buf->header.stride;
|
||||
uint8_t * line = (uint8_t *)draw_buf->data;
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
uint8_t * pixel = line;
|
||||
for(uint32_t x = 0; x < w; x++) {
|
||||
uint8_t alpha = pixel[2];
|
||||
lv_color16_premultiply((lv_color16_t *)pixel, alpha);
|
||||
pixel += 3;
|
||||
}
|
||||
line += stride;
|
||||
}
|
||||
}
|
||||
else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
|
||||
/*Pass*/
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("draw buf has no alpha, cf: %d", cf);
|
||||
}
|
||||
|
||||
draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
void lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf, uint8_t index, lv_color32_t color)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return;
|
||||
|
||||
if(!LV_COLOR_FORMAT_IS_INDEXED(draw_buf->header.cf)) {
|
||||
LV_LOG_WARN("Not indexed color format");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
|
||||
palette[index] = color;
|
||||
}
|
||||
|
||||
bool lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
|
||||
{
|
||||
return draw_buf->header.flags & flag;
|
||||
}
|
||||
|
||||
void lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
|
||||
{
|
||||
draw_buf->header.flags |= flag;
|
||||
}
|
||||
|
||||
void lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
|
||||
{
|
||||
draw_buf->header.flags &= ~flag;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_from_image(lv_draw_buf_t * buf, const lv_image_dsc_t * img)
|
||||
{
|
||||
const lv_result_t res = lv_draw_buf_init(buf, img->header.w, img->header.h, img->header.cf, img->header.stride,
|
||||
(void *)img->data, img->data_size);
|
||||
if(res != LV_RESULT_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
buf->header.flags = img->header.flags;
|
||||
return res;
|
||||
}
|
||||
|
||||
void lv_draw_buf_to_image(const lv_draw_buf_t * buf, lv_image_dsc_t * img)
|
||||
{
|
||||
lv_memcpy((void *)img, buf, sizeof(lv_image_dsc_t));
|
||||
}
|
||||
|
||||
void lv_image_buf_set_palette(lv_image_dsc_t * dsc, uint8_t id, lv_color32_t c)
|
||||
{
|
||||
LV_LOG_WARN("Deprecated API, use lv_draw_buf_set_palette instead.");
|
||||
lv_draw_buf_set_palette((lv_draw_buf_t *)dsc, id, c);
|
||||
}
|
||||
|
||||
void lv_image_buf_free(lv_image_dsc_t * dsc)
|
||||
{
|
||||
LV_LOG_WARN("Deprecated API, use lv_draw_buf_destroy instead.");
|
||||
if(dsc != NULL) {
|
||||
if(dsc->data != NULL)
|
||||
lv_free((void *)dsc->data);
|
||||
|
||||
lv_free((void *)dsc);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void * buf_malloc(size_t size_bytes, lv_color_format_t color_format)
|
||||
{
|
||||
LV_UNUSED(color_format);
|
||||
|
||||
/*Allocate larger memory to be sure it can be aligned as needed*/
|
||||
size_bytes += LV_DRAW_BUF_ALIGN - 1;
|
||||
return lv_malloc(size_bytes);
|
||||
}
|
||||
|
||||
static void buf_free(void * buf)
|
||||
{
|
||||
lv_free(buf);
|
||||
}
|
||||
|
||||
static void * buf_align(void * buf, lv_color_format_t color_format)
|
||||
{
|
||||
LV_UNUSED(color_format);
|
||||
|
||||
uint8_t * buf_u8 = buf;
|
||||
if(buf_u8) {
|
||||
buf_u8 = (uint8_t *)LV_ROUND_UP((lv_uintptr_t)buf_u8, LV_DRAW_BUF_ALIGN);
|
||||
}
|
||||
return buf_u8;
|
||||
}
|
||||
|
||||
static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format)
|
||||
{
|
||||
uint32_t width_byte;
|
||||
width_byte = w * lv_color_format_get_bpp(color_format);
|
||||
width_byte = (width_byte + 7) >> 3; /*Round up*/
|
||||
|
||||
return LV_ROUND_UP(width_byte, LV_DRAW_BUF_STRIDE_ALIGN);
|
||||
}
|
||||
|
||||
static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handlers, size_t size_bytes,
|
||||
lv_color_format_t color_format)
|
||||
{
|
||||
if(handlers->buf_malloc_cb) return handlers->buf_malloc_cb(size_bytes, color_format);
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
static void draw_buf_free(const lv_draw_buf_handlers_t * handlers, void * buf)
|
||||
{
|
||||
if(handlers->buf_free_cb)
|
||||
handlers->buf_free_cb(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* For given width, height, color format, and stride, calculate the size needed for a new draw buffer.
|
||||
*/
|
||||
static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
|
||||
size = stride * h;
|
||||
if(cf == LV_COLOR_FORMAT_RGB565A8) {
|
||||
size += (stride / 2) * h; /*A8 mask*/
|
||||
}
|
||||
else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
|
||||
/*@todo we have to include palette right before image data*/
|
||||
size += LV_COLOR_INDEXED_PALETTE_SIZE(cf) * 4;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area)
|
||||
{
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
lv_area_set(full_area, 0, 0, header->w - 1, header->h - 1);
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* @file lv_draw_buf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_BUF_H
|
||||
#define LV_DRAW_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "lv_image_dsc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/** Use this value to let LVGL calculate stride automatically */
|
||||
#define LV_STRIDE_AUTO 0
|
||||
LV_EXPORT_CONST_INT(LV_STRIDE_AUTO);
|
||||
|
||||
/**
|
||||
* Stride alignment for draw buffers.
|
||||
* It may vary between different color formats and hardware.
|
||||
* Refine it to suit your needs.
|
||||
*/
|
||||
|
||||
#define LV_DRAW_BUF_STRIDE(w, cf) \
|
||||
LV_ROUND_UP(((w) * LV_COLOR_FORMAT_GET_BPP(cf) + 7) / 8, LV_DRAW_BUF_STRIDE_ALIGN)
|
||||
|
||||
/** Allocate a slightly larger buffer, so we can adjust the start address to meet alignment */
|
||||
#define LV_DRAW_BUF_SIZE(w, h, cf) \
|
||||
(LV_DRAW_BUF_STRIDE(w, cf) * (h) + LV_DRAW_BUF_ALIGN + \
|
||||
LV_COLOR_INDEXED_PALETTE_SIZE(cf) * sizeof(lv_color32_t))
|
||||
|
||||
/**
|
||||
* Define a static draw buffer with the given width, height, and color format.
|
||||
* Stride alignment is set to LV_DRAW_BUF_STRIDE_ALIGN.
|
||||
*
|
||||
* For platform that needs special buffer alignment, call LV_DRAW_BUF_INIT_STATIC.
|
||||
*/
|
||||
#define LV_DRAW_BUF_DEFINE_STATIC(name, _w, _h, _cf) \
|
||||
static LV_ATTRIBUTE_MEM_ALIGN uint8_t buf_##name[LV_DRAW_BUF_SIZE(_w, _h, _cf)]; \
|
||||
static lv_draw_buf_t name = { \
|
||||
.header = { \
|
||||
.magic = LV_IMAGE_HEADER_MAGIC, \
|
||||
.cf = (_cf), \
|
||||
.flags = LV_IMAGE_FLAGS_MODIFIABLE, \
|
||||
.w = (_w), \
|
||||
.h = (_h), \
|
||||
.stride = LV_DRAW_BUF_STRIDE(_w, _cf), \
|
||||
.reserved_2 = 0, \
|
||||
}, \
|
||||
.data_size = sizeof(buf_##name), \
|
||||
.data = buf_##name, \
|
||||
.unaligned_data = buf_##name, \
|
||||
}
|
||||
|
||||
#define LV_DRAW_BUF_INIT_STATIC(name) \
|
||||
do { \
|
||||
lv_image_header_t * header = &name.header; \
|
||||
lv_draw_buf_init(&name, header->w, header->h, (lv_color_format_t)header->cf, header->stride, buf_##name, sizeof(buf_##name)); \
|
||||
lv_draw_buf_set_flag(&name, LV_IMAGE_FLAGS_MODIFIABLE); \
|
||||
} while(0)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef void * (*lv_draw_buf_malloc_cb)(size_t size, lv_color_format_t color_format);
|
||||
|
||||
typedef void (*lv_draw_buf_free_cb)(void * draw_buf);
|
||||
|
||||
typedef void * (*lv_draw_buf_align_cb)(void * buf, lv_color_format_t color_format);
|
||||
|
||||
typedef void (*lv_draw_buf_cache_operation_cb)(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
typedef uint32_t (*lv_draw_buf_width_to_stride_cb)(uint32_t w, lv_color_format_t color_format);
|
||||
|
||||
struct _lv_draw_buf_t {
|
||||
lv_image_header_t header;
|
||||
uint32_t data_size; /**< Total buf size in bytes */
|
||||
uint8_t * data;
|
||||
void * unaligned_data; /**< Unaligned address of `data`, used internally by lvgl */
|
||||
const lv_draw_buf_handlers_t * handlers; /**< draw buffer alloc/free ops. */
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the draw buffer with the default handlers.
|
||||
*
|
||||
* @param handlers the draw buffer handlers to set
|
||||
*/
|
||||
void lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers);
|
||||
|
||||
/**
|
||||
* Initialize the draw buffer with given handlers.
|
||||
*
|
||||
* @param handlers the draw buffer handlers to set
|
||||
* @param buf_malloc_cb the callback to allocate memory for the buffer
|
||||
* @param buf_free_cb the callback to free memory of the buffer
|
||||
* @param align_pointer_cb the callback to align the buffer
|
||||
* @param invalidate_cache_cb the callback to invalidate the cache of the buffer
|
||||
* @param flush_cache_cb the callback to flush buffer
|
||||
* @param width_to_stride_cb the callback to calculate the stride based on the width and color format
|
||||
*/
|
||||
void lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,
|
||||
lv_draw_buf_malloc_cb buf_malloc_cb,
|
||||
lv_draw_buf_free_cb buf_free_cb,
|
||||
lv_draw_buf_align_cb align_pointer_cb,
|
||||
lv_draw_buf_cache_operation_cb invalidate_cache_cb,
|
||||
lv_draw_buf_cache_operation_cb flush_cache_cb,
|
||||
lv_draw_buf_width_to_stride_cb width_to_stride_cb);
|
||||
|
||||
/**
|
||||
* Get the struct which holds the callbacks for draw buf management.
|
||||
* Custom callback can be set on the returned value
|
||||
* @return pointer to the struct of handlers
|
||||
*/
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_handlers(void);
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_font_handlers(void);
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_image_handlers(void);
|
||||
|
||||
|
||||
/**
|
||||
* Align the address of a buffer. The buffer needs to be large enough for the real data after alignment
|
||||
* @param buf the data to align
|
||||
* @param color_format the color format of the buffer
|
||||
* @return the aligned buffer
|
||||
*/
|
||||
void * lv_draw_buf_align(void * buf, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Align the address of a buffer with custom draw buffer handlers.
|
||||
* The buffer needs to be large enough for the real data after alignment
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param buf the data to align
|
||||
* @param color_format the color format of the buffer
|
||||
* @return the aligned buffer
|
||||
*/
|
||||
void * lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers, void * buf, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Invalidate the cache of the buffer
|
||||
* @param draw_buf the draw buffer needs to be invalidated
|
||||
* @param area the area to invalidate in the buffer,
|
||||
* use NULL to invalidate the whole draw buffer address range
|
||||
*/
|
||||
void lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Flush the cache of the buffer
|
||||
* @param draw_buf the draw buffer needs to be flushed
|
||||
* @param area the area to flush in the buffer,
|
||||
* use NULL to flush the whole draw buffer address range
|
||||
*/
|
||||
void lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Calculate the stride in bytes based on a width and color format
|
||||
* @param w the width in pixels
|
||||
* @param color_format the color format
|
||||
* @return the stride in bytes
|
||||
*/
|
||||
uint32_t lv_draw_buf_width_to_stride(uint32_t w, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Calculate the stride in bytes based on a width and color format
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param w the width in pixels
|
||||
* @param color_format the color format
|
||||
* @return the stride in bytes
|
||||
*/
|
||||
uint32_t lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w,
|
||||
lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Clear an area on the buffer
|
||||
* @param draw_buf pointer to draw buffer
|
||||
* @param a the area to clear, or NULL to clear the whole buffer
|
||||
*/
|
||||
void lv_draw_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * a);
|
||||
|
||||
/**
|
||||
* Copy an area from a buffer to another
|
||||
* @param dest pointer to the destination draw buffer
|
||||
* @param dest_area the area to copy from the destination buffer, if NULL, use the whole buffer
|
||||
* @param src pointer to the source draw buffer
|
||||
* @param src_area the area to copy from the destination buffer, if NULL, use the whole buffer
|
||||
* @note `dest_area` and `src_area` should have the same width and height
|
||||
* @note `dest` and `src` should have same color format. Color converting is not supported fow now.
|
||||
*/
|
||||
void lv_draw_buf_copy(lv_draw_buf_t * dest, const lv_area_t * dest_area,
|
||||
const lv_draw_buf_t * src, const lv_area_t * src_area);
|
||||
|
||||
/**
|
||||
* Note: Eventually, lv_draw_buf_malloc/free will be kept as private.
|
||||
* For now, we use `create` to distinguish with malloc.
|
||||
*
|
||||
* Create an draw buf by allocating struct for `lv_draw_buf_t` and allocating a buffer for it
|
||||
* that meets specified requirements.
|
||||
*
|
||||
* @param w the buffer width in pixels
|
||||
* @param h the buffer height in pixels
|
||||
* @param cf the color format for image
|
||||
* @param stride the stride in bytes for image. Use 0 for automatic calculation based on
|
||||
* w, cf, and global stride alignment configuration.
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_create(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride);
|
||||
|
||||
/**
|
||||
* Note: Eventually, lv_draw_buf_malloc/free will be kept as private.
|
||||
* For now, we use `create` to distinguish with malloc.
|
||||
*
|
||||
* Create an draw buf by allocating struct for `lv_draw_buf_t` and allocating a buffer for it
|
||||
* that meets specified requirements.
|
||||
*
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param w the buffer width in pixels
|
||||
* @param h the buffer height in pixels
|
||||
* @param cf the color format for image
|
||||
* @param stride the stride in bytes for image. Use 0 for automatic calculation based on
|
||||
* w, cf, and global stride alignment configuration.
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w, uint32_t h,
|
||||
lv_color_format_t cf, uint32_t stride);
|
||||
|
||||
/**
|
||||
* Duplicate a draw buf with same image size, stride and color format. Copy the image data too.
|
||||
* @param draw_buf the draw buf to duplicate
|
||||
* @return the duplicated draw buf on success, NULL if failed
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_dup(const lv_draw_buf_t * draw_buf);
|
||||
|
||||
/**
|
||||
* Duplicate a draw buf with same image size, stride and color format. Copy the image data too.
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param draw_buf the draw buf to duplicate
|
||||
* @return the duplicated draw buf on success, NULL if failed
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers, const lv_draw_buf_t * draw_buf);
|
||||
|
||||
/**
|
||||
* Initialize a draw buf with the given buffer and parameters. Clear draw buffer flag to zero.
|
||||
* @param draw_buf the draw buf to initialize
|
||||
* @param w the buffer width in pixels
|
||||
* @param h the buffer height in pixels
|
||||
* @param cf the color format
|
||||
* @param stride the stride in bytes. Use 0 for automatic calculation
|
||||
* @param data the buffer used for drawing. Unaligned `data` will be aligned internally
|
||||
* @param data_size the size of the buffer in bytes
|
||||
* @return return LV_RESULT_OK on success, LV_RESULT_INVALID otherwise
|
||||
*/
|
||||
lv_result_t lv_draw_buf_init(lv_draw_buf_t * draw_buf, uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride,
|
||||
void * data, uint32_t data_size);
|
||||
|
||||
/**
|
||||
* Keep using the existing memory, reshape the draw buffer to the given width and height.
|
||||
* Return NULL if data_size is smaller than the required size.
|
||||
* @param draw_buf pointer to a draw buffer
|
||||
* @param cf the new color format, use 0 or LV_COLOR_FORMAT_UNKNOWN to keep using the original color format.
|
||||
* @param w the new width in pixels
|
||||
* @param h the new height in pixels
|
||||
* @param stride the stride in bytes for image. Use 0 for automatic calculation.
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_reshape(lv_draw_buf_t * draw_buf, lv_color_format_t cf, uint32_t w, uint32_t h,
|
||||
uint32_t stride);
|
||||
|
||||
/**
|
||||
* Destroy a draw buf by freeing the actual buffer if it's marked as LV_IMAGE_FLAGS_ALLOCATED in header.
|
||||
* Then free the lv_draw_buf_t struct.
|
||||
*
|
||||
* @param draw_buf the draw buffer to destroy
|
||||
*/
|
||||
void lv_draw_buf_destroy(lv_draw_buf_t * draw_buf);
|
||||
|
||||
/**
|
||||
* Return pointer to the buffer at the given coordinates
|
||||
*/
|
||||
void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y);
|
||||
|
||||
/**
|
||||
* Adjust the stride of a draw buf in place.
|
||||
* @param src pointer to a draw buffer
|
||||
* @param stride the new stride in bytes for image. Use LV_STRIDE_AUTO for automatic calculation.
|
||||
* @return LV_RESULT_OK: success or LV_RESULT_INVALID: failed
|
||||
*/
|
||||
lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride);
|
||||
|
||||
/**
|
||||
* Premultiply draw buffer color with alpha channel.
|
||||
* If it's already premultiplied, return directly.
|
||||
* Only color formats with alpha channel will be processed.
|
||||
*
|
||||
* @return LV_RESULT_OK: premultiply success
|
||||
*/
|
||||
lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf);
|
||||
|
||||
bool lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf, lv_image_flags_t flag);
|
||||
|
||||
void lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag);
|
||||
|
||||
void lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag);
|
||||
|
||||
/**
|
||||
* As of now, draw buf share same definition as `lv_image_dsc_t`.
|
||||
* And is interchangeable with `lv_image_dsc_t`.
|
||||
*/
|
||||
|
||||
lv_result_t lv_draw_buf_from_image(lv_draw_buf_t * buf, const lv_image_dsc_t * img);
|
||||
|
||||
void lv_draw_buf_to_image(const lv_draw_buf_t * buf, lv_image_dsc_t * img);
|
||||
|
||||
/**
|
||||
* Set the palette color of an indexed image. Valid only for `LV_COLOR_FORMAT_I1/2/4/8`
|
||||
* @param draw_buf pointer to an image descriptor
|
||||
* @param index the palette color to set:
|
||||
* - for `LV_COLOR_FORMAT_I1`: 0..1
|
||||
* - for `LV_COLOR_FORMAT_I2`: 0..3
|
||||
* - for `LV_COLOR_FORMAT_I4`: 0..15
|
||||
* - for `LV_COLOR_FORMAT_I8`: 0..255
|
||||
* @param color the color to set in lv_color32_t format
|
||||
*/
|
||||
void lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf, uint8_t index, lv_color32_t color);
|
||||
|
||||
/**
|
||||
* @deprecated Use lv_draw_buf_set_palette instead.
|
||||
*/
|
||||
void lv_image_buf_set_palette(lv_image_dsc_t * dsc, uint8_t id, lv_color32_t c);
|
||||
|
||||
/**
|
||||
* @deprecated Use lv_draw_buffer_create/destroy instead.
|
||||
* Free the data pointer and dsc struct of an image.
|
||||
*/
|
||||
void lv_image_buf_free(lv_image_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_BUF_H*/
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file lv_draw_buf_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_BUF_PRIVATE_H
|
||||
#define LV_DRAW_BUF_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_buf.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_buf_handlers_t {
|
||||
lv_draw_buf_malloc_cb buf_malloc_cb;
|
||||
lv_draw_buf_free_cb buf_free_cb;
|
||||
lv_draw_buf_align_cb align_pointer_cb;
|
||||
lv_draw_buf_cache_operation_cb invalidate_cache_cb;
|
||||
lv_draw_buf_cache_operation_cb flush_cache_cb;
|
||||
lv_draw_buf_width_to_stride_cb width_to_stride_cb;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Called internally to initialize the draw_buf_handlers in lv_global
|
||||
*/
|
||||
void lv_draw_buf_init_handlers(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_BUF_PRIVATE_H*/
|
||||
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* @file lv_draw_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_image_private.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "lv_image_decoder_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../core/lv_obj_private.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void img_decode_and_draw(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
lv_image_decoder_dsc_t * decoder_dsc, lv_area_t * relative_decoded_area,
|
||||
const lv_area_t * img_area, const lv_area_t * clipped_img_area,
|
||||
lv_draw_image_core_cb draw_core_cb);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_image_dsc_init(lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_image_dsc_t));
|
||||
dsc->recolor = lv_color_black();
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->scale_x = LV_SCALE_NONE;
|
||||
dsc->scale_y = LV_SCALE_NONE;
|
||||
dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
|
||||
dsc->image_area.x2 = LV_COORD_MIN; /*Indicate invalid area by default by setting a negative size*/
|
||||
dsc->base.dsc_size = sizeof(lv_draw_image_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_image_dsc_t * lv_draw_task_get_image_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_IMAGE ? (lv_draw_image_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_layer(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->scale_x <= 0 || dsc->scale_y <= 0) {
|
||||
/* NOT draw if scale is negative or zero */
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_LAYER);
|
||||
lv_draw_image_dsc_t * new_image_dsc = t->draw_dsc;
|
||||
lv_memcpy(new_image_dsc, dsc, sizeof(*dsc));
|
||||
t->state = LV_DRAW_TASK_STATE_WAITING;
|
||||
|
||||
lv_image_buf_get_transformed_area(&t->_real_area, lv_area_get_width(coords), lv_area_get_height(coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&t->_real_area, coords->x1, coords->y1);
|
||||
|
||||
/*If the image_area is not set assume that it's the same as the rendering area */
|
||||
if(new_image_dsc->image_area.x2 == LV_COORD_MIN) {
|
||||
new_image_dsc->image_area = *coords;
|
||||
}
|
||||
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)dsc->src;
|
||||
layer_to_draw->all_tasks_added = true;
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_image(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * image_coords)
|
||||
{
|
||||
if(dsc->src == NULL) {
|
||||
LV_LOG_WARN("Image draw: src is NULL");
|
||||
return;
|
||||
}
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
if(dsc->scale_x <= 0 || dsc->scale_y <= 0) {
|
||||
/* NOT draw if scale is negative or zero */
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_image_dsc_t new_image_dsc;
|
||||
lv_memcpy(&new_image_dsc, dsc, sizeof(*dsc));
|
||||
lv_result_t res = lv_image_decoder_get_info(new_image_dsc.src, &new_image_dsc.header);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_WARN("Couldn't get info about the image");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
/*If the image_area is not set assume that it's the same as the rendering area */
|
||||
if(new_image_dsc.image_area.x2 == LV_COORD_MIN) {
|
||||
new_image_dsc.image_area = *image_coords;
|
||||
}
|
||||
|
||||
/*Typical case, draw the image as bitmap*/
|
||||
if(!(new_image_dsc.header.flags & LV_IMAGE_FLAGS_CUSTOM_DRAW)) {
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, image_coords, LV_DRAW_TASK_TYPE_IMAGE);
|
||||
lv_memcpy(t->draw_dsc, &new_image_dsc, sizeof(lv_draw_image_dsc_t));
|
||||
|
||||
lv_image_buf_get_transformed_area(&t->_real_area, lv_area_get_width(image_coords), lv_area_get_height(image_coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&t->_real_area, image_coords->x1, image_coords->y1);
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
/*Use a custom draw callback*/
|
||||
else {
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
res = lv_image_decoder_open(&decoder_dsc, new_image_dsc.src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(decoder_dsc.decoder && decoder_dsc.decoder->custom_draw_cb) {
|
||||
lv_area_t draw_area = layer->buf_area;
|
||||
lv_area_t coords_area = *image_coords;
|
||||
|
||||
lv_area_t obj_area = dsc->base.obj->coords;
|
||||
if(layer->parent) { /* child layer */
|
||||
if(lv_area_intersect(&coords_area, &coords_area, &obj_area)) {
|
||||
int32_t xpos = image_coords->x1 - draw_area.x1;
|
||||
int32_t ypos = image_coords->y1 - draw_area.y1;
|
||||
|
||||
lv_area_move(&coords_area, -(image_coords->x1 - xpos), -(image_coords->y1 - ypos));
|
||||
layer->_clip_area = coords_area;
|
||||
decoder_dsc.decoder->custom_draw_cb(layer, &decoder_dsc, &coords_area, &new_image_dsc, &coords_area);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lv_area_t clip_area = draw_area;
|
||||
if(lv_area_intersect(&clip_area, &clip_area, &coords_area)) {
|
||||
|
||||
lv_image_buf_get_transformed_area(&coords_area, lv_area_get_width(image_coords), lv_area_get_height(image_coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&coords_area, image_coords->x1, image_coords->y1);
|
||||
|
||||
lv_image_buf_get_transformed_area(&clip_area, lv_area_get_width(image_coords), lv_area_get_height(image_coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&clip_area, image_coords->x1, image_coords->y1);
|
||||
|
||||
if(lv_area_intersect(&clip_area, &clip_area, &obj_area)) {
|
||||
decoder_dsc.decoder->custom_draw_cb(layer, &decoder_dsc, &coords_area, &new_image_dsc, &clip_area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
lv_image_src_t lv_image_src_get_type(const void * src)
|
||||
{
|
||||
if(src == NULL) return LV_IMAGE_SRC_UNKNOWN;
|
||||
const uint8_t * u8_p = src;
|
||||
|
||||
/*The first byte shows the type of the image source*/
|
||||
if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
|
||||
return LV_IMAGE_SRC_FILE; /*If it's an ASCII character then it's file name*/
|
||||
}
|
||||
else if(u8_p[0] >= 0x80) {
|
||||
return LV_IMAGE_SRC_SYMBOL; /*Symbols begins after 0x7F*/
|
||||
}
|
||||
else {
|
||||
return LV_IMAGE_SRC_VARIABLE; /*`lv_image_dsc_t` is draw to the first byte < 0x20*/
|
||||
}
|
||||
}
|
||||
|
||||
void lv_draw_image_normal_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb)
|
||||
{
|
||||
if(draw_core_cb == NULL) {
|
||||
LV_LOG_WARN("draw_core_cb is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t draw_area;
|
||||
lv_area_copy(&draw_area, coords);
|
||||
if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) {
|
||||
int32_t w = lv_area_get_width(coords);
|
||||
int32_t h = lv_area_get_height(coords);
|
||||
|
||||
lv_image_buf_get_transformed_area(&draw_area, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y,
|
||||
&draw_dsc->pivot);
|
||||
|
||||
draw_area.x1 += coords->x1;
|
||||
draw_area.y1 += coords->y1;
|
||||
draw_area.x2 += coords->x1;
|
||||
draw_area.y2 += coords->y1;
|
||||
}
|
||||
|
||||
lv_area_t clipped_img_area;
|
||||
if(!lv_area_intersect(&clipped_img_area, &draw_area, &t->clip_area)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
return;
|
||||
}
|
||||
|
||||
img_decode_and_draw(t, draw_dsc, &decoder_dsc, NULL, coords, &clipped_img_area, draw_core_cb);
|
||||
|
||||
lv_image_decoder_close(&decoder_dsc);
|
||||
}
|
||||
|
||||
void lv_draw_image_tiled_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb)
|
||||
{
|
||||
if(draw_core_cb == NULL) {
|
||||
LV_LOG_WARN("draw_core_cb is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t img_w = draw_dsc->header.w;
|
||||
int32_t img_h = draw_dsc->header.h;
|
||||
|
||||
lv_area_t tile_area;
|
||||
if(lv_area_get_width(&draw_dsc->image_area) >= 0) {
|
||||
tile_area = draw_dsc->image_area;
|
||||
}
|
||||
else {
|
||||
tile_area = *coords;
|
||||
}
|
||||
lv_area_set_width(&tile_area, img_w);
|
||||
lv_area_set_height(&tile_area, img_h);
|
||||
|
||||
int32_t tile_x_start = tile_area.x1;
|
||||
|
||||
lv_area_t relative_decoded_area = {
|
||||
.x1 = LV_COORD_MIN,
|
||||
.y1 = LV_COORD_MIN,
|
||||
.x2 = LV_COORD_MIN,
|
||||
.y2 = LV_COORD_MIN,
|
||||
};
|
||||
|
||||
while(tile_area.y1 <= coords->y2) {
|
||||
while(tile_area.x1 <= coords->x2) {
|
||||
|
||||
lv_area_t clipped_img_area;
|
||||
if(lv_area_intersect(&clipped_img_area, &tile_area, coords)) {
|
||||
img_decode_and_draw(t, draw_dsc, &decoder_dsc, &relative_decoded_area, &tile_area, &clipped_img_area,
|
||||
draw_core_cb);
|
||||
}
|
||||
|
||||
tile_area.x1 += img_w;
|
||||
tile_area.x2 += img_w;
|
||||
}
|
||||
|
||||
tile_area.y1 += img_h;
|
||||
tile_area.y2 += img_h;
|
||||
tile_area.x1 = tile_x_start;
|
||||
tile_area.x2 = tile_x_start + img_w - 1;
|
||||
}
|
||||
|
||||
lv_image_decoder_close(&decoder_dsc);
|
||||
}
|
||||
|
||||
void lv_image_buf_get_transformed_area(lv_area_t * res, int32_t w, int32_t h, int32_t angle,
|
||||
uint16_t scale_x, uint16_t scale_y, const lv_point_t * pivot)
|
||||
{
|
||||
if(angle == 0 && scale_x == LV_SCALE_NONE && scale_y == LV_SCALE_NONE) {
|
||||
res->x1 = 0;
|
||||
res->y1 = 0;
|
||||
res->x2 = w - 1;
|
||||
res->y2 = h - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_point_t p[4] = {
|
||||
{0, 0},
|
||||
{w, 0},
|
||||
{0, h},
|
||||
{w, h},
|
||||
};
|
||||
lv_point_transform(&p[0], angle, scale_x, scale_y, pivot, true);
|
||||
lv_point_transform(&p[1], angle, scale_x, scale_y, pivot, true);
|
||||
lv_point_transform(&p[2], angle, scale_x, scale_y, pivot, true);
|
||||
lv_point_transform(&p[3], angle, scale_x, scale_y, pivot, true);
|
||||
res->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x);
|
||||
res->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x) - 1;
|
||||
res->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y);
|
||||
res->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y) - 1;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void img_decode_and_draw(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
lv_image_decoder_dsc_t * decoder_dsc, lv_area_t * relative_decoded_area,
|
||||
const lv_area_t * img_area, const lv_area_t * clipped_img_area,
|
||||
lv_draw_image_core_cb draw_core_cb)
|
||||
{
|
||||
lv_draw_image_sup_t sup;
|
||||
sup.alpha_color = draw_dsc->recolor;
|
||||
sup.palette = decoder_dsc->palette;
|
||||
sup.palette_size = decoder_dsc->palette_size;
|
||||
|
||||
/*The whole image is available, just draw it*/
|
||||
if(decoder_dsc->decoded && (relative_decoded_area == NULL || relative_decoded_area->x1 == LV_COORD_MIN)) {
|
||||
draw_core_cb(t, draw_dsc, decoder_dsc, &sup, img_area, clipped_img_area);
|
||||
}
|
||||
/*Draw in smaller pieces*/
|
||||
else {
|
||||
lv_area_t relative_full_area_to_decode = *clipped_img_area;
|
||||
lv_area_move(&relative_full_area_to_decode, -img_area->x1, -img_area->y1);
|
||||
lv_area_t tmp;
|
||||
if(relative_decoded_area == NULL) relative_decoded_area = &tmp;
|
||||
relative_decoded_area->x1 = LV_COORD_MIN;
|
||||
relative_decoded_area->y1 = LV_COORD_MIN;
|
||||
relative_decoded_area->x2 = LV_COORD_MIN;
|
||||
relative_decoded_area->y2 = LV_COORD_MIN;
|
||||
lv_result_t res = LV_RESULT_OK;
|
||||
|
||||
while(res == LV_RESULT_OK) {
|
||||
res = lv_image_decoder_get_area(decoder_dsc, &relative_full_area_to_decode, relative_decoded_area);
|
||||
|
||||
lv_area_t absolute_decoded_area = *relative_decoded_area;
|
||||
lv_area_move(&absolute_decoded_area, img_area->x1, img_area->y1);
|
||||
if(res == LV_RESULT_OK) {
|
||||
/*Limit draw area to the current decoded area and draw the image*/
|
||||
lv_area_t clipped_img_area_sub;
|
||||
if(lv_area_intersect(&clipped_img_area_sub, clipped_img_area, &absolute_decoded_area)) {
|
||||
draw_core_cb(t, draw_dsc, decoder_dsc, &sup,
|
||||
&absolute_decoded_area, &clipped_img_area_sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @file lv_draw_image.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_IMAGE_H
|
||||
#define LV_DRAW_IMAGE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "lv_image_decoder.h"
|
||||
#include "lv_draw_buf.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_image_dsc_t {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The image source: pointer to `lv_image_dsc_t` or a path to a file*/
|
||||
const void * src;
|
||||
|
||||
/**The header of the image. Initialized internally in `lv_draw_image` */
|
||||
lv_image_header_t header;
|
||||
|
||||
/**Clip the corner of the image with this radius. Use `LV_RADIUS_CIRCLE` for max. radius */
|
||||
int32_t clip_radius;
|
||||
|
||||
/**The rotation of the image in 0.1 degree unit. E.g. 234 means 23.4° */
|
||||
int32_t rotation;
|
||||
|
||||
/**Horizontal scale (zoom) of the image.
|
||||
* 256 (LV_SCALE_NONE): means no zoom, 512 double size, 128 half size.*/
|
||||
int32_t scale_x;
|
||||
|
||||
/**Same as `scale_y` but vertically*/
|
||||
int32_t scale_y;
|
||||
|
||||
/**Parallelogram like transformation of the image horizontally in 0.1 degree unit. E.g. 456 means 45.6°.*/
|
||||
int32_t skew_x;
|
||||
|
||||
/**Same as `skew_x` but vertically*/
|
||||
int32_t skew_y;
|
||||
|
||||
/**The pivot point of transformation (scale and rotation).
|
||||
* 0;0 is the top left corner of the image. Can be outside of the image too.*/
|
||||
lv_point_t pivot;
|
||||
|
||||
/**Mix this color to the images. In case of `LV_COLOR_FORMAT_A8` it will be the color of the visible pixels*/
|
||||
lv_color_t recolor;
|
||||
|
||||
/**The intensity of recoloring. 0 means, no recolor, 255 means full cover (transparent pixels remain transparent)*/
|
||||
lv_opa_t recolor_opa;
|
||||
|
||||
/**Opacity in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**Describes how to blend the pixels of the image to the background.
|
||||
* See `lv_blend_mode_t` for more details.
|
||||
*/
|
||||
lv_blend_mode_t blend_mode : 4;
|
||||
|
||||
/**1: perform the transformation with anti-alaising */
|
||||
uint16_t antialias : 1;
|
||||
|
||||
/**If the image is smaller than the `image_area` field of `lv_draw_image_dsc_t`
|
||||
* tile the image (repeat is both horizontally and vertically) to fill the
|
||||
* `image_area` area*/
|
||||
uint16_t tile : 1;
|
||||
|
||||
/**Used internally to store some information about the palette or the color of A8 images*/
|
||||
lv_draw_image_sup_t * sup;
|
||||
|
||||
/** Used to indicate the entire original, non-clipped area where the image is to be drawn.
|
||||
* This is important for:
|
||||
* 1. Layer rendering, where it might happen that only a smaller area of the layer is rendered and e.g.
|
||||
* `clip_radius` needs to know what the original image was.
|
||||
* 2. Tiled images, where the target draw area is larger than the image to be tiled.
|
||||
*/
|
||||
lv_area_t image_area;
|
||||
|
||||
/**Pointer to an A8 or L8 image descriptor to mask the image with.
|
||||
* The mask is always center aligned. */
|
||||
const lv_image_dsc_t * bitmap_mask_src;
|
||||
};
|
||||
|
||||
/**
|
||||
* PErform the actual rendering of a decoded image
|
||||
* @param t pointer to a draw task
|
||||
* @param draw_dsc the draw descriptor of the image
|
||||
* @param decoder_dsc pointer to the decoded image's descriptor
|
||||
* @param sup supplementary data
|
||||
* @param img_coords the absolute coordinates of the image
|
||||
* @param clipped_img_area the absolute clip coordinates
|
||||
*/
|
||||
typedef void (*lv_draw_image_core_cb)(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup,
|
||||
const lv_area_t * img_coords, const lv_area_t * clipped_img_area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an image draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_image_dsc_init(lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get an image draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_IMAGE
|
||||
*/
|
||||
lv_draw_image_dsc_t * lv_draw_task_get_image_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create an image draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor
|
||||
* @param coords the coordinates of the image
|
||||
* @note `coords` can be small than the real image area
|
||||
* (if only a part of the image is rendered)
|
||||
* or can be larger (in case of tiled images). .
|
||||
*/
|
||||
void lv_draw_image(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Create a draw task to blend a layer to another layer
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor. `src` must be set to the layer to blend
|
||||
* @param coords the coordinates of the layer.
|
||||
* @note `coords` can be small than the total widget area from which the layer is created
|
||||
* (if only a part of the widget was rendered to a layer)
|
||||
*/
|
||||
void lv_draw_layer(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Get the type of an image source
|
||||
* @param src pointer to an image source:
|
||||
* - pointer to an 'lv_image_t' variable (image stored internally and compiled into the code)
|
||||
* - a path to a file (e.g. "S:/folder/image.bin")
|
||||
* - or a symbol (e.g. LV_SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMAGE_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
|
||||
*/
|
||||
lv_image_src_t lv_image_src_get_type(const void * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_IMAGE_H*/
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file lv_draw_image_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_IMAGE_PRIVATE_H
|
||||
#define LV_DRAW_IMAGE_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_image.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_image_sup_t {
|
||||
lv_color_t alpha_color;
|
||||
const lv_color32_t * palette;
|
||||
uint32_t palette_size : 9;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Can be used by draw units to handle the decoding and
|
||||
* prepare everything for the actual image rendering
|
||||
* @param t pointer to a draw task
|
||||
* @param draw_dsc the draw descriptor of the image
|
||||
* @param coords the absolute coordinates of the image
|
||||
* @param draw_core_cb a callback to perform the actual rendering
|
||||
*/
|
||||
void lv_draw_image_normal_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb);
|
||||
|
||||
/**
|
||||
* Can be used by draw units for TILED images to handle the decoding and
|
||||
* prepare everything for the actual image rendering
|
||||
* @param t pointer to a draw task
|
||||
* @param draw_dsc the draw descriptor of the image
|
||||
* @param coords the absolute coordinates of the image
|
||||
* @param draw_core_cb a callback to perform the actual rendering
|
||||
*/
|
||||
void lv_draw_image_tiled_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb);
|
||||
|
||||
/**
|
||||
* Get the area of a rectangle if its rotated and scaled
|
||||
* @param res store the coordinates here
|
||||
* @param w width of the rectangle to transform
|
||||
* @param h height of the rectangle to transform
|
||||
* @param angle angle of rotation
|
||||
* @param scale_x zoom in x direction, (256 no zoom)
|
||||
* @param scale_y zoom in y direction, (256 no zoom)
|
||||
* @param pivot x,y pivot coordinates of rotation
|
||||
*/
|
||||
void lv_image_buf_get_transformed_area(lv_area_t * res, int32_t w, int32_t h, int32_t angle,
|
||||
uint16_t scale_x, uint16_t scale_y, const lv_point_t * pivot);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_IMAGE_PRIVATE_H*/
|
||||
@@ -0,0 +1,636 @@
|
||||
/**
|
||||
* @file lv_draw_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_label_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "lv_draw_vector_private.h"
|
||||
#include "lv_draw_rect_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../core/lv_obj_event.h"
|
||||
#include "../misc/lv_bidi_private.h"
|
||||
#include "../misc/lv_text_private.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LABEL_RECOLOR_PAR_LENGTH 6
|
||||
#define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/
|
||||
|
||||
#define font_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->font_draw_buf_handlers)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER,
|
||||
RECOLOR_CMD_STATE_PARAMETER,
|
||||
RECOLOR_CMD_STATE_TEXT_INPUT,
|
||||
};
|
||||
typedef unsigned char cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_letter_dsc_init(lv_draw_letter_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_letter_dsc_t));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->font = LV_FONT_DEFAULT;
|
||||
dsc->rotation = 0;
|
||||
dsc->scale_x = LV_SCALE_NONE;
|
||||
dsc->scale_y = LV_SCALE_NONE;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_letter_dsc_t);
|
||||
}
|
||||
|
||||
void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_label_dsc_t));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->text_length = LV_TEXT_LEN_MAX;
|
||||
dsc->font = LV_FONT_DEFAULT;
|
||||
dsc->sel_start = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
dsc->sel_end = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
dsc->sel_color = lv_color_black();
|
||||
dsc->sel_bg_color = lv_palette_main(LV_PALETTE_BLUE);
|
||||
dsc->bidi_dir = LV_BASE_DIR_LTR;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_label_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_label_dsc_t * lv_draw_task_get_label_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_LABEL ? (lv_draw_label_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_glyph_dsc_init(lv_draw_glyph_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_glyph_dsc_t));
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_label(lv_layer_t * layer, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->text == NULL || dsc->text[0] == '\0') return;
|
||||
if(dsc->font == NULL) {
|
||||
LV_LOG_WARN("dsc->font == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_LABEL);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
/*The text is stored in a local variable so malloc memory for it*/
|
||||
if(dsc->text_local) {
|
||||
lv_draw_label_dsc_t * new_dsc = t->draw_dsc;
|
||||
new_dsc->text = lv_strndup(dsc->text, dsc->text_length);
|
||||
LV_ASSERT_MALLOC(new_dsc->text);
|
||||
}
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_character(lv_layer_t * layer, lv_draw_label_dsc_t * dsc,
|
||||
const lv_point_t * point, uint32_t unicode_letter)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->font == NULL) {
|
||||
LV_LOG_WARN("dsc->font == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_text_is_marker(unicode_letter)) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_font_glyph_dsc_t g;
|
||||
lv_font_get_glyph_dsc(dsc->font, &g, unicode_letter, 0);
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = point->x;
|
||||
a.y1 = point->y;
|
||||
a.x2 = a.x1 + g.adv_w;
|
||||
a.y2 = a.y1 + lv_font_get_line_height(g.resolved_font ? g.resolved_font : dsc->font);
|
||||
|
||||
/*lv_draw_label needs UTF8 text so convert the Unicode character to an UTF8 string */
|
||||
uint32_t letter_buf[2];
|
||||
letter_buf[0] = lv_text_unicode_to_encoded(unicode_letter);
|
||||
letter_buf[1] = '\0';
|
||||
|
||||
const char * letter_buf_char = (const char *)letter_buf;
|
||||
|
||||
#if LV_BIG_ENDIAN_SYSTEM
|
||||
while(*letter_buf_char == 0) ++letter_buf_char;
|
||||
#endif
|
||||
|
||||
dsc->text = letter_buf_char;
|
||||
dsc->text_local = 1;
|
||||
|
||||
lv_draw_label(layer, dsc, &a);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_letter(lv_layer_t * layer, lv_draw_letter_dsc_t * dsc, const lv_point_t * point)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->font == NULL) {
|
||||
LV_LOG_WARN("dsc->font == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
const lv_font_t * font = dsc->font;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_font_glyph_dsc_t g;
|
||||
lv_font_get_glyph_dsc(font, &g, dsc->unicode, 0);
|
||||
|
||||
font = g.resolved_font ? g.resolved_font : dsc->font;
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = point->x;
|
||||
a.y1 = point->y;
|
||||
a.x2 = a.x1 + g.adv_w;
|
||||
a.y2 = a.y1 + lv_font_get_line_height(font);
|
||||
|
||||
dsc->pivot.x = g.adv_w / 2 ;
|
||||
dsc->pivot.y = font->line_height - font->base_line;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_LETTER);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords,
|
||||
lv_draw_glyph_cb_t cb)
|
||||
{
|
||||
lv_draw_dsc_base_t * base_dsc = t->draw_dsc;
|
||||
const lv_font_t * font = dsc->font;
|
||||
int32_t w;
|
||||
|
||||
lv_area_t clipped_area;
|
||||
bool clip_ok = lv_area_intersect(&clipped_area, coords, &t->clip_area);
|
||||
if(!clip_ok) return;
|
||||
|
||||
lv_text_align_t align = dsc->align;
|
||||
lv_base_dir_t base_dir = dsc->bidi_dir;
|
||||
|
||||
lv_bidi_calculate_align(&align, &base_dir, dsc->text);
|
||||
|
||||
if((dsc->flag & LV_TEXT_FLAG_EXPAND) == 0) {
|
||||
/*Normally use the label's width as width*/
|
||||
w = lv_area_get_width(coords);
|
||||
}
|
||||
else {
|
||||
/*If EXPAND is enabled then not limit the text's width to the object's width*/
|
||||
if(base_dsc->obj && !lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) {
|
||||
w = dsc->text_size.x;
|
||||
}
|
||||
else {
|
||||
lv_point_t p;
|
||||
lv_text_get_size(&p, dsc->text, dsc->font, dsc->letter_space, dsc->line_space, LV_COORD_MAX,
|
||||
dsc->flag);
|
||||
w = p.x;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t line_height_font = lv_font_get_line_height(font);
|
||||
int32_t line_height = line_height_font + dsc->line_space;
|
||||
|
||||
/*Init variables for the first line*/
|
||||
int32_t line_width = 0;
|
||||
lv_point_t pos;
|
||||
lv_point_set(&pos, coords->x1, coords->y1);
|
||||
|
||||
int32_t x_ofs = 0;
|
||||
int32_t y_ofs = 0;
|
||||
x_ofs = dsc->ofs_x;
|
||||
y_ofs = dsc->ofs_y;
|
||||
pos.y += y_ofs;
|
||||
|
||||
uint32_t line_start = 0;
|
||||
int32_t last_line_start = -1;
|
||||
|
||||
/*Check the hint to use the cached info*/
|
||||
if(dsc->hint && y_ofs == 0 && coords->y1 < 0) {
|
||||
/*If the label changed too much recalculate the hint.*/
|
||||
if(LV_ABS(dsc->hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) {
|
||||
dsc->hint->line_start = -1;
|
||||
}
|
||||
last_line_start = dsc->hint->line_start;
|
||||
}
|
||||
|
||||
/*Use the hint if it's valid*/
|
||||
if(dsc->hint && last_line_start >= 0) {
|
||||
line_start = last_line_start;
|
||||
pos.y += dsc->hint->y;
|
||||
}
|
||||
|
||||
uint32_t remaining_len = dsc->text_length;
|
||||
|
||||
uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space,
|
||||
w, NULL, dsc->flag);
|
||||
|
||||
/*Go the first visible line*/
|
||||
while(pos.y + line_height_font < t->clip_area.y1) {
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
|
||||
pos.y += line_height;
|
||||
|
||||
/*Save at the threshold coordinate*/
|
||||
if(dsc->hint && pos.y >= -LV_LABEL_HINT_UPDATE_TH && dsc->hint->line_start < 0) {
|
||||
dsc->hint->line_start = line_start;
|
||||
dsc->hint->y = pos.y - coords->y1;
|
||||
dsc->hint->coord_y = coords->y1;
|
||||
}
|
||||
|
||||
if(dsc->text[line_start] == '\0') return;
|
||||
}
|
||||
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
uint32_t sel_start = dsc->sel_start;
|
||||
uint32_t sel_end = dsc->sel_end;
|
||||
if(sel_start > sel_end) {
|
||||
uint32_t tmp = sel_start;
|
||||
sel_start = sel_end;
|
||||
sel_end = tmp;
|
||||
}
|
||||
|
||||
lv_area_t bg_coords;
|
||||
lv_draw_glyph_dsc_t draw_letter_dsc;
|
||||
lv_draw_glyph_dsc_init(&draw_letter_dsc);
|
||||
draw_letter_dsc.opa = dsc->opa;
|
||||
draw_letter_dsc.bg_coords = &bg_coords;
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
draw_letter_dsc.rotation = dsc->rotation;
|
||||
|
||||
/* Set letter outline stroke attributes */
|
||||
draw_letter_dsc.outline_stroke_width = dsc->outline_stroke_width;
|
||||
draw_letter_dsc.outline_stroke_opa = dsc->outline_stroke_opa;
|
||||
draw_letter_dsc.outline_stroke_color = dsc->outline_stroke_color;
|
||||
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.opa = dsc->opa;
|
||||
int32_t underline_width = font->underline_thickness ? font->underline_thickness : 1;
|
||||
int32_t line_start_x;
|
||||
uint32_t next_char_offset;
|
||||
uint32_t recolor_command_start_index = 0;
|
||||
int32_t letter_w;
|
||||
cmd_state_t recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
lv_color_t recolor = lv_color_black(); /* Holds the selected color inside the recolor command */
|
||||
uint8_t is_first_space_after_cmd = 0;
|
||||
|
||||
/*Write out all lines*/
|
||||
while(remaining_len && dsc->text[line_start] != '\0') {
|
||||
pos.x += x_ofs;
|
||||
line_start_x = pos.x;
|
||||
|
||||
/*Write all letter of a line*/
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
next_char_offset = 0;
|
||||
#if LV_USE_BIDI
|
||||
size_t bidi_size = line_end - line_start;
|
||||
char * bidi_txt = lv_malloc(bidi_size + 1);
|
||||
LV_ASSERT_MALLOC(bidi_txt);
|
||||
|
||||
/**
|
||||
* has_bided = 1: already executed lv_bidi_process_paragraph.
|
||||
* has_bided = 0: has not been executed lv_bidi_process_paragraph.*/
|
||||
if(dsc->has_bided) {
|
||||
lv_memcpy(bidi_txt, &dsc->text[line_start], bidi_size);
|
||||
}
|
||||
else {
|
||||
lv_bidi_process_paragraph(dsc->text + line_start, bidi_txt, bidi_size, base_dir, NULL, 0);
|
||||
}
|
||||
#else
|
||||
const char * bidi_txt = dsc->text + line_start;
|
||||
#endif
|
||||
|
||||
while(next_char_offset < remaining_len && next_char_offset < line_end - line_start) {
|
||||
uint32_t logical_char_pos = 0;
|
||||
|
||||
/* Check if the text selection is enabled */
|
||||
if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL) {
|
||||
#if LV_USE_BIDI
|
||||
if(dsc->has_bided) {
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + next_char_offset);
|
||||
}
|
||||
else {
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start);
|
||||
uint32_t c_idx = lv_text_encoded_get_char_id(bidi_txt, next_char_offset);
|
||||
logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, base_dir, c_idx, NULL);
|
||||
}
|
||||
#else
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + next_char_offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &next_char_offset);
|
||||
|
||||
/* If recolor is enabled */
|
||||
if((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
|
||||
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
/* Handle the recolor command marker depending of the current recolor state */
|
||||
|
||||
if(recolor_cmd_state == RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER) {
|
||||
recolor_command_start_index = next_char_offset;
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
/*Other start char in parameter escaped cmd. char*/
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) {
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
}
|
||||
/* If letter is LV_TXT_COLOR_CMD and we were in the CMD_STATE_IN then the recolor close marked has been found */
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) {
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the first space (aka ' ') after the recolor command parameter, we need to skip rendering it */
|
||||
if((recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) && (letter == ' ') && (is_first_space_after_cmd == 0)) {
|
||||
is_first_space_after_cmd = 1;
|
||||
}
|
||||
else {
|
||||
is_first_space_after_cmd = 0;
|
||||
}
|
||||
|
||||
/* Skip the color parameter and wait the space after it
|
||||
* Once we have reach the space ' ', then we will extract the color information
|
||||
* and store it into the recolor variable */
|
||||
if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) {
|
||||
/* Not an space? Continue with the next character */
|
||||
if(letter != ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*Get the recolor parameter*/
|
||||
if((next_char_offset - recolor_command_start_index) == LABEL_RECOLOR_PAR_LENGTH + 1) {
|
||||
/* Temporary buffer to hold the recolor information */
|
||||
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
|
||||
lv_memcpy(buf, &bidi_txt[recolor_command_start_index], LABEL_RECOLOR_PAR_LENGTH);
|
||||
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
|
||||
|
||||
uint8_t r, g, b;
|
||||
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
|
||||
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
|
||||
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
|
||||
|
||||
recolor = lv_color_make(r, g, b);
|
||||
}
|
||||
else {
|
||||
recolor.red = dsc->color.red;
|
||||
recolor.blue = dsc->color.blue;
|
||||
recolor.green = dsc->color.green;
|
||||
}
|
||||
|
||||
/*After the parameter the text is in the command*/
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_TEXT_INPUT;
|
||||
}
|
||||
|
||||
/* Don't draw the first space after the recolor command */
|
||||
if(is_first_space_after_cmd) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're in the CMD_STATE_IN state then we need to subtract the recolor command length */
|
||||
if(((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) && (recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT)) {
|
||||
logical_char_pos -= (LABEL_RECOLOR_PAR_LENGTH + 1);
|
||||
}
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
/*Always set the bg_coordinates for placeholder drawing*/
|
||||
bg_coords.x1 = pos.x;
|
||||
bg_coords.y1 = pos.y;
|
||||
bg_coords.x2 = pos.x + letter_w - 1;
|
||||
bg_coords.y2 = pos.y + line_height - 1;
|
||||
|
||||
if(next_char_offset >= line_end - line_start) {
|
||||
if(dsc->decor & LV_TEXT_DECOR_UNDERLINE) {
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = line_start_x;
|
||||
fill_area.x2 = pos.x + letter_w - 1;
|
||||
fill_area.y1 = pos.y + font->line_height - font->base_line - font->underline_position;
|
||||
fill_area.y2 = fill_area.y1 + underline_width - 1;
|
||||
|
||||
fill_dsc.color = dsc->color;
|
||||
cb(t, NULL, &fill_dsc, &fill_area);
|
||||
}
|
||||
if(dsc->decor & LV_TEXT_DECOR_STRIKETHROUGH) {
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = line_start_x;
|
||||
fill_area.x2 = pos.x + letter_w - 1;
|
||||
fill_area.y1 = pos.y + (font->line_height - font->base_line) * 2 / 3 + font->underline_thickness / 2;
|
||||
fill_area.y2 = fill_area.y1 + underline_width - 1;
|
||||
|
||||
fill_dsc.color = dsc->color;
|
||||
cb(t, NULL, &fill_dsc, &fill_area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle text selection */
|
||||
if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL
|
||||
&& logical_char_pos >= sel_start && logical_char_pos < sel_end) {
|
||||
draw_letter_dsc.color = dsc->sel_color;
|
||||
fill_dsc.color = dsc->sel_bg_color;
|
||||
cb(t, NULL, &fill_dsc, &bg_coords);
|
||||
}
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) {
|
||||
draw_letter_dsc.color = recolor;
|
||||
}
|
||||
else {
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
}
|
||||
|
||||
lv_draw_unit_draw_letter(t, &draw_letter_dsc, &pos, font, letter, cb);
|
||||
|
||||
if(letter_w > 0) {
|
||||
pos.x += letter_w + dsc->letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_BIDI
|
||||
lv_free(bidi_txt);
|
||||
bidi_txt = NULL;
|
||||
#endif
|
||||
/*Go to next line*/
|
||||
remaining_len -= line_end - line_start;
|
||||
line_start = line_end;
|
||||
if(remaining_len) {
|
||||
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
|
||||
}
|
||||
|
||||
pos.x = coords->x1;
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width =
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width =
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
/*Go the next line position*/
|
||||
pos.y += line_height;
|
||||
|
||||
if(pos.y > t->clip_area.y2) break;
|
||||
}
|
||||
|
||||
if(draw_letter_dsc._draw_buf) lv_draw_buf_destroy(draw_letter_dsc._draw_buf);
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal characters to a number (0..15)
|
||||
* @param hex Pointer to a hexadecimal character (0..9, A..F)
|
||||
* @return the numerical value of `hex` or 0 on error
|
||||
*/
|
||||
static uint8_t hex_char_to_num(char hex)
|
||||
{
|
||||
if(hex >= '0' && hex <= '9') return hex - '0';
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
return 'A' <= hex && hex <= 'F' ? hex - 'A' + 10 : 0;
|
||||
}
|
||||
|
||||
void lv_draw_unit_draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb)
|
||||
{
|
||||
lv_font_glyph_dsc_t g;
|
||||
|
||||
if(lv_text_is_marker(letter)) /*Markers are valid letters but should not be rendered.*/
|
||||
return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool g_ret = lv_font_get_glyph_dsc(font, &g, letter, '\0');
|
||||
if(g_ret == false) {
|
||||
/*Add warning if the dsc is not found*/
|
||||
LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%" LV_PRIX32, letter);
|
||||
}
|
||||
|
||||
/*Don't draw anything if the character is empty. E.g. space*/
|
||||
if((g.box_h == 0) || (g.box_w == 0)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t letter_coords;
|
||||
letter_coords.x1 = pos->x + g.ofs_x;
|
||||
letter_coords.x2 = letter_coords.x1 + g.box_w - 1;
|
||||
letter_coords.y1 = pos->y + (font->line_height - font->base_line) - g.box_h - g.ofs_y;
|
||||
letter_coords.y2 = letter_coords.y1 + g.box_h - 1;
|
||||
lv_area_move(&letter_coords, -dsc->pivot.x, -dsc->pivot.y);
|
||||
|
||||
/*If the letter is completely out of mask don't draw it*/
|
||||
if(lv_area_is_out(&letter_coords, &t->clip_area, 0) &&
|
||||
dsc->bg_coords &&
|
||||
lv_area_is_out(dsc->bg_coords, &t->clip_area, 0)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(g.resolved_font) {
|
||||
lv_draw_buf_t * draw_buf = NULL;
|
||||
if(LV_FONT_GLYPH_FORMAT_NONE < g.format && g.format < LV_FONT_GLYPH_FORMAT_IMAGE) {
|
||||
/*Only check draw buf for bitmap glyph*/
|
||||
draw_buf = lv_draw_buf_reshape(dsc->_draw_buf, 0, g.box_w, g.box_h, LV_STRIDE_AUTO);
|
||||
if(draw_buf == NULL) {
|
||||
if(dsc->_draw_buf) lv_draw_buf_destroy(dsc->_draw_buf);
|
||||
|
||||
uint32_t h = LV_ROUND_UP(g.box_h, 32); /*Assume a larger size to avoid many reallocations*/
|
||||
draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, g.box_w, h, LV_COLOR_FORMAT_A8, LV_STRIDE_AUTO);
|
||||
LV_ASSERT_MALLOC(draw_buf);
|
||||
draw_buf->header.h = g.box_h;
|
||||
dsc->_draw_buf = draw_buf;
|
||||
}
|
||||
}
|
||||
|
||||
dsc->format = g.format;
|
||||
|
||||
if(g.format == LV_FONT_GLYPH_FORMAT_VECTOR) {
|
||||
|
||||
/*Load the outline of the glyph, even if the function says bitmap*/
|
||||
g.outline_stroke_width = dsc->outline_stroke_width;
|
||||
dsc->glyph_data = (void *) lv_font_get_glyph_bitmap(&g, draw_buf);
|
||||
dsc->format = dsc->glyph_data ? g.format : LV_FONT_GLYPH_FORMAT_NONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dsc->format = LV_FONT_GLYPH_FORMAT_NONE;
|
||||
}
|
||||
|
||||
dsc->letter_coords = &letter_coords;
|
||||
dsc->g = &g;
|
||||
cb(t, dsc, NULL, NULL);
|
||||
|
||||
lv_font_glyph_release_draw_data(&g);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* @file lv_draw_label.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LABEL_H
|
||||
#define LV_DRAW_LABEL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "lv_draw_rect.h"
|
||||
#include "../misc/lv_bidi.h"
|
||||
#include "../misc/lv_text.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_DRAW_LABEL_NO_TXT_SEL (0xFFFF)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The text to draw*/
|
||||
const char * text;
|
||||
|
||||
/**The size of the text*/
|
||||
lv_point_t text_size;
|
||||
|
||||
/**The font to use. Fallback fonts are also handled.*/
|
||||
const lv_font_t * font;
|
||||
|
||||
/**Color of the text*/
|
||||
lv_color_t color;
|
||||
|
||||
/**Extra space between the lines*/
|
||||
int32_t line_space;
|
||||
|
||||
/**Extra space between the characters*/
|
||||
int32_t letter_space;
|
||||
|
||||
/**Offset the text with this value horizontally*/
|
||||
int32_t ofs_x;
|
||||
|
||||
/**Offset the text with this value vertically*/
|
||||
int32_t ofs_y;
|
||||
|
||||
/**Rotation of the letters in 0.1 degree unit*/
|
||||
int32_t rotation;
|
||||
|
||||
/**The first characters index for selection (not byte index). `LV_DRAW_LABEL_NO_TXT_SEL` for no selection*/
|
||||
uint32_t sel_start;
|
||||
|
||||
/**The last characters's index for selection (not byte index). `LV_DRAW_LABEL_NO_TXT_SEL` for no selection*/
|
||||
uint32_t sel_end;
|
||||
|
||||
/**Color of the selected characters*/
|
||||
lv_color_t sel_color;
|
||||
|
||||
/**Background color of the selected characters*/
|
||||
lv_color_t sel_bg_color;
|
||||
|
||||
/**The number of characters to render. 0: means render until reaching the `\0` termination.*/
|
||||
uint32_t text_length;
|
||||
|
||||
/**Opacity of the text in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**The alignment of the text `LV_TEXT_ALIGN_LEFT/RIGHT/CENTER`*/
|
||||
lv_text_align_t align;
|
||||
|
||||
/**The base direction. Used when type setting Right-to-left (e.g. Arabic) texts*/
|
||||
lv_base_dir_t bidi_dir;
|
||||
|
||||
/**Text decoration, e.g. underline*/
|
||||
lv_text_decor_t decor : 3;
|
||||
|
||||
/**Some flags to control type setting*/
|
||||
lv_text_flag_t flag : 5;
|
||||
|
||||
/**1: malloc a buffer and copy `text` there.
|
||||
* 0: `text` will be valid during rendering.*/
|
||||
uint8_t text_local : 1;
|
||||
|
||||
/**Indicate that the text is constant and its pointer can be safely saved e.g. in a cache.*/
|
||||
uint8_t text_static : 1;
|
||||
|
||||
/**1: already executed lv_bidi_process_paragraph.
|
||||
* 0: has not been executed lv_bidi_process_paragraph.*/
|
||||
uint8_t has_bided : 1;
|
||||
|
||||
/**Pointer to an externally stored struct where some data can be cached to speed up rendering*/
|
||||
lv_draw_label_hint_t * hint;
|
||||
|
||||
/* Properties of the letter outlines */
|
||||
lv_opa_t outline_stroke_opa;
|
||||
lv_color_t outline_stroke_color;
|
||||
int32_t outline_stroke_width;
|
||||
|
||||
} lv_draw_label_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
uint32_t unicode;
|
||||
const lv_font_t * font;
|
||||
lv_color_t color;
|
||||
|
||||
int32_t rotation;
|
||||
int32_t scale_x;
|
||||
int32_t scale_y;
|
||||
int32_t skew_x;
|
||||
int32_t skew_y;
|
||||
lv_point_t pivot;
|
||||
|
||||
lv_opa_t opa;
|
||||
lv_text_decor_t decor : 3;
|
||||
lv_blend_mode_t blend_mode : 3;
|
||||
|
||||
/* Properties of the letter outlines */
|
||||
lv_opa_t outline_stroke_opa;
|
||||
int32_t outline_stroke_width;
|
||||
lv_color_t outline_stroke_color;
|
||||
|
||||
} lv_draw_letter_dsc_t;
|
||||
|
||||
/**
|
||||
* Passed as a parameter to `lv_draw_label_iterate_characters` to
|
||||
* draw the characters one by one
|
||||
* @param t pointer to a draw task
|
||||
* @param dsc pointer to `lv_draw_glyph_dsc_t` to describe the character to draw
|
||||
* if NULL don't draw character
|
||||
* @param fill_dsc pointer to a fill descriptor to draw a background for the character or
|
||||
* underline or strike through
|
||||
* if NULL do not fill anything
|
||||
* @param fill_area the area to fill
|
||||
* if NULL do not fill anything
|
||||
*/
|
||||
typedef void(*lv_draw_glyph_cb_t)(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, lv_draw_fill_dsc_t * fill_dsc,
|
||||
const lv_area_t * fill_area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_letter_dsc_init(lv_draw_letter_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Initialize a label draw descriptor
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a label draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_LABEL
|
||||
*/
|
||||
lv_draw_label_dsc_t * lv_draw_task_get_label_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Initialize a glyph draw descriptor.
|
||||
* Used internally.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_glyph_dsc_init(lv_draw_glyph_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Create a draw task to render a text
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param coords coordinates of the character
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_label(lv_layer_t * layer, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Create a draw task to render a single character
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param point position of the label
|
||||
* @param unicode_letter the letter to draw
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_character(lv_layer_t * layer, lv_draw_label_dsc_t * dsc,
|
||||
const lv_point_t * point, uint32_t unicode_letter);
|
||||
|
||||
/**
|
||||
* Draw a single letter
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param point position of the label
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_letter(lv_layer_t * layer, lv_draw_letter_dsc_t * dsc,
|
||||
const lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Should be used during rendering the characters to get the position and other
|
||||
* parameters of the characters
|
||||
* @param t pointer to a draw task
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param coords coordinates of the label
|
||||
* @param cb a callback to call to draw each glyphs one by one
|
||||
*/
|
||||
void lv_draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords, lv_draw_glyph_cb_t cb);
|
||||
|
||||
/**
|
||||
* @brief Draw a single letter using the provided draw unit, glyph descriptor, position, font, and callback.
|
||||
*
|
||||
* This function is responsible for rendering a single character from a text string,
|
||||
* applying the necessary styling described by the glyph descriptor (`dsc`). It handles
|
||||
* the retrieval of the glyph's description, checks its visibility within the clipping area,
|
||||
* and invokes the callback (`cb`) to render the glyph at the specified position (`pos`)
|
||||
* using the given font (`font`).
|
||||
*
|
||||
* @param t Pointer to the drawing task.
|
||||
* @param dsc Pointer to the descriptor containing styling for the glyph to be drawn.
|
||||
* @param pos Pointer to the point coordinates where the letter should be drawn.
|
||||
* @param font Pointer to the font containing the glyph.
|
||||
* @param letter The Unicode code point of the letter to be drawn.
|
||||
* @param cb Callback function to execute the actual rendering of the glyph.
|
||||
*/
|
||||
void lv_draw_unit_draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb);
|
||||
|
||||
/***********************
|
||||
* GLOBAL VARIABLES
|
||||
***********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LABEL_H*/
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file lv_draw_label_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LABEL_PRIVATE_H
|
||||
#define LV_DRAW_LABEL_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_label.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/** Store some info to speed up drawing of very large texts
|
||||
* It takes a lot of time to get the first visible character because
|
||||
* all the previous characters needs to be checked to calculate the positions.
|
||||
* This structure stores an earlier (e.g. at -1000 px) coordinate and the index of that line.
|
||||
* Therefore the calculations can start from here.*/
|
||||
struct _lv_draw_label_hint_t {
|
||||
/** Index of the line at `y` coordinate*/
|
||||
int32_t line_start;
|
||||
|
||||
/** Give the `y` coordinate of the first letter at `line start` index. Relative to the label's coordinates*/
|
||||
int32_t y;
|
||||
|
||||
/** The 'y1' coordinate of the label when the hint was saved.
|
||||
* Used to invalidate the hint if the label has moved too much.*/
|
||||
int32_t coord_y;
|
||||
};
|
||||
|
||||
struct _lv_draw_glyph_dsc_t {
|
||||
/** Depends on `format` field, it could be image source or draw buf of bitmap or vector data. */
|
||||
const void * glyph_data;
|
||||
lv_font_glyph_format_t format;
|
||||
const lv_area_t * letter_coords;
|
||||
const lv_area_t * bg_coords;
|
||||
lv_font_glyph_dsc_t * g;
|
||||
lv_color_t color;
|
||||
lv_opa_t opa;
|
||||
lv_color_t outline_stroke_color;
|
||||
lv_opa_t outline_stroke_opa;
|
||||
int32_t outline_stroke_width;
|
||||
int32_t rotation;
|
||||
lv_point_t pivot; /**< Rotation pivot point associated with total glyph including line_height */
|
||||
lv_draw_buf_t * _draw_buf; /**< a shared draw buf for get_bitmap, do not use it directly, use glyph_data instead */
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LABEL_PRIVATE_H*/
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file lv_draw_line.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_line_dsc_t));
|
||||
dsc->width = 1;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->base.dsc_size = sizeof(lv_draw_line_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_line_dsc_t * lv_draw_task_get_line_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_LINE ? (lv_draw_line_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_line(lv_layer_t * layer, const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = (int32_t)LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width;
|
||||
a.x2 = (int32_t)LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width;
|
||||
a.y1 = (int32_t)LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width;
|
||||
a.y2 = (int32_t)LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_LINE);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file lv_draw_line.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LINE_H
|
||||
#define LV_DRAW_LINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The first point of the line. If `LV_USE_FLOAT` is enabled float number can be also used*/
|
||||
lv_point_precise_t p1;
|
||||
|
||||
/**The second point of the line. If `LV_USE_FLOAT` is enabled float number can be also used*/
|
||||
lv_point_precise_t p2;
|
||||
|
||||
/**The color of the line*/
|
||||
lv_color_t color;
|
||||
|
||||
/**The width (thickness) of the line*/
|
||||
int32_t width;
|
||||
|
||||
/** The length of a dash (0: don't dash)*/
|
||||
int32_t dash_width;
|
||||
|
||||
/** The length of the gaps between dashes (0: don't dash)*/
|
||||
int32_t dash_gap;
|
||||
|
||||
/**Opacity of the line in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**Make the line start rounded*/
|
||||
uint8_t round_start : 1;
|
||||
|
||||
/**Make the line end rounded*/
|
||||
uint8_t round_end : 1;
|
||||
|
||||
/**1: Do not bother with line ending (if it's not visible for any reason) */
|
||||
uint8_t raw_end : 1;
|
||||
} lv_draw_line_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a line draw descriptor
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a line draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_LINE
|
||||
*/
|
||||
lv_draw_line_dsc_t * lv_draw_task_get_line_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a line draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_line(lv_layer_t * layer, const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LINE_H*/
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file lv_draw_mask.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_mask_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_mask_rect_dsc_init(lv_draw_mask_rect_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_mask_rect_dsc_t));
|
||||
}
|
||||
|
||||
lv_draw_mask_rect_dsc_t * lv_draw_task_get_mask_rect_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_MASK_RECTANGLE ? (lv_draw_mask_rect_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_mask_rect(lv_layer_t * layer, const lv_draw_mask_rect_dsc_t * dsc)
|
||||
{
|
||||
if(!lv_color_format_has_alpha(layer->color_format)) {
|
||||
LV_LOG_WARN("Only layers with alpha channel can be masked");
|
||||
return;
|
||||
}
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &layer->buf_area, LV_DRAW_TASK_TYPE_MASK_RECTANGLE);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_dsc_base_t * base_dsc = t->draw_dsc;
|
||||
base_dsc->layer = layer;
|
||||
|
||||
if(base_dsc->obj && lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) {
|
||||
/*Disable sending LV_EVENT_DRAW_TASK_ADDED first to avoid triggering recursive
|
||||
*event calls due draw task adds in the event*/
|
||||
lv_obj_remove_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
lv_obj_send_event(dsc->base.obj, LV_EVENT_DRAW_TASK_ADDED, t);
|
||||
lv_obj_add_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
}
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file lv_draw_mask.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_MASK_H
|
||||
#define LV_DRAW_MASK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a rectangle mask draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_mask_rect_dsc_init(lv_draw_mask_rect_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a rectangle mask draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_MASK_RECTANGLE
|
||||
*/
|
||||
lv_draw_mask_rect_dsc_t * lv_draw_task_get_mask_rect_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a draw task to mask a rectangle from the buffer
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_mask_rect(lv_layer_t * layer, const lv_draw_mask_rect_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_MASK_H*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user