![]() |
#2
xyzdwf2021-09-22 18:26
|
另一方面套两层可以实现文字边距,而且计算坐标的时候不用再把边距给计算进去,不容易搞晕。
一开始为了效率考虑就使用二分法来确定文字中的坐标,但由于多字节字符串(汉字占两个字节),导致二分法截止条件设置错误,好几天了也没调试通,
网上搜了不少也根本没找到好的解决办法,今天终于调通了

发在论坛里,以前做过的帮我看看还有没有问题,也给需要的坛友提供点思路,以后自己也好找到
只有本站会员才能查看附件,请 登录
打的32位exe也不知道64位系统能不能用
只有本站会员才能查看附件,请 登录

/**
* @brief 获取字符串中某个index的子串占位rect
* @param ctx ui上下文
* @param wgt widget ui组件
* @param style 文字样式(和draw方法必须相同,否则会不一致)
* @param indx 字符在字符串中的index
* @return 占位rect
*/
static gui_rect_t gui_itxt_indx_rect(gui_context_p ctx, gui_widget_p wgt, gui_text_style_t style, int indx)
{
char* str = wgt->text;
int num = indx+1;
char txt[num+1];
int j;
for(j = 0; j<num; j++){
txt[j] = *(str+j);
}
txt[num] = '\0';
gui_rect_t rect = gui_base_measuretext(ctx->context, wgt->px, wgt->py, 65535, wgt->ph, txt, style);
return rect;
}
/**
* @brief 获取鼠标在文本中的位置和字符index(用于绘制文字中的光标和选中背景)
* @param ctx ui 上下文
* @param wgt widget ui组件
* @param x 点击坐标x
* @param y 点击坐标x
* @param style 文字样式(和draw方法必须相同,否则会不一致)
* @param indx 用于返回字符在字符串中的index
* @param rec 占位rect
*/
static void gui_itxt_measure_pos(gui_context_p ctx, gui_widget_p wgt, int x, int y,
gui_text_style_t style, int* indx, gui_rect_t* rec)
{
gui_rect_t rect = {0};
char* str = wgt->text;
if(!str || strlen(str)<1)return;
int m = 0;
int n = strlen(str)-1;
int i;
byte bol = 0;//
while(n - m > 4){//因为是多字节字符的字符串,汉字占两个字节,两个相邻汉字差4个char
i=0;
int mid = (m+n)/2;
while(i <= mid){
if(*(str+i)<0){
if(i == mid){i--;break;}//汉字不能完整舍弃
if(i == mid-1){i++;break;}//汉字刚好占满结束
i+=2;
}else{
if(i == mid)break;
i++;
}
}
rect = gui_itxt_indx_rect(ctx, wgt, style, i);
if(rect.x+rect.w > x){
n = i;
}else if(rect.x+rect.w < x){
m = i+1;
}else{//点击位置正好为光标位置
bol = 1;
break;
}
}
if(bol){
rec->x = rect.x;
rec->y = rect.y;
rec->w = rect.w-2;//-2为一点差值,根据实际测试得来
rec->h = rect.h;
*indx = i;
return;
}
while(m <= n){//小于4个char逐char定位
byte bla = *(str+m) < 0;//同样需要处理汉字
int rlm = bla?m+1:m;
rect = gui_itxt_indx_rect(ctx, wgt, style, rlm);
*indx = rlm;
if(x < rect.x+rect.w){
if(m == 0){//第0个字符处理
int per = rect.w/2;//用于处理电子字符左右半边,定位该字符前后
if(x <= rect.x + per){
rect.w=3;
*indx = -1;
}
}else{
gui_rect_t recta = gui_itxt_indx_rect(ctx, wgt, style, m-1);
int pera = (rect.w - recta.w)/2;//用于处理电子字符左右半边,定位该字符前后
if(x <= recta.x + recta.w + pera - 2){
rect = recta;
*indx = m-1;
}
}
break;
}
if(bla)m+=2;
else m++;
}
rec->x = rect.x;
rec->y = rect.y;
rec->w = rect.w-2;//-2为一点差值,根据实际测试得来
rec->h = rect.h;
}