Bill Medland (medbi01@accpac.com) 1. Introduce a significant design decision. 2. Recalculate the prefix location if ellipsification alters it. This carefully does NOT emulate a Microsoft bug in which reprefixing is wrong when the first character removed by ellipsification is the one that would have been underlined (under Win98 at least). Index: wine/dlls/user/text.c =================================================================== RCS file: /home/wine/wine/dlls/user/text.c,v retrieving revision 1.20 diff -u -r1.20 text.c --- wine/dlls/user/text.c 2002/01/29 02:46:09 1.20 +++ wine/dlls/user/text.c 2002/01/31 14:43:36 @@ -28,6 +28,40 @@ /********************************************************************* * * DrawText functions + * + * Design issues + * How many buffers to use + * While processing in DrawText there are potentially three different forms + * of the text that need to be held. How are they best held? + * 1. The original text is needed, of course, to see what to display. + * 2. The text that will be returned to the user if the DT_MODIFYSTRING is + * in effect. + * 3. The buffered text that is about to be displayed e.g. the current line. + * Typically this will exclude the ampersands used for prefixing etc. + * + * Complications. + * a. If the buffered text to be displayed includes the ampersands then + * we will need special measurement and draw functions that will ignore + * the ampersands (e.g. by copying to a buffer without the prefix and + * then using the normal forms). This may involve less space but may + * require more processing. e.g. since a line containing tabs may + * contain several underlined characters either we need to carry around + * a list of prefix locations or we may need to locate them several + * times. + * b. If we actually directly modify the "original text" as we go then we + * will need some special "caching" to handle the fact that when we + * ellipsify the text the ellipsis may modify the next line of text, + * which we have not yet processed. (e.g. ellipsification of a W at the + * end of a line will overwrite the W, the \n and the first character of + * the next line, and a \0 will overwrite the second. Try it!!) + * + * Option 1. Three separate storages. (To be implemented) + * If DT_MODIFYSTRING is in effect then allocate an extra buffer to hold + * the edited string in some form, either as the string itself or as some + * sort of "edit list" to be applied just before returning. + * Use a buffer that holds the ellipsified current line sans ampersands + * and accept the need occasionally to recalculate the prefixes (if + * DT_EXPANDTABS and not DT_NOPREFIX and not DT_HIDEPREFIX) */ #define TAB 9 @@ -51,6 +85,56 @@ static int spacewidth; static int prefix_offset; +/********************************************************************* + * TEXT_Reprefix + * + * Reanalyse the text to find the prefixed character. This is called when + * wordbreaking or ellipsification has shortened the string such that the + * previously noted prefixed character is no longer visible. + * + * Parameters + * str [in] The original string segment (including all characters) + * n1 [in] The number of characters visible before the path ellipsis + * n2 [in] The number of characters replaced by the path ellipsis + * ne [in] The number of characters in the path ellipsis, ignored if + * n2 is zero + * n3 [in] The number of characters visible after the path ellipsis + * + * Return Values + * The prefix offset within the new string segment (the one that contains the + * ellipses and does not contain the prefix characters) (-1 if none) + * + * Remarks + * We know that n1+n2+n3 must be strictly less than the length of the segment + * (because otherwise there would be no need to call this function) + */ + +static int TEXT_Reprefix (const WCHAR *str, unsigned int n1, unsigned int n2, + unsigned int ne, unsigned int n3) +{ + int result = -1; + unsigned int i = 0; + unsigned int n = n1 + n2 + n3; + if (!n2) ne = 0; + while (i < n) + { + if (i == n1) + { + /* Reached the path ellipsis; jump over it */ + str += n2; + i += n2; + if (!n3) break; /* Nothing after the path ellipsis */ + } + if (*str++ == PREFIX) + { + result = (i < n1) ? i : i - n2 + ne; + str++; + } + else; + i++; + } + return result; +} /********************************************************************* * Return next line of text from a string. @@ -329,6 +413,8 @@ int totalLen = i_count >= 0 ? i_count : strlenW(str); int fnameLen = totalLen; int old_prefix_offset = prefix_offset; + int len_before_ellipsis; + int len_after_ellipsis; /* allow room for '...' */ count = min(totalLen+3, countof(line)-3); @@ -386,17 +472,21 @@ if (fnameLen < len-3) /* some of the path will fit */ { + len_before_ellipsis = len-3-fnameLen; + len_after_ellipsis = fnameLen; /* put the ELLIPSIS between the path and filename */ - strncpyW(swapStr, &line[fnameLen+3], len-3-fnameLen); - swapStr[len-3-fnameLen] = '\0'; + strncpyW(swapStr, &line[fnameLen+3], len_before_ellipsis); + swapStr[len_before_ellipsis] = '\0'; strcatW(swapStr, ELLIPSISW); strncpyW(swapStr+strlenW(swapStr), &line[3], fnameLen); } else { /* move the ELLIPSIS to the end */ - strncpyW(swapStr, &line[3], len-3); - swapStr[len-3] = '\0'; + len_before_ellipsis = len-3; + len_after_ellipsis = 0; + strncpyW(swapStr, &line[3], len_before_ellipsis); + swapStr[len_before_ellipsis] = '\0'; strcpyW(swapStr+strlenW(swapStr), ELLIPSISW); } @@ -404,12 +494,9 @@ line[len] = '\0'; strPtr = NULL; - /* Note that really we ought to refigure the location of - * the underline for the prefix; it might be currently set for - * something we have just ellipsified out. - * NB We had better do it before modifying the string and - * loosing the ampersands - */ + if (prefix_offset >= 0 && + prefix_offset >= len_before_ellipsis) + prefix_offset = TEXT_Reprefix (str, len_before_ellipsis, strlenW(str)-3-len_before_ellipsis-len_after_ellipsis, 3, len_after_ellipsis); if (flags & DT_MODIFYSTRING) strcpyW(str, swapStr);