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

583 lines
20 KiB
C

#include "include.h"
#define TRACE_EN 0
#if TRACE_EN
#define TRACE(...) printf(__VA_ARGS__)
#else
#define TRACE(...)
#endif
#define KALE_GET_ANGLE(angle) ((angle >= 0) ? (angle % 3600) : (angle % 3600 + 3600)) //度数转换
#define KALE_GET_ICON_REL_X(r, angle) (-muls_shift16(r, SIN(KALE_GET_ANGLE(angle)))) //根据角度获取相对X
#define KALE_GET_ICON_REL_Y(r, angle) (-muls_shift16(r, COS(KALE_GET_ANGLE(angle)))) //根据角度获取相对Y
static const int16_t tbl_angle[KALE_CIR_ICON_NUM] = {
3150, 0, 450, 900, 1350, 1800, 2250, 2700,
};
int limit_range(int val, int min, int max)
{
if (val > max) {
val = max;
} else if (val < min) {
val = min;
}
return val;
}
void cycle_plus(u8 *val, u8 min, u8 max)
{
if(*val >= max){
*val = min;
}else{
(*val)++;
}
}
void cycle_sub(u8 *val, u8 min, u8 max)
{
if(*val <= min){
*val = max;
}else{
(*val)--;
}
}
/**
* @brief 创建一个万花筒组件
* @param[in] frm : 窗体指针
* @return 返回万花筒指针
**/
compo_kaleidoscope_t *compo_kaleidoscope_create(compo_form_t *frm)
{
// printf("compo_kaleidoscope_t size->%d\n", sizeof(compo_kaleidoscope_t));
compo_kaleidoscope_t *kale = compo_create(frm, COMPO_TYPE_KALEIDOSCOPE);
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);
widget_page_set_client(page, 0, 0); //圆心
kale->page = page;
return kale;
}
/**
* @brief 万花筒图标角度初始化
* @param[in] kale : 万花筒图标集合指针
**/
void compo_kaleidoscope_angle_init(compo_kaleidoscope_t *kale)
{
compo_kale_icon_t *p = NULL;
for (u8 k = 0; k < KALE_CIR_MAX; k++) {
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
p = &kale->dcir[k].icon[i];
p->angle = tbl_angle[i] + k * KALE_CIR_ANGLE_DEV;
}
}
}
/**
* @brief 初始化万花筒内外圈层
* 注:根据屏幕大小自适应内外圈层半径
* @param[in] kale : 万花筒图标集合指针
* @param[in] dc_width : 屏幕宽度
* @param[in] dc_height : 屏幕高度
* @param[in] osize : 外圈图标尺寸
* @param[in] isize : 内圈图标尺寸
* @param[in] edge_space : 离屏幕边缘距离
* @param[in] icon_space : 内外圈图标间距离
**/
void compo_kaleidoscope_init(compo_kaleidoscope_t *kale, s16 dc_width, s16 dc_height, u16 osize, u16 isize, s16 edge_space, s16 icon_space)
{
u16 short_side , sw, sh = 0;
sw = dc_width;
sh = dc_height;
kale->cen.x = sw >> 1;
kale->cen.y = sh >> 1;
short_side = (sw > sh) ? sh : sw;
kale->ctl.osize = osize;
kale->ctl.isize = isize;
kale->ctl.org_or = (short_side >> 1) - edge_space - (kale->ctl.osize >> 1);
kale->ctl.org_ir = kale->ctl.org_or - (kale->ctl.osize >> 1) - icon_space - (kale->ctl.isize >> 1);
kale->ctl.oidx = KALE_CIR_0;
kale->ctl.iidx = KALE_CIR_1;
kale->dcir[kale->ctl.oidx].size = kale->ctl.osize;
kale->dcir[kale->ctl.oidx].r = kale->ctl.org_or;
kale->dcir[kale->ctl.oidx].lay = KALE_FUNC_LAY_MAX;
kale->dcir[kale->ctl.iidx].size = kale->ctl.isize;
kale->dcir[kale->ctl.iidx].r = kale->ctl.org_ir;
kale->dcir[kale->ctl.iidx].lay = KALE_FUNC_LAY_0;
compo_kaleidoscope_angle_init(kale);
}
/**
* @brief 往万花筒图标集合里面添加图标
* @param[in] kale : 万花筒图标集合指针
* @param[in] item : 图标集指针
* @param[in] item_cnt : 图标集总数
**/
void compo_kaleidoscope_icon_add(compo_kaleidoscope_t *kale, menu_kale_item_t const *item, int item_cnt)
{
if (item_cnt <= 0) {
halt(HALT_GUI_COMPO_ICONLIST_ADD);
}
if (item_cnt > (KALE_FUNC_LAYER * KALE_CIR_ICON_NUM)) {
item_cnt = KALE_FUNC_LAYER * KALE_CIR_ICON_NUM;
}
kale->dcir[kale->ctl.oidx].lay = (item_cnt - 1) / KALE_CIR_ICON_NUM;
kale->dcir[kale->ctl.iidx].lay = KALE_FUNC_LAY_0;
for (int i = 0; i < item_cnt; i++) {
u8 idx_cir = i / KALE_CIR_ICON_NUM;
u8 idx_icon = i % KALE_CIR_ICON_NUM;
widget_icon_t *icon = widget_icon_create(kale->page, item[i].res_addr);
kale->ofunc[idx_cir].fsub[idx_icon].widget = icon;
kale->ofunc[idx_cir].fsub[idx_icon].func_sta = item[i].func_sta;
compo_kale_func_t *fp = &kale->ofunc[idx_cir].fsub[idx_icon];
if (idx_cir == kale->dcir[kale->ctl.oidx].lay) {
compo_kale_icon_t *dp = &kale->dcir[kale->ctl.oidx].icon[idx_icon];
dp->fsub.widget = fp->widget;
dp->fsub.func_sta = fp->func_sta;
}
if (idx_cir == kale->dcir[kale->ctl.iidx].lay) {
compo_kale_icon_t *dp = &kale->dcir[kale->ctl.iidx].icon[idx_icon];
dp->fsub.widget = fp->widget;
dp->fsub.func_sta = fp->func_sta;
}
kale->total_cnt++;
}
}
/**
* @brief 根据变化半径,万花筒内外圈半径更新
* @param[in] kale : 万花筒图标集合指针
* @param[in] dr : 变化半径
**/
void compo_kaleidoscope_update_r(compo_kaleidoscope_t *kale, s16 dr)
{
kale->dcir[kale->ctl.oidx].r -= dr;
kale->dcir[kale->ctl.iidx].r += dr;
kale->dcir[kale->ctl.oidx].r = limit_range(kale->dcir[kale->ctl.oidx].r, kale->ctl.org_ir, kale->ctl.org_or);
kale->dcir[kale->ctl.iidx].r = limit_range(kale->dcir[kale->ctl.iidx].r, kale->ctl.org_ir, kale->ctl.org_or);
if (kale->dcir[kale->ctl.oidx].r == kale->ctl.org_ir || kale->dcir[kale->ctl.oidx].r == kale->ctl.org_or) {
kale->ctl.sta = KALE_CTL_ROTATE;
}
}
/**
* @brief 根据内外圈半径,获取当前圈层的图标尺寸
* @param[in] kale : 万花筒图标集合指针
* @param[in] r : 内外圈半径
* @return 返回当前圈层图标尺寸
**/
u16 compo_kaleidoscope_size_from_r(compo_kaleidoscope_t *kale, u16 r)
{
return ((kale->ctl.osize - kale->ctl.isize) * (r - kale->ctl.org_ir) / (kale->ctl.org_or - kale->ctl.org_ir) + kale->ctl.isize);
}
/**
* @brief 万花筒图标尺寸更新
* @param[in] kale : 万花筒图标集合指针
**/
void compo_kaleidoscope_update_size(compo_kaleidoscope_t *kale)
{
kale->dcir[kale->ctl.oidx].size = compo_kaleidoscope_size_from_r(kale, kale->dcir[kale->ctl.oidx].r);
kale->dcir[kale->ctl.iidx].size = compo_kaleidoscope_size_from_r(kale, kale->dcir[kale->ctl.iidx].r);
}
/**
* @brief 根据变化角度,万花筒旋转角度更新
* @param[in] kale : 万花筒图标集合指针
* @param[in] dr : 变化半径
**/
void compo_kaleidoscope_update_angle(compo_kaleidoscope_t *kale, int16_t dangle)
{
int16_t angle = dangle;
angle = (angle < 0 || angle > KALE_CIR_ANGLE_COM) ? 1 : angle;
compo_kale_icon_t *p = NULL;
for (u8 k = 0; k < KALE_CIR_MAX; k++) {
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
p = &kale->dcir[k].icon[i];
p->angle = (kale->ctl.oidx == k) ? (p->angle - angle) : (p->angle + angle);
if (kale->ctl.oidx == k) {
if (kale->ctl.oidx == KALE_CIR_0) {
p->angle = (p->angle <= (tbl_angle[i] - KALE_CIR_ANGLE_COM)) ? (tbl_angle[i] - KALE_CIR_ANGLE_COM) : p->angle;
} else if (kale->ctl.oidx == KALE_CIR_1) {
p->angle = (p->angle <= (tbl_angle[i] + KALE_CIR_ANGLE_DEV)) ? (tbl_angle[i] + KALE_CIR_ANGLE_DEV) : p->angle;
}
} else {
if (kale->ctl.oidx == KALE_CIR_0) {
p->angle = (p->angle >= (tbl_angle[i] + KALE_CIR_ANGLE_DEV_OI)) ? (tbl_angle[i] + KALE_CIR_ANGLE_DEV_OI) : p->angle;
} else if (kale->ctl.oidx == KALE_CIR_1) {
p->angle = (p->angle >= (tbl_angle[i])) ? (tbl_angle[i]) : p->angle;
}
}
}
}
p = &kale->dcir[kale->ctl.oidx].icon[0];
if (p->angle == (tbl_angle[0] - KALE_CIR_ANGLE_COM) || p->angle == tbl_angle[0] + KALE_CIR_ANGLE_DEV) {
kale->ctl.oidx = (kale->ctl.oidx == KALE_CIR_0) ? KALE_CIR_1 : KALE_CIR_0;
kale->ctl.iidx = (kale->ctl.iidx == KALE_CIR_0) ? KALE_CIR_1 : KALE_CIR_0;
kale->ctl.sta = KALE_CTL_SWAP;
}
}
/**
* @brief 万花筒上下层任务切换设置
* @param[in] kale : 万花筒图标集合指针
* @param[in] msg : 消息
**/
void compo_kaleidoscope_ctl_swap_set(compo_kaleidoscope_t *kale, size_msg_t msg)
{
if (kale->ctl.sta) return;
switch (msg) {
case MSG_CTP_SHORT_UP:
case MSG_CTP_SHORT_RIGHT:
case MSG_QDEC_FORWARD:
kale->ctl.swap = KALE_SWAP_LAST;
break;
case MSG_CTP_SHORT_DOWN:
case MSG_CTP_SHORT_LEFT:
case MSG_QDEC_BACKWARD:
kale->ctl.swap = KALE_SWAP_NEXT;
break;
default:
kale->ctl.swap = KALE_SWAP_NULL;
break;
}
}
/**
* @brief 万花筒上下层任务信息更替
* @param[in] kale : 万花筒图标集合指针
* @param[in] swap : 上下切换
* @return true 切换成功
* false 切换失败
**/
bool compo_kaleidoscope_ctl_swap_pro(compo_kaleidoscope_t *kale, u8 swap)
{
bool sf = false;
if (kale->ctl.sta) return sf;
u8 lay;
compo_kale_func_t *fp, *dp = NULL;
if (swap == KALE_SWAP_LAST) { //上一级
lay = kale->dcir[kale->ctl.oidx].lay;
cycle_sub((u8 *)&lay, KALE_FUNC_LAY_0, ((kale->total_cnt - 1) / KALE_CIR_ICON_NUM));
kale->dcir[kale->ctl.iidx].lay = lay;
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
fp = &kale->ofunc[kale->dcir[kale->ctl.iidx].lay].fsub[i];
dp = &kale->dcir[kale->ctl.iidx].icon[i].fsub;
dp->widget = fp->widget;
dp->func_sta = fp->func_sta;
}
sf = true;
} else if (kale->ctl.swap == KALE_SWAP_NEXT) { //下一级
lay = kale->dcir[kale->ctl.iidx].lay;
cycle_plus((u8 *)&lay, KALE_FUNC_LAY_0, ((kale->total_cnt - 1) / KALE_CIR_ICON_NUM));
kale->dcir[kale->ctl.oidx].lay = lay;
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
fp = &kale->ofunc[kale->dcir[kale->ctl.oidx].lay].fsub[i];
dp = &kale->dcir[kale->ctl.oidx].icon[i].fsub;
dp->widget = fp->widget;
dp->func_sta = fp->func_sta;
}
sf = true;
}
return sf;
}
/**
* @brief 万花筒上下层任务切换处理
* @param[in] kale : 万花筒图标集合指针
* @param[in] sta : 切换状态
**/
void compo_kaleidoscope_ctl_switch_pro(compo_kaleidoscope_t *kale, u8 sta)
{
if (kale->ctl.sta) return;
if (compo_kaleidoscope_ctl_swap_pro(kale, kale->ctl.swap)) {
compo_kale_update(kale);
kale->ctl.sta = sta;
}
}
/**
* @brief 万花筒上下层任务切换处KICK
* @param[in] kale : 万花筒图标集合指针
* @param[in] msg : 消息
**/
void compo_kaleidoscope_ctl_switch_kick(compo_kaleidoscope_t *kale, size_msg_t msg)
{
if (kale->ctl.sta) return;
compo_kaleidoscope_ctl_swap_set(kale, msg);
compo_kaleidoscope_ctl_switch_pro(kale, KALE_CTL_SWITCH);
}
/**
* @brief 万花筒入场动画KICK
* 注:从表盘页面进入万花筒,使能入场动画
* 注:从子任务返回不具备入场动画,并返回子任务所在的层级
* @param[in] kale : 万花筒图标集合指针
**/
void compo_kaleidoscope_adm_animation_kick(compo_kaleidoscope_t *kale)
{
if (kale->ctl.sta) return;
if (kale->focus_icon_idx) return;
kale->ctl.adm = true;
kale->ctl.sta = KALE_CTL_SWITCH;
}
/**
* @brief 万花筒入场动画
* 注:从表盘页面进入万花筒,使能入场动画
* 注:从子任务返回不具备入场动画,并返回子任务所在的层级
* @param[in] kale : 万花筒图标集合指针
**/
void compo_kaleidoscope_adm_animation_pro(compo_kaleidoscope_t *kale)
{
if (!kale->ctl.adm) return;
compo_kale_func_t *fp, *dp = NULL;
kale->dcir[kale->ctl.iidx].lay = kale->dcir[kale->ctl.oidx].lay + 1;
if (kale->dcir[kale->ctl.iidx].lay > ((kale->total_cnt - 1) / KALE_CIR_ICON_NUM)) {
printf("%s ctl.iidx lay over %d\n", __func__, ((kale->total_cnt - 1) / KALE_CIR_ICON_NUM));
kale->dcir[kale->ctl.iidx].lay = ((kale->total_cnt - 1) / KALE_CIR_ICON_NUM);
}
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
fp = &kale->ofunc[kale->dcir[kale->ctl.iidx].lay].fsub[i];
dp = &kale->dcir[kale->ctl.iidx].icon[i].fsub;
dp->widget = fp->widget;
dp->func_sta = fp->func_sta;
}
compo_kale_update(kale);
kale->ctl.adm = false;
}
/**
* @brief 万花筒图标可视化设置
* 注:显示内外圈层所在任务层图标
* @param[in] kale : 万花筒图标集合指针
**/
void compo_kaleidoscope_set_vis(compo_kaleidoscope_t *kale)
{
u8 dolay = kale->dcir[kale->ctl.oidx].lay;
u8 dilay = kale->dcir[kale->ctl.iidx].lay;
for (int i = 0; i < kale->total_cnt; i++) {
u8 idx_cir = i / KALE_CIR_ICON_NUM;
u8 idx_icon = i % KALE_CIR_ICON_NUM;
compo_kale_func_t *fp = &kale->ofunc[idx_cir].fsub[idx_icon];
if (fp->widget) {
widget_set_visible(fp->widget, false);
if (idx_cir == dolay || idx_cir == dilay) {
widget_set_visible(fp->widget, true);
}
}
}
}
/**
* @brief 万花筒切换动画
* @param[in] kale : 万花筒图标集合指针
**/
void compo_kaleidoscope_switch_animation(compo_kaleidoscope_t *kale, u32 expire, s16 dr, int16_t dangle)
{
if (!kale->ctl.sta) return;
static u32 ticks = 0;
if (kale->ctl.sta == KALE_CTL_SWITCH) {
if (tick_check_expire(ticks, expire)) {
ticks = tick_get();
compo_kaleidoscope_update_r(kale, dr);
compo_kaleidoscope_update_size(kale);
compo_kale_update(kale);
}
} else if (kale->ctl.sta == KALE_CTL_ROTATE) {
if (tick_check_expire(ticks, expire)) {
ticks = tick_get();
compo_kaleidoscope_update_angle(kale, dangle);
compo_kale_update(kale);
}
} else if (kale->ctl.sta == KALE_CTL_SWAP) {
compo_kaleidoscope_adm_animation_pro(kale);
kale->ctl.sta = KALE_CTL_NULL;
}
}
/**
* @brief 更新图标集合Widget
* @param[in] kale : 图标集指针
**/
void compo_kale_update(compo_kaleidoscope_t *kale)
{
if (kale == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_UPDATE);
}
compo_kaleidoscope_set_vis(kale);
//刷新显示层
compo_kale_icon_t *p = NULL;
for (u8 k = 0; k < KALE_CIR_MAX; k++) {
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
p = &kale->dcir[k].icon[i];
if (p->fsub.widget) {
int16_t ix = kale->cen.x + KALE_GET_ICON_REL_X(kale->dcir[k].r, p->angle);
int16_t iy = kale->cen.y + KALE_GET_ICON_REL_Y(kale->dcir[k].r, p->angle);
widget_set_location(p->fsub.widget, ix, iy, kale->dcir[k].size, kale->dcir[k].size);
}
}
}
}
/**
* @brief 按坐标选择图标
* @param[in] kale : 图标集指针
* @param[in] x : x轴坐标
* @param[in] y : y轴坐标
* @return 返回图标索引
**/
int compo_kale_select(compo_kaleidoscope_t *kale, int x, int y)
{
if (kale == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_SELECT);
}
compo_kale_icon_t *p = NULL;
bool select = false;
int idx;
for (u8 k = 0; k < KALE_CIR_MAX; k++) {
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
p = &kale->dcir[k].icon[i];
if (p->fsub.widget) {
rect_t rect = widget_get_absolute(p->fsub.widget);
select = rect.wid > kale->ctl.isize && abs_s(x - rect.x) * 2 <= rect.wid && abs_s(y - rect.y) * 2 <= rect.hei;
idx = kale->dcir[k].lay * KALE_CIR_ICON_NUM + i;
if (select) {
kale->sel_icon = p->fsub.widget;
kale->sel_idx = idx;
return kale->sel_idx;
}
}
}
}
kale->sel_icon = NULL;
kale->sel_idx = -1;
return -1;
}
/**
* @brief 按索引选择图标
* @param[in] kale : 图标集指针
* @param[in] idx : 编号索引
* @return 返回图标指针
**/
widget_icon_t *compo_kale_select_byidx(compo_kaleidoscope_t *kale, int idx)
{
if (kale == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_SELECT);
}
compo_kale_icon_t *p = NULL;
int byidx;
for (u8 k = 0; k < KALE_CIR_MAX; k++) {
for (u8 i = 0; i < KALE_CIR_ICON_NUM; i++) {
p = &kale->dcir[k].icon[i];
if (p->fsub.widget) {
byidx = kale->dcir[k].lay * KALE_CIR_ICON_NUM + i;
if (byidx == idx) {
kale->sel_icon = p->fsub.widget;
kale->sel_idx = idx;
return kale->sel_icon;
}
}
}
}
kale->sel_icon = NULL;
kale->sel_idx = -1;
return NULL;
}
/**
* @brief 按索引设置图标集合焦点坐标 并设置当前任务圈层
* @param[in] kale : 图标集指针
* @param[in] idx : 编号索引
**/
void compo_kale_set_focus_byidx(compo_kaleidoscope_t *kale, int idx)
{
if (kale == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_SELECT);
}
kale->focus_icon_idx = idx;
if (kale->focus_icon_idx == 0) {
return;
}
//索引图标所处的外圈任务层及内圈为外圈的下一级任务层
u8 dolay, dilay = 0;
dilay = dolay = (idx / KALE_CIR_ICON_NUM);
cycle_plus((u8 *)&dilay, KALE_FUNC_LAY_0, ((kale->total_cnt - 1) / KALE_CIR_ICON_NUM));
//更新内外圈的圈层编号
if ((dolay % 2) == 0) { //任务在外圈 圈层为 KALE_CIR_1
kale->ctl.oidx = KALE_CIR_1;
kale->ctl.iidx = KALE_CIR_0;
} else { //任务在外圈 圈层为 KALE_CIR_0
kale->ctl.oidx = KALE_CIR_0;
kale->ctl.iidx = KALE_CIR_1;
}
//更新内外圈的半径
kale->dcir[kale->ctl.oidx].r = kale->ctl.org_or;
kale->dcir[kale->ctl.iidx].r = kale->ctl.org_ir;
//更新内外圈的图标尺寸
kale->dcir[kale->ctl.oidx].size = kale->ctl.osize;
kale->dcir[kale->ctl.iidx].size = kale->ctl.isize;
//更新内外圈的任务层
kale->dcir[kale->ctl.oidx].lay = dolay;
kale->dcir[kale->ctl.iidx].lay = dilay;
for (int i = 0; i < kale->total_cnt; i++) {
u8 idx_cir = i / KALE_CIR_ICON_NUM;
u8 idx_icon = i % KALE_CIR_ICON_NUM;
compo_kale_func_t *fp = &kale->ofunc[idx_cir].fsub[idx_icon];
//设置外圈的任务层
if (idx_cir == kale->dcir[kale->ctl.oidx].lay) { //外圈
compo_kale_icon_t *dp = &kale->dcir[kale->ctl.oidx].icon[idx_icon];
dp->fsub.widget = fp->widget;
dp->fsub.func_sta = fp->func_sta;
if ((idx_cir % 2) == 0) { //任务在外圈 圈层为 KALE_CIR_1
dp->angle += KALE_CIR_ANGLE_DEV;
}
}
//设置内圈的任务层
if (idx_cir == kale->dcir[kale->ctl.iidx].lay) { //内圈
compo_kale_icon_t *dp = &kale->dcir[kale->ctl.iidx].icon[idx_icon];
dp->fsub.widget = fp->widget;
dp->fsub.func_sta = fp->func_sta;
if ((idx_cir % 2) != 0) { //任务在外圈 圈层为 KALE_CIR_0
dp->angle -= KALE_CIR_ANGLE_DEV;
}
}
}
}