CHANGELOG: Correctly handle unicode strings for edit boxes.

fixes ticket:2209
(cherry picked from commit 3012fde61ef92151e0ec5125551a7b3481f05fb8)

Conflicts:

	lib/widget/editbox.c
master
buginator 2010-11-06 15:55:13 -04:00
parent 4492a1fbff
commit 5a35eb9f89
1 changed files with 108 additions and 66 deletions

View File

@ -266,11 +266,11 @@ static void delCharLeft(utf_32_char *pBuffer, UDWORD *pPos)
/* Calculate how much of the start of a string can fit into the edit box */ /* Calculate how much of the start of a string can fit into the edit box */
static void fitStringStart(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pCount, UWORD *pCharWidth) static void fitStringStart(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pCount, UWORD *pCharWidth)
{ {
UDWORD len; UDWORD size32;
UWORD printChars = 0, pixelWidth = 0; UWORD pixelWidth = 0;
char *utf = NULL; char *utf = NULL;
char *utf2 = NULL;
size32 = utf32len(pBuffer);
utf = UTF32toUTF8(pBuffer, NULL); utf = UTF32toUTF8(pBuffer, NULL);
if (!utf) if (!utf)
{ {
@ -278,46 +278,58 @@ static void fitStringStart(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pCount,
*pCount = *pCharWidth = 0; *pCount = *pCharWidth = 0;
return; return;
} }
len = strlen(utf);
// We need to calculate the whole string's pixel size. // We need to calculate the whole string's pixel size.
// From QuesoGLC's notes: additional processing like kerning creates strings of text whose dimensions are not directly // From QuesoGLC's notes: additional processing like kerning creates strings of text whose dimensions are not directly
// related to the simple juxtaposition of individual glyph metrics. For example, the advance width of "VA" isn't the // related to the simple juxtaposition of individual glyph metrics. For example, the advance width of "VA" isn't the
// sum of the advances of "V" and "A" taken separately. // sum of the advances of "V" and "A" taken separately.
pixelWidth = iV_GetTextWidth(utf); pixelWidth = iV_GetTextWidth(utf);
free(utf); // release the utf buffer
// Find the number of characters that will fit in boxWidth // Find the number of characters that will fit in boxWidth
if (pixelWidth < boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE)) if (pixelWidth < boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE))
{ {
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string *pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
*pCount = len; // and the length of said string. *pCount = size32; // and the length of said string.
return;
} }
else else
{ {
utf2 = utf; utf_32_char *tmp;
int printChars = 0;
tmp = malloc( sizeof(utf_32_char) * size32 + sizeof(utf_32_char));
memcpy(tmp, pBuffer, sizeof(utf_32_char) * size32);
tmp[size32] = 0;
// we must do this, since it is possible to have invalid utf8 when you start removing just 1 byte at a time
do do
{ {
pixelWidth = iV_GetTextWidth(utf2); utf = UTF32toUTF8(tmp, NULL);
pixelWidth = iV_GetTextWidth(utf);
printChars++; printChars++;
utf2[(len - printChars)] = 0; // keep chopping off end until it fits free(utf);
tmp[(size32 - printChars)] = 0; // keep chopping off end until it fits
} }
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < len); while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < size32);
size32 = utf32len(tmp); // length we ended up with
free(tmp);
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string *pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
*pCount = len - printChars; // and the length of the new string. *pCount = size32; // and the length of the new string.
} }
free(utf); // release the utf buffer
} }
/* Calculate how much of the end of a string can fit into the edit box */ /* Calculate how much of the end of a string can fit into the edit box */
static void fitStringEnd(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pStart, UWORD *pCount, UWORD *pCharWidth) static void fitStringEnd(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pStart, UWORD *pCount, UWORD *pCharWidth)
{ {
UDWORD len; UDWORD olen32, nlen32;
UWORD printChars = 0, pixelWidth = 0; UWORD pixelWidth = 0;
char *utf = NULL; char *utf = NULL;
char *utf2 = NULL;
olen32 = utf32len(pBuffer); // original length
utf = UTF32toUTF8(pBuffer, NULL); utf = UTF32toUTF8(pBuffer, NULL);
if (!utf) if (!utf)
{ {
@ -325,35 +337,48 @@ static void fitStringEnd(utf_32_char *pBuffer, UDWORD boxWidth, UWORD *pStart, U
*pCount = *pStart = *pCharWidth = 0; *pCount = *pStart = *pCharWidth = 0;
return; return;
} }
len = strlen(utf);
// We need to calculate the whole string's pixel size. // We need to calculate the whole string's pixel size.
// From QuesoGLC's notes: additional processing like kerning creates strings of text whose dimensions are not directly // From QuesoGLC's notes: additional processing like kerning creates strings of text whose dimensions are not directly
// related to the simple juxtaposition of individual glyph metrics. For example, the advance width of "VA" isn't the // related to the simple juxtaposition of individual glyph metrics. For example, the advance width of "VA" isn't the
// sum of the advances of "V" and "A" taken separately. // sum of the advances of "V" and "A" taken separately.
pixelWidth = iV_GetTextWidth(utf); pixelWidth = iV_GetTextWidth(utf);
free(utf); // release the utf buffer
// Find the number of characters that will fit in boxWidth // Find the number of characters that will fit in boxWidth
if (pixelWidth < boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE)) if (pixelWidth < boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE))
{ {
*pStart = 0 ; // nothing to trim *pStart = 0 ; // nothing to trim
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string *pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
*pCount = len; // and the length of said string. *pCount = olen32; // and the length of said string.
return;
} }
else else
{ {
utf2 = utf; utf_32_char *tmp = NULL, *utf32buf = NULL;
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < len) int printChars = 0;
utf32buf = malloc( sizeof(utf_32_char) * olen32 + sizeof(utf_32_char));
memcpy(utf32buf, pBuffer, sizeof(utf_32_char) * olen32);
utf32buf[olen32] = 0;
tmp = utf32buf;
while (pixelWidth > boxWidth - (WEDB_XGAP*2 + WEDB_CURSORSIZE) && printChars < olen32)
{ {
utf2++; // new string is 1 char shorter [abc] is now [bc] tmp++; // new string is 1 char shorter [abc] is now [bc]
pixelWidth = iV_GetTextWidth(utf2); utf = UTF32toUTF8(tmp, NULL);
pixelWidth = iV_GetTextWidth(utf);
printChars++; printChars++;
free(utf);
} }
*pStart = len - (len - printChars); // the starting position of the string to display
nlen32 = utf32len(tmp); // new size of string
*pStart = printChars; // the starting position of the string to display
*pCharWidth = pixelWidth; // the actual pixelWidth we use for the string *pCharWidth = pixelWidth; // the actual pixelWidth we use for the string
*pCount = len - printChars; // and the length of the new string. *pCount = nlen32; // and the length of the new string.
free(utf32buf);
} }
free(utf); // release the utf buffer
} }
@ -497,8 +522,7 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
delCharRight(pBuffer, &pos); delCharRight(pBuffer, &pos);
/* Update the printable text */ /* Update the printable text */
fitStringStart(pBuffer + printStart, psWidget->width, fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
&printChars, &printWidth);
debug(LOG_INPUT, "EditBox cursor delete"); debug(LOG_INPUT, "EditBox cursor delete");
break; break;
case INPBUF_PGUP : case INPBUF_PGUP :
@ -523,14 +547,12 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
else else
{ {
printStart -= WEDB_CHARJUMP; printStart -= WEDB_CHARJUMP;
fitStringStart(pBuffer + printStart, psWidget->width, fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
&printChars, &printWidth);
} }
} }
else else
{ {
fitStringStart(pBuffer + printStart, psWidget->width, fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
&printChars, &printWidth);
} }
debug(LOG_INPUT, "EditBox cursor backspace"); debug(LOG_INPUT, "EditBox cursor backspace");
break; break;
@ -563,9 +585,9 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
{ {
overwriteChar(&pBuffer, &pBufferAllocated, &pos, unicode, psWidget); overwriteChar(&pBuffer, &pBufferAllocated, &pos, unicode, psWidget);
} }
len = utf32len(pBuffer);
/* Update the printable chars */ /* Update the printable chars */
if (pos == utf32len(pBuffer)) if (pos == len)
{ {
fitStringEnd(pBuffer, psWidget->width, &printStart, &printChars, &printWidth); fitStringEnd(pBuffer, psWidget->width, &printStart, &printChars, &printWidth);
} }
@ -578,8 +600,7 @@ void editBoxRun(W_EDITBOX *psWidget, W_CONTEXT *psContext)
if (printStart >= len) if (printStart >= len)
{ {
printStart = (UWORD)(len - 1); printStart = (UWORD)(len - 1);
fitStringStart(pBuffer + printStart, psWidget->width, fitStringStart(pBuffer + printStart, psWidget->width, &printChars, &printWidth);
&printChars, &printWidth);
} }
} }
} }
@ -666,8 +687,7 @@ void editBoxFocusLost(W_SCREEN* psScreen, W_EDITBOX *psWidget)
/* Stop editing the widget */ /* Stop editing the widget */
psWidget->state = WEDBS_FIXED; psWidget->state = WEDBS_FIXED;
psWidget->printStart = 0; psWidget->printStart = 0;
fitStringStart(psWidget->aText,psWidget->width, fitStringStart(psWidget->aText,psWidget->width, &psWidget->printChars, &psWidget->printWidth);
&psWidget->printChars, &psWidget->printWidth);
widgSetReturn(psScreen, (WIDGET *)psWidget); widgSetReturn(psScreen, (WIDGET *)psWidget);
@ -689,7 +709,8 @@ void editBoxHiLite(W_EDITBOX *psWidget)
return; return;
} }
if(psWidget->AudioCallback) { if(psWidget->AudioCallback)
{
psWidget->AudioCallback(psWidget->HilightAudioID); psWidget->AudioCallback(psWidget->HilightAudioID);
} }
@ -715,11 +736,13 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
W_EDITBOX *psEdBox; W_EDITBOX *psEdBox;
SDWORD x0,y0,x1,y1, fx,fy, cx,cy; SDWORD x0,y0,x1,y1, fx,fy, cx,cy;
enum iV_fonts CurrFontID; enum iV_fonts CurrFontID;
utf_32_char ch, *pInsPoint, *pPrint;
#if CURSOR_BLINK #if CURSOR_BLINK
BOOL blink; BOOL blink;
#endif #endif
char *utf; char *utf;
utf_32_char *pInsPoint, *UTF32string;
int size=0;
psEdBox = (W_EDITBOX *)psWidget; psEdBox = (W_EDITBOX *)psWidget;
CurrFontID = psEdBox->FontID; CurrFontID = psEdBox->FontID;
@ -729,9 +752,12 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
x1=x0 + psEdBox->width; x1=x0 + psEdBox->width;
y1=y0 + psEdBox->height; y1=y0 + psEdBox->height;
if(psEdBox->pBoxDisplay) { if(psEdBox->pBoxDisplay)
{
psEdBox->pBoxDisplay((WIDGET *)psEdBox, xOffset, yOffset, pColours); psEdBox->pBoxDisplay((WIDGET *)psEdBox, xOffset, yOffset, pColours);
} else { }
else
{
pie_BoxFill(x0, y0, x1, y1, pColours[WCOL_BKGRND]); pie_BoxFill(x0, y0, x1, y1, pColours[WCOL_BKGRND]);
iV_Line(x0,y0, x1,y0, pColours[WCOL_DARK]); iV_Line(x0,y0, x1,y0, pColours[WCOL_DARK]);
@ -745,26 +771,27 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
iV_SetFont(CurrFontID); iV_SetFont(CurrFontID);
iV_SetTextColour(pColours[WCOL_TEXT]); iV_SetTextColour(pColours[WCOL_TEXT]);
fy = y0 + (psEdBox->height - iV_GetTextLineSize())/2 - iV_GetTextAboveBase(); fy = y0 + (psEdBox->height - iV_GetTextLineSize())/2 - iV_GetTextAboveBase();
/* If there is more text than will fit into the box, display the bit with the cursor in it */
size = utf32len(psEdBox->aText);
UTF32string = malloc( sizeof(utf_32_char) * size + sizeof(utf_32_char));
memcpy(UTF32string, psEdBox->aText, sizeof(utf_32_char) * size);
/* If there is more text than will fit into the box, pInsPoint = UTF32string + psEdBox->printStart; // deal with position
display the bit with the cursor in it */ pInsPoint[psEdBox->printChars] = 0;
pPrint = psEdBox->aText + psEdBox->printStart;
pInsPoint = pPrint + psEdBox->printChars; utf = UTF32toUTF8(pInsPoint, NULL);
ch = *pInsPoint;
*pInsPoint = '\0';
utf = UTF32toUTF8(pPrint, NULL);
// if(psEdBox->pFontDisplay) { // if(psEdBox->pFontDisplay) {
// psEdBox->pFontDisplay(fx,fy, pPrint); // psEdBox->pFontDisplay(fx,fy, pPrint);
// } else { // } else {
iV_DrawText(utf, fx, fy); iV_DrawText(utf, fx, fy);
// } // }
free(utf); free(utf);
*pInsPoint = ch; free(UTF32string);
/* Display the cursor if editing */ // Display the cursor if editing
#if CURSOR_BLINK #if CURSOR_BLINK
blink = !(((SDL_GetTicks() - psEdBox->blinkOffset)/WEDB_BLINKRATE) % 2); blink = !(((SDL_GetTicks() - psEdBox->blinkOffset)/WEDB_BLINKRATE) % 2);
if ((psEdBox->state & WEDBS_MASK) == WEDBS_INSERT && blink) if ((psEdBox->state & WEDBS_MASK) == WEDBS_INSERT && blink)
@ -772,14 +799,22 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
if ((psEdBox->state & WEDBS_MASK) == WEDBS_INSERT) if ((psEdBox->state & WEDBS_MASK) == WEDBS_INSERT)
#endif #endif
{ {
pInsPoint = psEdBox->aText + psEdBox->insPos; // insert mode
ch = *pInsPoint;
*pInsPoint = '\0'; utf_32_char *pInsPoint, *UTF32string;
utf = UTF32toUTF8(psEdBox->aText + psEdBox->printStart, NULL); int size=0;
size = utf32len(psEdBox->aText);
UTF32string = malloc( sizeof(utf_32_char) * size + sizeof(utf_32_char));
memcpy(UTF32string, psEdBox->aText, sizeof(utf_32_char) * size);
pInsPoint = UTF32string + psEdBox->insPos; // deal with position
*pInsPoint = 0;
utf = UTF32toUTF8(UTF32string + psEdBox->printStart, NULL);
cx = x0 + WEDB_XGAP + iV_GetTextWidth(utf); cx = x0 + WEDB_XGAP + iV_GetTextWidth(utf);
cx += iV_GetTextWidth("-"); cx += iV_GetTextWidth("-");
free(utf); free(utf);
*pInsPoint = ch; free(UTF32string);
cy = fy; cy = fy;
iV_Line(cx, cy + iV_GetTextAboveBase(), cx, cy - iV_GetTextBelowBase(), pColours[WCOL_CURSOR]); iV_Line(cx, cy + iV_GetTextAboveBase(), cx, cy - iV_GetTextBelowBase(), pColours[WCOL_CURSOR]);
} }
@ -789,19 +824,26 @@ void editBoxDisplay(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *
else if ((psEdBox->state & WEDBS_MASK) == WEDBS_OVER) else if ((psEdBox->state & WEDBS_MASK) == WEDBS_OVER)
#endif #endif
{ {
pInsPoint = psEdBox->aText + psEdBox->insPos; // overwrite mode
ch = *pInsPoint; utf_32_char *pInsPoint, *UTF32string;
*pInsPoint = '\0'; int size=0;
utf = UTF32toUTF8(psEdBox->aText + psEdBox->printStart, NULL);
size = utf32len(psEdBox->aText);
UTF32string = malloc( sizeof(utf_32_char) * size + sizeof(utf_32_char));
memcpy(UTF32string, psEdBox->aText, sizeof(utf_32_char) * size);
pInsPoint = UTF32string + psEdBox->insPos; // deal with position
*pInsPoint = 0;
utf = UTF32toUTF8(UTF32string + psEdBox->printStart, NULL);
cx = x0 + WEDB_XGAP + iV_GetTextWidth(utf); cx = x0 + WEDB_XGAP + iV_GetTextWidth(utf);
free(utf); free(utf);
*pInsPoint = ch; free(UTF32string);
cy = fy; cy = fy;
iV_Line(cx, cy, cx + WEDB_CURSORSIZE, cy, pColours[WCOL_CURSOR]); iV_Line(cx, cy, cx + WEDB_CURSORSIZE, cy, pColours[WCOL_CURSOR]);
} }
if(psEdBox->pBoxDisplay == NULL)
if(psEdBox->pBoxDisplay == NULL) { {
if (psEdBox->state & WEDBS_HILITE) if (psEdBox->state & WEDBS_HILITE)
{ {
/* Display the button hilite */ /* Display the button hilite */