#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; }