4 * Copyright David W. Metcalfe, 1994
5 * Copyright William Magro, 1995, 1996
6 * Copyright Frans van Dorsselaer, 1996, 1997
11 * please read EDIT.TODO (and update it when you change things)
21 #include "wine/winbase16.h"
22 #include "wine/winuser16.h"
25 #include "selectors.h"
26 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(edit
);
30 DECLARE_DEBUG_CHANNEL(combo
);
31 DECLARE_DEBUG_CHANNEL(relay
);
33 #define BUFLIMIT_MULTI 65534 /* maximum buffer size (not including '\0')
34 FIXME: BTW, new specs say 65535 (do you dare ???) */
35 #define BUFLIMIT_SINGLE 32766 /* maximum buffer size (not including '\0') */
36 #define BUFSTART_MULTI 1024 /* starting size */
37 #define BUFSTART_SINGLE 256 /* starting size */
38 #define GROWLENGTH 64 /* buffers grow by this much */
39 #define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */
42 * extra flags for EDITSTATE.flags field
44 #define EF_MODIFIED 0x0001 /* text has been modified */
45 #define EF_FOCUSED 0x0002 /* we have input focus */
46 #define EF_UPDATE 0x0004 /* notify parent of changed state on next WM_PAINT */
47 #define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */
48 #define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */
49 #define EF_VSCROLL_HACK 0x0020 /* we already have informed the user of the hacked handler */
50 #define EF_HSCROLL_HACK 0x0040 /* we already have informed the user of the hacked handler */
51 #define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a
52 wrapped line, instead of in front of the next character */
53 #define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */
57 END_0
= 0, /* line ends with terminating '\0' character */
58 END_WRAP
, /* line is wrapped */
59 END_HARD
, /* line ends with a hard return '\r\n' */
60 END_SOFT
/* line ends with a soft return '\r\r\n' */
63 typedef struct tagLINEDEF
{
64 INT length
; /* bruto length of a line in bytes */
65 INT net_length
; /* netto length of a line in visible characters */
67 INT width
; /* width of the line in pixels */
68 struct tagLINEDEF
*next
;
73 HANDLE heap
; /* our own heap */
74 LPSTR text
; /* the actual contents of the control */
75 INT buffer_size
; /* the size of the buffer */
76 INT buffer_limit
; /* the maximum size to which the buffer may grow */
77 HFONT font
; /* NULL means standard system font */
78 INT x_offset
; /* scroll offset for multi lines this is in pixels
79 for single lines it's in characters */
80 INT line_height
; /* height of a screen line in pixels */
81 INT char_width
; /* average character width in pixels */
82 DWORD style
; /* sane version of wnd->dwStyle */
83 WORD flags
; /* flags that are not in es->style or wnd->flags (EF_XXX) */
84 INT undo_insert_count
; /* number of characters inserted in sequence */
85 INT undo_position
; /* character index of the insertion and deletion */
86 LPSTR undo_text
; /* deleted text */
87 INT undo_buffer_size
; /* size of the deleted text buffer */
88 INT selection_start
; /* == selection_end if no selection */
89 INT selection_end
; /* == current caret position */
90 CHAR password_char
; /* == 0 if no password char, and for multi line controls */
91 INT left_margin
; /* in pixels */
92 INT right_margin
; /* in pixels */
94 INT region_posx
; /* Position of cursor relative to region: */
95 INT region_posy
; /* -1: to left, 0: within, 1: to right */
96 EDITWORDBREAKPROC16 word_break_proc16
;
97 EDITWORDBREAKPROCA word_break_proc32A
;
98 INT line_count
; /* number of lines */
99 INT y_offset
; /* scroll offset in number of lines */
100 BOOL bCaptureState
; /* flag indicating whether mouse was captured */
101 BOOL bEnableState
; /* flag keeping the enable state */
102 HWND hwndListBox
; /* handle of ComboBox's listbox or NULL */
104 * only for multi line controls
106 INT lock_count
; /* amount of re-entries in the EditWndProc */
109 INT text_width
; /* width of the widest line in pixels */
110 LINEDEF
*first_line_def
; /* linked list of (soft) linebreaks */
111 HLOCAL16 hloc16
; /* for controls receiving EM_GETHANDLE16 */
112 HLOCAL hloc32
; /* for controls receiving EM_GETHANDLE */
116 #define SWAP_INT32(x,y) do { INT temp = (INT)(x); (x) = (INT)(y); (y) = temp; } while(0)
117 #define ORDER_INT(x,y) do { if ((INT)(y) < (INT)(x)) SWAP_INT32((x),(y)); } while(0)
119 #define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
120 #define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
122 #define DPRINTF_EDIT_NOTIFY(hwnd, str) \
123 do {TRACE("notification " str " sent to hwnd=%08x\n", \
124 (UINT)(hwnd));} while(0)
126 /* used for disabled or read-only edit control */
127 #define EDIT_SEND_CTLCOLORSTATIC(wnd,hdc) \
128 (SendMessageA((wnd)->parent->hwndSelf, WM_CTLCOLORSTATIC, \
129 (WPARAM)(hdc), (LPARAM)(wnd)->hwndSelf))
130 #define EDIT_SEND_CTLCOLOR(wnd,hdc) \
131 (SendMessageA((wnd)->parent->hwndSelf, WM_CTLCOLOREDIT, \
132 (WPARAM)(hdc), (LPARAM)(wnd)->hwndSelf))
133 #define EDIT_NOTIFY_PARENT(wnd, wNotifyCode, str) \
134 do {DPRINTF_EDIT_NOTIFY((wnd)->parent->hwndSelf, str); \
135 SendMessageA((wnd)->parent->hwndSelf, WM_COMMAND, \
136 MAKEWPARAM((wnd)->wIDmenu, wNotifyCode), \
137 (LPARAM)(wnd)->hwndSelf);} while(0)
138 #define DPRINTF_EDIT_MSG16(str) \
140 "16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
141 (UINT)hwnd, (UINT)wParam, (UINT)lParam)
142 #define DPRINTF_EDIT_MSG32(str) \
144 "32 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
145 (UINT)hwnd, (UINT)wParam, (UINT)lParam)
147 /*********************************************************************
154 * These functions have trivial implementations
155 * We still like to call them internally
156 * "static inline" makes them more like macro's
158 static inline BOOL
EDIT_EM_CanUndo(WND
*wnd
, EDITSTATE
*es
);
159 static inline void EDIT_EM_EmptyUndoBuffer(WND
*wnd
, EDITSTATE
*es
);
160 static inline void EDIT_WM_Clear(WND
*wnd
, EDITSTATE
*es
);
161 static inline void EDIT_WM_Cut(WND
*wnd
, EDITSTATE
*es
);
164 * Helper functions only valid for one type of control
166 static void EDIT_BuildLineDefs_ML(WND
*wnd
, EDITSTATE
*es
);
167 static LPSTR
EDIT_GetPasswordPointer_SL(WND
*wnd
, EDITSTATE
*es
);
168 static void EDIT_MoveDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
169 static void EDIT_MovePageDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
170 static void EDIT_MovePageUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
171 static void EDIT_MoveUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
173 * Helper functions valid for both single line _and_ multi line controls
175 static INT
EDIT_CallWordBreakProc(WND
*wnd
, EDITSTATE
*es
, INT start
, INT index
, INT count
, INT action
);
176 static INT
EDIT_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT x
, INT y
, LPBOOL after_wrap
);
177 static void EDIT_ConfinePoint(WND
*wnd
, EDITSTATE
*es
, LPINT x
, LPINT y
);
178 static void EDIT_GetLineRect(WND
*wnd
, EDITSTATE
*es
, INT line
, INT scol
, INT ecol
, LPRECT rc
);
179 static void EDIT_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT start
, INT end
);
180 static void EDIT_LockBuffer(WND
*wnd
, EDITSTATE
*es
);
181 static BOOL
EDIT_MakeFit(WND
*wnd
, EDITSTATE
*es
, INT size
);
182 static BOOL
EDIT_MakeUndoFit(WND
*wnd
, EDITSTATE
*es
, INT size
);
183 static void EDIT_MoveBackward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
184 static void EDIT_MoveEnd(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
185 static void EDIT_MoveForward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
186 static void EDIT_MoveHome(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
187 static void EDIT_MoveWordBackward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
188 static void EDIT_MoveWordForward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
);
189 static void EDIT_PaintLine(WND
*wnd
, EDITSTATE
*es
, HDC hdc
, INT line
, BOOL rev
);
190 static INT
EDIT_PaintText(WND
*wnd
, EDITSTATE
*es
, HDC hdc
, INT x
, INT y
, INT line
, INT col
, INT count
, BOOL rev
);
191 static void EDIT_SetCaretPos(WND
*wnd
, EDITSTATE
*es
, INT pos
, BOOL after_wrap
);
192 static void EDIT_SetRectNP(WND
*wnd
, EDITSTATE
*es
, LPRECT lprc
);
193 static void EDIT_UnlockBuffer(WND
*wnd
, EDITSTATE
*es
, BOOL force
);
194 static INT
EDIT_WordBreakProc(LPSTR s
, INT index
, INT count
, INT action
);
196 * EM_XXX message handlers
198 static LRESULT
EDIT_EM_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT x
, INT y
);
199 static BOOL
EDIT_EM_FmtLines(WND
*wnd
, EDITSTATE
*es
, BOOL add_eol
);
200 static HLOCAL
EDIT_EM_GetHandle(WND
*wnd
, EDITSTATE
*es
);
201 static HLOCAL16
EDIT_EM_GetHandle16(WND
*wnd
, EDITSTATE
*es
);
202 static INT
EDIT_EM_GetLine(WND
*wnd
, EDITSTATE
*es
, INT line
, LPSTR lpch
);
203 static LRESULT
EDIT_EM_GetSel(WND
*wnd
, EDITSTATE
*es
, LPUINT start
, LPUINT end
);
204 static LRESULT
EDIT_EM_GetThumb(WND
*wnd
, EDITSTATE
*es
);
205 static INT
EDIT_EM_LineFromChar(WND
*wnd
, EDITSTATE
*es
, INT index
);
206 static INT
EDIT_EM_LineIndex(WND
*wnd
, EDITSTATE
*es
, INT line
);
207 static INT
EDIT_EM_LineLength(WND
*wnd
, EDITSTATE
*es
, INT index
);
208 static BOOL
EDIT_EM_LineScroll(WND
*wnd
, EDITSTATE
*es
, INT dx
, INT dy
);
209 static LRESULT
EDIT_EM_PosFromChar(WND
*wnd
, EDITSTATE
*es
, INT index
, BOOL after_wrap
);
210 static void EDIT_EM_ReplaceSel(WND
*wnd
, EDITSTATE
*es
, BOOL can_undo
, LPCSTR lpsz_replace
);
211 static LRESULT
EDIT_EM_Scroll(WND
*wnd
, EDITSTATE
*es
, INT action
);
212 static void EDIT_EM_ScrollCaret(WND
*wnd
, EDITSTATE
*es
);
213 static void EDIT_EM_SetHandle(WND
*wnd
, EDITSTATE
*es
, HLOCAL hloc
);
214 static void EDIT_EM_SetHandle16(WND
*wnd
, EDITSTATE
*es
, HLOCAL16 hloc
);
215 static void EDIT_EM_SetLimitText(WND
*wnd
, EDITSTATE
*es
, INT limit
);
216 static void EDIT_EM_SetMargins(WND
*wnd
, EDITSTATE
*es
, INT action
, INT left
, INT right
);
217 static void EDIT_EM_SetPasswordChar(WND
*wnd
, EDITSTATE
*es
, CHAR c
);
218 static void EDIT_EM_SetSel(WND
*wnd
, EDITSTATE
*es
, UINT start
, UINT end
, BOOL after_wrap
);
219 static BOOL
EDIT_EM_SetTabStops(WND
*wnd
, EDITSTATE
*es
, INT count
, LPINT tabs
);
220 static BOOL
EDIT_EM_SetTabStops16(WND
*wnd
, EDITSTATE
*es
, INT count
, LPINT16 tabs
);
221 static void EDIT_EM_SetWordBreakProc(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROCA wbp
);
222 static void EDIT_EM_SetWordBreakProc16(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC16 wbp
);
223 static BOOL
EDIT_EM_Undo(WND
*wnd
, EDITSTATE
*es
);
225 * WM_XXX message handlers
227 static void EDIT_WM_Char(WND
*wnd
, EDITSTATE
*es
, CHAR c
, DWORD key_data
);
228 static void EDIT_WM_Command(WND
*wnd
, EDITSTATE
*es
, INT code
, INT id
, HWND conrtol
);
229 static void EDIT_WM_ContextMenu(WND
*wnd
, EDITSTATE
*es
, HWND hwnd
, INT x
, INT y
);
230 static void EDIT_WM_Copy(WND
*wnd
, EDITSTATE
*es
);
231 static LRESULT
EDIT_WM_Create(WND
*wnd
, EDITSTATE
*es
, LPCREATESTRUCTA cs
);
232 static void EDIT_WM_Destroy(WND
*wnd
, EDITSTATE
*es
);
233 static LRESULT
EDIT_WM_EraseBkGnd(WND
*wnd
, EDITSTATE
*es
, HDC dc
);
234 static INT
EDIT_WM_GetText(WND
*wnd
, EDITSTATE
*es
, INT count
, LPSTR text
);
235 static LRESULT
EDIT_WM_HScroll(WND
*wnd
, EDITSTATE
*es
, INT action
, INT pos
, HWND scroll_bar
);
236 static LRESULT
EDIT_WM_KeyDown(WND
*wnd
, EDITSTATE
*es
, INT key
, DWORD key_data
);
237 static LRESULT
EDIT_WM_KillFocus(WND
*wnd
, EDITSTATE
*es
, HWND window_getting_focus
);
238 static LRESULT
EDIT_WM_LButtonDblClk(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
);
239 static LRESULT
EDIT_WM_LButtonDown(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
);
240 static LRESULT
EDIT_WM_LButtonUp(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
);
241 static LRESULT
EDIT_WM_MButtonDown(WND
*wnd
);
242 static LRESULT
EDIT_WM_MouseMove(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
);
243 static LRESULT
EDIT_WM_NCCreate(WND
*wnd
, LPCREATESTRUCTA cs
);
244 static void EDIT_WM_Paint(WND
*wnd
, EDITSTATE
*es
, WPARAM wParam
);
245 static void EDIT_WM_Paste(WND
*wnd
, EDITSTATE
*es
);
246 static void EDIT_WM_SetFocus(WND
*wnd
, EDITSTATE
*es
, HWND window_losing_focus
);
247 static void EDIT_WM_SetFont(WND
*wnd
, EDITSTATE
*es
, HFONT font
, BOOL redraw
);
248 static void EDIT_WM_SetText(WND
*wnd
, EDITSTATE
*es
, LPCSTR text
);
249 static void EDIT_WM_Size(WND
*wnd
, EDITSTATE
*es
, UINT action
, INT width
, INT height
);
250 static LRESULT
EDIT_WM_SysKeyDown(WND
*wnd
, EDITSTATE
*es
, INT key
, DWORD key_data
);
251 static void EDIT_WM_Timer(WND
*wnd
, EDITSTATE
*es
, INT id
, TIMERPROC timer_proc
);
252 static LRESULT
EDIT_WM_VScroll(WND
*wnd
, EDITSTATE
*es
, INT action
, INT pos
, HWND scroll_bar
);
253 static void EDIT_UpdateText(WND
*wnd
, LPRECT rc
, BOOL bErase
);
256 /*********************************************************************
261 static inline BOOL
EDIT_EM_CanUndo(WND
*wnd
, EDITSTATE
*es
)
263 return (es
->undo_insert_count
|| strlen(es
->undo_text
));
267 /*********************************************************************
272 static inline void EDIT_EM_EmptyUndoBuffer(WND
*wnd
, EDITSTATE
*es
)
274 es
->undo_insert_count
= 0;
275 *es
->undo_text
= '\0';
279 /*********************************************************************
284 static inline void EDIT_WM_Clear(WND
*wnd
, EDITSTATE
*es
)
286 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "");
288 if (es
->flags
& EF_UPDATE
) {
289 es
->flags
&= ~EF_UPDATE
;
290 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
295 /*********************************************************************
300 static inline void EDIT_WM_Cut(WND
*wnd
, EDITSTATE
*es
)
302 EDIT_WM_Copy(wnd
, es
);
303 EDIT_WM_Clear(wnd
, es
);
307 /**********************************************************************
310 * Returns the window version in case Wine emulates a later version
311 * of windows then the application expects.
313 * In a number of cases when windows runs an application that was
314 * designed for an earlier windows version, windows reverts
315 * to "old" behaviour of that earlier version.
317 * An example is a disabled edit control that needs to be painted.
318 * Old style behaviour is to send a WM_CTLCOLOREDIT message. This was
319 * changed in Win95, NT4.0 by a WM_CTLCOLORSTATIC message _only_ for
320 * applications with an expected version 0f 4.0 or higher.
323 static DWORD
get_app_version(void)
325 static DWORD version
;
328 DWORD dwEmulatedVersion
;
330 DWORD dwProcVersion
= GetProcessVersion(0);
332 GetVersionExA( &info
);
333 dwEmulatedVersion
= MAKELONG( info
.dwMinorVersion
, info
.dwMajorVersion
);
334 /* fixme: this may not be 100% correct; see discussion on the
335 * wine developer list in Nov 1999 */
336 version
= dwProcVersion
< dwEmulatedVersion
? dwProcVersion
: dwEmulatedVersion
;
342 /*********************************************************************
346 * The messages are in the order of the actual integer values
347 * (which can be found in include/windows.h)
348 * Whereever possible the 16 bit versions are converted to
349 * the 32 bit ones, so that we can 'fall through' to the
350 * helper functions. These are mostly 32 bit (with a few
351 * exceptions, clearly indicated by a '16' extension to their
355 LRESULT WINAPI
EditWndProc( HWND hwnd
, UINT msg
,
356 WPARAM wParam
, LPARAM lParam
)
358 WND
*wnd
= WIN_FindWndPtr(hwnd
);
359 EDITSTATE
*es
= *(EDITSTATE
**)((wnd
)->wExtra
);
364 DPRINTF_EDIT_MSG32("WM_DESTROY");
365 EDIT_WM_Destroy(wnd
, es
);
370 DPRINTF_EDIT_MSG32("WM_NCCREATE");
371 result
= EDIT_WM_NCCreate(wnd
, (LPCREATESTRUCTA
)lParam
);
377 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
382 EDIT_LockBuffer(wnd
, es
);
385 DPRINTF_EDIT_MSG16("EM_GETSEL");
390 DPRINTF_EDIT_MSG32("EM_GETSEL");
391 result
= EDIT_EM_GetSel(wnd
, es
, (LPUINT
)wParam
, (LPUINT
)lParam
);
395 DPRINTF_EDIT_MSG16("EM_SETSEL");
396 if (SLOWORD(lParam
) == -1)
397 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
399 EDIT_EM_SetSel(wnd
, es
, LOWORD(lParam
), HIWORD(lParam
), FALSE
);
401 EDIT_EM_ScrollCaret(wnd
, es
);
405 DPRINTF_EDIT_MSG32("EM_SETSEL");
406 EDIT_EM_SetSel(wnd
, es
, wParam
, lParam
, FALSE
);
407 EDIT_EM_ScrollCaret(wnd
, es
);
412 DPRINTF_EDIT_MSG16("EM_GETRECT");
414 CONV_RECT32TO16(&es
->format_rect
, (LPRECT16
)PTR_SEG_TO_LIN(lParam
));
417 DPRINTF_EDIT_MSG32("EM_GETRECT");
419 CopyRect((LPRECT
)lParam
, &es
->format_rect
);
423 DPRINTF_EDIT_MSG16("EM_SETRECT");
424 if ((es
->style
& ES_MULTILINE
) && lParam
) {
426 CONV_RECT16TO32((LPRECT16
)PTR_SEG_TO_LIN(lParam
), &rc
);
427 EDIT_SetRectNP(wnd
, es
, &rc
);
428 EDIT_UpdateText(wnd
, NULL
, TRUE
);
432 DPRINTF_EDIT_MSG32("EM_SETRECT");
433 if ((es
->style
& ES_MULTILINE
) && lParam
) {
434 EDIT_SetRectNP(wnd
, es
, (LPRECT
)lParam
);
435 EDIT_UpdateText(wnd
, NULL
, TRUE
);
440 DPRINTF_EDIT_MSG16("EM_SETRECTNP");
441 if ((es
->style
& ES_MULTILINE
) && lParam
) {
443 CONV_RECT16TO32((LPRECT16
)PTR_SEG_TO_LIN(lParam
), &rc
);
444 EDIT_SetRectNP(wnd
, es
, &rc
);
448 DPRINTF_EDIT_MSG32("EM_SETRECTNP");
449 if ((es
->style
& ES_MULTILINE
) && lParam
)
450 EDIT_SetRectNP(wnd
, es
, (LPRECT
)lParam
);
454 DPRINTF_EDIT_MSG16("EM_SCROLL");
457 DPRINTF_EDIT_MSG32("EM_SCROLL");
458 result
= EDIT_EM_Scroll(wnd
, es
, (INT
)wParam
);
461 case EM_LINESCROLL16
:
462 DPRINTF_EDIT_MSG16("EM_LINESCROLL");
463 wParam
= (WPARAM
)(INT
)SHIWORD(lParam
);
464 lParam
= (LPARAM
)(INT
)SLOWORD(lParam
);
467 DPRINTF_EDIT_MSG32("EM_LINESCROLL");
468 result
= (LRESULT
)EDIT_EM_LineScroll(wnd
, es
, (INT
)wParam
, (INT
)lParam
);
471 case EM_SCROLLCARET16
:
472 DPRINTF_EDIT_MSG16("EM_SCROLLCARET");
475 DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
476 EDIT_EM_ScrollCaret(wnd
, es
);
481 DPRINTF_EDIT_MSG16("EM_GETMODIFY");
484 DPRINTF_EDIT_MSG32("EM_GETMODIFY");
485 result
= ((es
->flags
& EF_MODIFIED
) != 0);
489 DPRINTF_EDIT_MSG16("EM_SETMODIFY");
492 DPRINTF_EDIT_MSG32("EM_SETMODIFY");
494 es
->flags
|= EF_MODIFIED
;
496 es
->flags
&= ~(EF_MODIFIED
| EF_UPDATE
); /* reset pending updates */
499 case EM_GETLINECOUNT16
:
500 DPRINTF_EDIT_MSG16("EM_GETLINECOUNT");
502 case EM_GETLINECOUNT
:
503 DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
504 result
= (es
->style
& ES_MULTILINE
) ? es
->line_count
: 1;
508 DPRINTF_EDIT_MSG16("EM_LINEINDEX");
509 if ((INT16
)wParam
== -1)
513 DPRINTF_EDIT_MSG32("EM_LINEINDEX");
514 result
= (LRESULT
)EDIT_EM_LineIndex(wnd
, es
, (INT
)wParam
);
518 DPRINTF_EDIT_MSG16("EM_SETHANDLE");
519 EDIT_EM_SetHandle16(wnd
, es
, (HLOCAL16
)wParam
);
522 DPRINTF_EDIT_MSG32("EM_SETHANDLE");
523 EDIT_EM_SetHandle(wnd
, es
, (HLOCAL
)wParam
);
527 DPRINTF_EDIT_MSG16("EM_GETHANDLE");
528 result
= (LRESULT
)EDIT_EM_GetHandle16(wnd
, es
);
531 DPRINTF_EDIT_MSG32("EM_GETHANDLE");
532 result
= (LRESULT
)EDIT_EM_GetHandle(wnd
, es
);
536 DPRINTF_EDIT_MSG16("EM_GETTHUMB");
539 DPRINTF_EDIT_MSG32("EM_GETTHUMB");
540 result
= EDIT_EM_GetThumb(wnd
, es
);
543 /* messages 0x00bf and 0x00c0 missing from specs */
546 DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
549 DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
550 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
554 DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
557 DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
558 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
561 case EM_LINELENGTH16
:
562 DPRINTF_EDIT_MSG16("EM_LINELENGTH");
565 DPRINTF_EDIT_MSG32("EM_LINELENGTH");
566 result
= (LRESULT
)EDIT_EM_LineLength(wnd
, es
, (INT
)wParam
);
569 case EM_REPLACESEL16
:
570 DPRINTF_EDIT_MSG16("EM_REPLACESEL");
571 lParam
= (LPARAM
)PTR_SEG_TO_LIN((SEGPTR
)lParam
);
574 DPRINTF_EDIT_MSG32("EM_REPLACESEL");
575 EDIT_EM_ReplaceSel(wnd
, es
, (BOOL
)wParam
, (LPCSTR
)lParam
);
576 if (es
->flags
& EF_UPDATE
) {
577 es
->flags
&= ~EF_UPDATE
;
578 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
583 /* message 0x00c3 missing from specs */
586 DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
589 DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
590 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
594 DPRINTF_EDIT_MSG16("EM_GETLINE");
595 lParam
= (LPARAM
)PTR_SEG_TO_LIN((SEGPTR
)lParam
);
598 DPRINTF_EDIT_MSG32("EM_GETLINE");
599 result
= (LRESULT
)EDIT_EM_GetLine(wnd
, es
, (INT
)wParam
, (LPSTR
)lParam
);
603 DPRINTF_EDIT_MSG16("EM_LIMITTEXT");
605 case EM_SETLIMITTEXT
:
606 DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
607 EDIT_EM_SetLimitText(wnd
, es
, (INT
)wParam
);
611 DPRINTF_EDIT_MSG16("EM_CANUNDO");
614 DPRINTF_EDIT_MSG32("EM_CANUNDO");
615 result
= (LRESULT
)EDIT_EM_CanUndo(wnd
, es
);
619 DPRINTF_EDIT_MSG16("EM_UNDO");
624 DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
625 result
= (LRESULT
)EDIT_EM_Undo(wnd
, es
);
629 DPRINTF_EDIT_MSG16("EM_FMTLINES");
632 DPRINTF_EDIT_MSG32("EM_FMTLINES");
633 result
= (LRESULT
)EDIT_EM_FmtLines(wnd
, es
, (BOOL
)wParam
);
636 case EM_LINEFROMCHAR16
:
637 DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR");
639 case EM_LINEFROMCHAR
:
640 DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
641 result
= (LRESULT
)EDIT_EM_LineFromChar(wnd
, es
, (INT
)wParam
);
644 /* message 0x00ca missing from specs */
647 DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
650 DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
651 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
654 case EM_SETTABSTOPS16
:
655 DPRINTF_EDIT_MSG16("EM_SETTABSTOPS");
656 result
= (LRESULT
)EDIT_EM_SetTabStops16(wnd
, es
, (INT
)wParam
, (LPINT16
)PTR_SEG_TO_LIN((SEGPTR
)lParam
));
659 DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
660 result
= (LRESULT
)EDIT_EM_SetTabStops(wnd
, es
, (INT
)wParam
, (LPINT
)lParam
);
663 case EM_SETPASSWORDCHAR16
:
664 DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR");
666 case EM_SETPASSWORDCHAR
:
667 DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
668 EDIT_EM_SetPasswordChar(wnd
, es
, (CHAR
)wParam
);
671 case EM_EMPTYUNDOBUFFER16
:
672 DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER");
674 case EM_EMPTYUNDOBUFFER
:
675 DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
676 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
679 case EM_GETFIRSTVISIBLELINE16
:
680 DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE");
681 result
= es
->y_offset
;
683 case EM_GETFIRSTVISIBLELINE
:
684 DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
685 result
= (es
->style
& ES_MULTILINE
) ? es
->y_offset
: es
->x_offset
;
688 case EM_SETREADONLY16
:
689 DPRINTF_EDIT_MSG16("EM_SETREADONLY");
692 DPRINTF_EDIT_MSG32("EM_SETREADONLY");
694 wnd
->dwStyle
|= ES_READONLY
;
695 es
->style
|= ES_READONLY
;
697 wnd
->dwStyle
&= ~ES_READONLY
;
698 es
->style
&= ~ES_READONLY
;
703 case EM_SETWORDBREAKPROC16
:
704 DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC");
705 EDIT_EM_SetWordBreakProc16(wnd
, es
, (EDITWORDBREAKPROC16
)lParam
);
707 case EM_SETWORDBREAKPROC
:
708 DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
709 EDIT_EM_SetWordBreakProc(wnd
, es
, (EDITWORDBREAKPROCA
)lParam
);
712 case EM_GETWORDBREAKPROC16
:
713 DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC");
714 result
= (LRESULT
)es
->word_break_proc16
;
716 case EM_GETWORDBREAKPROC
:
717 DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
718 result
= (LRESULT
)es
->word_break_proc32A
;
721 case EM_GETPASSWORDCHAR16
:
722 DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR");
724 case EM_GETPASSWORDCHAR
:
725 DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
726 result
= es
->password_char
;
729 /* The following EM_xxx are new to win95 and don't exist for 16 bit */
732 DPRINTF_EDIT_MSG32("EM_SETMARGINS");
733 EDIT_EM_SetMargins(wnd
, es
, (INT
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
737 DPRINTF_EDIT_MSG32("EM_GETMARGINS");
738 result
= MAKELONG(es
->left_margin
, es
->right_margin
);
741 case EM_GETLIMITTEXT
:
742 DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
743 result
= es
->buffer_limit
;
747 DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
748 result
= EDIT_EM_PosFromChar(wnd
, es
, (INT
)wParam
, FALSE
);
752 DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
753 result
= EDIT_EM_CharFromPos(wnd
, es
, SLOWORD(lParam
), SHIWORD(lParam
));
757 DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
758 result
= DLGC_HASSETSEL
| DLGC_WANTCHARS
| DLGC_WANTARROWS
;
760 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
762 int vk
= (int)((LPMSG
)lParam
)->wParam
;
764 if ((wnd
->dwStyle
& ES_WANTRETURN
) && vk
== VK_RETURN
)
766 result
|= DLGC_WANTMESSAGE
;
768 else if (es
->hwndListBox
&& (vk
== VK_RETURN
|| vk
== VK_ESCAPE
))
770 if (SendMessageA(wnd
->parent
->hwndSelf
, CB_GETDROPPEDSTATE
, 0, 0))
771 result
|= DLGC_WANTMESSAGE
;
777 DPRINTF_EDIT_MSG32("WM_CHAR");
778 if (((CHAR
)wParam
== VK_RETURN
|| (CHAR
)wParam
== VK_ESCAPE
) && es
->hwndListBox
)
780 if (SendMessageA(wnd
->parent
->hwndSelf
, CB_GETDROPPEDSTATE
, 0, 0))
781 SendMessageA(wnd
->parent
->hwndSelf
, WM_KEYDOWN
, wParam
, 0);
784 EDIT_WM_Char(wnd
, es
, (CHAR
)wParam
, (DWORD
)lParam
);
788 DPRINTF_EDIT_MSG32("WM_CLEAR");
789 EDIT_WM_Clear(wnd
, es
);
793 DPRINTF_EDIT_MSG32("WM_COMMAND");
794 EDIT_WM_Command(wnd
, es
, HIWORD(wParam
), LOWORD(wParam
), (HWND
)lParam
);
798 DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
799 EDIT_WM_ContextMenu(wnd
, es
, (HWND
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
803 DPRINTF_EDIT_MSG32("WM_COPY");
804 EDIT_WM_Copy(wnd
, es
);
808 DPRINTF_EDIT_MSG32("WM_CREATE");
809 result
= EDIT_WM_Create(wnd
, es
, (LPCREATESTRUCTA
)lParam
);
813 DPRINTF_EDIT_MSG32("WM_CUT");
814 EDIT_WM_Cut(wnd
, es
);
818 DPRINTF_EDIT_MSG32("WM_ENABLE");
819 es
->bEnableState
= (BOOL
) wParam
;
820 EDIT_UpdateText(wnd
, NULL
, TRUE
);
824 DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
825 result
= EDIT_WM_EraseBkGnd(wnd
, es
, (HDC
)wParam
);
829 DPRINTF_EDIT_MSG32("WM_GETFONT");
830 result
= (LRESULT
)es
->font
;
834 DPRINTF_EDIT_MSG32("WM_GETTEXT");
835 result
= (LRESULT
)EDIT_WM_GetText(wnd
, es
, (INT
)wParam
, (LPSTR
)lParam
);
838 case WM_GETTEXTLENGTH
:
839 DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
840 result
= strlen(es
->text
);
844 DPRINTF_EDIT_MSG32("WM_HSCROLL");
845 result
= EDIT_WM_HScroll(wnd
, es
, LOWORD(wParam
), SHIWORD(wParam
), (HWND
)lParam
);
849 DPRINTF_EDIT_MSG32("WM_KEYDOWN");
850 result
= EDIT_WM_KeyDown(wnd
, es
, (INT
)wParam
, (DWORD
)lParam
);
854 DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
855 result
= EDIT_WM_KillFocus(wnd
, es
, (HWND
)wParam
);
858 case WM_LBUTTONDBLCLK
:
859 DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
860 result
= EDIT_WM_LButtonDblClk(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
864 DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
865 result
= EDIT_WM_LButtonDown(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
869 DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
870 result
= EDIT_WM_LButtonUp(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
874 DPRINTF_EDIT_MSG32("WM_MBUTTONDOWN");
875 result
= EDIT_WM_MButtonDown(wnd
);
878 case WM_MOUSEACTIVATE
:
880 * FIXME: maybe DefWindowProc() screws up, but it seems that
881 * modeless dialog boxes need this. If we don't do this, the focus
882 * will _not_ be set by DefWindowProc() for edit controls in a
883 * modeless dialog box ???
885 DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
886 SetFocus(wnd
->hwndSelf
);
887 result
= MA_ACTIVATE
;
892 * DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
894 result
= EDIT_WM_MouseMove(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
898 DPRINTF_EDIT_MSG32("WM_PAINT");
899 EDIT_WM_Paint(wnd
, es
, wParam
);
903 DPRINTF_EDIT_MSG32("WM_PASTE");
904 EDIT_WM_Paste(wnd
, es
);
908 DPRINTF_EDIT_MSG32("WM_SETFOCUS");
909 EDIT_WM_SetFocus(wnd
, es
, (HWND
)wParam
);
913 DPRINTF_EDIT_MSG32("WM_SETFONT");
914 EDIT_WM_SetFont(wnd
, es
, (HFONT
)wParam
, LOWORD(lParam
) != 0);
918 DPRINTF_EDIT_MSG32("WM_SETTEXT");
919 EDIT_WM_SetText(wnd
, es
, (LPCSTR
)lParam
);
924 DPRINTF_EDIT_MSG32("WM_SIZE");
925 EDIT_WM_Size(wnd
, es
, (UINT
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
929 DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
930 result
= EDIT_WM_SysKeyDown(wnd
, es
, (INT
)wParam
, (DWORD
)lParam
);
934 DPRINTF_EDIT_MSG32("WM_TIMER");
935 EDIT_WM_Timer(wnd
, es
, (INT
)wParam
, (TIMERPROC
)lParam
);
939 DPRINTF_EDIT_MSG32("WM_VSCROLL");
940 result
= EDIT_WM_VScroll(wnd
, es
, LOWORD(wParam
), SHIWORD(wParam
), (HWND
)(lParam
));
945 short gcWheelDelta
= 0;
946 UINT pulScrollLines
= 3;
947 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
,0, &pulScrollLines
, 0);
949 if (wParam
& (MK_SHIFT
| MK_CONTROL
)) {
950 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
953 gcWheelDelta
-= (short) HIWORD(wParam
);
954 if (abs(gcWheelDelta
) >= WHEEL_DELTA
&& pulScrollLines
)
956 int cLineScroll
= (int) min((UINT
) es
->line_count
, pulScrollLines
);
957 cLineScroll
*= (gcWheelDelta
/ WHEEL_DELTA
);
958 result
= EDIT_EM_LineScroll(wnd
, es
, 0, cLineScroll
);
963 result
= DefWindowProcA(hwnd
, msg
, wParam
, lParam
);
966 EDIT_UnlockBuffer(wnd
, es
, FALSE
);
968 WIN_ReleaseWndPtr(wnd
);
974 /*********************************************************************
976 * EDIT_BuildLineDefs_ML
978 * Build linked list of text lines.
979 * Lines can end with '\0' (last line), a character (if it is wrapped),
980 * a soft return '\r\r\n' or a hard return '\r\n'
983 static void EDIT_BuildLineDefs_ML(WND
*wnd
, EDITSTATE
*es
)
989 LINEDEF
*current_def
;
990 LINEDEF
**previous_next
;
992 current_def
= es
->first_line_def
;
994 LINEDEF
*next_def
= current_def
->next
;
995 HeapFree(es
->heap
, 0, current_def
);
996 current_def
= next_def
;
997 } while (current_def
);
1001 dc
= GetDC(wnd
->hwndSelf
);
1003 old_font
= SelectObject(dc
, es
->font
);
1005 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
1007 previous_next
= &es
->first_line_def
;
1009 current_def
= HeapAlloc(es
->heap
, 0, sizeof(LINEDEF
));
1010 current_def
->next
= NULL
;
1013 if ((*cp
== '\r') && (*(cp
+ 1) == '\n'))
1018 current_def
->ending
= END_0
;
1019 current_def
->net_length
= strlen(start
);
1020 } else if ((cp
> start
) && (*(cp
- 1) == '\r')) {
1021 current_def
->ending
= END_SOFT
;
1022 current_def
->net_length
= cp
- start
- 1;
1024 current_def
->ending
= END_HARD
;
1025 current_def
->net_length
= cp
- start
;
1027 current_def
->width
= (INT
)LOWORD(GetTabbedTextExtentA(dc
,
1028 start
, current_def
->net_length
,
1029 es
->tabs_count
, es
->tabs
));
1030 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
1031 if ((!(es
->style
& ES_AUTOHSCROLL
)) && (current_def
->width
> fw
)) {
1036 next
= EDIT_CallWordBreakProc(wnd
, es
, start
- es
->text
,
1037 prev
+ 1, current_def
->net_length
, WB_RIGHT
);
1038 current_def
->width
= (INT
)LOWORD(GetTabbedTextExtentA(dc
,
1039 start
, next
, es
->tabs_count
, es
->tabs
));
1040 } while (current_def
->width
<= fw
);
1046 current_def
->width
= (INT
)LOWORD(GetTabbedTextExtentA(dc
,
1047 start
, next
, es
->tabs_count
, es
->tabs
));
1048 } while (current_def
->width
<= fw
);
1052 current_def
->net_length
= prev
;
1053 current_def
->ending
= END_WRAP
;
1054 current_def
->width
= (INT
)LOWORD(GetTabbedTextExtentA(dc
, start
,
1055 current_def
->net_length
, es
->tabs_count
, es
->tabs
));
1057 switch (current_def
->ending
) {
1059 current_def
->length
= current_def
->net_length
+ 3;
1062 current_def
->length
= current_def
->net_length
+ 2;
1066 current_def
->length
= current_def
->net_length
;
1069 es
->text_width
= max(es
->text_width
, current_def
->width
);
1070 start
+= current_def
->length
;
1071 *previous_next
= current_def
;
1072 previous_next
= ¤t_def
->next
;
1074 } while (current_def
->ending
!= END_0
);
1076 SelectObject(dc
, old_font
);
1077 ReleaseDC(wnd
->hwndSelf
, dc
);
1081 /*********************************************************************
1083 * EDIT_CallWordBreakProc
1085 * Call appropriate WordBreakProc (internal or external).
1087 * Note: The "start" argument should always be an index refering
1088 * to es->text. The actual wordbreak proc might be
1089 * 16 bit, so we can't always pass any 32 bit LPSTR.
1090 * Hence we assume that es->text is the buffer that holds
1091 * the string under examination (we can decide this for ourselves).
1094 /* ### start build ### */
1095 extern WORD CALLBACK
EDIT_CallTo16_word_lwww(EDITWORDBREAKPROC16
,SEGPTR
,WORD
,WORD
,WORD
);
1096 /* ### stop build ### */
1097 static INT
EDIT_CallWordBreakProc(WND
*wnd
, EDITSTATE
*es
, INT start
, INT index
, INT count
, INT action
)
1099 if (es
->word_break_proc16
) {
1100 HLOCAL16 hloc16
= EDIT_EM_GetHandle16(wnd
, es
);
1101 SEGPTR segptr
= LocalLock16(hloc16
);
1102 INT ret
= (INT
)EDIT_CallTo16_word_lwww(es
->word_break_proc16
,
1103 segptr
+ start
, index
, count
, action
);
1104 LocalUnlock16(hloc16
);
1107 else if (es
->word_break_proc32A
)
1109 TRACE_(relay
)("(wordbrk=%p,str='%s',idx=%d,cnt=%d,act=%d)\n",
1110 es
->word_break_proc32A
, es
->text
+ start
, index
,
1112 return (INT
)es
->word_break_proc32A( es
->text
+ start
, index
,
1116 return EDIT_WordBreakProc(es
->text
+ start
, index
, count
, action
);
1120 /*********************************************************************
1124 * Beware: This is not the function called on EM_CHARFROMPOS
1125 * The position _can_ be outside the formatting / client
1127 * The return value is only the character index
1130 static INT
EDIT_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT x
, INT y
, LPBOOL after_wrap
)
1136 if (es
->style
& ES_MULTILINE
) {
1137 INT line
= (y
- es
->format_rect
.top
) / es
->line_height
+ es
->y_offset
;
1139 LINEDEF
*line_def
= es
->first_line_def
;
1141 while ((line
> 0) && line_def
->next
) {
1142 line_index
+= line_def
->length
;
1143 line_def
= line_def
->next
;
1146 x
+= es
->x_offset
- es
->format_rect
.left
;
1147 if (x
>= line_def
->width
) {
1149 *after_wrap
= (line_def
->ending
== END_WRAP
);
1150 return line_index
+ line_def
->net_length
;
1154 *after_wrap
= FALSE
;
1157 dc
= GetDC(wnd
->hwndSelf
);
1159 old_font
= SelectObject(dc
, es
->font
);
1160 low
= line_index
+ 1;
1161 high
= line_index
+ line_def
->net_length
+ 1;
1162 while (low
< high
- 1)
1164 INT mid
= (low
+ high
) / 2;
1165 if (LOWORD(GetTabbedTextExtentA(dc
, es
->text
+ line_index
,mid
- line_index
, es
->tabs_count
, es
->tabs
)) > x
) high
= mid
;
1171 *after_wrap
= ((index
== line_index
+ line_def
->net_length
) &&
1172 (line_def
->ending
== END_WRAP
));
1177 *after_wrap
= FALSE
;
1178 x
-= es
->format_rect
.left
;
1180 return es
->x_offset
;
1181 text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
1182 dc
= GetDC(wnd
->hwndSelf
);
1184 old_font
= SelectObject(dc
, es
->font
);
1188 INT high
= es
->x_offset
;
1189 while (low
< high
- 1)
1191 INT mid
= (low
+ high
) / 2;
1192 GetTextExtentPoint32A( dc
, text
+ mid
,
1193 es
->x_offset
- mid
, &size
);
1194 if (size
.cx
> -x
) low
= mid
;
1201 INT low
= es
->x_offset
;
1202 INT high
= strlen(es
->text
) + 1;
1203 while (low
< high
- 1)
1205 INT mid
= (low
+ high
) / 2;
1206 GetTextExtentPoint32A( dc
, text
+ es
->x_offset
,
1207 mid
- es
->x_offset
, &size
);
1208 if (size
.cx
> x
) high
= mid
;
1213 if (es
->style
& ES_PASSWORD
)
1214 HeapFree(es
->heap
, 0 ,text
);
1217 SelectObject(dc
, old_font
);
1218 ReleaseDC(wnd
->hwndSelf
, dc
);
1223 /*********************************************************************
1227 * adjusts the point to be within the formatting rectangle
1228 * (so CharFromPos returns the nearest _visible_ character)
1231 static void EDIT_ConfinePoint(WND
*wnd
, EDITSTATE
*es
, LPINT x
, LPINT y
)
1233 *x
= min(max(*x
, es
->format_rect
.left
), es
->format_rect
.right
- 1);
1234 *y
= min(max(*y
, es
->format_rect
.top
), es
->format_rect
.bottom
- 1);
1238 /*********************************************************************
1242 * Calculates the bounding rectangle for a line from a starting
1243 * column to an ending column.
1246 static void EDIT_GetLineRect(WND
*wnd
, EDITSTATE
*es
, INT line
, INT scol
, INT ecol
, LPRECT rc
)
1248 INT line_index
= EDIT_EM_LineIndex(wnd
, es
, line
);
1250 if (es
->style
& ES_MULTILINE
)
1251 rc
->top
= es
->format_rect
.top
+ (line
- es
->y_offset
) * es
->line_height
;
1253 rc
->top
= es
->format_rect
.top
;
1254 rc
->bottom
= rc
->top
+ es
->line_height
;
1255 rc
->left
= (scol
== 0) ? es
->format_rect
.left
: SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, line_index
+ scol
, TRUE
));
1256 rc
->right
= (ecol
== -1) ? es
->format_rect
.right
: SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, line_index
+ ecol
, TRUE
));
1260 /*********************************************************************
1262 * EDIT_GetPasswordPointer_SL
1264 * note: caller should free the (optionally) allocated buffer
1267 static LPSTR
EDIT_GetPasswordPointer_SL(WND
*wnd
, EDITSTATE
*es
)
1269 if (es
->style
& ES_PASSWORD
) {
1270 INT len
= strlen(es
->text
);
1271 LPSTR text
= HeapAlloc(es
->heap
, 0, len
+ 1);
1272 RtlFillMemory(text
, len
, es
->password_char
);
1280 /*********************************************************************
1284 * This acts as a LOCAL_Lock(), but it locks only once. This way
1285 * you can call it whenever you like, without unlocking.
1288 static void EDIT_LockBuffer(WND
*wnd
, EDITSTATE
*es
)
1291 ERR("no EDITSTATE ... please report\n");
1294 if (!(es
->style
& ES_MULTILINE
))
1298 es
->text
= LocalLock(es
->hloc32
);
1299 else if (es
->hloc16
)
1300 es
->text
= LOCAL_Lock(wnd
->hInstance
, es
->hloc16
);
1302 ERR("no buffer ... please report\n");
1310 /*********************************************************************
1312 * EDIT_SL_InvalidateText
1314 * Called from EDIT_InvalidateText().
1315 * Does the job for single-line controls only.
1318 static void EDIT_SL_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT start
, INT end
)
1323 EDIT_GetLineRect(wnd
, es
, 0, start
, end
, &line_rect
);
1324 if (IntersectRect(&rc
, &line_rect
, &es
->format_rect
))
1325 EDIT_UpdateText(wnd
, &rc
, FALSE
);
1329 /*********************************************************************
1331 * EDIT_ML_InvalidateText
1333 * Called from EDIT_InvalidateText().
1334 * Does the job for multi-line controls only.
1337 static void EDIT_ML_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT start
, INT end
)
1339 INT vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1340 INT sl
= EDIT_EM_LineFromChar(wnd
, es
, start
);
1341 INT el
= EDIT_EM_LineFromChar(wnd
, es
, end
);
1350 if ((el
< es
->y_offset
) || (sl
> es
->y_offset
+ vlc
))
1353 sc
= start
- EDIT_EM_LineIndex(wnd
, es
, sl
);
1354 ec
= end
- EDIT_EM_LineIndex(wnd
, es
, el
);
1355 if (sl
< es
->y_offset
) {
1359 if (el
> es
->y_offset
+ vlc
) {
1360 el
= es
->y_offset
+ vlc
;
1361 ec
= EDIT_EM_LineLength(wnd
, es
, EDIT_EM_LineIndex(wnd
, es
, el
));
1363 GetClientRect(wnd
->hwndSelf
, &rc1
);
1364 IntersectRect(&rcWnd
, &rc1
, &es
->format_rect
);
1366 EDIT_GetLineRect(wnd
, es
, sl
, sc
, ec
, &rcLine
);
1367 if (IntersectRect(&rcUpdate
, &rcWnd
, &rcLine
))
1368 EDIT_UpdateText(wnd
, &rcUpdate
, FALSE
);
1370 EDIT_GetLineRect(wnd
, es
, sl
, sc
,
1371 EDIT_EM_LineLength(wnd
, es
,
1372 EDIT_EM_LineIndex(wnd
, es
, sl
)),
1374 if (IntersectRect(&rcUpdate
, &rcWnd
, &rcLine
))
1375 EDIT_UpdateText(wnd
, &rcUpdate
, FALSE
);
1376 for (l
= sl
+ 1 ; l
< el
; l
++) {
1377 EDIT_GetLineRect(wnd
, es
, l
, 0,
1378 EDIT_EM_LineLength(wnd
, es
,
1379 EDIT_EM_LineIndex(wnd
, es
, l
)),
1381 if (IntersectRect(&rcUpdate
, &rcWnd
, &rcLine
))
1382 EDIT_UpdateText(wnd
, &rcUpdate
, FALSE
);
1384 EDIT_GetLineRect(wnd
, es
, el
, 0, ec
, &rcLine
);
1385 if (IntersectRect(&rcUpdate
, &rcWnd
, &rcLine
))
1386 EDIT_UpdateText(wnd
, &rcUpdate
, FALSE
);
1391 /*********************************************************************
1393 * EDIT_InvalidateText
1395 * Invalidate the text from offset start upto, but not including,
1396 * offset end. Useful for (re)painting the selection.
1397 * Regions outside the linewidth are not invalidated.
1398 * end == -1 means end == TextLength.
1399 * start and end need not be ordered.
1402 static void EDIT_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT start
, INT end
)
1408 end
= strlen(es
->text
);
1410 ORDER_INT(start
, end
);
1412 if (es
->style
& ES_MULTILINE
)
1413 EDIT_ML_InvalidateText(wnd
, es
, start
, end
);
1415 EDIT_SL_InvalidateText(wnd
, es
, start
, end
);
1419 /*********************************************************************
1423 * Try to fit size + 1 bytes in the buffer. Constrain to limits.
1426 static BOOL
EDIT_MakeFit(WND
*wnd
, EDITSTATE
*es
, INT size
)
1431 if (size
<= es
->buffer_size
)
1433 if (size
> es
->buffer_limit
) {
1434 EDIT_NOTIFY_PARENT(wnd
, EN_MAXTEXT
, "EN_MAXTEXT");
1437 size
= ((size
/ GROWLENGTH
) + 1) * GROWLENGTH
;
1438 if (size
> es
->buffer_limit
)
1439 size
= es
->buffer_limit
;
1441 TRACE("trying to ReAlloc to %d+1\n", size
);
1443 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
1445 if ((es
->text
= HeapReAlloc(es
->heap
, 0, es
->text
, size
+ 1)))
1446 es
->buffer_size
= min(HeapSize(es
->heap
, 0, es
->text
) - 1, es
->buffer_limit
);
1448 es
->buffer_size
= 0;
1449 } else if (es
->hloc32
) {
1450 if ((hNew32
= LocalReAlloc(es
->hloc32
, size
+ 1, 0))) {
1451 TRACE("Old 32 bit handle %08x, new handle %08x\n", es
->hloc32
, hNew32
);
1452 es
->hloc32
= hNew32
;
1453 es
->buffer_size
= min(LocalSize(es
->hloc32
) - 1, es
->buffer_limit
);
1455 } else if (es
->hloc16
) {
1456 if ((hNew16
= LOCAL_ReAlloc(wnd
->hInstance
, es
->hloc16
, size
+ 1, LMEM_MOVEABLE
))) {
1457 TRACE("Old 16 bit handle %08x, new handle %08x\n", es
->hloc16
, hNew16
);
1458 es
->hloc16
= hNew16
;
1459 es
->buffer_size
= min(LOCAL_Size(wnd
->hInstance
, es
->hloc16
) - 1, es
->buffer_limit
);
1462 if (es
->buffer_size
< size
) {
1463 EDIT_LockBuffer(wnd
, es
);
1464 WARN("FAILED ! We now have %d+1\n", es
->buffer_size
);
1465 EDIT_NOTIFY_PARENT(wnd
, EN_ERRSPACE
, "EN_ERRSPACE");
1468 EDIT_LockBuffer(wnd
, es
);
1469 TRACE("We now have %d+1\n", es
->buffer_size
);
1475 /*********************************************************************
1479 * Try to fit size + 1 bytes in the undo buffer.
1482 static BOOL
EDIT_MakeUndoFit(WND
*wnd
, EDITSTATE
*es
, INT size
)
1484 if (size
<= es
->undo_buffer_size
)
1486 size
= ((size
/ GROWLENGTH
) + 1) * GROWLENGTH
;
1488 TRACE("trying to ReAlloc to %d+1\n", size
);
1490 if ((es
->undo_text
= HeapReAlloc(es
->heap
, 0, es
->undo_text
, size
+ 1))) {
1491 es
->undo_buffer_size
= HeapSize(es
->heap
, 0, es
->undo_text
) - 1;
1492 if (es
->undo_buffer_size
< size
) {
1493 WARN("FAILED ! We now have %d+1\n", es
->undo_buffer_size
);
1502 /*********************************************************************
1507 static void EDIT_MoveBackward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1509 INT e
= es
->selection_end
;
1513 if ((es
->style
& ES_MULTILINE
) && e
&&
1514 (es
->text
[e
- 1] == '\r') && (es
->text
[e
] == '\n')) {
1516 if (e
&& (es
->text
[e
- 1] == '\r'))
1520 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1521 EDIT_EM_ScrollCaret(wnd
, es
);
1525 /*********************************************************************
1529 * Only for multi line controls
1530 * Move the caret one line down, on a column with the nearest
1531 * x coordinate on the screen (might be a different column).
1534 static void EDIT_MoveDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1536 INT s
= es
->selection_start
;
1537 INT e
= es
->selection_end
;
1538 BOOL after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1539 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1540 INT x
= SLOWORD(pos
);
1541 INT y
= SHIWORD(pos
);
1543 e
= EDIT_CharFromPos(wnd
, es
, x
, y
+ es
->line_height
, &after_wrap
);
1546 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1547 EDIT_EM_ScrollCaret(wnd
, es
);
1551 /*********************************************************************
1556 static void EDIT_MoveEnd(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1558 BOOL after_wrap
= FALSE
;
1561 /* Pass a high value in x to make sure of receiving the en of the line */
1562 if (es
->style
& ES_MULTILINE
)
1563 e
= EDIT_CharFromPos(wnd
, es
, 0x3fffffff,
1564 HIWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
)), &after_wrap
);
1566 e
= strlen(es
->text
);
1567 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, after_wrap
);
1568 EDIT_EM_ScrollCaret(wnd
, es
);
1572 /*********************************************************************
1577 static void EDIT_MoveForward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1579 INT e
= es
->selection_end
;
1583 if ((es
->style
& ES_MULTILINE
) && (es
->text
[e
- 1] == '\r')) {
1584 if (es
->text
[e
] == '\n')
1586 else if ((es
->text
[e
] == '\r') && (es
->text
[e
+ 1] == '\n'))
1590 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1591 EDIT_EM_ScrollCaret(wnd
, es
);
1595 /*********************************************************************
1599 * Home key: move to beginning of line.
1602 static void EDIT_MoveHome(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1606 /* Pass the x_offset in x to make sure of receiving the first position of the line */
1607 if (es
->style
& ES_MULTILINE
)
1608 e
= EDIT_CharFromPos(wnd
, es
, -es
->x_offset
,
1609 HIWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
)), NULL
);
1612 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1613 EDIT_EM_ScrollCaret(wnd
, es
);
1617 /*********************************************************************
1619 * EDIT_MovePageDown_ML
1621 * Only for multi line controls
1622 * Move the caret one page down, on a column with the nearest
1623 * x coordinate on the screen (might be a different column).
1626 static void EDIT_MovePageDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1628 INT s
= es
->selection_start
;
1629 INT e
= es
->selection_end
;
1630 BOOL after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1631 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1632 INT x
= SLOWORD(pos
);
1633 INT y
= SHIWORD(pos
);
1635 e
= EDIT_CharFromPos(wnd
, es
, x
,
1636 y
+ (es
->format_rect
.bottom
- es
->format_rect
.top
),
1640 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1641 EDIT_EM_ScrollCaret(wnd
, es
);
1645 /*********************************************************************
1647 * EDIT_MovePageUp_ML
1649 * Only for multi line controls
1650 * Move the caret one page up, on a column with the nearest
1651 * x coordinate on the screen (might be a different column).
1654 static void EDIT_MovePageUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1656 INT s
= es
->selection_start
;
1657 INT e
= es
->selection_end
;
1658 BOOL after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1659 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1660 INT x
= SLOWORD(pos
);
1661 INT y
= SHIWORD(pos
);
1663 e
= EDIT_CharFromPos(wnd
, es
, x
,
1664 y
- (es
->format_rect
.bottom
- es
->format_rect
.top
),
1668 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1669 EDIT_EM_ScrollCaret(wnd
, es
);
1673 /*********************************************************************
1677 * Only for multi line controls
1678 * Move the caret one line up, on a column with the nearest
1679 * x coordinate on the screen (might be a different column).
1682 static void EDIT_MoveUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1684 INT s
= es
->selection_start
;
1685 INT e
= es
->selection_end
;
1686 BOOL after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1687 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1688 INT x
= SLOWORD(pos
);
1689 INT y
= SHIWORD(pos
);
1691 e
= EDIT_CharFromPos(wnd
, es
, x
, y
- es
->line_height
, &after_wrap
);
1694 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1695 EDIT_EM_ScrollCaret(wnd
, es
);
1699 /*********************************************************************
1701 * EDIT_MoveWordBackward
1704 static void EDIT_MoveWordBackward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1706 INT s
= es
->selection_start
;
1707 INT e
= es
->selection_end
;
1712 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
1713 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
1714 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1717 li
= EDIT_EM_LineIndex(wnd
, es
, l
- 1);
1718 e
= li
+ EDIT_EM_LineLength(wnd
, es
, li
);
1721 e
= li
+ (INT
)EDIT_CallWordBreakProc(wnd
, es
,
1722 li
, e
- li
, ll
, WB_LEFT
);
1726 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
1727 EDIT_EM_ScrollCaret(wnd
, es
);
1731 /*********************************************************************
1733 * EDIT_MoveWordForward
1736 static void EDIT_MoveWordForward(WND
*wnd
, EDITSTATE
*es
, BOOL extend
)
1738 INT s
= es
->selection_start
;
1739 INT e
= es
->selection_end
;
1744 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
1745 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
1746 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1748 if ((es
->style
& ES_MULTILINE
) && (l
!= es
->line_count
- 1))
1749 e
= EDIT_EM_LineIndex(wnd
, es
, l
+ 1);
1751 e
= li
+ EDIT_CallWordBreakProc(wnd
, es
,
1752 li
, e
- li
+ 1, ll
, WB_RIGHT
);
1756 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
1757 EDIT_EM_ScrollCaret(wnd
, es
);
1761 /*********************************************************************
1766 static void EDIT_PaintLine(WND
*wnd
, EDITSTATE
*es
, HDC dc
, INT line
, BOOL rev
)
1768 INT s
= es
->selection_start
;
1769 INT e
= es
->selection_end
;
1776 if (es
->style
& ES_MULTILINE
) {
1777 INT vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1778 if ((line
< es
->y_offset
) || (line
> es
->y_offset
+ vlc
) || (line
>= es
->line_count
))
1783 TRACE("line=%d\n", line
);
1785 pos
= EDIT_EM_PosFromChar(wnd
, es
, EDIT_EM_LineIndex(wnd
, es
, line
), FALSE
);
1788 li
= EDIT_EM_LineIndex(wnd
, es
, line
);
1789 ll
= EDIT_EM_LineLength(wnd
, es
, li
);
1790 s
= es
->selection_start
;
1791 e
= es
->selection_end
;
1793 s
= min(li
+ ll
, max(li
, s
));
1794 e
= min(li
+ ll
, max(li
, e
));
1795 if (rev
&& (s
!= e
) &&
1796 ((es
->flags
& EF_FOCUSED
) || (es
->style
& ES_NOHIDESEL
))) {
1797 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, 0, s
- li
, FALSE
);
1798 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, s
- li
, e
- s
, TRUE
);
1799 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, e
- li
, li
+ ll
- e
, FALSE
);
1801 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, 0, ll
, FALSE
);
1805 /*********************************************************************
1810 static INT
EDIT_PaintText(WND
*wnd
, EDITSTATE
*es
, HDC dc
, INT x
, INT y
, INT line
, INT col
, INT count
, BOOL rev
)
1820 BkColor
= GetBkColor(dc
);
1821 TextColor
= GetTextColor(dc
);
1823 SetBkColor(dc
, GetSysColor(COLOR_HIGHLIGHT
));
1824 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1826 li
= EDIT_EM_LineIndex(wnd
, es
, line
);
1827 if (es
->style
& ES_MULTILINE
) {
1828 ret
= (INT
)LOWORD(TabbedTextOutA(dc
, x
, y
, es
->text
+ li
+ col
, count
,
1829 es
->tabs_count
, es
->tabs
, es
->format_rect
.left
- es
->x_offset
));
1831 LPSTR text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
1832 TextOutA(dc
, x
, y
, text
+ li
+ col
, count
);
1833 GetTextExtentPoint32A(dc
, text
+ li
+ col
, count
, &size
);
1835 if (es
->style
& ES_PASSWORD
)
1836 HeapFree(es
->heap
, 0, text
);
1839 SetBkColor(dc
, BkColor
);
1840 SetTextColor(dc
, TextColor
);
1846 /*********************************************************************
1851 static void EDIT_SetCaretPos(WND
*wnd
, EDITSTATE
*es
, INT pos
,
1854 LRESULT res
= EDIT_EM_PosFromChar(wnd
, es
, pos
, after_wrap
);
1855 INT x
= SLOWORD(res
);
1856 INT y
= SHIWORD(res
);
1858 if(x
< es
->format_rect
.left
)
1859 x
= es
->format_rect
.left
;
1860 if(x
> es
->format_rect
.right
- 2)
1861 x
= es
->format_rect
.right
- 2;
1862 if(y
> es
->format_rect
.bottom
)
1863 y
= es
->format_rect
.bottom
;
1864 if(y
< es
->format_rect
.top
)
1865 y
= es
->format_rect
.top
;
1871 /*********************************************************************
1875 * note: this is not (exactly) the handler called on EM_SETRECTNP
1876 * it is also used to set the rect of a single line control
1879 static void EDIT_SetRectNP(WND
*wnd
, EDITSTATE
*es
, LPRECT rc
)
1881 CopyRect(&es
->format_rect
, rc
);
1882 if (es
->style
& WS_BORDER
) {
1883 INT bw
= GetSystemMetrics(SM_CXBORDER
) + 1;
1884 if(TWEAK_WineLook
== WIN31_LOOK
)
1886 es
->format_rect
.left
+= bw
;
1887 es
->format_rect
.top
+= bw
;
1888 es
->format_rect
.right
-= bw
;
1889 es
->format_rect
.bottom
-= bw
;
1891 es
->format_rect
.left
+= es
->left_margin
;
1892 es
->format_rect
.right
-= es
->right_margin
;
1893 es
->format_rect
.right
= max(es
->format_rect
.right
, es
->format_rect
.left
+ es
->char_width
);
1894 if (es
->style
& ES_MULTILINE
)
1895 es
->format_rect
.bottom
= es
->format_rect
.top
+
1896 max(1, (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
) * es
->line_height
;
1898 es
->format_rect
.bottom
= es
->format_rect
.top
+ es
->line_height
;
1899 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
))
1900 EDIT_BuildLineDefs_ML(wnd
, es
);
1904 /*********************************************************************
1909 static void EDIT_UnlockBuffer(WND
*wnd
, EDITSTATE
*es
, BOOL force
)
1912 ERR("no EDITSTATE ... please report\n");
1915 if (!(es
->style
& ES_MULTILINE
))
1917 if (!es
->lock_count
) {
1918 ERR("lock_count == 0 ... please report\n");
1922 ERR("es->text == 0 ... please report\n");
1925 if (force
|| (es
->lock_count
== 1)) {
1927 LocalUnlock(es
->hloc32
);
1929 } else if (es
->hloc16
) {
1930 LOCAL_Unlock(wnd
->hInstance
, es
->hloc16
);
1938 /*********************************************************************
1940 * EDIT_WordBreakProc
1942 * Find the beginning of words.
1943 * Note: unlike the specs for a WordBreakProc, this function only
1944 * allows to be called without linebreaks between s[0] upto
1945 * s[count - 1]. Remember it is only called
1946 * internally, so we can decide this for ourselves.
1949 static INT
EDIT_WordBreakProc(LPSTR s
, INT index
, INT count
, INT action
)
1953 TRACE("s=%p, index=%u, count=%u, action=%d\n",
1954 s
, index
, count
, action
);
1962 if (s
[index
] == ' ') {
1963 while (index
&& (s
[index
] == ' '))
1966 while (index
&& (s
[index
] != ' '))
1968 if (s
[index
] == ' ')
1972 while (index
&& (s
[index
] != ' '))
1974 if (s
[index
] == ' ')
1984 if (s
[index
] == ' ')
1985 while ((index
< count
) && (s
[index
] == ' ')) index
++;
1987 while (s
[index
] && (s
[index
] != ' ') && (index
< count
))
1989 while ((s
[index
] == ' ') && (index
< count
)) index
++;
1993 case WB_ISDELIMITER
:
1994 ret
= (s
[index
] == ' ');
1997 ERR("unknown action code, please report !\n");
2004 /*********************************************************************
2008 * returns line number (not index) in high-order word of result.
2009 * NB : Q137805 is unclear about this. POINT * pointer in lParam apply
2010 * to Richedit, not to the edit control. Original documentation is valid.
2011 * FIXME: do the specs mean to return -1 if outside client area or
2012 * if outside formatting rectangle ???
2015 static LRESULT
EDIT_EM_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT x
, INT y
)
2023 GetClientRect(wnd
->hwndSelf
, &rc
);
2024 if (!PtInRect(&rc
, pt
))
2027 index
= EDIT_CharFromPos(wnd
, es
, x
, y
, NULL
);
2028 return MAKELONG(index
, EDIT_EM_LineFromChar(wnd
, es
, index
));
2032 /*********************************************************************
2036 * Enable or disable soft breaks.
2038 static BOOL
EDIT_EM_FmtLines(WND
*wnd
, EDITSTATE
*es
, BOOL add_eol
)
2040 es
->flags
&= ~EF_USE_SOFTBRK
;
2042 es
->flags
|= EF_USE_SOFTBRK
;
2043 FIXME("soft break enabled, not implemented\n");
2049 /*********************************************************************
2053 * Hopefully this won't fire back at us.
2054 * We always start with a fixed buffer in our own heap.
2055 * However, with this message a 32 bit application requests
2056 * a handle to 32 bit moveable local heap memory, where it expects
2058 * It's a pity that from this moment on we have to use this
2059 * local heap, because applications may rely on the handle
2062 * In this function we'll try to switch to local heap.
2065 static HLOCAL
EDIT_EM_GetHandle(WND
*wnd
, EDITSTATE
*es
)
2071 if (!(es
->style
& ES_MULTILINE
))
2076 else if (es
->hloc16
)
2077 return (HLOCAL
)es
->hloc16
;
2079 if (!(newBuf
= LocalAlloc(LMEM_MOVEABLE
, strlen(es
->text
) + 1))) {
2080 ERR("could not allocate new 32 bit buffer\n");
2083 newSize
= min(LocalSize(newBuf
) - 1, es
->buffer_limit
);
2084 if (!(newText
= LocalLock(newBuf
))) {
2085 ERR("could not lock new 32 bit buffer\n");
2089 strcpy(newText
, es
->text
);
2090 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2092 HeapFree(es
->heap
, 0, es
->text
);
2093 es
->hloc32
= newBuf
;
2094 es
->hloc16
= (HLOCAL16
)NULL
;
2095 es
->buffer_size
= newSize
;
2097 EDIT_LockBuffer(wnd
, es
);
2098 TRACE("switched to 32 bit local heap\n");
2104 /*********************************************************************
2108 * Hopefully this won't fire back at us.
2109 * We always start with a buffer in 32 bit linear memory.
2110 * However, with this message a 16 bit application requests
2111 * a handle of 16 bit local heap memory, where it expects to find
2113 * It's a pitty that from this moment on we have to use this
2114 * local heap, because applications may rely on the handle
2117 * In this function we'll try to switch to local heap.
2119 static HLOCAL16
EDIT_EM_GetHandle16(WND
*wnd
, EDITSTATE
*es
)
2125 if (!(es
->style
& ES_MULTILINE
))
2131 if (!LOCAL_HeapSize(wnd
->hInstance
)) {
2132 if (!LocalInit16(wnd
->hInstance
, 0,
2133 GlobalSize16(wnd
->hInstance
))) {
2134 ERR("could not initialize local heap\n");
2137 TRACE("local heap initialized\n");
2139 if (!(newBuf
= LOCAL_Alloc(wnd
->hInstance
, LMEM_MOVEABLE
, strlen(es
->text
) + 1))) {
2140 ERR("could not allocate new 16 bit buffer\n");
2143 newSize
= min(LOCAL_Size(wnd
->hInstance
, newBuf
) - 1, es
->buffer_limit
);
2144 if (!(newText
= LOCAL_Lock(wnd
->hInstance
, newBuf
))) {
2145 ERR("could not lock new 16 bit buffer\n");
2146 LOCAL_Free(wnd
->hInstance
, newBuf
);
2149 strcpy(newText
, es
->text
);
2150 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2152 HeapFree(es
->heap
, 0, es
->text
);
2153 else if (es
->hloc32
) {
2154 while (LocalFree(es
->hloc32
)) ;
2155 LocalFree(es
->hloc32
);
2157 es
->hloc32
= (HLOCAL
)NULL
;
2158 es
->hloc16
= newBuf
;
2159 es
->buffer_size
= newSize
;
2161 EDIT_LockBuffer(wnd
, es
);
2162 TRACE("switched to 16 bit buffer\n");
2168 /*********************************************************************
2173 static INT
EDIT_EM_GetLine(WND
*wnd
, EDITSTATE
*es
, INT line
, LPSTR lpch
)
2179 if (es
->style
& ES_MULTILINE
) {
2180 if (line
>= es
->line_count
)
2184 i
= EDIT_EM_LineIndex(wnd
, es
, line
);
2186 len
= min(*(WORD
*)lpch
, EDIT_EM_LineLength(wnd
, es
, i
));
2187 for (i
= 0 ; i
< len
; i
++) {
2192 return (LRESULT
)len
;
2196 /*********************************************************************
2201 static LRESULT
EDIT_EM_GetSel(WND
*wnd
, EDITSTATE
*es
, LPUINT start
, LPUINT end
)
2203 UINT s
= es
->selection_start
;
2204 UINT e
= es
->selection_end
;
2211 return MAKELONG(s
, e
);
2215 /*********************************************************************
2219 * FIXME: is this right ? (or should it be only VSCROLL)
2220 * (and maybe only for edit controls that really have their
2221 * own scrollbars) (and maybe only for multiline controls ?)
2222 * All in all: very poorly documented
2224 * FIXME: now it's also broken, because of the new WM_HSCROLL /
2225 * WM_VSCROLL handlers
2228 static LRESULT
EDIT_EM_GetThumb(WND
*wnd
, EDITSTATE
*es
)
2230 return MAKELONG(EDIT_WM_VScroll(wnd
, es
, EM_GETTHUMB16
, 0, 0),
2231 EDIT_WM_HScroll(wnd
, es
, EM_GETTHUMB16
, 0, 0));
2235 /*********************************************************************
2240 static INT
EDIT_EM_LineFromChar(WND
*wnd
, EDITSTATE
*es
, INT index
)
2245 if (!(es
->style
& ES_MULTILINE
))
2247 if (index
> strlen(es
->text
))
2248 return es
->line_count
- 1;
2250 index
= min(es
->selection_start
, es
->selection_end
);
2253 line_def
= es
->first_line_def
;
2254 index
-= line_def
->length
;
2255 while ((index
>= 0) && line_def
->next
) {
2257 line_def
= line_def
->next
;
2258 index
-= line_def
->length
;
2264 /*********************************************************************
2269 static INT
EDIT_EM_LineIndex(WND
*wnd
, EDITSTATE
*es
, INT line
)
2274 if (!(es
->style
& ES_MULTILINE
))
2276 if (line
>= es
->line_count
)
2280 line_def
= es
->first_line_def
;
2282 INT index
= es
->selection_end
- line_def
->length
;
2283 while ((index
>= 0) && line_def
->next
) {
2284 line_index
+= line_def
->length
;
2285 line_def
= line_def
->next
;
2286 index
-= line_def
->length
;
2290 line_index
+= line_def
->length
;
2291 line_def
= line_def
->next
;
2299 /*********************************************************************
2304 static INT
EDIT_EM_LineLength(WND
*wnd
, EDITSTATE
*es
, INT index
)
2308 if (!(es
->style
& ES_MULTILINE
))
2309 return strlen(es
->text
);
2312 /* get the number of remaining non-selected chars of selected lines */
2315 li
= EDIT_EM_LineFromChar(wnd
, es
, es
->selection_start
);
2316 /* # chars before start of selection area */
2317 count
= es
->selection_start
- EDIT_EM_LineIndex(wnd
, es
, li
);
2318 li
= EDIT_EM_LineFromChar(wnd
, es
, es
->selection_end
);
2319 /* # chars after end of selection */
2320 count
+= EDIT_EM_LineIndex(wnd
, es
, li
) +
2321 EDIT_EM_LineLength(wnd
, es
, li
) - es
->selection_end
;
2324 line_def
= es
->first_line_def
;
2325 index
-= line_def
->length
;
2326 while ((index
>= 0) && line_def
->next
) {
2327 line_def
= line_def
->next
;
2328 index
-= line_def
->length
;
2330 return line_def
->net_length
;
2334 /*********************************************************************
2338 * FIXME: dx is in average character widths
2339 * However, we assume it is in pixels when we use this
2340 * function internally
2343 static BOOL
EDIT_EM_LineScroll(WND
*wnd
, EDITSTATE
*es
, INT dx
, INT dy
)
2347 if (!(es
->style
& ES_MULTILINE
))
2350 if (-dx
> es
->x_offset
)
2352 if (dx
> es
->text_width
- es
->x_offset
)
2353 dx
= es
->text_width
- es
->x_offset
;
2354 nyoff
= max(0, es
->y_offset
+ dy
);
2355 if (nyoff
>= es
->line_count
)
2356 nyoff
= es
->line_count
- 1;
2357 dy
= (es
->y_offset
- nyoff
) * es
->line_height
;
2361 GetClientRect(wnd
->hwndSelf
, &rc1
);
2362 IntersectRect(&rc
, &rc1
, &es
->format_rect
);
2363 ScrollWindowEx(wnd
->hwndSelf
, -dx
, dy
,
2364 NULL
, &rc
, (HRGN
)NULL
, NULL
, SW_INVALIDATE
);
2365 es
->y_offset
= nyoff
;
2368 if (dx
&& !(es
->flags
& EF_HSCROLL_TRACK
))
2369 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
2370 if (dy
&& !(es
->flags
& EF_VSCROLL_TRACK
))
2371 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
2376 /*********************************************************************
2381 static LRESULT
EDIT_EM_PosFromChar(WND
*wnd
, EDITSTATE
*es
, INT index
, BOOL after_wrap
)
2383 INT len
= strlen(es
->text
);
2392 index
= min(index
, len
);
2393 dc
= GetDC(wnd
->hwndSelf
);
2395 old_font
= SelectObject(dc
, es
->font
);
2396 if (es
->style
& ES_MULTILINE
) {
2397 l
= EDIT_EM_LineFromChar(wnd
, es
, index
);
2398 y
= (l
- es
->y_offset
) * es
->line_height
;
2399 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2400 if (after_wrap
&& (li
== index
) && l
) {
2402 LINEDEF
*line_def
= es
->first_line_def
;
2404 line_def
= line_def
->next
;
2407 if (line_def
->ending
== END_WRAP
) {
2409 y
-= es
->line_height
;
2410 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2413 x
= LOWORD(GetTabbedTextExtentA(dc
, es
->text
+ li
, index
- li
,
2414 es
->tabs_count
, es
->tabs
)) - es
->x_offset
;
2416 LPSTR text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
2417 if (index
< es
->x_offset
) {
2418 GetTextExtentPoint32A(dc
, text
+ index
,
2419 es
->x_offset
- index
, &size
);
2422 GetTextExtentPoint32A(dc
, text
+ es
->x_offset
,
2423 index
- es
->x_offset
, &size
);
2427 if (es
->style
& ES_PASSWORD
)
2428 HeapFree(es
->heap
, 0 ,text
);
2430 x
+= es
->format_rect
.left
;
2431 y
+= es
->format_rect
.top
;
2433 SelectObject(dc
, old_font
);
2434 ReleaseDC(wnd
->hwndSelf
, dc
);
2435 return MAKELONG((INT16
)x
, (INT16
)y
);
2439 /*********************************************************************
2443 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here
2446 static void EDIT_EM_ReplaceSel(WND
*wnd
, EDITSTATE
*es
, BOOL can_undo
, LPCSTR lpsz_replace
)
2448 INT strl
= strlen(lpsz_replace
);
2449 INT tl
= strlen(es
->text
);
2456 s
= es
->selection_start
;
2457 e
= es
->selection_end
;
2459 if ((s
== e
) && !strl
)
2464 if (!EDIT_MakeFit(wnd
, es
, tl
- (e
- s
) + strl
))
2468 /* there is something to be deleted */
2470 utl
= strlen(es
->undo_text
);
2471 if (!es
->undo_insert_count
&& (*es
->undo_text
&& (s
== es
->undo_position
))) {
2472 /* undo-buffer is extended to the right */
2473 EDIT_MakeUndoFit(wnd
, es
, utl
+ e
- s
);
2474 lstrcpynA(es
->undo_text
+ utl
, es
->text
+ s
, e
- s
+ 1);
2475 } else if (!es
->undo_insert_count
&& (*es
->undo_text
&& (e
== es
->undo_position
))) {
2476 /* undo-buffer is extended to the left */
2477 EDIT_MakeUndoFit(wnd
, es
, utl
+ e
- s
);
2478 for (p
= es
->undo_text
+ utl
; p
>= es
->undo_text
; p
--)
2480 for (i
= 0 , p
= es
->undo_text
; i
< e
- s
; i
++)
2481 p
[i
] = (es
->text
+ s
)[i
];
2482 es
->undo_position
= s
;
2484 /* new undo-buffer */
2485 EDIT_MakeUndoFit(wnd
, es
, e
- s
);
2486 lstrcpynA(es
->undo_text
, es
->text
+ s
, e
- s
+ 1);
2487 es
->undo_position
= s
;
2489 /* any deletion makes the old insertion-undo invalid */
2490 es
->undo_insert_count
= 0;
2492 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2495 strcpy(es
->text
+ s
, es
->text
+ e
);
2498 /* there is an insertion */
2500 if ((s
== es
->undo_position
) ||
2501 ((es
->undo_insert_count
) &&
2502 (s
== es
->undo_position
+ es
->undo_insert_count
)))
2504 * insertion is new and at delete position or
2505 * an extension to either left or right
2507 es
->undo_insert_count
+= strl
;
2509 /* new insertion undo */
2510 es
->undo_position
= s
;
2511 es
->undo_insert_count
= strl
;
2512 /* new insertion makes old delete-buffer invalid */
2513 *es
->undo_text
= '\0';
2516 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2519 tl
= strlen(es
->text
);
2520 for (p
= es
->text
+ tl
; p
>= es
->text
+ s
; p
--)
2522 for (i
= 0 , p
= es
->text
+ s
; i
< strl
; i
++)
2523 p
[i
] = lpsz_replace
[i
];
2524 if(es
->style
& ES_UPPERCASE
)
2525 CharUpperBuffA(p
, strl
);
2526 else if(es
->style
& ES_LOWERCASE
)
2527 CharLowerBuffA(p
, strl
);
2530 /* FIXME: really inefficient */
2531 if (es
->style
& ES_MULTILINE
)
2532 EDIT_BuildLineDefs_ML(wnd
, es
);
2534 EDIT_EM_SetSel(wnd
, es
, s
, s
, FALSE
);
2535 es
->flags
|= EF_MODIFIED
;
2536 es
->flags
|= EF_UPDATE
;
2537 EDIT_EM_ScrollCaret(wnd
, es
);
2539 /* FIXME: really inefficient */
2540 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2544 /*********************************************************************
2549 static LRESULT
EDIT_EM_Scroll(WND
*wnd
, EDITSTATE
*es
, INT action
)
2553 if (!(es
->style
& ES_MULTILINE
))
2554 return (LRESULT
)FALSE
;
2564 if (es
->y_offset
< es
->line_count
- 1)
2569 dy
= -(es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2572 if (es
->y_offset
< es
->line_count
- 1)
2573 dy
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2576 return (LRESULT
)FALSE
;
2579 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
2580 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
2582 return MAKELONG((INT16
)dy
, (BOOL16
)TRUE
);
2586 /*********************************************************************
2591 static void EDIT_EM_ScrollCaret(WND
*wnd
, EDITSTATE
*es
)
2593 if (es
->style
& ES_MULTILINE
) {
2598 INT cw
= es
->char_width
;
2603 l
= EDIT_EM_LineFromChar(wnd
, es
, es
->selection_end
);
2604 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2605 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
));
2606 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2607 if (l
>= es
->y_offset
+ vlc
)
2608 dy
= l
- vlc
+ 1 - es
->y_offset
;
2609 if (l
< es
->y_offset
)
2610 dy
= l
- es
->y_offset
;
2611 ww
= es
->format_rect
.right
- es
->format_rect
.left
;
2612 if (x
< es
->format_rect
.left
)
2613 dx
= x
- es
->format_rect
.left
- ww
/ HSCROLL_FRACTION
/ cw
* cw
;
2614 if (x
> es
->format_rect
.right
)
2615 dx
= x
- es
->format_rect
.left
- (HSCROLL_FRACTION
- 1) * ww
/ HSCROLL_FRACTION
/ cw
* cw
;
2617 EDIT_EM_LineScroll(wnd
, es
, dx
, dy
);
2623 if (!(es
->style
& ES_AUTOHSCROLL
))
2626 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
2627 format_width
= es
->format_rect
.right
- es
->format_rect
.left
;
2628 if (x
< es
->format_rect
.left
) {
2629 goal
= es
->format_rect
.left
+ format_width
/ HSCROLL_FRACTION
;
2632 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
2633 } while ((x
< goal
) && es
->x_offset
);
2634 /* FIXME: use ScrollWindow() somehow to improve performance */
2635 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2636 } else if (x
> es
->format_rect
.right
) {
2638 INT len
= strlen(es
->text
);
2639 goal
= es
->format_rect
.right
- format_width
/ HSCROLL_FRACTION
;
2642 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
2643 x_last
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, len
, FALSE
));
2644 } while ((x
> goal
) && (x_last
> es
->format_rect
.right
));
2645 /* FIXME: use ScrollWindow() somehow to improve performance */
2646 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2652 /*********************************************************************
2656 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2659 static void EDIT_EM_SetHandle(WND
*wnd
, EDITSTATE
*es
, HLOCAL hloc
)
2661 if (!(es
->style
& ES_MULTILINE
))
2665 WARN("called with NULL handle\n");
2669 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2671 * old buffer is freed by caller, unless
2672 * it is still in our own heap. (in that case
2673 * we free it, correcting the buggy caller.)
2676 HeapFree(es
->heap
, 0, es
->text
);
2678 es
->hloc16
= (HLOCAL16
)NULL
;
2681 es
->buffer_size
= LocalSize(es
->hloc32
) - 1;
2682 EDIT_LockBuffer(wnd
, es
);
2684 es
->x_offset
= es
->y_offset
= 0;
2685 es
->selection_start
= es
->selection_end
= 0;
2686 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2687 es
->flags
&= ~EF_MODIFIED
;
2688 es
->flags
&= ~EF_UPDATE
;
2689 EDIT_BuildLineDefs_ML(wnd
, es
);
2690 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2691 EDIT_EM_ScrollCaret(wnd
, es
);
2695 /*********************************************************************
2699 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2702 static void EDIT_EM_SetHandle16(WND
*wnd
, EDITSTATE
*es
, HLOCAL16 hloc
)
2704 if (!(es
->style
& ES_MULTILINE
))
2708 WARN("called with NULL handle\n");
2712 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2714 * old buffer is freed by caller, unless
2715 * it is still in our own heap. (in that case
2716 * we free it, correcting the buggy caller.)
2719 HeapFree(es
->heap
, 0, es
->text
);
2722 es
->hloc32
= (HLOCAL
)NULL
;
2724 es
->buffer_size
= LOCAL_Size(wnd
->hInstance
, es
->hloc16
) - 1;
2725 EDIT_LockBuffer(wnd
, es
);
2727 es
->x_offset
= es
->y_offset
= 0;
2728 es
->selection_start
= es
->selection_end
= 0;
2729 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2730 es
->flags
&= ~EF_MODIFIED
;
2731 es
->flags
&= ~EF_UPDATE
;
2732 EDIT_BuildLineDefs_ML(wnd
, es
);
2733 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2734 EDIT_EM_ScrollCaret(wnd
, es
);
2738 /*********************************************************************
2742 * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
2743 * However, the windows version is not complied to yet in all of edit.c
2746 static void EDIT_EM_SetLimitText(WND
*wnd
, EDITSTATE
*es
, INT limit
)
2748 if (es
->style
& ES_MULTILINE
) {
2750 es
->buffer_limit
= min(limit
, BUFLIMIT_MULTI
);
2752 es
->buffer_limit
= BUFLIMIT_MULTI
;
2755 es
->buffer_limit
= min(limit
, BUFLIMIT_SINGLE
);
2757 es
->buffer_limit
= BUFLIMIT_SINGLE
;
2762 /*********************************************************************
2766 * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
2767 * action wParam despite what the docs say. EC_USEFONTINFO means one third
2768 * of the char's width, according to the new docs.
2771 static void EDIT_EM_SetMargins(WND
*wnd
, EDITSTATE
*es
, INT action
,
2772 INT left
, INT right
)
2774 if (action
& EC_LEFTMARGIN
) {
2775 if (left
!= EC_USEFONTINFO
)
2776 es
->left_margin
= left
;
2778 es
->left_margin
= es
->char_width
/ 3;
2781 if (action
& EC_RIGHTMARGIN
) {
2782 if (right
!= EC_USEFONTINFO
)
2783 es
->right_margin
= right
;
2785 es
->right_margin
= es
->char_width
/ 3;
2787 TRACE("left=%d, right=%d\n", es
->left_margin
, es
->right_margin
);
2791 /*********************************************************************
2793 * EM_SETPASSWORDCHAR
2796 static void EDIT_EM_SetPasswordChar(WND
*wnd
, EDITSTATE
*es
, CHAR c
)
2798 if (es
->style
& ES_MULTILINE
)
2801 if (es
->password_char
== c
)
2804 es
->password_char
= c
;
2806 wnd
->dwStyle
|= ES_PASSWORD
;
2807 es
->style
|= ES_PASSWORD
;
2809 wnd
->dwStyle
&= ~ES_PASSWORD
;
2810 es
->style
&= ~ES_PASSWORD
;
2812 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2816 /*********************************************************************
2820 * note: unlike the specs say: the order of start and end
2821 * _is_ preserved in Windows. (i.e. start can be > end)
2822 * In other words: this handler is OK
2825 static void EDIT_EM_SetSel(WND
*wnd
, EDITSTATE
*es
, UINT start
, UINT end
, BOOL after_wrap
)
2827 UINT old_start
= es
->selection_start
;
2828 UINT old_end
= es
->selection_end
;
2829 UINT len
= strlen(es
->text
);
2832 start
= es
->selection_end
;
2833 end
= es
->selection_end
;
2835 start
= min(start
, len
);
2836 end
= min(end
, len
);
2838 es
->selection_start
= start
;
2839 es
->selection_end
= end
;
2841 es
->flags
|= EF_AFTER_WRAP
;
2843 es
->flags
&= ~EF_AFTER_WRAP
;
2844 if (es
->flags
& EF_FOCUSED
)
2845 EDIT_SetCaretPos(wnd
, es
, end
, after_wrap
);
2846 /* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */
2847 ORDER_UINT(start
, end
);
2848 ORDER_UINT(end
, old_end
);
2849 ORDER_UINT(start
, old_start
);
2850 ORDER_UINT(old_start
, old_end
);
2851 if (end
!= old_start
)
2855 * ORDER_UINT32(end, old_start);
2856 * EDIT_InvalidateText(wnd, es, start, end);
2857 * EDIT_InvalidateText(wnd, es, old_start, old_end);
2858 * in place of the following if statement.
2860 if (old_start
> end
)
2862 EDIT_InvalidateText(wnd
, es
, start
, end
);
2863 EDIT_InvalidateText(wnd
, es
, old_start
, old_end
);
2867 EDIT_InvalidateText(wnd
, es
, start
, old_start
);
2868 EDIT_InvalidateText(wnd
, es
, end
, old_end
);
2871 else EDIT_InvalidateText(wnd
, es
, start
, old_end
);
2875 /*********************************************************************
2880 static BOOL
EDIT_EM_SetTabStops(WND
*wnd
, EDITSTATE
*es
, INT count
, LPINT tabs
)
2882 if (!(es
->style
& ES_MULTILINE
))
2885 HeapFree(es
->heap
, 0, es
->tabs
);
2886 es
->tabs_count
= count
;
2890 es
->tabs
= HeapAlloc(es
->heap
, 0, count
* sizeof(INT
));
2891 memcpy(es
->tabs
, tabs
, count
* sizeof(INT
));
2897 /*********************************************************************
2902 static BOOL
EDIT_EM_SetTabStops16(WND
*wnd
, EDITSTATE
*es
, INT count
, LPINT16 tabs
)
2904 if (!(es
->style
& ES_MULTILINE
))
2907 HeapFree(es
->heap
, 0, es
->tabs
);
2908 es
->tabs_count
= count
;
2913 es
->tabs
= HeapAlloc(es
->heap
, 0, count
* sizeof(INT
));
2914 for (i
= 0 ; i
< count
; i
++)
2915 es
->tabs
[i
] = *tabs
++;
2921 /*********************************************************************
2923 * EM_SETWORDBREAKPROC
2926 static void EDIT_EM_SetWordBreakProc(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROCA wbp
)
2928 if (es
->word_break_proc32A
== wbp
)
2931 es
->word_break_proc32A
= wbp
;
2932 es
->word_break_proc16
= NULL
;
2933 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
)) {
2934 EDIT_BuildLineDefs_ML(wnd
, es
);
2935 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2940 /*********************************************************************
2942 * EM_SETWORDBREAKPROC16
2945 static void EDIT_EM_SetWordBreakProc16(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC16 wbp
)
2947 if (es
->word_break_proc16
== wbp
)
2950 es
->word_break_proc32A
= NULL
;
2951 es
->word_break_proc16
= wbp
;
2952 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
)) {
2953 EDIT_BuildLineDefs_ML(wnd
, es
);
2954 EDIT_UpdateText(wnd
, NULL
, TRUE
);
2959 /*********************************************************************
2964 static BOOL
EDIT_EM_Undo(WND
*wnd
, EDITSTATE
*es
)
2966 INT ulength
= strlen(es
->undo_text
);
2967 LPSTR utext
= HeapAlloc(es
->heap
, 0, ulength
+ 1);
2969 strcpy(utext
, es
->undo_text
);
2971 TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
2972 es
->undo_insert_count
, utext
);
2974 EDIT_EM_SetSel(wnd
, es
, es
->undo_position
, es
->undo_position
+ es
->undo_insert_count
, FALSE
);
2975 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2976 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, utext
);
2977 EDIT_EM_SetSel(wnd
, es
, es
->undo_position
, es
->undo_position
+ es
->undo_insert_count
, FALSE
);
2978 HeapFree(es
->heap
, 0, utext
);
2980 TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
2981 es
->undo_insert_count
, es
->undo_text
);
2983 if (es
->flags
& EF_UPDATE
) {
2984 es
->flags
&= ~EF_UPDATE
;
2985 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
2992 /*********************************************************************
2997 static void EDIT_WM_Char(WND
*wnd
, EDITSTATE
*es
, CHAR c
, DWORD key_data
)
2999 BOOL control
= GetKeyState(VK_CONTROL
) & 0x8000;
3002 /* If the edit doesn't want the return and it's not a multiline edit, do nothing */
3003 if(!(es
->style
& ES_MULTILINE
) && !(es
->style
& ES_WANTRETURN
))
3006 if (es
->style
& ES_MULTILINE
) {
3007 if (es
->style
& ES_READONLY
) {
3008 EDIT_MoveHome(wnd
, es
, FALSE
);
3009 EDIT_MoveDown_ML(wnd
, es
, FALSE
);
3011 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "\r\n");
3012 if (es
->flags
& EF_UPDATE
) {
3013 es
->flags
&= ~EF_UPDATE
;
3014 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3020 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_READONLY
))
3022 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "\t");
3023 if (es
->flags
& EF_UPDATE
) {
3024 es
->flags
&= ~EF_UPDATE
;
3025 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3030 if (!(es
->style
& ES_READONLY
) && !control
) {
3031 if (es
->selection_start
!= es
->selection_end
)
3032 EDIT_WM_Clear(wnd
, es
);
3034 /* delete character left of caret */
3035 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3036 EDIT_MoveBackward(wnd
, es
, TRUE
);
3037 EDIT_WM_Clear(wnd
, es
);
3042 SendMessageA(wnd
->hwndSelf
, WM_COPY
, 0, 0);
3045 SendMessageA(wnd
->hwndSelf
, WM_PASTE
, 0, 0);
3048 SendMessageA(wnd
->hwndSelf
, WM_CUT
, 0, 0);
3052 if (!(es
->style
& ES_READONLY
) && ((BYTE
)c
>= ' ') && (c
!= 127)) {
3056 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, str
);
3057 if (es
->flags
& EF_UPDATE
) {
3058 es
->flags
&= ~EF_UPDATE
;
3059 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3067 /*********************************************************************
3072 static void EDIT_WM_Command(WND
*wnd
, EDITSTATE
*es
, INT code
, INT id
, HWND control
)
3074 if (code
|| control
)
3079 EDIT_EM_Undo(wnd
, es
);
3082 EDIT_WM_Cut(wnd
, es
);
3085 EDIT_WM_Copy(wnd
, es
);
3088 EDIT_WM_Paste(wnd
, es
);
3091 EDIT_WM_Clear(wnd
, es
);
3094 EDIT_EM_SetSel(wnd
, es
, 0, -1, FALSE
);
3095 EDIT_EM_ScrollCaret(wnd
, es
);
3098 ERR("unknown menu item, please report\n");
3104 /*********************************************************************
3108 * Note: the resource files resource/sysres_??.rc cannot define a
3109 * single popup menu. Hence we use a (dummy) menubar
3110 * containing the single popup menu as its first item.
3112 * FIXME: the message identifiers have been chosen arbitrarily,
3113 * hence we use MF_BYPOSITION.
3114 * We might as well use the "real" values (anybody knows ?)
3115 * The menu definition is in resources/sysres_??.rc.
3116 * Once these are OK, we better use MF_BYCOMMAND here
3117 * (as we do in EDIT_WM_Command()).
3120 static void EDIT_WM_ContextMenu(WND
*wnd
, EDITSTATE
*es
, HWND hwnd
, INT x
, INT y
)
3122 HMENU menu
= LoadMenuA(GetModuleHandleA("USER32"), "EDITMENU");
3123 HMENU popup
= GetSubMenu(menu
, 0);
3124 UINT start
= es
->selection_start
;
3125 UINT end
= es
->selection_end
;
3127 ORDER_UINT(start
, end
);
3130 EnableMenuItem(popup
, 0, MF_BYPOSITION
| (EDIT_EM_CanUndo(wnd
, es
) ? MF_ENABLED
: MF_GRAYED
));
3132 EnableMenuItem(popup
, 2, MF_BYPOSITION
| ((end
- start
) && !(es
->style
& ES_PASSWORD
) ? MF_ENABLED
: MF_GRAYED
));
3134 EnableMenuItem(popup
, 3, MF_BYPOSITION
| ((end
- start
) && !(es
->style
& ES_PASSWORD
) ? MF_ENABLED
: MF_GRAYED
));
3136 EnableMenuItem(popup
, 4, MF_BYPOSITION
| (IsClipboardFormatAvailable(CF_TEXT
) ? MF_ENABLED
: MF_GRAYED
));
3138 EnableMenuItem(popup
, 5, MF_BYPOSITION
| ((end
- start
) ? MF_ENABLED
: MF_GRAYED
));
3140 EnableMenuItem(popup
, 7, MF_BYPOSITION
| (start
|| (end
!= strlen(es
->text
)) ? MF_ENABLED
: MF_GRAYED
));
3142 TrackPopupMenu(popup
, TPM_LEFTALIGN
| TPM_RIGHTBUTTON
, x
, y
, 0, wnd
->hwndSelf
, NULL
);
3147 /*********************************************************************
3152 static void EDIT_WM_Copy(WND
*wnd
, EDITSTATE
*es
)
3154 INT s
= es
->selection_start
;
3155 INT e
= es
->selection_end
;
3162 hdst
= GlobalAlloc(GMEM_MOVEABLE
, (DWORD
)(e
- s
+ 1));
3163 dst
= GlobalLock(hdst
);
3164 lstrcpynA(dst
, es
->text
+ s
, e
- s
+ 1);
3166 OpenClipboard(wnd
->hwndSelf
);
3168 SetClipboardData(CF_TEXT
, hdst
);
3173 /*********************************************************************
3178 static LRESULT
EDIT_WM_Create(WND
*wnd
, EDITSTATE
*es
, LPCREATESTRUCTA cs
)
3181 * To initialize some final structure members, we call some helper
3182 * functions. However, since the EDITSTATE is not consistent (i.e.
3183 * not fully initialized), we should be very careful which
3184 * functions can be called, and in what order.
3186 EDIT_WM_SetFont(wnd
, es
, 0, FALSE
);
3187 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
3189 if (cs
->lpszName
&& *(cs
->lpszName
) != '\0') {
3190 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, cs
->lpszName
);
3191 /* if we insert text to the editline, the text scrolls out
3192 * of the window, as the caret is placed after the insert
3193 * pos normally; thus we reset es->selection... to 0 and
3196 es
->selection_start
= es
->selection_end
= 0;
3197 EDIT_EM_ScrollCaret(wnd
, es
);
3198 if (es
->flags
& EF_UPDATE
) {
3199 es
->flags
&= ~EF_UPDATE
;
3200 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3207 /*********************************************************************
3212 static void EDIT_WM_Destroy(WND
*wnd
, EDITSTATE
*es
)
3215 while (LocalUnlock(es
->hloc32
)) ;
3216 LocalFree(es
->hloc32
);
3219 while (LOCAL_Unlock(wnd
->hInstance
, es
->hloc16
)) ;
3220 LOCAL_Free(wnd
->hInstance
, es
->hloc16
);
3222 HeapDestroy(es
->heap
);
3223 HeapFree(GetProcessHeap(), 0, es
);
3224 *(EDITSTATE
**)wnd
->wExtra
= NULL
;
3228 /*********************************************************************
3233 static LRESULT
EDIT_WM_EraseBkGnd(WND
*wnd
, EDITSTATE
*es
, HDC dc
)
3238 if ( get_app_version() >= 0x40000 &&(
3239 !es
->bEnableState
|| (es
->style
& ES_READONLY
)))
3240 brush
= (HBRUSH
)EDIT_SEND_CTLCOLORSTATIC(wnd
, dc
);
3242 brush
= (HBRUSH
)EDIT_SEND_CTLCOLOR(wnd
, dc
);
3245 brush
= (HBRUSH
)GetStockObject(WHITE_BRUSH
);
3247 GetClientRect(wnd
->hwndSelf
, &rc
);
3248 IntersectClipRect(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3249 GetClipBox(dc
, &rc
);
3251 * FIXME: specs say that we should UnrealizeObject() the brush,
3252 * but the specs of UnrealizeObject() say that we shouldn't
3253 * unrealize a stock object. The default brush that
3254 * DefWndProc() returns is ... a stock object.
3256 FillRect(dc
, &rc
, brush
);
3261 /*********************************************************************
3266 static INT
EDIT_WM_GetText(WND
*wnd
, EDITSTATE
*es
, INT count
, LPSTR text
)
3268 lstrcpynA(text
, es
->text
, count
);
3269 return strlen(text
);
3273 /*********************************************************************
3277 * 16 bit notepad needs this. Actually it is not _our_ hack,
3278 * it is notepad's. Notepad is sending us scrollbar messages with
3279 * undocumented parameters without us even having a scrollbar ... !?!?
3282 static LRESULT
EDIT_HScroll_Hack(WND
*wnd
, EDITSTATE
*es
, INT action
, INT pos
, HWND scroll_bar
)
3285 INT fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3288 if (!(es
->flags
& EF_HSCROLL_HACK
)) {
3289 ERR("hacked WM_HSCROLL handler invoked\n");
3290 ERR(" if you are _not_ running 16 bit notepad, please report\n");
3291 ERR(" (this message is only displayed once per edit control)\n");
3292 es
->flags
|= EF_HSCROLL_HACK
;
3298 dx
= -es
->char_width
;
3301 if (es
->x_offset
< es
->text_width
)
3302 dx
= es
->char_width
;
3306 dx
= -fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3309 if (es
->x_offset
< es
->text_width
)
3310 dx
= fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3317 if (es
->x_offset
< es
->text_width
)
3318 dx
= es
->text_width
- es
->x_offset
;
3321 es
->flags
|= EF_HSCROLL_TRACK
;
3322 dx
= pos
* es
->text_width
/ 100 - es
->x_offset
;
3324 case SB_THUMBPOSITION
:
3325 es
->flags
&= ~EF_HSCROLL_TRACK
;
3326 if (!(dx
= pos
* es
->text_width
/ 100 - es
->x_offset
))
3327 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
3333 * FIXME : the next two are undocumented !
3334 * Are we doing the right thing ?
3335 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
3336 * although it's also a regular control message.
3339 ret
= es
->text_width
? es
->x_offset
* 100 / es
->text_width
: 0;
3341 case EM_LINESCROLL16
:
3346 ERR("undocumented (hacked) WM_HSCROLL parameter, please report\n");
3350 EDIT_EM_LineScroll(wnd
, es
, dx
, 0);
3355 /*********************************************************************
3360 static LRESULT
EDIT_WM_HScroll(WND
*wnd
, EDITSTATE
*es
, INT action
, INT pos
, HWND scroll_bar
)
3365 if (!(es
->style
& ES_MULTILINE
))
3368 if (!(es
->style
& ES_AUTOHSCROLL
))
3371 if (!(es
->style
& WS_HSCROLL
))
3372 return EDIT_HScroll_Hack(wnd
, es
, action
, pos
, scroll_bar
);
3375 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3379 dx
= -es
->char_width
;
3382 if (es
->x_offset
< es
->text_width
)
3383 dx
= es
->char_width
;
3387 dx
= -fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3390 if (es
->x_offset
< es
->text_width
)
3391 dx
= fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3398 if (es
->x_offset
< es
->text_width
)
3399 dx
= es
->text_width
- es
->x_offset
;
3402 es
->flags
|= EF_HSCROLL_TRACK
;
3403 dx
= pos
- es
->x_offset
;
3405 case SB_THUMBPOSITION
:
3406 es
->flags
&= ~EF_HSCROLL_TRACK
;
3407 if (!(dx
= pos
- es
->x_offset
)) {
3408 SetScrollPos(wnd
->hwndSelf
, SB_HORZ
, pos
, TRUE
);
3409 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
3416 ERR("undocumented WM_HSCROLL parameter, please report\n");
3420 EDIT_EM_LineScroll(wnd
, es
, dx
, 0);
3425 /*********************************************************************
3430 static BOOL
EDIT_CheckCombo(WND
*wnd
, EDITSTATE
*es
, UINT msg
, INT key
, DWORD key_data
)
3432 HWND hLBox
= es
->hwndListBox
;
3440 hCombo
= wnd
->parent
->hwndSelf
;
3444 TRACE_(combo
)("[%04x]: handling msg %04x (%04x)\n",
3445 wnd
->hwndSelf
, (UINT16
)msg
, (UINT16
)key
);
3447 if (key
== VK_UP
|| key
== VK_DOWN
)
3449 if (SendMessageA(hCombo
, CB_GETEXTENDEDUI
, 0, 0))
3452 if (msg
== WM_KEYDOWN
|| nEUI
)
3453 bDropped
= (BOOL
)SendMessageA(hCombo
, CB_GETDROPPEDSTATE
, 0, 0);
3459 if (!bDropped
&& nEUI
&& (key
== VK_UP
|| key
== VK_DOWN
))
3461 /* make sure ComboLBox pops up */
3462 SendMessageA(hCombo
, CB_SETEXTENDEDUI
, FALSE
, 0);
3467 SendMessageA(hLBox
, WM_KEYDOWN
, (WPARAM
)key
, 0);
3470 case WM_SYSKEYDOWN
: /* Handle Alt+up/down arrows */
3472 SendMessageA(hCombo
, CB_SHOWDROPDOWN
, bDropped
? FALSE
: TRUE
, 0);
3474 SendMessageA(hLBox
, WM_KEYDOWN
, (WPARAM
)VK_F4
, 0);
3479 SendMessageA(hCombo
, CB_SETEXTENDEDUI
, TRUE
, 0);
3485 /*********************************************************************
3489 * Handling of special keys that don't produce a WM_CHAR
3490 * (i.e. non-printable keys) & Backspace & Delete
3493 static LRESULT
EDIT_WM_KeyDown(WND
*wnd
, EDITSTATE
*es
, INT key
, DWORD key_data
)
3498 if (GetKeyState(VK_MENU
) & 0x8000)
3501 shift
= GetKeyState(VK_SHIFT
) & 0x8000;
3502 control
= GetKeyState(VK_CONTROL
) & 0x8000;
3507 if (EDIT_CheckCombo(wnd
, es
, WM_KEYDOWN
, key
, key_data
) || key
== VK_F4
)
3512 if ((es
->style
& ES_MULTILINE
) && (key
== VK_UP
))
3513 EDIT_MoveUp_ML(wnd
, es
, shift
);
3516 EDIT_MoveWordBackward(wnd
, es
, shift
);
3518 EDIT_MoveBackward(wnd
, es
, shift
);
3521 if (EDIT_CheckCombo(wnd
, es
, WM_KEYDOWN
, key
, key_data
))
3525 if ((es
->style
& ES_MULTILINE
) && (key
== VK_DOWN
))
3526 EDIT_MoveDown_ML(wnd
, es
, shift
);
3528 EDIT_MoveWordForward(wnd
, es
, shift
);
3530 EDIT_MoveForward(wnd
, es
, shift
);
3533 EDIT_MoveHome(wnd
, es
, shift
);
3536 EDIT_MoveEnd(wnd
, es
, shift
);
3539 if (es
->style
& ES_MULTILINE
)
3540 EDIT_MovePageUp_ML(wnd
, es
, shift
);
3542 EDIT_CheckCombo(wnd
, es
, WM_KEYDOWN
, key
, key_data
);
3545 if (es
->style
& ES_MULTILINE
)
3546 EDIT_MovePageDown_ML(wnd
, es
, shift
);
3548 EDIT_CheckCombo(wnd
, es
, WM_KEYDOWN
, key
, key_data
);
3551 if (!(es
->style
& ES_READONLY
) && !(shift
&& control
)) {
3552 if (es
->selection_start
!= es
->selection_end
) {
3554 EDIT_WM_Cut(wnd
, es
);
3556 EDIT_WM_Clear(wnd
, es
);
3559 /* delete character left of caret */
3560 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3561 EDIT_MoveBackward(wnd
, es
, TRUE
);
3562 EDIT_WM_Clear(wnd
, es
);
3563 } else if (control
) {
3564 /* delete to end of line */
3565 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3566 EDIT_MoveEnd(wnd
, es
, TRUE
);
3567 EDIT_WM_Clear(wnd
, es
);
3569 /* delete character right of caret */
3570 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3571 EDIT_MoveForward(wnd
, es
, TRUE
);
3572 EDIT_WM_Clear(wnd
, es
);
3579 if (!(es
->style
& ES_READONLY
))
3580 EDIT_WM_Paste(wnd
, es
);
3582 EDIT_WM_Copy(wnd
, es
);
3585 /* If the edit doesn't want the return send a message to the default object */
3586 if(!(es
->style
& ES_WANTRETURN
))
3588 HWND hwndParent
= GetParent(wnd
->hwndSelf
);
3589 DWORD dw
= SendMessage16( hwndParent
, DM_GETDEFID
, 0, 0 );
3590 if (HIWORD(dw
) == DC_HASDEFID
)
3592 SendMessageA( hwndParent
, WM_COMMAND
,
3593 MAKEWPARAM( LOWORD(dw
), BN_CLICKED
),
3594 (LPARAM
)GetDlgItem( hwndParent
, LOWORD(dw
) ) );
3603 /*********************************************************************
3608 static LRESULT
EDIT_WM_KillFocus(WND
*wnd
, EDITSTATE
*es
, HWND window_getting_focus
)
3610 es
->flags
&= ~EF_FOCUSED
;
3612 if(!(es
->style
& ES_NOHIDESEL
))
3613 EDIT_InvalidateText(wnd
, es
, es
->selection_start
, es
->selection_end
);
3614 EDIT_NOTIFY_PARENT(wnd
, EN_KILLFOCUS
, "EN_KILLFOCUS");
3619 /*********************************************************************
3623 * The caret position has been set on the WM_LBUTTONDOWN message
3626 static LRESULT
EDIT_WM_LButtonDblClk(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
)
3629 INT e
= es
->selection_end
;
3634 if (!(es
->flags
& EF_FOCUSED
))
3637 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
3638 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
3639 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
3640 s
= li
+ EDIT_CallWordBreakProc (wnd
, es
, li
, e
- li
, ll
, WB_LEFT
);
3641 e
= li
+ EDIT_CallWordBreakProc(wnd
, es
, li
, e
- li
, ll
, WB_RIGHT
);
3642 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
3643 EDIT_EM_ScrollCaret(wnd
, es
);
3648 /*********************************************************************
3653 static LRESULT
EDIT_WM_LButtonDown(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
)
3658 if (!(es
->flags
& EF_FOCUSED
))
3661 es
->bCaptureState
= TRUE
;
3662 SetCapture(wnd
->hwndSelf
);
3663 EDIT_ConfinePoint(wnd
, es
, &x
, &y
);
3664 e
= EDIT_CharFromPos(wnd
, es
, x
, y
, &after_wrap
);
3665 EDIT_EM_SetSel(wnd
, es
, (keys
& MK_SHIFT
) ? es
->selection_start
: e
, e
, after_wrap
);
3666 EDIT_EM_ScrollCaret(wnd
, es
);
3667 es
->region_posx
= es
->region_posy
= 0;
3668 SetTimer(wnd
->hwndSelf
, 0, 100, NULL
);
3673 /*********************************************************************
3678 static LRESULT
EDIT_WM_LButtonUp(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
)
3680 if (es
->bCaptureState
&& GetCapture() == wnd
->hwndSelf
) {
3681 KillTimer(wnd
->hwndSelf
, 0);
3684 es
->bCaptureState
= FALSE
;
3689 /*********************************************************************
3694 static LRESULT
EDIT_WM_MButtonDown(WND
*wnd
)
3696 SendMessageA(wnd
->hwndSelf
,WM_PASTE
,0,0);
3701 /*********************************************************************
3706 static LRESULT
EDIT_WM_MouseMove(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT x
, INT y
)
3712 if (GetCapture() != wnd
->hwndSelf
)
3716 * FIXME: gotta do some scrolling if outside client
3717 * area. Maybe reset the timer ?
3720 EDIT_ConfinePoint(wnd
, es
, &x
, &y
);
3721 es
->region_posx
= (prex
< x
) ? -1 : ((prex
> x
) ? 1 : 0);
3722 es
->region_posy
= (prey
< y
) ? -1 : ((prey
> y
) ? 1 : 0);
3723 e
= EDIT_CharFromPos(wnd
, es
, x
, y
, &after_wrap
);
3724 EDIT_EM_SetSel(wnd
, es
, es
->selection_start
, e
, after_wrap
);
3729 /*********************************************************************
3734 static LRESULT
EDIT_WM_NCCreate(WND
*wnd
, LPCREATESTRUCTA cs
)
3738 if (!(es
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*es
))))
3740 *(EDITSTATE
**)wnd
->wExtra
= es
;
3743 * Note: since the EDITSTATE has not been fully initialized yet,
3744 * we can't use any API calls that may send
3745 * WM_XXX messages before WM_NCCREATE is completed.
3748 if (!(es
->heap
= HeapCreate(0, 0x10000, 0)))
3750 es
->style
= cs
->style
;
3752 es
->bEnableState
= !(cs
->style
& WS_DISABLED
);
3755 * In Win95 look and feel, the WS_BORDER style is replaced by the
3756 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
3757 * control a non client area.
3759 if (TWEAK_WineLook
!= WIN31_LOOK
)
3761 if (es
->style
& WS_BORDER
)
3763 es
->style
&= ~WS_BORDER
;
3764 wnd
->dwStyle
&= ~WS_BORDER
;
3765 wnd
->dwExStyle
|= WS_EX_CLIENTEDGE
;
3770 if ((es
->style
& WS_BORDER
) && !(es
->style
& WS_DLGFRAME
))
3771 wnd
->dwStyle
&= ~WS_BORDER
;
3774 if (es
->style
& ES_COMBO
)
3775 es
->hwndListBox
= GetDlgItem(cs
->hwndParent
, ID_CB_LISTBOX
);
3777 if (es
->style
& ES_MULTILINE
) {
3778 es
->buffer_size
= BUFSTART_MULTI
;
3779 es
->buffer_limit
= BUFLIMIT_MULTI
;
3780 if (es
->style
& WS_VSCROLL
)
3781 es
->style
|= ES_AUTOVSCROLL
;
3782 if (es
->style
& WS_HSCROLL
)
3783 es
->style
|= ES_AUTOHSCROLL
;
3784 es
->style
&= ~ES_PASSWORD
;
3785 if ((es
->style
& ES_CENTER
) || (es
->style
& ES_RIGHT
)) {
3786 if (es
->style
& ES_RIGHT
)
3787 es
->style
&= ~ES_CENTER
;
3788 es
->style
&= ~WS_HSCROLL
;
3789 es
->style
&= ~ES_AUTOHSCROLL
;
3792 /* FIXME: for now, all multi line controls are AUTOVSCROLL */
3793 es
->style
|= ES_AUTOVSCROLL
;
3795 es
->buffer_size
= BUFSTART_SINGLE
;
3796 es
->buffer_limit
= BUFLIMIT_SINGLE
;
3797 es
->style
&= ~ES_CENTER
;
3798 es
->style
&= ~ES_RIGHT
;
3799 es
->style
&= ~WS_HSCROLL
;
3800 es
->style
&= ~WS_VSCROLL
;
3801 es
->style
&= ~ES_AUTOVSCROLL
;
3802 es
->style
&= ~ES_WANTRETURN
;
3803 if (es
->style
& ES_UPPERCASE
) {
3804 es
->style
&= ~ES_LOWERCASE
;
3805 es
->style
&= ~ES_NUMBER
;
3806 } else if (es
->style
& ES_LOWERCASE
)
3807 es
->style
&= ~ES_NUMBER
;
3808 if (es
->style
& ES_PASSWORD
)
3809 es
->password_char
= '*';
3811 /* FIXME: for now, all single line controls are AUTOHSCROLL */
3812 es
->style
|= ES_AUTOHSCROLL
;
3814 if (!(es
->text
= HeapAlloc(es
->heap
, 0, es
->buffer_size
+ 1)))
3816 es
->buffer_size
= HeapSize(es
->heap
, 0, es
->text
) - 1;
3817 if (!(es
->undo_text
= HeapAlloc(es
->heap
, 0, es
->buffer_size
+ 1)))
3819 es
->undo_buffer_size
= HeapSize(es
->heap
, 0, es
->undo_text
) - 1;
3821 if (es
->style
& ES_MULTILINE
)
3822 if (!(es
->first_line_def
= HeapAlloc(es
->heap
, HEAP_ZERO_MEMORY
, sizeof(LINEDEF
))))
3829 /*********************************************************************
3834 static void EDIT_WM_Paint(WND
*wnd
, EDITSTATE
*es
, WPARAM wParam
)
3843 BOOL rev
= es
->bEnableState
&&
3844 ((es
->flags
& EF_FOCUSED
) ||
3845 (es
->style
& ES_NOHIDESEL
));
3847 dc
= BeginPaint(wnd
->hwndSelf
, &ps
);
3850 if(es
->style
& WS_BORDER
) {
3851 GetClientRect(wnd
->hwndSelf
, &rc
);
3852 if(es
->style
& ES_MULTILINE
) {
3853 if(es
->style
& WS_HSCROLL
) rc
.bottom
++;
3854 if(es
->style
& WS_VSCROLL
) rc
.right
++;
3856 Rectangle(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3858 IntersectClipRect(dc
, es
->format_rect
.left
,
3859 es
->format_rect
.top
,
3860 es
->format_rect
.right
,
3861 es
->format_rect
.bottom
);
3862 if (es
->style
& ES_MULTILINE
) {
3863 GetClientRect(wnd
->hwndSelf
, &rc
);
3864 IntersectClipRect(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3867 old_font
= SelectObject(dc
, es
->font
);
3868 if ( get_app_version() >= 0x40000 &&(
3869 !es
->bEnableState
|| (es
->style
& ES_READONLY
)))
3870 EDIT_SEND_CTLCOLORSTATIC(wnd
, dc
);
3872 EDIT_SEND_CTLCOLOR(wnd
, dc
);
3874 if (!es
->bEnableState
)
3875 SetTextColor(dc
, GetSysColor(COLOR_GRAYTEXT
));
3876 GetClipBox(dc
, &rcRgn
);
3877 if (es
->style
& ES_MULTILINE
) {
3878 INT vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
3879 for (i
= es
->y_offset
; i
<= min(es
->y_offset
+ vlc
, es
->y_offset
+ es
->line_count
- 1) ; i
++) {
3880 EDIT_GetLineRect(wnd
, es
, i
, 0, -1, &rcLine
);
3881 if (IntersectRect(&rc
, &rcRgn
, &rcLine
))
3882 EDIT_PaintLine(wnd
, es
, dc
, i
, rev
);
3885 EDIT_GetLineRect(wnd
, es
, 0, 0, -1, &rcLine
);
3886 if (IntersectRect(&rc
, &rcRgn
, &rcLine
))
3887 EDIT_PaintLine(wnd
, es
, dc
, 0, rev
);
3890 SelectObject(dc
, old_font
);
3891 if (es
->flags
& EF_FOCUSED
)
3892 EDIT_SetCaretPos(wnd
, es
, es
->selection_end
,
3893 es
->flags
& EF_AFTER_WRAP
);
3895 EndPaint(wnd
->hwndSelf
, &ps
);
3896 if ((es
->style
& WS_VSCROLL
) && !(es
->flags
& EF_VSCROLL_TRACK
)) {
3897 INT vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
3899 si
.cbSize
= sizeof(SCROLLINFO
);
3900 si
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
3902 si
.nMax
= es
->line_count
+ vlc
- 2;
3904 si
.nPos
= es
->y_offset
;
3905 SetScrollInfo(wnd
->hwndSelf
, SB_VERT
, &si
, TRUE
);
3907 if ((es
->style
& WS_HSCROLL
) && !(es
->flags
& EF_HSCROLL_TRACK
)) {
3909 INT fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3910 si
.cbSize
= sizeof(SCROLLINFO
);
3911 si
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
3913 si
.nMax
= es
->text_width
+ fw
- 1;
3915 si
.nPos
= es
->x_offset
;
3916 SetScrollInfo(wnd
->hwndSelf
, SB_HORZ
, &si
, TRUE
);
3921 /*********************************************************************
3926 static void EDIT_WM_Paste(WND
*wnd
, EDITSTATE
*es
)
3931 OpenClipboard(wnd
->hwndSelf
);
3932 if ((hsrc
= GetClipboardData(CF_TEXT
))) {
3933 src
= (LPSTR
)GlobalLock(hsrc
);
3934 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, src
);
3937 if (es
->flags
& EF_UPDATE
) {
3938 es
->flags
&= ~EF_UPDATE
;
3939 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3946 /*********************************************************************
3951 static void EDIT_WM_SetFocus(WND
*wnd
, EDITSTATE
*es
, HWND window_losing_focus
)
3953 es
->flags
|= EF_FOCUSED
;
3954 CreateCaret(wnd
->hwndSelf
, 0, 2, es
->line_height
);
3955 EDIT_SetCaretPos(wnd
, es
, es
->selection_end
,
3956 es
->flags
& EF_AFTER_WRAP
);
3957 if(!(es
->style
& ES_NOHIDESEL
))
3958 EDIT_InvalidateText(wnd
, es
, es
->selection_start
, es
->selection_end
);
3959 ShowCaret(wnd
->hwndSelf
);
3960 EDIT_NOTIFY_PARENT(wnd
, EN_SETFOCUS
, "EN_SETFOCUS");
3964 /*********************************************************************
3968 * With Win95 look the margins are set to default font value unless
3969 * the system font (font == 0) is being set, in which case they are left
3973 static void EDIT_WM_SetFont(WND
*wnd
, EDITSTATE
*es
, HFONT font
, BOOL redraw
)
3981 dc
= GetDC(wnd
->hwndSelf
);
3983 old_font
= SelectObject(dc
, font
);
3984 GetTextMetricsA(dc
, &tm
);
3985 es
->line_height
= tm
.tmHeight
;
3986 es
->char_width
= tm
.tmAveCharWidth
;
3988 SelectObject(dc
, old_font
);
3989 ReleaseDC(wnd
->hwndSelf
, dc
);
3990 if (font
&& (TWEAK_WineLook
> WIN31_LOOK
))
3991 EDIT_EM_SetMargins(wnd
, es
, EC_LEFTMARGIN
| EC_RIGHTMARGIN
,
3992 EC_USEFONTINFO
, EC_USEFONTINFO
);
3994 /* Force the recalculation of the format rect for each font change */
3995 GetClientRect(wnd
->hwndSelf
, &r
);
3996 EDIT_SetRectNP(wnd
, es
, &r
);
3998 if (es
->style
& ES_MULTILINE
)
3999 EDIT_BuildLineDefs_ML(wnd
, es
);
4002 EDIT_UpdateText(wnd
, NULL
, TRUE
);
4003 if (es
->flags
& EF_FOCUSED
) {
4005 CreateCaret(wnd
->hwndSelf
, 0, 2, es
->line_height
);
4006 EDIT_SetCaretPos(wnd
, es
, es
->selection_end
,
4007 es
->flags
& EF_AFTER_WRAP
);
4008 ShowCaret(wnd
->hwndSelf
);
4013 /*********************************************************************
4018 * For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
4019 * The modified flag is reset. No notifications are sent.
4021 * For single-line controls, reception of WM_SETTEXT triggers:
4022 * The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
4025 static void EDIT_WM_SetText(WND
*wnd
, EDITSTATE
*es
, LPCSTR text
)
4027 EDIT_EM_SetSel(wnd
, es
, 0, -1, FALSE
);
4029 TRACE("\t'%p'\n", text
);
4030 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, text
);
4032 TRACE("\t<NULL>\n");
4033 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, "");
4036 if (es
->style
& ES_MULTILINE
) {
4037 es
->flags
&= ~EF_UPDATE
;
4039 es
->flags
|= EF_UPDATE
;
4041 es
->flags
&= ~EF_MODIFIED
;
4042 EDIT_EM_SetSel(wnd
, es
, 0, 0, FALSE
);
4043 EDIT_EM_ScrollCaret(wnd
, es
);
4045 if (es
->flags
& EF_UPDATE
) {
4046 es
->flags
&= ~EF_UPDATE
;
4047 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
4052 /*********************************************************************
4057 static void EDIT_WM_Size(WND
*wnd
, EDITSTATE
*es
, UINT action
, INT width
, INT height
)
4059 if ((action
== SIZE_MAXIMIZED
) || (action
== SIZE_RESTORED
)) {
4061 SetRect(&rc
, 0, 0, width
, height
);
4062 EDIT_SetRectNP(wnd
, es
, &rc
);
4063 EDIT_UpdateText(wnd
, NULL
, TRUE
);
4068 /*********************************************************************
4073 static LRESULT
EDIT_WM_SysKeyDown(WND
*wnd
, EDITSTATE
*es
, INT key
, DWORD key_data
)
4075 if ((key
== VK_BACK
) && (key_data
& 0x2000)) {
4076 if (EDIT_EM_CanUndo(wnd
, es
))
4077 EDIT_EM_Undo(wnd
, es
);
4079 } else if (key
== VK_UP
|| key
== VK_DOWN
) {
4080 if (EDIT_CheckCombo(wnd
, es
, WM_SYSKEYDOWN
, key
, key_data
))
4083 return DefWindowProcA(wnd
->hwndSelf
, WM_SYSKEYDOWN
, (WPARAM
)key
, (LPARAM
)key_data
);
4087 /*********************************************************************
4092 static void EDIT_WM_Timer(WND
*wnd
, EDITSTATE
*es
, INT id
, TIMERPROC timer_proc
)
4094 if (es
->region_posx
< 0) {
4095 EDIT_MoveBackward(wnd
, es
, TRUE
);
4096 } else if (es
->region_posx
> 0) {
4097 EDIT_MoveForward(wnd
, es
, TRUE
);
4100 * FIXME: gotta do some vertical scrolling here, like
4101 * EDIT_EM_LineScroll(wnd, 0, 1);
4106 /*********************************************************************
4110 * 16 bit notepad needs this. Actually it is not _our_ hack,
4111 * it is notepad's. Notepad is sending us scrollbar messages with
4112 * undocumented parameters without us even having a scrollbar ... !?!?
4115 static LRESULT
EDIT_VScroll_Hack(WND
*wnd
, EDITSTATE
*es
, INT action
, INT pos
, HWND scroll_bar
)
4120 if (!(es
->flags
& EF_VSCROLL_HACK
)) {
4121 ERR("hacked WM_VSCROLL handler invoked\n");
4122 ERR(" if you are _not_ running 16 bit notepad, please report\n");
4123 ERR(" (this message is only displayed once per edit control)\n");
4124 es
->flags
|= EF_VSCROLL_HACK
;
4132 EDIT_EM_Scroll(wnd
, es
, action
);
4138 dy
= es
->line_count
- 1 - es
->y_offset
;
4141 es
->flags
|= EF_VSCROLL_TRACK
;
4142 dy
= (pos
* (es
->line_count
- 1) + 50) / 100 - es
->y_offset
;
4144 case SB_THUMBPOSITION
:
4145 es
->flags
&= ~EF_VSCROLL_TRACK
;
4146 if (!(dy
= (pos
* (es
->line_count
- 1) + 50) / 100 - es
->y_offset
))
4147 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
4153 * FIXME : the next two are undocumented !
4154 * Are we doing the right thing ?
4155 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
4156 * although it's also a regular control message.
4159 ret
= (es
->line_count
> 1) ? es
->y_offset
* 100 / (es
->line_count
- 1) : 0;
4161 case EM_LINESCROLL16
:
4166 ERR("undocumented (hacked) WM_VSCROLL parameter, please report\n");
4170 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
4175 /*********************************************************************
4180 static LRESULT
EDIT_WM_VScroll(WND
*wnd
, EDITSTATE
*es
, INT action
, INT pos
, HWND scroll_bar
)
4184 if (!(es
->style
& ES_MULTILINE
))
4187 if (!(es
->style
& ES_AUTOVSCROLL
))
4190 if (!(es
->style
& WS_VSCROLL
))
4191 return EDIT_VScroll_Hack(wnd
, es
, action
, pos
, scroll_bar
);
4199 EDIT_EM_Scroll(wnd
, es
, action
);
4206 dy
= es
->line_count
- 1 - es
->y_offset
;
4209 es
->flags
|= EF_VSCROLL_TRACK
;
4210 dy
= pos
- es
->y_offset
;
4212 case SB_THUMBPOSITION
:
4213 es
->flags
&= ~EF_VSCROLL_TRACK
;
4214 if (!(dy
= pos
- es
->y_offset
)) {
4215 SetScrollPos(wnd
->hwndSelf
, SB_VERT
, pos
, TRUE
);
4216 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
4223 ERR("undocumented WM_VSCROLL action %d, please report\n",
4228 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
4233 /*********************************************************************
4238 static void EDIT_UpdateText(WND
*wnd
, LPRECT rc
, BOOL bErase
)
4240 EDITSTATE
*es
= *(EDITSTATE
**)((wnd
)->wExtra
);
4242 /* EF_UPDATE will be turned off in paint */
4243 if (es
->flags
& EF_UPDATE
)
4244 EDIT_NOTIFY_PARENT(wnd
, EN_UPDATE
, "EN_UPDATE");
4246 InvalidateRect(wnd
->hwndSelf
, rc
, bErase
);