--- trunk/reactos/lib/user32/controls/edit.c 2005-12-10 19:22:43 UTC (rev 20041)
+++ trunk/reactos/lib/user32/controls/edit.c 2005-12-10 20:44:57 UTC (rev 20042)
@@ -20,20 +20,26 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
+ * NOTES
+ *
+ * This code was audited for completeness against the documented features
+ * of Comctl32.dll version 6.0 on Oct. 8, 2004, by Dimitrie O. Paun.
+ *
+ * Unless otherwise noted, we believe this code to be complete, as per
+ * the specification mentioned above.
+ * If you discover missing features, or bugs, please note them below.
+ *
* TODO:
- * - ES_CENTER
- * - ES_RIGHT
+ * - EDITBALLOONTIP structure
+ * - EM_GETCUEBANNER/Edit_GetCueBannerText
+ * - EM_HIDEBALLOONTIP/Edit_HideBalloonTip
+ * - EM_SETCUEBANNER/Edit_SetCueBannerText
+ * - EM_SHOWBALLOONTIP/Edit_ShowBalloonTip
+ * - EM_GETIMESTATUS, EM_SETIMESTATUS
+ * - EN_ALIGN_LTR_EC
+ * - EN_ALIGN_RTL_EC
* - ES_OEMCONVERT
- * -!ES_AUTOVSCROLL (every multi line control *is* auto vscroll)
- * -!ES_AUTOHSCROLL (every single line control *is* auto hscroll)
*
- * When there is no autoscrolling, the control should first check whether
- * the new text would fit. If not, an EN_MAXTEXT should be sent.
- * However, currently this would require the actual change to be made,
- * then call EDIT_BuildLineDefs() and then find out that the new text doesn't
- * fit. After all this, things should be put back in the state before the
- * changes. Note that for multi line controls !ES_AUTOHSCROLL works : wordwrap.
- *
*/
#include <user32.h>
@@ -142,12 +148,12 @@
#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
/* used for disabled or read-only edit control */
-#define EDIT_NOTIFY_PARENT(es, wNotifyCode, str) \
+#define EDIT_NOTIFY_PARENT(es, wNotifyCode) \
do \
{ /* Notify parent which has created this edit control */ \
- TRACE("notification " str " sent to hwnd=%p\n", es->hwndParent); \
+ TRACE("notification " #wNotifyCode " sent to hwnd=%p\n", es->hwndParent); \
SendMessageW(es->hwndParent, WM_COMMAND, \
- MAKEWPARAM(GetWindowLongW((es->hwndSelf),GWL_ID), wNotifyCode), \
+ MAKEWPARAM(GetWindowLongPtrW((es->hwndSelf),GWLP_ID), wNotifyCode), \
(LPARAM)(es->hwndSelf)); \
} while(0)
@@ -210,7 +216,7 @@
#ifndef __REACTOS__
static HLOCAL16 EDIT_EM_GetHandle16(EDITSTATE *es);
#endif
-static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode);
+static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode);
static LRESULT EDIT_EM_GetSel(EDITSTATE *es, PUINT start, PUINT end);
static LRESULT EDIT_EM_GetThumb(EDITSTATE *es);
static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index);
@@ -227,14 +233,14 @@
static void EDIT_EM_SetHandle16(EDITSTATE *es, HLOCAL16 hloc);
#endif
static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
-static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right);
+static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right, BOOL repaint);
static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c);
static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
#ifndef __REACTOS__
static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs);
#endif
-static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, LPARAM lParam);
+static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp);
#ifndef __REACTOS__
static void EDIT_EM_SetWordBreakProc16(EDITSTATE *es, EDITWORDBREAKPROC16 wbp);
#endif
@@ -249,7 +255,7 @@
static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name);
static LRESULT EDIT_WM_Destroy(EDITSTATE *es);
static LRESULT EDIT_WM_EraseBkGnd(EDITSTATE *es, HDC dc);
-static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode);
+static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode);
static LRESULT EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos);
static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key);
static LRESULT EDIT_WM_KillFocus(EDITSTATE *es);
@@ -259,11 +265,11 @@
static LRESULT EDIT_WM_MButtonDown(EDITSTATE *es);
static LRESULT EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y);
static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode);
-static void EDIT_WM_Paint(EDITSTATE *es, WPARAM wParam);
+static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc);
static void EDIT_WM_Paste(EDITSTATE *es);
static void EDIT_WM_SetFocus(EDITSTATE *es);
static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw);
-static void EDIT_WM_SetText(EDITSTATE *es, LPARAM lParam, BOOL unicode);
+static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode);
static void EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height);
static LRESULT EDIT_WM_StyleChanged(EDITSTATE *es, WPARAM which, const STYLESTRUCT *style);
static LRESULT EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data);
@@ -390,6 +396,7 @@
static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
{
+ HBRUSH hbrush;
UINT msg;
if ( get_app_version() >= 0x40000 && (!es->bEnableState || (es->style & ES_READONLY)))
@@ -398,7 +405,10 @@
msg = WM_CTLCOLOREDIT;
/* why do we notify to es->hwndParent, and we send this one to GetParent()? */
- return (HBRUSH)SendMessageW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
+ hbrush = (HBRUSH)SendMessageW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
+ if (!hbrush)
+ hbrush = (HBRUSH)DefWindowProcW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
+ return hbrush;
}
static __inline LRESULT DefWindowProcT(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode)
@@ -425,21 +435,16 @@
static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam, BOOL unicode )
{
- EDITSTATE *es = (EDITSTATE *)GetWindowLongW( hwnd, 0 );
+ EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );
LRESULT result = 0;
//TRACE("hwnd=%p msg=%x (%s) wparam=%x lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam);
if (!es && msg != WM_NCCREATE)
return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
- else if (msg == WM_NCCREATE)
- return EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
- else if (msg == WM_DESTROY)
- return EDIT_WM_Destroy(es);
+ if (es && (msg != WM_DESTROY)) EDIT_LockBuffer(es);
- if (es) EDIT_LockBuffer(es);
-
switch (msg) {
#ifndef __REACTOS__
case EM_GETSEL16:
@@ -649,7 +654,7 @@
/* fall through */
#endif
case EM_GETLINE:
- result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, lParam, unicode);
+ result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
break;
#ifndef __REACTOS__
@@ -756,7 +761,7 @@
break;
#endif
case EM_SETWORDBREAKPROC:
- EDIT_EM_SetWordBreakProc(es, lParam);
+ EDIT_EM_SetWordBreakProc(es, (void *)lParam);
break;
#ifndef __REACTOS__
@@ -790,7 +795,7 @@
/* The following EM_xxx are new to win95 and don't exist for 16 bit */
case EM_SETMARGINS:
- EDIT_EM_SetMargins(es, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
+ EDIT_EM_SetMargins(es, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam), TRUE);
break;
case EM_GETMARGINS:
@@ -802,7 +807,9 @@
break;
case EM_POSFROMCHAR:
- result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
+ result = strlenW(es->text);
+ if ((INT)wParam >= result) result = -1;
+ else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
break;
case EM_CHARFROMPOS:
@@ -813,6 +820,15 @@
* are these in? vaguely alphabetical?
*/
+ case WM_NCCREATE:
+ result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
+ break;
+
+ case WM_DESTROY:
+ result = EDIT_WM_Destroy(es);
+ es = NULL;
+ break;
+
case WM_GETDLGCODE:
result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
@@ -900,8 +916,7 @@
MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
}
result = EDIT_WM_Create(es, nameW);
- if(nameW)
- HeapFree(GetProcessHeap(), 0, nameW);
+ HeapFree(GetProcessHeap(), 0, nameW);
}
break;
@@ -923,7 +938,7 @@
break;
case WM_GETTEXT:
- result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, lParam, unicode);
+ result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
break;
case WM_GETTEXTLENGTH:
@@ -960,16 +975,13 @@
result = EDIT_WM_MButtonDown(es);
break;
- case WM_MOUSEACTIVATE:
- result = MA_ACTIVATE;
- break;
-
case WM_MOUSEMOVE:
result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
break;
+ case WM_PRINTCLIENT:
case WM_PAINT:
- EDIT_WM_Paint(es, wParam);
+ EDIT_WM_Paint(es, (HDC)wParam);
break;
case WM_PASTE:
@@ -989,7 +1001,7 @@
break;
case WM_SETTEXT:
- EDIT_WM_SetText(es, lParam, unicode);
+ EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
result = TRUE;
break;
@@ -1309,7 +1321,10 @@
rc.top = es->format_rect.top + nstart_line * es->line_height -
(es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
rc.bottom = rc.top + es->line_height;
- rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
+ if ((es->style & ES_CENTER) || (es->style & ES_RIGHT))
+ rc.left = es->format_rect.left;
+ else
+ rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
es->text + nstart_index, istart - nstart_index,
es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
rc.right = es->format_rect.right;
@@ -1328,6 +1343,7 @@
rc.bottom = line_count * es->line_height;
else
rc.bottom = line_index * es->line_height;
+ rc.bottom += es->format_rect.top;
rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
@@ -1347,7 +1363,27 @@
*/
static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
{
- es->text_width = (short)LOWORD(EDIT_EM_PosFromChar(es, strlenW(es->text), FALSE));
+ SIZE size;
+ LPWSTR text;
+ HDC dc;
+ HFONT old_font = 0;
+
+ text = EDIT_GetPasswordPointer_SL(es);
+
+ dc = GetDC(es->hwndSelf);
+ if (es->font)
+ old_font = SelectObject(dc, es->font);
+
+ GetTextExtentPoint32W(dc, text, strlenW(text), &size);
+
+ if (es->font)
+ SelectObject(dc, old_font);
+ ReleaseDC(es->hwndSelf, dc);
+
+ if (es->style & ES_PASSWORD)
+ HeapFree(GetProcessHeap(), 0, text);
+
+ es->text_width = size.cx;
}
/*********************************************************************
@@ -1450,6 +1486,7 @@
INT index;
HDC dc;
HFONT old_font = 0;
+ INT x_high = 0, x_low = 0;
if (es->style & ES_MULTILINE) {
INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
@@ -1462,6 +1499,10 @@
line--;
}
x += es->x_offset - es->format_rect.left;
+ if (es->style & ES_RIGHT)
+ x -= (es->format_rect.right - es->format_rect.left) - line_def->width;
+ else if (es->style & ES_CENTER)
+ x -= ((es->format_rect.right - es->format_rect.left) - line_def->width) / 2;
if (x >= line_def->width) {
if (after_wrap)
*after_wrap = (line_def->ending == END_WRAP);
@@ -1475,15 +1516,24 @@
dc = GetDC(es->hwndSelf);
if (es->font)
old_font = SelectObject(dc, es->font);
- low = line_index + 1;
+ low = line_index;
high = line_index + line_def->net_length + 1;
while (low < high - 1)
{
INT mid = (low + high) / 2;
- if (LOWORD(GetTabbedTextExtentW(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid;
- else low = mid;
+ INT x_now = LOWORD(GetTabbedTextExtentW(dc, es->text + line_index, mid - line_index, es->tabs_count, es->tabs));
+ if (x_now > x) {
+ high = mid;
+ x_high = x_now;
+ } else {
+ low = mid;
+ x_low = x_now;
+ }
}
- index = low;
+ if (abs(x_high - x) + 1 <= abs(x_low - x))
+ index = high;
+ else
+ index = low;
if (after_wrap)
*after_wrap = ((index == line_index + line_def->net_length) &&
@@ -1496,6 +1546,16 @@
x -= es->format_rect.left;
if (!x)
return es->x_offset;
+
+ if (!es->x_offset)
+ {
+ INT indent = (es->format_rect.right - es->format_rect.left) - es->text_width;
+ if (es->style & ES_RIGHT)
+ x -= indent;
+ else if (es->style & ES_CENTER)
+ x -= indent / 2;
+ }
+
text = EDIT_GetPasswordPointer_SL(es);
dc = GetDC(es->hwndSelf);
if (es->font)
@@ -1509,10 +1569,18 @@
INT mid = (low + high) / 2;
GetTextExtentPoint32W( dc, text + mid,
es->x_offset - mid, &size );
- if (size.cx > -x) low = mid;
- else high = mid;
+ if (size.cx > -x) {
+ low = mid;
+ x_low = size.cx;
+ } else {
+ high = mid;
+ x_high = size.cx;
+ }
}
- index = low;
+ if (abs(x_high + x) <= abs(x_low + x) + 1)
+ index = high;
+ else
+ index = low;
}
else
{
@@ -1523,10 +1591,18 @@
INT mid = (low + high) / 2;
GetTextExtentPoint32W( dc, text + es->x_offset,
mid - es->x_offset, &size );
- if (size.cx > x) high = mid;
- else low = mid;
+ if (size.cx > x) {
+ high = mid;
+ x_high = size.cx;
+ } else {
+ low = mid;
+ x_low = size.cx;
+ }
}
- index = low;
+ if (abs(x_high - x) <= abs(x_low - x) + 1)
+ index = high;
+ else
+ index = low;
}
if (es->style & ES_PASSWORD)
HeapFree(GetProcessHeap(), 0, text);
@@ -1829,7 +1905,7 @@
if (es->buffer_size < size) {
WARN("FAILED ! We now have %d+1\n", es->buffer_size);
- EDIT_NOTIFY_PARENT(es, EN_ERRSPACE, "EN_ERRSPACE");
+ EDIT_NOTIFY_PARENT(es, EN_ERRSPACE);
return FALSE;
} else {
TRACE("We now have %d+1\n", es->buffer_size);
@@ -2230,50 +2306,16 @@
/*********************************************************************
*
- * EDIT_SetRectNP
+ * EDIT_AdjustFormatRect
*
- * note: this is not (exactly) the handler called on EM_SETRECTNP
- * it is also used to set the rect of a single line control
+ * Adjusts the format rectangle for the current font and the
+ * current client rectangle.
*
*/
-static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
+static void EDIT_AdjustFormatRect(EDITSTATE *es)
{
RECT ClientRect;
- LONG_PTR ExStyle;
-
- CopyRect(&es->format_rect, rc);
- if (es->style & ES_MULTILINE)
- {
- if (es->style & WS_BORDER) {
- INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
- es->format_rect.left += bw;
- es->format_rect.right -= bw;
- es->format_rect.top += bw;
- es->format_rect.bottom -= bw;
- }
- }
- else
- {
- ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
- if (ExStyle & WS_EX_CLIENTEDGE) {
- if (es->line_height + 2 <=
- es->format_rect.bottom - es->format_rect.top) {
- es->format_rect.top++;
- es->format_rect.bottom--;
- }
- } else if (es->style & WS_BORDER) {
- INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
- es->format_rect.left += bw;
- es->format_rect.right -= bw;
- if (es->line_height + 2 * bw <=
- es->format_rect.bottom - es->format_rect.top) {
- es->format_rect.top += bw;
- es->format_rect.bottom -= bw;
- }
- }
- }
- es->format_rect.left += es->left_margin;
- es->format_rect.right -= es->right_margin;
+
es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
if (es->style & ES_MULTILINE)
{
@@ -2308,11 +2350,59 @@
if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
+
+ EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
}
/*********************************************************************
*
+ * EDIT_SetRectNP
+ *
+ * note: this is not (exactly) the handler called on EM_SETRECTNP
+ * it is also used to set the rect of a single line control
+ *
+ */
+static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
+{
+ LONG_PTR ExStyle;
+ INT bw, bh;
+ ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
+
+ CopyRect(&es->format_rect, rc);
+
+ if (ExStyle & WS_EX_CLIENTEDGE) {
+ es->format_rect.left++;
+ es->format_rect.right--;
+
+ if (es->format_rect.bottom - es->format_rect.top
+ >= es->line_height + 2)
+ {
+ es->format_rect.top++;
+ es->format_rect.bottom--;
+ }
+ }
+ else if (es->style & WS_BORDER) {
+ bw = GetSystemMetrics(SM_CXBORDER) + 1;
+ bh = GetSystemMetrics(SM_CYBORDER) + 1;
+ es->format_rect.left += bw;
+ es->format_rect.right -= bw;
+ if (es->format_rect.bottom - es->format_rect.top
+ >= es->line_height + 2 * bh)
+ {
+ es->format_rect.top += bh;
+ es->format_rect.bottom -= bh;
+ }
+ }
+
+ es->format_rect.left += es->left_margin;
+ es->format_rect.right -= es->right_margin;
+ EDIT_AdjustFormatRect(es);
+}
+
+
+/*********************************************************************
+ *
* EDIT_UnlockBuffer
*
*/
@@ -2686,7 +2776,7 @@
* EM_GETLINE
*
*/
-static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode)
+static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode)
{
LPWSTR src;
INT line_len, dst_len;
@@ -2700,10 +2790,9 @@
i = EDIT_EM_LineIndex(es, line);
src = es->text + i;
line_len = EDIT_EM_LineLength(es, i);
- dst_len = *(WORD *)lParam;
+ dst_len = *(WORD *)dst;
if(unicode)
{
- LPWSTR dst = (LPWSTR)lParam;
if(dst_len <= line_len)
{
memcpy(dst, src, dst_len * sizeof(WCHAR));
@@ -2718,13 +2807,11 @@
}
else
{
- LPSTR dst = (LPSTR)lParam;
- INT ret;
- ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, dst, dst_len, NULL, NULL);
- if(!ret) /* Insufficient buffer size */
+ INT ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, (LPSTR)dst, dst_len, NULL, NULL);
+ if(!ret && line_len) /* Insufficient buffer size */
return dst_len;
if(ret < dst_len) /* Append 0 if enough space */
- dst[ret] = 0;
+ ((LPSTR)dst)[ret] = 0;
return ret;
}
}
@@ -2939,9 +3026,9 @@
EDIT_UpdateScrollInfo(es);
}
if (dx && !(es->flags & EF_HSCROLL_TRACK))
- EDIT_NOTIFY_PARENT(es, EN_HSCROLL, "EN_HSCROLL");
+ EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
if (dy && !(es->flags & EF_VSCROLL_TRACK))
- EDIT_NOTIFY_PARENT(es, EN_VSCROLL, "EN_VSCROLL");
+ EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
return TRUE;
}
@@ -2958,9 +3045,13 @@
INT li;
INT x;
INT y = 0;
+ INT w;
+ INT lw = 0;
+ INT ll = 0;
HDC dc;
HFONT old_font = 0;
SIZE size;
+ LINEDEF *line_def;
index = min(index, len);
dc = GetDC(es->hwndSelf);
@@ -2972,7 +3063,7 @@
li = EDIT_EM_LineIndex(es, l);
if (after_wrap && (li == index) && l) {
INT l2 = l - 1;
- LINEDEF *line_def = es->first_line_def;
+ line_def = es->first_line_def;
while (l2) {
line_def = line_def->next;
l2--;
@@ -2983,8 +3074,32 @@
li = EDIT_EM_LineIndex(es, l);
}
}
- x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+
+ line_def = es->first_line_def;
+ while (line_def->index != li)
+ line_def = line_def->next;
+
+ ll = line_def->net_length;
+ lw = line_def->width;
+
+ w = es->format_rect.right - es->format_rect.left;
+ if (es->style & ES_RIGHT)
+ {
+ x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li),
es->tabs_count, es->tabs)) - es->x_offset;
+ x = w - x;
+ }
+ else if (es->style & ES_CENTER)
+ {
+ x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+ es->tabs_count, es->tabs)) - es->x_offset;
+ x += (w - lw) / 2;
+ }
+ else /* ES_LEFT */
+ {
+ x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
+ es->tabs_count, es->tabs)) - es->x_offset;
+ }
} else {
LPWSTR text = EDIT_GetPasswordPointer_SL(es);
if (index < es->x_offset) {
@@ -2995,6 +3110,18 @@
GetTextExtentPoint32W(dc, text + es->x_offset,
index - es->x_offset, &size);
x = size.cx;
+
+ if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
+ {
+ w = es->format_rect.right - es->format_rect.left;
+ if (w > es->text_width)
+ {
+ if (es->style & ES_RIGHT)
+ x += w - es->text_width;
+ else if (es->style & ES_CENTER)
+ x += (w - es->text_width) / 2;
+ }
+ }
}
y = 0;
if (es->style & ES_PASSWORD)
@@ -3027,6 +3154,8 @@
UINT size;
LPWSTR p;
HRGN hrgn = 0;
+ LPWSTR buf = NULL;
+ UINT bufl = 0;
TRACE("%s, can_undo %d, send_update %d\n",
debugstr_w(lpsz_replace), can_undo, send_update);
@@ -3039,11 +3168,14 @@
ORDER_UINT(s, e);
+ size = tl - (e - s) + strl;
+ if (!size)
+ es->text_width = 0;
+
/* Issue the EN_MAXTEXT notification and continue with replacing text
* such that buffer limit is honored. */
- size = tl - (e - s) + strl;
if ((honor_limit) && (es->buffer_limit > 0) && (size > es->buffer_limit)) {
- EDIT_NOTIFY_PARENT(es, EN_MAXTEXT, "EN_MAXTEXT");
+ EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
strl = es->buffer_limit - (tl - (e-s));
}
@@ -3053,12 +3185,71 @@
if (e != s) {
/* there is something to be deleted */
TRACE("deleting stuff.\n");
+ bufl = e - s;
+ buf = HeapAlloc(GetProcessHeap(), 0, (bufl + 1) * sizeof(WCHAR));
+ if (!buf) return;
+ memcpy(buf, es->text + s, bufl * sizeof(WCHAR));
+ buf[bufl] = 0; /* ensure 0 termination */
+ /* now delete */
+ strcpyW(es->text + s, es->text + e);
+ }
+ if (strl) {
+ /* there is an insertion */
+ tl = strlenW(es->text);
+ TRACE("inserting stuff (tl %d, strl %d, selstart %d ('%s'), text '%s')\n", tl, strl, s, debugstr_w(es->text + s), debugstr_w(es->text));
+ for (p = es->text + tl ; p >= es->text + s ; p--)
+ p[strl] = p[0];
+ for (i = 0 , p = es->text + s ; i < strl ; i++)
+ p[i] = lpsz_replace[i];
+ if(es->style & ES_UPPERCASE)
+ CharUpperBuffW(p, strl);
+ else if(es->style & ES_LOWERCASE)
+ CharLowerBuffW(p, strl);
+ }
+ if (es->style & ES_MULTILINE)
+ {
+ INT st = min(es->selection_start, es->selection_end);
+ INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ EDIT_BuildLineDefs_ML(es, st, st + strl,
+ strl - abs(es->selection_end - es->selection_start), hrgn);
+ /* if text is too long undo all changes */
+ if (honor_limit && !(es->style & ES_AUTOVSCROLL) && (es->line_count > vlc)) {
+ if (strl)
+ strcpyW(es->text + e, es->text + e + strl);
+ if (e != s)
+ for (i = 0 , p = es->text ; i < e - s ; i++)
+ p[i + s] = buf[i];
+ EDIT_BuildLineDefs_ML(es, s, e,
+ abs(es->selection_end - es->selection_start) - strl, hrgn);
+ strl = 0;
+ e = s;
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
+ }
+ }
+ else {
+ INT fw = es->format_rect.right - es->format_rect.left;
+ EDIT_CalcLineWidth_SL(es);
+ /* remove chars that don't fit */
+ if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) {
+ while ((es->text_width > fw) && s + strl >= s) {
+ strcpyW(es->text + s + strl - 1, es->text + s + strl);
+ strl--;
+ EDIT_CalcLineWidth_SL(es);
+ }
+ EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
+ }
+ }
+
+ if (e != s) {
if (can_undo) {
utl = strlenW(es->undo_text);
if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
/* undo-buffer is extended to the right */
EDIT_MakeUndoFit(es, utl + e - s);
- strncpyW(es->undo_text + utl, es->text + s, e - s + 1);
+ memcpy(es->undo_text + utl, buf, (e - s)*sizeof(WCHAR));
(es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */
} else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
/* undo-buffer is extended to the left */
@@ -3066,12 +3257,12 @@
for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
p[e - s] = p[0];
for (i = 0 , p = es->undo_text ; i < e - s ; i++)
- p[i] = (es->text + s)[i];
+ p[i] = buf[i];
es->undo_position = s;
} else {
/* new undo-buffer */
EDIT_MakeUndoFit(es, e - s);
- strncpyW(es->undo_text, es->text + s, e - s + 1);
+ memcpy(es->undo_text, buf, (e - s)*sizeof(WCHAR));
es->undo_text[e - s] = 0; /* ensure 0 termination */
es->undo_position = s;
}
@@ -3079,16 +3270,12 @@
es->undo_insert_count = 0;
} else
EDIT_EM_EmptyUndoBuffer(es);
-
- /* now delete */
- strcpyW(es->text + s, es->text + e);
}
if (strl) {
- /* there is an insertion */
if (can_undo) {
if ((s == es->undo_position) ||
- ((es->undo_insert_count) &&
- (s == es->undo_position + es->undo_insert_count)))
+ ((es->undo_insert_count) &&
+ (s == es->undo_position + es->undo_insert_count)))
/*
* insertion is new and at delete position or
* an extension to either left or right
@@ -3103,30 +3290,26 @@
}
} else
EDIT_EM_EmptyUndoBuffer(es);
+ }
- /* now insert */
- tl = strlenW(es->text);
- TRACE("inserting stuff (tl %d, strl %d, selstart %d ('%s'), text '%s')\n", tl, strl, s, debugstr_w(es->text + s), debugstr_w(es->text));
- for (p = es->text + tl ; p >= es->text + s ; p--)
- p[strl] = p[0];
- for (i = 0 , p = es->text + s ; i < strl ; i++)
- p[i] = lpsz_replace[i];
- if(es->style & ES_UPPERCASE)
- CharUpperBuffW(p, strl);
- else if(es->style & ES_LOWERCASE)
- CharLowerBuffW(p, strl);
- s += strl;
- }
- if (es->style & ES_MULTILINE)
+ if (bufl)
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ s += strl;
+
+ /* If text has been deleted and we're right or center aligned then scroll rightward */
+ if (es->style & (ES_RIGHT | ES_CENTER))
{
- INT s = min(es->selection_start, es->selection_end);
+ INT delta = strl - abs(es->selection_end - es->selection_start);
- hrgn = CreateRectRgn(0, 0, 0, 0);
- EDIT_BuildLineDefs_ML(es, s, s + strl,
- strl - abs(es->selection_end - es->selection_start), hrgn);
+ if (delta < 0 && es->x_offset)
+ {
+ if (abs(delta) > es->x_offset)
+ es->x_offset = 0;
+ else
+ es->x_offset += delta;
+ }
}
- else
- EDIT_CalcLineWidth_SL(es);
EDIT_EM_SetSel(es, s, s, FALSE);
es->flags |= EF_MODIFIED;
@@ -3145,10 +3328,10 @@
EDIT_UpdateScrollInfo(es);
- if(es->flags & EF_UPDATE)
+ if(send_update || (es->flags & EF_UPDATE))
{
es->flags &= ~EF_UPDATE;
- EDIT_NOTIFY_PARENT(es, EN_CHANGE, "EN_CHANGE");
+ EDIT_NOTIFY_PARENT(es, EN_CHANGE);
}
}
@@ -3235,12 +3418,12 @@
dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
if (x > es->format_rect.right)
dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
- if (dy || dx)
+ if (dy || dx || (es->y_offset && (es->line_count - es->y_offset < vlc)))
{
/* check if we are going to move too far */
if(es->x_offset + dx + ww > es->text_width)
dx = es->text_width - ww - es->x_offset;
- if(dx || dy)
+ if(dx || dy || (es->y_offset && (es->line_count - es->y_offset < vlc)))
EDIT_EM_LineScroll_internal(es, dx, dy);
}
} else {
@@ -3248,9 +3431,6 @@
INT goal;
INT format_width;
- if (!(es->style & ES_AUTOHSCROLL))
- return;
-
x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
format_width = es->format_rect.right - es->format_rect.left;
if (x < es->format_rect.left) {
@@ -3475,7 +3655,7 @@
*
*/
static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
- INT left, INT right)
+ INT left, INT right, BOOL repaint)
{
TEXTMETRICW tm;
INT default_left_margin = 0; /* in pixels */
@@ -3497,18 +3677,28 @@
}
if (action & EC_LEFTMARGIN) {
+ es->format_rect.left -= es->left_margin;
if (left != EC_USEFONTINFO)
es->left_margin = left;
else
es->left_margin = default_left_margin;
+ es->format_rect.left += es->left_margin;
}
if (action & EC_RIGHTMARGIN) {
+ es->format_rect.right += es->right_margin;
if (right != EC_USEFONTINFO)
es->right_margin = right;
else
es->right_margin = default_right_margin;
+ es->format_rect.right -= es->right_margin;
}
+
+ if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) {
+ EDIT_AdjustFormatRect(es);
+ if (repaint) EDIT_UpdateText(es, NULL, TRUE);
+ }
+
TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
}
@@ -3569,11 +3759,23 @@
es->flags |= EF_AFTER_WRAP;
else
es->flags &= ~EF_AFTER_WRAP;
-/* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */
- ORDER_UINT(start, end);
+ /* Compute the necessary invalidation region. */
+ /* Note that we don't need to invalidate regions which have
+ * "never" been selected, or those which are "still" selected.
+ * In fact, every time we hit a selection boundary, we can
+ * *toggle* whether we need to invalidate. Thus we can optimize by
+ * *sorting* the interval endpoints. Let's assume that we sort them
+ * in this order:
+ * start <= end <= old_start <= old_end
+ * Knuth 5.3.1 (p 183) asssures us that this can be done optimally
+ * in 5 comparisons; ie it's impossible to do better than the
+ * following: */
ORDER_UINT(end, old_end);
ORDER_UINT(start, old_start);
ORDER_UINT(old_start, old_end);
+ ORDER_UINT(start, end);
+ /* Note that at this point 'end' and 'old_start' are not in order, but
+ * start is definitely the min. and old_end is definitely the max. */
if (end != old_start)
{
/*
@@ -3582,6 +3784,7 @@
* EDIT_InvalidateText(es, start, end);
* EDIT_InvalidateText(es, old_start, old_end);
* in place of the following if statement.
+ * (That would complete the optimal five-comparison four-element sort.)
*/
if (old_start > end )
{
@@ -3607,8 +3810,7 @@
{
if (!(es->style & ES_MULTILINE))
return FALSE;
- if (es->tabs)
- HeapFree(GetProcessHeap(), 0, es->tabs);
+ HeapFree(GetProcessHeap(), 0, es->tabs);
es->tabs_count = count;
if (!count)
es->tabs = NULL;
@@ -3651,12 +3853,12 @@
* EM_SETWORDBREAKPROC
*
*/
-static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, LPARAM lParam)
+static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp)
{
- if (es->word_break_proc == (void *)lParam)
+ if (es->word_break_proc == wbp)
return;
- es->word_break_proc = (void *)lParam;
+ es->word_break_proc = wbp;
#ifndef __REACTOS__
es->word_break_proc16 = NULL;
#endif
@@ -3718,7 +3920,7 @@
EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE);
EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
/* send the notification after the selection start and end are set */
- EDIT_NOTIFY_PARENT(es, EN_CHANGE, "EN_CHANGE");
+ EDIT_NOTIFY_PARENT(es, EN_CHANGE);
EDIT_EM_ScrollCaret(es);
HeapFree(GetProcessHeap(), 0, utext);
@@ -3897,13 +4099,15 @@
INT e = max(es->selection_start, es->selection_end);
HGLOBAL hdst;
LPWSTR dst;
+ DWORD len;
if (e == s) return;
- hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)(e - s + 1) * sizeof(WCHAR));
+ len = e - s;
+ hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
dst = GlobalLock(hdst);
- strncpyW(dst, es->text + s, e - s);
- dst[e - s] = 0; /* ensure 0 termination */
[truncated at 1000 lines; 468 more skipped]