forked from bartvdbraak/blender
utf8 editing for UI text input, this means backspace, delete, arrow keys properly move the cursor with multi-byte chars.
Note that this is only for the interface, text editor and python console still miss this feature.
This commit is contained in:
parent
92bc72dca1
commit
b6d0daa9cb
@ -147,6 +147,10 @@ void BLI_ascii_strtoupper(char *str, int len);
|
||||
char *BLI_strncpy_utf8(char *dst, const char *src, size_t maxncpy);
|
||||
int BLI_utf8_invalid_byte(const char *str, int length);
|
||||
int BLI_utf8_invalid_strip(char *str, int length);
|
||||
/* copied from glib */
|
||||
char *BLI_str_find_prev_char_utf8(const char *str, const char *p);
|
||||
char *BLI_str_find_next_char_utf8(const char *p, const char *end);
|
||||
char *BLI_str_prev_char_utf8(const char *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -183,3 +183,83 @@ char *BLI_strncpy_utf8(char *dst, const char *src, size_t maxncpy)
|
||||
return dst_r;
|
||||
}
|
||||
|
||||
/* copied from glib */
|
||||
/**
|
||||
* g_utf8_find_prev_char:
|
||||
* @str: pointer to the beginning of a UTF-8 encoded string
|
||||
* @p: pointer to some position within @str
|
||||
*
|
||||
* Given a position @p with a UTF-8 encoded string @str, find the start
|
||||
* of the previous UTF-8 character starting before @p. Returns %NULL if no
|
||||
* UTF-8 characters are present in @str before @p.
|
||||
*
|
||||
* @p does not have to be at the beginning of a UTF-8 character. No check
|
||||
* is made to see if the character found is actually valid other than
|
||||
* it starts with an appropriate byte.
|
||||
*
|
||||
* Return value: a pointer to the found character or %NULL.
|
||||
**/
|
||||
char * BLI_str_find_prev_char_utf8(const char *str, const char *p)
|
||||
{
|
||||
for (--p; p >= str; --p) {
|
||||
if ((*p & 0xc0) != 0x80) {
|
||||
return (char *)p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_utf8_find_next_char:
|
||||
* @p: a pointer to a position within a UTF-8 encoded string
|
||||
* @end: a pointer to the byte following the end of the string,
|
||||
* or %NULL to indicate that the string is nul-terminated.
|
||||
*
|
||||
* Finds the start of the next UTF-8 character in the string after @p.
|
||||
*
|
||||
* @p does not have to be at the beginning of a UTF-8 character. No check
|
||||
* is made to see if the character found is actually valid other than
|
||||
* it starts with an appropriate byte.
|
||||
*
|
||||
* Return value: a pointer to the found character or %NULL
|
||||
**/
|
||||
char *BLI_str_find_next_char_utf8(const char *p, const char *end)
|
||||
{
|
||||
if (*p) {
|
||||
if (end) {
|
||||
for (++p; p < end && (*p & 0xc0) == 0x80; ++p) {
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (++p; (*p & 0xc0) == 0x80; ++p) {
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
}
|
||||
return (p == end) ? NULL : (char *)p;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_utf8_prev_char:
|
||||
* @p: a pointer to a position within a UTF-8 encoded string
|
||||
*
|
||||
* Finds the previous UTF-8 character in the string before @p.
|
||||
*
|
||||
* @p does not have to be at the beginning of a UTF-8 character. No check
|
||||
* is made to see if the character found is actually valid other than
|
||||
* it starts with an appropriate byte. If @p might be the first
|
||||
* character of the string, you must use g_utf8_find_prev_char() instead.
|
||||
*
|
||||
* Return value: a pointer to the found character.
|
||||
**/
|
||||
char *BLI_str_prev_char_utf8(const char *p)
|
||||
{
|
||||
while (1) {
|
||||
p--;
|
||||
if ((*p & 0xc0) != 0x80) {
|
||||
return (char *)p;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* end glib copy */
|
||||
|
@ -1252,6 +1252,86 @@ static short test_special_char(char ch)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ui_textedit_step_next_utf8(const char *str, size_t maxlen, short *pos)
|
||||
{
|
||||
const char *str_end= str + (maxlen + 1);
|
||||
const char *str_pos= str + (*pos);
|
||||
const char *str_next= BLI_str_find_next_char_utf8(str_pos, str_end);
|
||||
if (str_next) {
|
||||
(*pos) += (str_next - str_pos);
|
||||
if((*pos) > maxlen) (*pos)= maxlen;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ui_textedit_step_prev_utf8(const char *str, size_t UNUSED(maxlen), short *pos)
|
||||
{
|
||||
if((*pos) > 0) {
|
||||
const char *str_pos= str + (*pos);
|
||||
const char *str_prev= BLI_str_find_prev_char_utf8(str, str_pos);
|
||||
if (str_prev) {
|
||||
(*pos) -= (str_pos - str_prev);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ui_textedit_step_utf8(const char *str, size_t maxlen,
|
||||
short *pos, const char direction,
|
||||
const short do_jump, const short do_all)
|
||||
{
|
||||
const short pos_prev= *pos;
|
||||
|
||||
if(direction) { /* right*/
|
||||
if(do_jump) {
|
||||
/* jump between special characters (/,\,_,-, etc.),
|
||||
* look at function test_special_char() for complete
|
||||
* list of special character, ctr -> */
|
||||
while((*pos) < maxlen) {
|
||||
if (ui_textedit_step_next_utf8(str, maxlen, pos)) {
|
||||
if(!do_all && test_special_char(str[(*pos)])) break;
|
||||
}
|
||||
else {
|
||||
break; /* unlikely but just incase */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui_textedit_step_next_utf8(str, maxlen, pos);
|
||||
}
|
||||
}
|
||||
else { /* left */
|
||||
if(do_jump) {
|
||||
/* left only: compensate for index/change in direction */
|
||||
ui_textedit_step_prev_utf8(str, maxlen, pos);
|
||||
|
||||
/* jump between special characters (/,\,_,-, etc.),
|
||||
* look at function test_special_char() for complete
|
||||
* list of special character, ctr -> */
|
||||
while ((*pos) > 0) {
|
||||
if (ui_textedit_step_prev_utf8(str, maxlen, pos)) {
|
||||
if(!do_all && test_special_char(str[(*pos)])) break;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* left only: compensate for index/change in direction */
|
||||
if(((*pos) != 0) && ABS(pos_prev - (*pos)) > 1) {
|
||||
ui_textedit_step_next_utf8(str, maxlen, pos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui_textedit_step_prev_utf8(str, maxlen, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
|
||||
{
|
||||
char *str= data->str;
|
||||
@ -1294,13 +1374,17 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, sho
|
||||
|
||||
/* mouse dragged outside the widget to the left */
|
||||
if (x < startx && but->ofs > 0) {
|
||||
int i= but->ofs;
|
||||
short i= but->ofs;
|
||||
|
||||
origstr[but->ofs] = 0;
|
||||
|
||||
while (i > 0) {
|
||||
i--;
|
||||
if (BLF_width(fstyle->uifont_id, origstr+i) > (startx - x)*0.25f) break; // 0.25 == scale factor for less sensitivity
|
||||
if (ui_textedit_step_prev_utf8(origstr, but->ofs, &i)) {
|
||||
if (BLF_width(fstyle->uifont_id, origstr+i) > (startx - x)*0.25f) break; // 0.25 == scale factor for less sensitivity
|
||||
}
|
||||
else {
|
||||
break; /* unlikely but possible */
|
||||
}
|
||||
}
|
||||
but->ofs = i;
|
||||
but->pos = but->ofs;
|
||||
@ -1314,9 +1398,13 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, sho
|
||||
/* XXX does not take zoom level into account */
|
||||
while (startx + aspect_sqrt * BLF_width(fstyle->uifont_id, origstr+but->ofs) > x) {
|
||||
if (but->pos <= 0) break;
|
||||
but->pos--;
|
||||
origstr[but->pos+but->ofs] = 0;
|
||||
}
|
||||
if (ui_textedit_step_prev_utf8(origstr, but->ofs, &but->pos)) {
|
||||
origstr[but->pos+but->ofs] = 0;
|
||||
}
|
||||
else {
|
||||
break; /* unlikely but possible */
|
||||
}
|
||||
}
|
||||
but->pos += but->ofs;
|
||||
if(but->pos<0) but->pos= 0;
|
||||
}
|
||||
@ -1391,48 +1479,7 @@ static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction
|
||||
data->selextend = 0;
|
||||
}
|
||||
else {
|
||||
if(direction) { /* right*/
|
||||
if(jump) {
|
||||
/* jump between special characters (/,\,_,-, etc.),
|
||||
* look at function test_special_char() for complete
|
||||
* list of special character, ctr -> */
|
||||
while(but->pos < len) {
|
||||
but->pos++;
|
||||
if(!jump_all && test_special_char(str[but->pos])) break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
but->pos++;
|
||||
if(but->pos > len) but->pos= len;
|
||||
}
|
||||
}
|
||||
else { /* left */
|
||||
if(jump) {
|
||||
|
||||
/* left only: compensate for index/change in direction */
|
||||
if(but->pos > 0) {
|
||||
but->pos--;
|
||||
}
|
||||
|
||||
/* jump between special characters (/,\,_,-, etc.),
|
||||
* look at function test_special_char() for complete
|
||||
* list of special character, ctr -> */
|
||||
while(but->pos > 0){
|
||||
but->pos--;
|
||||
if(!jump_all && test_special_char(str[but->pos])) break;
|
||||
}
|
||||
|
||||
/* left only: compensate for index/change in direction */
|
||||
if((but->pos != 0) && ABS(pos_prev - but->pos) > 1) {
|
||||
but->pos++;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
if(but->pos>0) but->pos--;
|
||||
}
|
||||
}
|
||||
|
||||
ui_textedit_step_utf8(str, len, &but->pos, direction, jump, jump_all);
|
||||
|
||||
if(select) {
|
||||
/* existing selection */
|
||||
@ -1498,21 +1545,10 @@ static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int directio
|
||||
changed= ui_textedit_delete_selection(but, data);
|
||||
}
|
||||
else if(but->pos>=0 && but->pos<len) {
|
||||
short pos= but->pos;
|
||||
int step;
|
||||
|
||||
if (jump) {
|
||||
x = but->pos;
|
||||
step= 0;
|
||||
while(x < len) {
|
||||
x++;
|
||||
step++;
|
||||
if(test_special_char(str[x])) break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
step= 1;
|
||||
}
|
||||
|
||||
ui_textedit_step_utf8(str, len, &pos, direction, jump, all);
|
||||
step= pos - but->pos;
|
||||
for(x=but->pos; x<len; x++)
|
||||
str[x]= str[x+step];
|
||||
str[len-step]='\0';
|
||||
@ -1525,20 +1561,11 @@ static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int directio
|
||||
changed= ui_textedit_delete_selection(but, data);
|
||||
}
|
||||
else if(but->pos>0) {
|
||||
short pos= but->pos;
|
||||
int step;
|
||||
|
||||
if (jump) {
|
||||
x = but->pos;
|
||||
step= 0;
|
||||
while(x > 0) {
|
||||
x--;
|
||||
step++;
|
||||
if((step > 1) && test_special_char(str[x])) break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
step= 1;
|
||||
}
|
||||
ui_textedit_step_utf8(str, len, &pos, direction, jump, all);
|
||||
step= but->pos - pos;
|
||||
|
||||
for(x=but->pos; x<len; x++)
|
||||
str[x-step]= str[x];
|
||||
|
Loading…
Reference in New Issue
Block a user