diff options
Diffstat (limited to 'pd/src/g_rtext.c')
-rw-r--r-- | pd/src/g_rtext.c | 187 |
1 files changed, 129 insertions, 58 deletions
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c index 976901e9..e63a172d 100644 --- a/pd/src/g_rtext.c +++ b/pd/src/g_rtext.c @@ -13,6 +13,7 @@ #include "m_pd.h" #include "s_stuff.h" #include "g_canvas.h" +#include "s_utf8.h" #define LMARGIN 2 @@ -32,10 +33,10 @@ struct _rtext { - char *x_buf; - int x_bufsize; - int x_selstart; - int x_selend; + char *x_buf; /*-- raw byte string, assumed UTF-8 encoded (moo) --*/ + int x_bufsize; /*-- byte length --*/ + int x_selstart; /*-- byte offset --*/ + int x_selend; /*-- byte offset --*/ int x_active; int x_dragfrom; int x_height; @@ -104,8 +105,30 @@ void rtext_getseltext(t_rtext *x, char **buf, int *bufsize) *bufsize = x->x_selend - x->x_selstart; } +/* convert t_text te_type symbol for use as a Tk tag */ +static t_symbol *rtext_gettype(t_rtext *x) +{ + switch (x->x_text->te_type) + { + case T_TEXT: return gensym("text"); + case T_OBJECT: return gensym("obj"); + case T_MESSAGE: return gensym("msg"); + case T_ATOM: return gensym("atom"); + } + return (&s_); +} + /* LATER deal with tcl-significant characters */ +/* firstone(), lastone() + * + returns byte offset of (first|last) occurrence of 'c' in 's[0..n-1]', or + * -1 if none was found + * + 's' is a raw byte string + * + 'c' is a byte value + * + 'n' is the length (in bytes) of the prefix of 's' to be searched. + * + we could make these functions work on logical characters in utf8 strings, + * but we don't really need to... + */ static int firstone(char *s, int c, int n) { char *s2 = s + n; @@ -142,6 +165,16 @@ static int lastone(char *s, int c, int n) of the entire text in pixels. */ + /*-- moo: + * + some variables from the original version have been renamed + * + variables with a "_b" suffix are raw byte strings, lengths, or offsets + * + variables with a "_c" suffix are logical character lengths or offsets + * (assuming valid UTF-8 encoded byte string in x->x_buf) + * + a fair amount of O(n) computations required to convert between raw byte + * offsets (needed by the C side) and logical character offsets (needed by + * the GUI) + */ + /* LATER get this and sys_vgui to work together properly, breaking up messages as needed. As of now, there's a limit of 1950 characters, imposed by sys_vgui(). */ @@ -158,14 +191,16 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, { t_float dispx, dispy; char smallbuf[200], *tempbuf; - int outchars = 0, nlines = 0, ncolumns = 0, + int outchars_b = 0, nlines = 0, ncolumns = 0, pixwide, pixhigh, font, fontwidth, fontheight, findx, findy; int reportedindex = 0; t_canvas *canvas = glist_getcanvas(x->x_glist); - int widthspec = x->x_text->te_width; - int widthlimit = (widthspec ? widthspec : BOXWIDTH); - int inindex = 0; - int selstart = 0, selend = 0; + int widthspec_c = x->x_text->te_width; + int widthlimit_c = (widthspec_c ? widthspec_c : BOXWIDTH); + int inindex_b = 0; + int inindex_c = 0; + int selstart_b = 0, selend_b = 0; + int x_bufsize_c = u8_charnum(x->x_buf, x->x_bufsize); /* if we're a GOP (the new, "goprect" style) borrow the font size from the inside to preserve the spacing */ if (pd_class(&x->x_text->te_pd) == canvas_class && @@ -180,97 +215,109 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, if (x->x_bufsize >= 100) tempbuf = (char *)t_getbytes(2 * x->x_bufsize + 1); else tempbuf = smallbuf; - while (x->x_bufsize - inindex > 0) + while (x_bufsize_c - inindex_c > 0) { - int inchars = x->x_bufsize - inindex; - int maxindex = (inchars > widthlimit ? widthlimit : inchars); + int inchars_b = x->x_bufsize - inindex_b; + int inchars_c = x_bufsize_c - inindex_c; + int maxindex_c = (inchars_c > widthlimit_c ? widthlimit_c : inchars_c); + int maxindex_b = u8_offset(x->x_buf + inindex_b, maxindex_c); int eatchar = 1; - int foundit = firstone(x->x_buf + inindex, '\n', maxindex); - if (foundit < 0) + int foundit_b = firstone(x->x_buf + inindex_b, '\n', maxindex_b); + int foundit_c; + if (foundit_b < 0) { - if (inchars > widthlimit) + if (inchars_c > widthlimit_c) { - foundit = lastone(x->x_buf + inindex, ' ', maxindex); - if (foundit < 0) + foundit_b = lastone(x->x_buf + inindex_b, ' ', maxindex_b); + if (foundit_b < 0) { - foundit = maxindex; + foundit_b = maxindex_b; + foundit_c = maxindex_c; eatchar = 0; } + else + foundit_c = u8_charnum(x->x_buf + inindex_b, foundit_b); } else { - foundit = inchars; + foundit_b = inchars_b; + foundit_c = inchars_c; eatchar = 0; } } + else + foundit_c = u8_charnum(x->x_buf + inindex_b, foundit_b); + if (nlines == findy) { int actualx = (findx < 0 ? 0 : - (findx > foundit ? foundit : findx)); - *indexp = inindex + actualx; + (findx > foundit_c ? foundit_c : findx)); + *indexp = inindex_b + u8_offset(x->x_buf + inindex_b, actualx); reportedindex = 1; } - strncpy(tempbuf+outchars, x->x_buf + inindex, foundit); - if (x->x_selstart >= inindex && - x->x_selstart <= inindex + foundit + eatchar) - selstart = x->x_selstart + outchars - inindex; - if (x->x_selend >= inindex && - x->x_selend <= inindex + foundit + eatchar) - selend = x->x_selend + outchars - inindex; - outchars += foundit; - inindex += (foundit + eatchar); - if (inindex < x->x_bufsize) - tempbuf[outchars++] = '\n'; - if (foundit > ncolumns) - ncolumns = foundit; + strncpy(tempbuf+outchars_b, x->x_buf + inindex_b, foundit_b); + if (x->x_selstart >= inindex_b && + x->x_selstart <= inindex_b + foundit_b + eatchar) + selstart_b = x->x_selstart + outchars_b - inindex_b; + if (x->x_selend >= inindex_b && + x->x_selend <= inindex_b + foundit_b + eatchar) + selend_b = x->x_selend + outchars_b - inindex_b; + outchars_b += foundit_b; + inindex_b += (foundit_b + eatchar); + inindex_c += (foundit_c + eatchar); + if (inindex_b < x->x_bufsize) + tempbuf[outchars_b++] = '\n'; + if (foundit_c > ncolumns) + ncolumns = foundit_c; nlines++; } if (!reportedindex) - *indexp = outchars; + *indexp = outchars_b; dispx = text_xpix(x->x_text, x->x_glist); dispy = text_ypix(x->x_text, x->x_glist); if (nlines < 1) nlines = 1; - if (!widthspec) + if (!widthspec_c) { while (ncolumns < 3) { - tempbuf[outchars++] = ' '; + tempbuf[outchars_b++] = ' '; ncolumns++; } } - else ncolumns = widthspec; + else ncolumns = widthspec_c; pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN); pixhigh = nlines * fontheight + (TMARGIN + BMARGIN); if (action == SEND_FIRST) - sys_vgui("pdtk_text_new .x%lx.c %s %f %f {%.*s} %d %s\n", - canvas, x->x_tag, + sys_vgui("pdtk_text_new .x%lx.c {%s %s text} %f %f {%.*s} %d %s\n", + canvas, x->x_tag, rtext_gettype(x)->s_name, dispx + LMARGIN, dispy + TMARGIN, - outchars, tempbuf, sys_hostfontsize(font), + outchars_b, tempbuf, sys_hostfontsize(font), (glist_isselected(x->x_glist, &x->x_glist->gl_gobj)? "blue" : "black")); else if (action == SEND_UPDATE) { sys_vgui("pdtk_text_set .x%lx.c %s {%.*s}\n", - canvas, x->x_tag, outchars, tempbuf); + canvas, x->x_tag, outchars_b, tempbuf); if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight) text_drawborder(x->x_text, x->x_glist, x->x_tag, pixwide, pixhigh, 0); if (x->x_active) { - if (selend > selstart) + if (selend_b > selstart_b) { sys_vgui(".x%lx.c select from %s %d\n", canvas, - x->x_tag, selstart); + x->x_tag, u8_charnum(x->x_buf, selstart_b)); sys_vgui(".x%lx.c select to %s %d\n", canvas, - x->x_tag, selend + (sys_oldtclversion ? 0 : -1)); + x->x_tag, u8_charnum(x->x_buf, selend_b) + + (sys_oldtclversion ? 0 : -1)); sys_vgui(".x%lx.c focus \"\"\n", canvas); } else { sys_vgui(".x%lx.c select clear\n", canvas); sys_vgui(".x%lx.c icursor %s %d\n", canvas, x->x_tag, - selstart); + u8_charnum(x->x_buf, selstart_b)); sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag); } } @@ -398,7 +445,7 @@ void rtext_activate(t_rtext *x, int state) t_canvas *canvas = glist_getcanvas(glist); if (state) { - sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag); + sys_vgui("pdtk_text_editing .x%lx %s 1\n", canvas, x->x_tag); glist->gl_editor->e_textedfor = x; glist->gl_editor->e_textdirty = 0; x->x_dragfrom = x->x_selstart = 0; @@ -407,8 +454,7 @@ void rtext_activate(t_rtext *x, int state) } else { - sys_vgui("selection clear .x%lx.c\n", canvas); - sys_vgui(".x%lx.c focus \"\"\n", canvas); + sys_vgui("pdtk_text_editing .x%lx {} 0\n", canvas); if (glist->gl_editor->e_textedfor == x) glist->gl_editor->e_textedfor = 0; x->x_active = 0; @@ -433,12 +479,12 @@ void rtext_key(t_rtext *x, int keynum, t_symbol *keysym) .... } */ if (x->x_selstart && (x->x_selstart == x->x_selend)) - x->x_selstart--; + u8_dec(x->x_buf, &x->x_selstart); } else if (n == 127) /* delete */ { if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend)) - x->x_selend++; + u8_inc(x->x_buf, &x->x_selend); } ndel = x->x_selend - x->x_selstart; @@ -451,7 +497,13 @@ void rtext_key(t_rtext *x, int keynum, t_symbol *keysym) /* at Guenter's suggestion, use 'n>31' to test wither a character might be printable in whatever 8-bit character set we find ourselves. */ - if (n == '\n' || (n > 31 && n != 127)) +/*-- moo: + ... but test with "<" rather than "!=" in order to accomodate unicode + codepoints for n (which we get since Tk is sending the "%A" substitution + for bind <Key>), effectively reducing the coverage of this clause to 7 + bits. Case n>127 is covered by the next clause. +*/ + if (n == '\n' || (n > 31 && n < 127)) { newsize = x->x_bufsize+1; x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize); @@ -461,20 +513,39 @@ be printable in whatever 8-bit character set we find ourselves. */ x->x_bufsize = newsize; x->x_selstart = x->x_selstart + 1; } + /*--moo: check for unicode codepoints beyond 7-bit ASCII --*/ + else if (n > 127) + { + int ch_nbytes = u8_wc_nbytes(n); + newsize = x->x_bufsize + ch_nbytes; + x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize); + for (i = x->x_bufsize; i > x->x_selstart; i--) + x->x_buf[i] = x->x_buf[i-1]; + x->x_bufsize = newsize; + /*-- moo: assume canvas_key() has encoded keysym as UTF-8 */ + strncpy(x->x_buf+x->x_selstart, keysym->s_name, ch_nbytes); + x->x_selstart = x->x_selstart + ch_nbytes; + } x->x_selend = x->x_selstart; x->x_glist->gl_editor->e_textdirty = 1; } else if (!strcmp(keysym->s_name, "Right")) { if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize) - x->x_selend = x->x_selstart = x->x_selstart + 1; + { + u8_inc(x->x_buf, &x->x_selstart); + x->x_selend = x->x_selstart; + } else x->x_selstart = x->x_selend; } else if (!strcmp(keysym->s_name, "Left")) { if (x->x_selend == x->x_selstart && x->x_selstart > 0) - x->x_selend = x->x_selstart = x->x_selstart - 1; + { + u8_dec(x->x_buf, &x->x_selstart); + x->x_selend = x->x_selstart; + } else x->x_selend = x->x_selstart; } @@ -482,18 +553,18 @@ be printable in whatever 8-bit character set we find ourselves. */ else if (!strcmp(keysym->s_name, "Up")) { if (x->x_selstart) - x->x_selstart--; + u8_dec(x->x_buf, &x->x_selstart); while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n') - x->x_selstart--; + u8_dec(x->x_buf, &x->x_selstart); x->x_selend = x->x_selstart; } else if (!strcmp(keysym->s_name, "Down")) { while (x->x_selend < x->x_bufsize && x->x_buf[x->x_selend] != '\n') - x->x_selend++; + u8_inc(x->x_buf, &x->x_selend); if (x->x_selend < x->x_bufsize) - x->x_selend++; + u8_inc(x->x_buf, &x->x_selend); x->x_selstart = x->x_selend; } rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); |