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

518 lines
17 KiB
C
Raw 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 TABLE_SIZE 181
static const int cos_table[TABLE_SIZE] = {
10000, 9998, 9994, 9986, 9976, 9962, 9945, 9925, 9903, 9877, 9848, 9816, 9781, 9743, 9702, 9659, 9612, 9563,
9511, 9455, 9397, 9336, 9272, 9205, 9135, 9063, 8988, 8910, 8829, 8746, 8660, 8571, 8480, 8386, 8290, 8191,
8090, 7986, 7880, 7771, 7660, 7547, 7431, 7313, 7193, 7071, 6947, 6820, 6691, 6561, 6428, 6293, 6157, 6018,
5878, 5736, 5592, 5446, 5299, 5150, 5000, 4848, 4695, 4540, 4384, 4226, 4067, 3907, 3746, 3584, 3420, 3256,
3090, 2924, 2756, 2588, 2419, 2250, 2079, 1908, 1736, 1564, 1391, 1218, 1045, 871, 697, 523, 349, 175, 0,
-175, -349, -523, -697, -871, -1045, -1218, -1391, -1564, -1736, -1908, -2079, -2250, -2419, -2588, -2756,
-2924, -3090, -3256, -3420, -3584, -3746, -3907, -4067, -4226, -4384, -4540, -4695, -4848, -5000, -5150,
-5299, -5446, -5592, -5736, -5878, -6018, -6157, -6293, -6428, -6561, -6691, -6820, -6947, -7071, -7193,
-7313, -7431, -7547, -7660, -7771, -7880, -7986, -8090, -8191, -8290, -8386, -8480, -8571, -8660, -8746,
-8829, -8910, -8988, -9063, -9135, -9205, -9272, -9336, -9397, -9455, -9511, -9563, -9612, -9659, -9702,
-9743, -9781, -9816, -9848, -9877, -9903, -9925, -9945, -9962, -9976, -9986, -9994, -9998, -10000
};
/**
* @brief 二分法查找最接近的余弦值
* 注放大系数10000
* @param[in] value : 余弦值 * 放大系数
* @return 返回对应的弧度 精度为1° 0~180°
**/
int binarysearch(int value)
{
int low = 0;
int high = TABLE_SIZE - 1;
while (low <= high) {
int mid = adds(low, high) >> 1;
if (cos_table[mid] == value) {
return mid;
} else if (cos_table[mid] < value) {
high = mid - 1;
} else {
low = mid + 1;
}
}
if (low > TABLE_SIZE - 1) {
return high;
} else if (high < 0) {
return low;
} else {
return (subs(value, cos_table[high]) < subs(cos_table[low], value)) ? high : low;
}
}
/**
* @brief acos函数
* 注放大系数10000
* @param[in] value : 余弦值 * 放大系数
* @return 返回对应的弧度 精度为1° 0~180°
**/
int myacos(int value)
{
int angle = binarysearch(value);
return angle;
}
/**
* @brief 弧度计算
* 注:根据当前点和中心点确定余弦值并计算弧度值 精度为1°
* @param[in] cx :中心点X
* @param[in] cy :中心点Y
* @param[in] x :当前点X
* @param[in] y :当前点Y
* @return 返回对应的弧度 精度为1° 0~180°
**/
int myrad(int cx, int cy, int x, int y)
{
int dx = subs(x, cx);
int dy = subs(y, cy);
int cos_value = (int)((int)muls(dx, COS_SCALE)) / (int)(sqrt64(muls(dx, dx) + muls(dy, dy)));
return ACOS(cos_value);
}
/**
* @brief 创建一个环形组件
* @param[in] frm : 窗体指针
* @return 返回环形组件指针
**/
compo_rings_t *compo_rings_create(compo_form_t *frm)
{
compo_rings_t *rings = compo_create(frm, COMPO_TYPE_RINGS);
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);
rings->page = page;
return rings;
}
/**
* @brief 初始一个环形组件
* @param[in] rings : 环形组件指针
* @param[in] ele : 初始元素指针
* @return 无
**/
void compo_rings_set(compo_rings_t *rings, compo_rings_ele_t *ele)
{
if (rings == NULL && (ele->loop_icon_num + ele->other_icon_num) > RINGS_MAX_ICON_CNT) {
halt(HALT_GUI_COMPO_LISTBOX_SET);
return;
}
rings->ele.x = ele->x;
rings->ele.y = ele->y;
rings->ele.r = ele->r;
rings->ele.div = ele->div;
rings->ele.angle = ele->angle;
rings->ele.loop_icon_num = ele->loop_icon_num;
rings->ele.other_icon_num = ele->other_icon_num;
rings->ele.item_num = ele->item_num;
rings->ele.item = ele->item;
}
/**
* @brief 往环形图标集上面添加图标
* @param[in] rings : 环形组件指针
* @param[in] res_addr : 图标资源地址
* @param[in] idx : 图标任务编号
* @param[in] loop : 是否为环形图标
* @return 图标信息指针
**/
compo_rings_icon_t *compo_rings_icon_add(compo_rings_t *rings, u32 res_addr, int idx, bool loop)
{
if (rings == NULL) {
halt(HALT_GUI_COMPO_ICONLIST_ADD);
}
compo_rings_icon_t *icon = NULL;
if (loop) { //加载环形上的图标
if (rings->loop_icon_cnt < rings->ele.loop_icon_num) {
widget_icon_t *widget = widget_icon_create(rings->page, res_addr);
rect_t location = widget_get_location(widget);
icon = &rings->icon[rings->loop_icon_cnt];
icon->widget = widget;
icon->size = location.wid;
icon->idx = idx;
icon->angle = rings->ele.angle + rings->loop_icon_cnt * rings->ele.div;
icon->angle = RINGS_GET_ANGLE(icon->angle);
rings->loop_icon_cnt++;
widget_set_visible(widget, false);
}
} else { //加载非环形上的图标
if (rings->other_icon_cnt < rings->ele.other_icon_num) {
widget_icon_t *widget = widget_icon_create(rings->page, res_addr);
rect_t location = widget_get_location(widget);
icon = &rings->icon[rings->ele.loop_icon_num + rings->other_icon_cnt];
icon->widget = widget;
icon->size = location.wid;
icon->idx = idx;
rings->other_icon_cnt++;
icon->angle = -rings->other_icon_cnt;
widget_set_visible(widget, false);
}
}
return icon;
}
/**
* @brief 返回当前点相对于中心点坐标正Y轴的角度
* @param[in] rings : 环形组件指针
* @param[in] touch : 触摸信息指针
* @param[in] cx : 中心点X
* @param[in] cy : 中心点Y
* @param[in] x : 当前点X
* @param[in] y : 当前点Y
* @return 相对角度
**/
int32_t compo_rings_touch_angle(compo_rings_t *rings, compo_rings_touch_t *touch, s16 cx, s16 cy, s16 x, s16 y)
{
//触摸点相对坐标
int dx = x - cx;
int dy = -(y - cy);
touch->angle = -1;
//触摸点的象限
if (dx > 0 && dy > 0) {
touch->quad = QUADRANT_1;
} else if (dx < 0 && dy > 0) {
touch->quad = QUADRANT_2;
} else if (dx < 0 && dy < 0) {
touch->quad = QUADRANT_3;
} else if (dx > 0 && dy < 0) {
touch->quad = QUADRANT_4;
}
//根据象限确定和正向Y轴的夹角 0~3600
if (touch->quad == QUADRANT_1 || touch->quad == QUADRANT_2) {
touch->angle = RINGS_GET_ANGLE((90 - myrad(cx, cy, x, y)) * 10);
} else if (touch->quad == QUADRANT_3 || touch->quad == QUADRANT_4) {
touch->angle = RINGS_GET_ANGLE((90 + myrad(cx, cy, x, y)) * 10);
}
if (touch->angle == -1) {
if ((dx == 0 && dy == 0) || (dx == 0 && dy > 0)) {
touch->angle = 0;
} else if (dx > 0 && dy == 0) {
touch->angle = 900;
} else if (dx == 0 && dy < 0) {
touch->angle = 1800;
} else if (dx < 0 && dy == 0) {
touch->angle = 2700;
}
}
return touch->angle;
}
/**
* @brief 设置滑动前的触摸信息
* @param[in] rings : 环形组件指针
* @param[in] cx : 中心点X
* @param[in] cy : 中心点Y
* @param[in] x : 当前点X
* @param[in] y : 当前点Y
* @return 无
**/
void compo_rings_touch_angle_pre(compo_rings_t *rings, s16 cx, s16 cy, s16 x, s16 y)
{
compo_rings_touch_angle(rings, &rings->pre, cx, cy, x, y);
}
/**
* @brief 获取滑动差量角度
* @param[in] rings : 环形组件指针
* @param[in] cx : 中心点X
* @param[in] cy : 中心点Y
* @param[in] x : 当前点X
* @param[in] y : 当前点Y
* @return 差量角度
* 正值:正向顺时针;
* 负值:逆向逆时针;
**/
int32_t compo_rings_touch_angle_diff(compo_rings_t *rings, s16 cx, s16 cy, s16 x, s16 y)
{
compo_rings_touch_angle(rings, &rings->cur, cx, cy, x, y);
int32_t diff_angle = 0;
if (rings->cur.angle == rings->pre.angle) return diff_angle;
if (rings->pre.quad == QUADRANT_2 && rings->cur.quad == QUADRANT_1) { //临界区域 顺时针
diff_angle = rings->cur.angle + 3600 - rings->pre.angle;
} else if (rings->pre.quad == QUADRANT_1 && rings->cur.quad == QUADRANT_2) { //临界区域 逆时针
diff_angle = rings->cur.angle - 3600 - rings->pre.angle;
} else {
diff_angle = rings->cur.angle - rings->pre.angle;
}
diff_angle = abs(diff_angle) > 10 ? diff_angle : 0; //消抖
rings->pre.angle = rings->cur.angle;
rings->pre.quad = rings->cur.quad;
return diff_angle;
}
/**
* @brief 查找环形图标集上的图标角度
* @param[in] rings : 环形组件指针
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 角度
**/
int32_t compo_rings_loop_icon_find_angle(compo_rings_t *rings, int id)
{
if (id > RINGS_MAX_ICON_CNT) return -1;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) return icon->angle;
return -2;
}
/**
* @brief 查找环形图标集上的图标任务编号
* @param[in] rings : 环形组件指针
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 任务编号
**/
u8 compo_rings_loop_icon_find_idx(compo_rings_t *rings, u8 id)
{
if (id > RINGS_MAX_ICON_CNT) return 0xFF;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) return icon->idx;
return 0xFF;
}
/**
* @brief 查找环形图标集上的图标尺寸
* @param[in] rings : 环形组件指针
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 图标尺寸
**/
u8 compo_rings_loop_icon_find_size(compo_rings_t *rings, u8 id)
{
if (id > RINGS_MAX_ICON_CNT) return 0xFF;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) return icon->size;
return 0xFF;
}
/**
* @brief 设置环形图标集上的图标偏移角度
* @param[in] rings : 环形组件指针
* @param[in] diff_angle: 差量角度
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 无
**/
void compo_rings_loop_icon_set_angle_diff(compo_rings_t *rings, int32_t diff_angle, int id)
{
if (id > RINGS_MAX_ICON_CNT) return;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) {
icon->angle += diff_angle;
icon->angle = RINGS_GET_ANGLE(icon->angle);
}
}
/**
* @brief 设置环形图标集上的图标绝对角度
* @param[in] rings : 环形组件指针
* @param[in] angle : 绝对角度
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 无
**/
void compo_rings_set_angle(compo_rings_t *rings, int32_t angle, int id)
{
if (id > RINGS_MAX_ICON_CNT) return;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) icon->angle = angle;
}
/**
* @brief 设置环形图标集上的图标尺寸
* @param[in] rings : 环形组件指针
* @param[in] size : 尺寸
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 无
**/
void compo_rings_set_size(compo_rings_t *rings, uint16_t size, int id)
{
if (id > RINGS_MAX_ICON_CNT) return;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) icon->size = size;
}
/**
* @brief 设置环形图标集上的图标任务编号
* @param[in] rings : 环形组件指针
* @param[in] idx : 任务编号
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 无
**/
void compo_rings_set_uidx(compo_rings_t *rings, u8 idx, int id)
{
if (id > RINGS_MAX_ICON_CNT) return;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) icon->idx = idx;
}
/**
* @brief 设置环形图标集上的图标资源地址
* @param[in] rings : 环形组件指针
* @param[in] res_addr : 资源地址
* @param[in] id : compo_rings_icon_t icon[RINGS_MAX_ICON_CNT] 数组下标
* @return 无
**/
void compo_rings_set_res(compo_rings_t *rings, u32 res_addr, int id)
{
if (id > RINGS_MAX_ICON_CNT) return;
compo_rings_icon_t *icon = &rings->icon[id];
if (icon->widget) widget_icon_set(icon->widget, res_addr);
}
/**
* @brief 设置环形图标集上的图标任务编号
* @param[in] rings : 环形组件指针
* @param[in] uidx : 变更图标任务编号
* @param[in] idx : 原始图标任务编号
* @return 无
**/
void compo_rings_set_uidx_from_idx(compo_rings_t *rings, int uidx, int idx)
{
for (int i = 0; i < RINGS_MAX_ICON_CNT; i++) {
compo_rings_icon_t *icon = &rings->icon[i];
if (icon->idx == idx) {
if (icon->widget) {
icon->idx = uidx;
break;
}
}
}
}
/**
* @brief 设置环形图标集上的图标资源地址
* @param[in] rings : 环形组件指针
* @param[in] res_addr : 资源地址
* @param[in] idx : 图标任务编号
* @return 无
**/
void compo_rings_set_res_from_idx(compo_rings_t *rings, u32 res_addr, int idx)
{
for (int i = 0; i < RINGS_MAX_ICON_CNT; i++) {
compo_rings_icon_t *icon = &rings->icon[i];
if (icon->idx == idx) {
if (icon->widget) {
widget_icon_set(icon->widget, res_addr);
break;
}
}
}
}
/**
* @brief 设置环形图标集上的图标位置信息
* @param[in] rings : 环形组件指针
* @param[in] x : X
* @param[in] y : Y
* @param[in] width : W
* @param[in] height : H
* @param[in] idx : 图标任务编号
* @return 无
**/
void compo_rings_set_location(compo_rings_t *rings, s16 x, s16 y, s16 width, s16 height, int idx)
{
for (int i = 0; i < RINGS_MAX_ICON_CNT; i++) {
compo_rings_icon_t *icon = &rings->icon[i];
if (icon->widget) {
if (icon->idx == idx) {
widget_set_visible(icon->widget, true);
widget_set_location(icon->widget, x, y, width, height);
break;
}
}
}
}
/**
* @brief 更新环形图标集合
* 注:仅更新在环形上的,非环形上的图标请单独更新
* @param[in] rings : 图标集指针
**/
void compo_rings_update_loop(compo_rings_t *rings)
{
if (rings == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_UPDATE);
}
for (int i = 0; i < rings->ele.loop_icon_num; i++) {
compo_rings_icon_t *icon = &rings->icon[i];
if (icon->widget) {
int ix = rings->ele.x + RINGS_GET_ICON_REL_X(rings->ele.r, icon->angle);
int iy = rings->ele.y + RINGS_GET_ICON_REL_Y(rings->ele.r, icon->angle);
widget_set_visible(icon->widget, true);
widget_set_location(icon->widget, ix, iy, icon->size, icon->size);
}
}
}
/**
* @brief 按坐标选择图标
* @param[in] rings : 图标集指针
* @param[in] x : x轴坐标
* @param[in] y : y轴坐标
* @return 返回图标索引
**/
compo_rings_sel_t *compo_rings_select(compo_rings_t *rings, int x, int y)
{
if (rings == NULL) {
halt(HALT_GUI_COMPO_LISTBOX_SELECT);
}
for (int i = 0; i < RINGS_MAX_ICON_CNT; i++) {
compo_rings_icon_t *icon = &rings->icon[i];
if (icon->widget) {
rect_t rect = widget_get_absolute(icon->widget);
if (abs_s(x - rect.x) * 2 <= rect.wid && abs_s(y - rect.y) * 2 <= rect.hei) {
rings->sel.icon = icon->widget;
rings->sel.idx = icon->idx;
return &rings->sel;
}
}
}
rings->sel.icon = NULL;
rings->sel.idx = -1;
return &rings->sel;
}
/**
* @brief 按索引选择图标
* @param[in] rings : 图标集指针
* @param[in] idx : 编号索引
* @return 返回图标指针
**/
widget_icon_t *compo_rings_select_byidx(compo_rings_t *rings, int idx)
{
for (int i = 0; i < RINGS_MAX_ICON_CNT; i++) {
compo_rings_icon_t *icon = &rings->icon[i];
if (icon->widget) {
if (icon->idx == idx) {
rings->sel.icon = icon->widget;
rings->sel.idx = idx;
return rings->sel.icon;
}
}
}
rings->sel.icon = NULL;
rings->sel.idx = -1;
return NULL;
}