[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [41049] trunk/blender/source/blender: utf8 editing for UI text input, this means backspace, delete, arrow keys properly move the cursor with multi-byte chars.

Campbell Barton ideasman42 at gmail.com
Sun Oct 16 14:25:43 CEST 2011


Revision: 41049
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=41049
Author:   campbellbarton
Date:     2011-10-16 12:25:42 +0000 (Sun, 16 Oct 2011)
Log Message:
-----------
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.

Modified Paths:
--------------
    trunk/blender/source/blender/blenlib/BLI_string.h
    trunk/blender/source/blender/blenlib/intern/string_utf8.c
    trunk/blender/source/blender/editors/interface/interface_handlers.c

Modified: trunk/blender/source/blender/blenlib/BLI_string.h
===================================================================
--- trunk/blender/source/blender/blenlib/BLI_string.h	2011-10-16 11:09:15 UTC (rev 41048)
+++ trunk/blender/source/blender/blenlib/BLI_string.h	2011-10-16 12:25:42 UTC (rev 41049)
@@ -147,6 +147,10 @@
 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
 }

Modified: trunk/blender/source/blender/blenlib/intern/string_utf8.c
===================================================================
--- trunk/blender/source/blender/blenlib/intern/string_utf8.c	2011-10-16 11:09:15 UTC (rev 41048)
+++ trunk/blender/source/blender/blenlib/intern/string_utf8.c	2011-10-16 12:25:42 UTC (rev 41049)
@@ -183,3 +183,83 @@
 	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 */

Modified: trunk/blender/source/blender/editors/interface/interface_handlers.c
===================================================================
--- trunk/blender/source/blender/editors/interface/interface_handlers.c	2011-10-16 11:09:15 UTC (rev 41048)
+++ trunk/blender/source/blender/editors/interface/interface_handlers.c	2011-10-16 12:25:42 UTC (rev 41049)
@@ -1252,6 +1252,86 @@
 	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 @@
 	
 	/* 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 @@
 		/* 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,49 +1479,8 @@
 		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) {
+		ui_textedit_step_utf8(str, len, &but->pos, direction, jump, jump_all);
 
-				/* 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--;
-			}
-		}
-
-
 		if(select) {
 			/* existing selection */
 			if (has_sel) {
@@ -1498,21 +1545,10 @@
 			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 @@
 				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];




More information about the Bf-blender-cvs mailing list