mcu_ab568x/app/platform/gui/components/compo_rowbox.c
2025-05-30 18:03:10 +08:00

337 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "include.h"
#define TRACE_EN 0
#if TRACE_EN
#define TRACE(...) printf(__VA_ARGS__)
#else
#define TRACE(...)
#endif
//移动相关控制
#define FOCUS_AUTO_TICK_EXPIRE 10 //松手后自动对齐焦点单位时间(ms)
#define FOCUS_AUTO_STEP 5 //松手后自动对齐焦点单位时间步进
#define FOCUS_AUTO_STEP_DIV 16
#define DRAG_AUTO_SPEED 80 //拖动松手后的速度
/**
* @brief 创建一个列表(横向)控件
* @param[in] frm : 窗体指针
* @return 返回列表(横向)指针
**/
compo_rowbox_t *compo_rowbox_create(compo_form_t *frm)
{
compo_rowbox_t *rowbox = compo_create(frm, COMPO_TYPE_ROWBOX);
widget_page_t *page = widget_page_create(frm->page_body);
widget_set_location(page, GUI_SCREEN_CENTER_X, GUI_SCREEN_CENTER_Y, GUI_SCREEN_WIDTH, GUI_SCREEN_HEIGHT);
rowbox->page = page;
for (int i=0; i<IMG_MAX; i++) {
widget_image_t *img = widget_image_create(page, 0);
rowbox->img[i] = img;
}
return rowbox;
}
//根据表盘的基地址获取对应的预览图
static u32 compo_rowbox_preview_style(u32 base_addr)
{
uitool_header_t uitool_header;
os_spiflash_read(&uitool_header, base_addr, UITOOL_HEADER);
for(u16 i=0; i<uitool_header.num; i++) {
uitool_res_t uitool_res = {0};
os_spiflash_read(&uitool_res, base_addr + UITOOL_HEADER + i * UITOOL_RES_HEADER, UITOOL_RES_HEADER);
u32 res_addr = base_addr + uitool_res.res_addr;
//预览图
if (uitool_res.res_type == UITOOL_TYPE_IMAGE && uitool_res.bond_type == COMPO_BOND_IMAGE_CLOCK_PREVIEW) {
return res_addr;
}
}
return 0;
}
/**
* @brief 设置列表(横向)控件内容
* @param[in] rowbox : 列表(横向)指针
* @param[in] *res_tbl : 存放图像资源的地址
* @param[in] img_cnt : 图像数量
**/
void compo_rowbox_set(compo_rowbox_t *rowbox, const u32 *res_tbl, u8 img_cnt)
{
area_t img_area;
if (rowbox->style == COMPO_ROWBOX_STYLE_NORMAL) {
img_area = gui_image_get_size(res_tbl[0]);
} else {
img_area = gui_image_get_size(compo_rowbox_preview_style(res_tbl[0]));
}
s16 row_space = 15; //空白间隙
s16 row_width = img_area.wid; //图片宽度
s16 row_center_x = row_width >> 1; //图片x轴中心位置
s16 row_width_total = row_space + row_width; //图片宽度+空白
s16 total_width = row_width_total * img_cnt - row_space; //图片拼接的总长度
s16 cycle_width = row_width_total * img_cnt; //循环时,图片拼接的总长度
rowbox->row_space = row_space;
rowbox->row_width = row_width;
rowbox->row_center_x = row_center_x;
rowbox->row_width_total = row_width_total;
rowbox->total_width = total_width;
rowbox->cycle_width = cycle_width;
rowbox->res_tbl = res_tbl;
rowbox->img_area = img_area;
rowbox->img_cnt = img_cnt;
// printf("row_space:%d\n", row_space);
// printf("row_width:%d\n", row_width);
// printf("row_center_x:%d\n", row_center_x);
// printf("row_width_total:%d\n", row_width_total);
// printf("total_width:%d\n", total_width);
// printf("cycle_width:%d\n", cycle_width);
// printf("img_cnt:%d\n", img_cnt);
}
/**
* @brief 根据编号获取x坐标
* @param[in] rowbox : 列表(横向)指针
* @param[in] idx : 菜单编号
* @return x坐标
**/
int compo_rowbox_getx_byidx(compo_rowbox_t *rowbox, int idx)
{
return (rowbox->row_center_x + rowbox->row_width_total * idx);
}
/**
* @brief 按x坐标设置列表横向焦点
* @param[in] rowbox : 列表(横向)指针
* @param[in] x : x坐标
**/
void compo_rowbox_set_focus(compo_rowbox_t *rowbox, s16 x)
{
int ix;
rect_t location;
if (!rowbox->flag_cycle) {
if (x < 0) {
x = 0;
} else if (x > rowbox->total_width) {
x = rowbox->total_width;
}
}
rowbox->ofs_x = x;
location = widget_get_location(rowbox->page);
ix = location.x - rowbox->ofs_x;
widget_page_set_client(rowbox->page, ix, 0);
}
/**
* @brief 将选择的图标设为焦点
* @param[in] rowbox : 列表(横向)指针
* @param[in] idx : 图标编号
**/
void compo_rowbox_set_focus_byidx(compo_rowbox_t *rowbox, int idx)
{
int x = compo_rowbox_getx_byidx(rowbox, idx);
compo_rowbox_set_focus(rowbox, x);
}
/**
* @brief 设置列表(横向)样式
* @param[in] rowbox : 列表(横向)指针
* @param[in] style : 样式
**/
void compo_rowbox_set_style(compo_rowbox_t *rowbox, u8 style)
{
rowbox->style = style;
}
/**
* @brief 更新列表框Widget
* @param[in] rowbox : 列表(横向)指针
**/
void compo_rowbox_update(compo_rowbox_t *rowbox)
{
int i;
int cidx, sidx;
cidx = rowbox->ofs_x / rowbox->row_width_total;
cidx -= rowbox->ofs_x < 0 ? 1 : 0; //逆向(循环滑动)
rowbox->focus_icon_idx = cidx;
sidx = cidx - 3;
for (i=0; i<IMG_MAX; i++) {
int idx = sidx + i;
int idx_tmp;
if (!rowbox->flag_cycle) { //normal
if (idx < 0 || idx >= rowbox->img_cnt) {
widget_set_visible(rowbox->img[i], false);
rowbox->img_idx[i] = -1;
continue;
} else {
rowbox->img_idx[i] = idx;
widget_set_visible(rowbox->img[i], true);
}
} else { //cycle
idx_tmp = idx + (idx < 0 ? rowbox->img_cnt : (idx >= rowbox->img_cnt ? -rowbox->img_cnt : 0));
while (idx_tmp < 0 || idx_tmp >= rowbox->img_cnt) {
idx_tmp = idx_tmp + (idx_tmp < 0 ? rowbox->img_cnt : (idx_tmp >= rowbox->img_cnt ? -rowbox->img_cnt : 0));
}
rowbox->img_idx[i] = idx_tmp;
}
if (rowbox->style == COMPO_ROWBOX_STYLE_NORMAL) {
widget_image_set(rowbox->img[i], rowbox->res_tbl[rowbox->img_idx[i]]);
} else { //表盘的图片需要解析一下地址,才能获取预览图
widget_image_set(rowbox->img[i], compo_rowbox_preview_style(rowbox->res_tbl[rowbox->img_idx[i]]));
}
int lnx = rowbox->row_center_x + idx * rowbox->row_width_total;
int lny = GUI_SCREEN_CENTER_Y;
int dx = lnx - rowbox->ofs_x; //离中心距离
int udx = abs_s(dx);
int img_wid = rowbox->img_area.wid;
int img_hei = rowbox->img_area.hei;
int udx_th = 25;
img_hei = img_hei - img_hei * (udx - udx_th) / 320;
img_wid = img_hei * img_wid / rowbox->img_area.hei;
widget_set_size(rowbox->img[i], img_wid, img_hei);
widget_set_alpha(rowbox->img[i], img_wid >= rowbox->img_area.wid ? 255 : (img_wid * 255 / rowbox->img_area.wid));
widget_set_pos(rowbox->img[i], lnx, lny);
}
}
/**
* @brief 列表框拖动与移动初始化
* @param[in] rowbox : 列表(横向)指针
**/
void compo_rowbox_move_init(compo_rowbox_t *rowbox)
{
compo_rowbox_move_cb_t *mcb = rowbox->mcb;
if (mcb == NULL) {
return;
}
mcb->focus_x = rowbox->ofs_x;
mcb->first_x = compo_rowbox_getx_byidx(rowbox, 0);
mcb->last_x = compo_rowbox_getx_byidx(rowbox, rowbox->img_cnt - 1);
}
/**
* @brief 列表框拖动与移动处理
* @param[in] rowbox : 列表(横向)指针
**/
void compo_rowbox_move(compo_rowbox_t *rowbox)
{
compo_rowbox_move_cb_t *mcb = rowbox->mcb;
if (mcb == NULL) {
return;
}
if (mcb->flag_drag) {
s32 dx = mcb->focus_dx;
s32 dy;
mcb->flag_drag = ctp_get_dxy(&mcb->focus_dx, &dy);
if (mcb->flag_drag) {
//拖动菜单图标
mcb->focus_xstep = mcb->focus_dx - dx;
compo_rowbox_set_focus(rowbox, mcb->focus_x - mcb->focus_dx);
compo_rowbox_update(rowbox);
} else {
//抬手后开始自动移动
s32 last_dx = ctp_get_last_dxy().x;
mcb->focus_x = rowbox->ofs_x;
mcb->flag_move_auto = true;
mcb->moveto_idx = rowbox->focus_icon_idx - (last_dx * DRAG_AUTO_SPEED / GUI_SCREEN_HEIGHT);
if (mcb->moveto_idx > rowbox->img_cnt && !rowbox->flag_cycle) {
mcb->moveto_idx = rowbox->img_cnt;
} else if (mcb->moveto_idx < -1 && !rowbox->flag_cycle) {
mcb->moveto_idx = -1;
}
mcb->moveto_x = compo_rowbox_getx_byidx(rowbox, mcb->moveto_idx);
mcb->tick = tick_get();
}
}
if (mcb->flag_move_auto) {
//自动移动
if (mcb->focus_x == mcb->moveto_x) {
if (mcb->focus_x < mcb->first_x && !rowbox->flag_cycle) {
mcb->moveto_x = mcb->first_x; //超过第1个回弹
} else if (mcb->focus_x > mcb->last_x && !rowbox->flag_cycle) {
mcb->moveto_x = mcb->last_x; //超过最后1个回弹
} else {
mcb->flag_move_auto = false; //移动完成
rowbox->ofs_x %= rowbox->cycle_width; //循环滑动防止ofs_y溢出
rowbox->focus_icon_idx = rowbox->ofs_x / rowbox->row_width_total - (rowbox->ofs_x < 0 ? 1 : 0);
mcb->focus_x = rowbox->ofs_x;
}
} else if (tick_check_expire(mcb->tick, FOCUS_AUTO_TICK_EXPIRE)) {
s32 dx;
mcb->tick = tick_get();
dx = mcb->moveto_x - mcb->focus_x;
if (dx > 0) {
if (dx > FOCUS_AUTO_STEP * FOCUS_AUTO_STEP_DIV) {
dx = dx / FOCUS_AUTO_STEP_DIV;
} else if (dx > FOCUS_AUTO_STEP) {
dx = FOCUS_AUTO_STEP;
} else {
dx = 1;
}
} else {
if (dx < -FOCUS_AUTO_STEP * FOCUS_AUTO_STEP_DIV) {
dx = dx / FOCUS_AUTO_STEP_DIV;
} else if (dx < -FOCUS_AUTO_STEP) {
dx = -FOCUS_AUTO_STEP;
} else {
dx = -1;
}
}
mcb->focus_x += dx;
compo_rowbox_set_focus(rowbox, mcb->focus_x);
compo_rowbox_update(rowbox);
}
}
}
/**
* @brief 按坐标选择菜单项
* @param[in] rowbox : 列表(横向)指针
* @param[in] pt : 坐标
* @return 返回菜单项索引
**/
int compo_rowbox_select(compo_rowbox_t *rowbox, point_t pt)
{
if (rowbox == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_SELECT);
}
int i;
for (i=0; i<IMG_MAX; i++) {
if (rowbox->img_idx[i] < 0) {
continue;
}
rect_t rect = widget_get_absolute(rowbox->img[i]);
if (abs_s(pt.y - rect.y) * 2 <= rect.hei && abs_s(pt.x - rect.x) * 2 <= rect.wid) {
return rowbox->img_idx[i];
}
}
return -1;
}
/**
* @brief 是否使能列表循环滑动功能
* @param[in] rowbox : 列表(横向)指针
* @param[in] cycle : true 使能循环滑动
false 关闭循环滑动
**/
void compo_rowbox_cycle_en(compo_rowbox_t *rowbox, bool cycle)
{
rowbox->flag_cycle = cycle;
}