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)
24 #define BUFLIMIT_MULTI 65534 /* maximum buffer size (not including '\0')
25 FIXME: BTW, new specs say 65535 (do you dare ???) */
26 #define BUFLIMIT_SINGLE 32766 /* maximum buffer size (not including '\0') */
27 #define BUFSTART_MULTI 1024 /* starting size */
28 #define BUFSTART_SINGLE 256 /* starting size */
29 #define GROWLENGTH 64 /* buffers grow by this much */
30 #define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */
33 * extra flags for EDITSTATE.flags field
35 #define EF_MODIFIED 0x0001 /* text has been modified */
36 #define EF_FOCUSED 0x0002 /* we have input focus */
37 #define EF_UPDATE 0x0004 /* notify parent of changed state on next WM_PAINT */
38 #define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */
39 #define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */
40 #define EF_VSCROLL_HACK 0x0020 /* we already have informed the user of the hacked handler */
41 #define EF_HSCROLL_HACK 0x0040 /* we already have informed the user of the hacked handler */
42 #define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a
43 wrapped line, instead of in front of the next character */
44 #define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */
46 typedef BOOL32
*LPBOOL32
;
50 END_0
= 0, /* line ends with terminating '\0' character */
51 END_WRAP
, /* line is wrapped */
52 END_HARD
, /* line ends with a hard return '\r\n' */
53 END_SOFT
/* line ends with a soft return '\r\r\n' */
56 typedef struct tagLINEDEF
{
57 INT32 length
; /* bruto length of a line in bytes */
58 INT32 net_length
; /* netto length of a line in visible characters */
60 INT32 width
; /* width of the line in pixels */
61 struct tagLINEDEF
*next
;
66 HANDLE32 heap
; /* our own heap */
67 LPSTR text
; /* the actual contents of the control */
68 INT32 buffer_size
; /* the size of the buffer */
69 INT32 buffer_limit
; /* the maximum size to which the buffer may grow */
70 HFONT32 font
; /* NULL means standard system font */
71 INT32 x_offset
; /* scroll offset for multi lines this is in pixels
72 for single lines it's in characters */
73 INT32 line_height
; /* height of a screen line in pixels */
74 INT32 char_width
; /* average character width in pixels */
75 DWORD style
; /* sane version of wnd->dwStyle */
76 WORD flags
; /* flags that are not in es->style or wnd->flags (EF_XXX) */
77 INT32 undo_insert_count
; /* number of characters inserted in sequence */
78 INT32 undo_position
; /* character index of the insertion and deletion */
79 LPSTR undo_text
; /* deleted text */
80 INT32 undo_buffer_size
; /* size of the deleted text buffer */
81 INT32 selection_start
; /* == selection_end if no selection */
82 INT32 selection_end
; /* == current caret position */
83 CHAR password_char
; /* == 0 if no password char, and for multi line controls */
84 INT32 left_margin
; /* in pixels */
85 INT32 right_margin
; /* in pixels */
87 INT32 region_posx
; /* Position of cursor relative to region: */
88 INT32 region_posy
; /* -1: to left, 0: within, 1: to right */
89 EDITWORDBREAKPROC16 word_break_proc16
;
90 EDITWORDBREAKPROC32A word_break_proc32A
;
91 INT32 line_count
; /* number of lines */
92 INT32 y_offset
; /* scroll offset in number of lines */
94 * only for multi line controls
96 INT32 lock_count
; /* amount of re-entries in the EditWndProc */
99 INT32 text_width
; /* width of the widest line in pixels */
100 LINEDEF
*first_line_def
; /* linked list of (soft) linebreaks */
101 HLOCAL16 hloc16
; /* for controls receiving EM_GETHANDLE16 */
102 HLOCAL32 hloc32
; /* for controls receiving EM_GETHANDLE */
106 #define SWAP_INT32(x,y) do { INT32 temp = (INT32)(x); (x) = (INT32)(y); (y) = temp; } while(0)
107 #define ORDER_INT32(x,y) do { if ((INT32)(y) < (INT32)(x)) SWAP_INT32((x),(y)); } while(0)
109 #define SWAP_UINT32(x,y) do { UINT32 temp = (UINT32)(x); (x) = (UINT32)(y); (y) = temp; } while(0)
110 #define ORDER_UINT32(x,y) do { if ((UINT32)(y) < (UINT32)(x)) SWAP_UINT32((x),(y)); } while(0)
112 #define DPRINTF_EDIT_NOTIFY(hwnd, str) \
113 ({TRACE(edit, "notification " str " sent to hwnd=%08x\n", \
116 #define EDIT_SEND_CTLCOLOR(wnd,hdc) \
117 (SendMessage32A((wnd)->parent->hwndSelf, WM_CTLCOLOREDIT, \
118 (WPARAM32)(hdc), (LPARAM)(wnd)->hwndSelf))
119 #define EDIT_NOTIFY_PARENT(wnd, wNotifyCode, str) \
120 (DPRINTF_EDIT_NOTIFY((wnd)->parent->hwndSelf, str), \
121 SendMessage32A((wnd)->parent->hwndSelf, WM_COMMAND, \
122 MAKEWPARAM((wnd)->wIDmenu, wNotifyCode), \
123 (LPARAM)(wnd)->hwndSelf))
124 #define DPRINTF_EDIT_MSG16(str) \
126 "16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
127 (UINT32)hwnd, (UINT32)wParam, (UINT32)lParam)
128 #define DPRINTF_EDIT_MSG32(str) \
130 "32 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
131 (UINT32)hwnd, (UINT32)wParam, (UINT32)lParam)
133 /*********************************************************************
140 * These functions have trivial implementations
141 * We still like to call them internally
142 * "static __inline__" makes them more like macro's
144 static __inline__ BOOL32
EDIT_EM_CanUndo(WND
*wnd
, EDITSTATE
*es
);
145 static __inline__
void EDIT_EM_EmptyUndoBuffer(WND
*wnd
, EDITSTATE
*es
);
146 static __inline__
void EDIT_WM_Clear(WND
*wnd
, EDITSTATE
*es
);
147 static __inline__
void EDIT_WM_Cut(WND
*wnd
, EDITSTATE
*es
);
149 * This is the only exported function
151 LRESULT WINAPI
EditWndProc( HWND32 hwnd
, UINT32 msg
,
152 WPARAM32 wParam
, LPARAM lParam
);
154 * Helper functions only valid for one type of control
156 static void EDIT_BuildLineDefs_ML(WND
*wnd
, EDITSTATE
*es
);
157 static LPSTR
EDIT_GetPasswordPointer_SL(WND
*wnd
, EDITSTATE
*es
);
158 static void EDIT_MoveDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
159 static void EDIT_MovePageDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
160 static void EDIT_MovePageUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
161 static void EDIT_MoveUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
163 * Helper functions valid for both single line _and_ multi line controls
165 static INT32
EDIT_CallWordBreakProc(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 index
, INT32 count
, INT32 action
);
166 static INT32
EDIT_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
, LPBOOL32 after_wrap
);
167 static void EDIT_ConfinePoint(WND
*wnd
, EDITSTATE
*es
, LPINT32 x
, LPINT32 y
);
168 static void EDIT_GetLineRect(WND
*wnd
, EDITSTATE
*es
, INT32 line
, INT32 scol
, INT32 ecol
, LPRECT32 rc
);
169 static void EDIT_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
);
170 static void EDIT_LockBuffer(WND
*wnd
, EDITSTATE
*es
);
171 static BOOL32
EDIT_MakeFit(WND
*wnd
, EDITSTATE
*es
, INT32 size
);
172 static BOOL32
EDIT_MakeUndoFit(WND
*wnd
, EDITSTATE
*es
, INT32 size
);
173 static void EDIT_MoveBackward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
174 static void EDIT_MoveEnd(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
175 static void EDIT_MoveForward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
176 static void EDIT_MoveHome(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
177 static void EDIT_MoveWordBackward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
178 static void EDIT_MoveWordForward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
);
179 static void EDIT_PaintLine(WND
*wnd
, EDITSTATE
*es
, HDC32 hdc
, INT32 line
, BOOL32 rev
);
180 static INT32
EDIT_PaintText(WND
*wnd
, EDITSTATE
*es
, HDC32 hdc
, INT32 x
, INT32 y
, INT32 line
, INT32 col
, INT32 count
, BOOL32 rev
);
181 static void EDIT_SetCaretPos(WND
*wnd
, EDITSTATE
*es
, INT32 pos
, BOOL32 after_wrap
);
182 static void EDIT_SetRectNP(WND
*wnd
, EDITSTATE
*es
, LPRECT32 lprc
);
183 static void EDIT_UnlockBuffer(WND
*wnd
, EDITSTATE
*es
, BOOL32 force
);
184 static INT32
EDIT_WordBreakProc(LPSTR s
, INT32 index
, INT32 count
, INT32 action
);
186 * EM_XXX message handlers
188 static LRESULT
EDIT_EM_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
);
189 static BOOL32
EDIT_EM_FmtLines(WND
*wnd
, EDITSTATE
*es
, BOOL32 add_eol
);
190 static HLOCAL32
EDIT_EM_GetHandle(WND
*wnd
, EDITSTATE
*es
);
191 static HLOCAL16
EDIT_EM_GetHandle16(WND
*wnd
, EDITSTATE
*es
);
192 static INT32
EDIT_EM_GetLine(WND
*wnd
, EDITSTATE
*es
, INT32 line
, LPSTR lpch
);
193 static LRESULT
EDIT_EM_GetSel(WND
*wnd
, EDITSTATE
*es
, LPUINT32 start
, LPUINT32 end
);
194 static LRESULT
EDIT_EM_GetThumb(WND
*wnd
, EDITSTATE
*es
);
195 static INT32
EDIT_EM_LineFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
);
196 static INT32
EDIT_EM_LineIndex(WND
*wnd
, EDITSTATE
*es
, INT32 line
);
197 static INT32
EDIT_EM_LineLength(WND
*wnd
, EDITSTATE
*es
, INT32 index
);
198 static BOOL32
EDIT_EM_LineScroll(WND
*wnd
, EDITSTATE
*es
, INT32 dx
, INT32 dy
);
199 static LRESULT
EDIT_EM_PosFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
, BOOL32 after_wrap
);
200 static void EDIT_EM_ReplaceSel(WND
*wnd
, EDITSTATE
*es
, BOOL32 can_undo
, LPCSTR lpsz_replace
);
201 static LRESULT
EDIT_EM_Scroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
);
202 static void EDIT_EM_ScrollCaret(WND
*wnd
, EDITSTATE
*es
);
203 static void EDIT_EM_SetHandle(WND
*wnd
, EDITSTATE
*es
, HLOCAL32 hloc
);
204 static void EDIT_EM_SetHandle16(WND
*wnd
, EDITSTATE
*es
, HLOCAL16 hloc
);
205 static void EDIT_EM_SetLimitText(WND
*wnd
, EDITSTATE
*es
, INT32 limit
);
206 static void EDIT_EM_SetMargins(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 left
, INT32 right
);
207 static void EDIT_EM_SetPasswordChar(WND
*wnd
, EDITSTATE
*es
, CHAR c
);
208 static void EDIT_EM_SetSel(WND
*wnd
, EDITSTATE
*es
, UINT32 start
, UINT32 end
, BOOL32 after_wrap
);
209 static BOOL32
EDIT_EM_SetTabStops(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT32 tabs
);
210 static BOOL32
EDIT_EM_SetTabStops16(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT16 tabs
);
211 static void EDIT_EM_SetWordBreakProc(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC32A wbp
);
212 static void EDIT_EM_SetWordBreakProc16(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC16 wbp
);
213 static BOOL32
EDIT_EM_Undo(WND
*wnd
, EDITSTATE
*es
);
215 * WM_XXX message handlers
217 static void EDIT_WM_Char(WND
*wnd
, EDITSTATE
*es
, CHAR c
, DWORD key_data
);
218 static void EDIT_WM_Command(WND
*wnd
, EDITSTATE
*es
, INT32 code
, INT32 id
, HWND32 conrtol
);
219 static void EDIT_WM_ContextMenu(WND
*wnd
, EDITSTATE
*es
, HWND32 hwnd
, INT32 x
, INT32 y
);
220 static void EDIT_WM_Copy(WND
*wnd
, EDITSTATE
*es
);
221 static LRESULT
EDIT_WM_Create(WND
*wnd
, EDITSTATE
*es
, LPCREATESTRUCT32A cs
);
222 static void EDIT_WM_Destroy(WND
*wnd
, EDITSTATE
*es
);
223 static LRESULT
EDIT_WM_EraseBkGnd(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
);
224 static INT32
EDIT_WM_GetText(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPSTR text
);
225 static LRESULT
EDIT_WM_HScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
);
226 static LRESULT
EDIT_WM_KeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
);
227 static LRESULT
EDIT_WM_KillFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_getting_focus
);
228 static LRESULT
EDIT_WM_LButtonDblClk(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
229 static LRESULT
EDIT_WM_LButtonDown(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
230 static LRESULT
EDIT_WM_LButtonUp(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
231 static LRESULT
EDIT_WM_MouseMove(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
232 static LRESULT
EDIT_WM_NCCreate(WND
*wnd
, LPCREATESTRUCT32A cs
);
233 static void EDIT_WM_Paint(WND
*wnd
, EDITSTATE
*es
);
234 static void EDIT_WM_Paste(WND
*wnd
, EDITSTATE
*es
);
235 static void EDIT_WM_SetFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_losing_focus
);
236 static void EDIT_WM_SetFont(WND
*wnd
, EDITSTATE
*es
, HFONT32 font
, BOOL32 redraw
);
237 static void EDIT_WM_SetText(WND
*wnd
, EDITSTATE
*es
, LPCSTR text
);
238 static void EDIT_WM_Size(WND
*wnd
, EDITSTATE
*es
, UINT32 action
, INT32 width
, INT32 height
);
239 static LRESULT
EDIT_WM_SysKeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
);
240 static void EDIT_WM_Timer(WND
*wnd
, EDITSTATE
*es
, INT32 id
, TIMERPROC32 timer_proc
);
241 static LRESULT
EDIT_WM_VScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
);
244 /*********************************************************************
249 static __inline__ BOOL32
EDIT_EM_CanUndo(WND
*wnd
, EDITSTATE
*es
)
251 return (es
->undo_insert_count
|| lstrlen32A(es
->undo_text
));
255 /*********************************************************************
260 static __inline__
void EDIT_EM_EmptyUndoBuffer(WND
*wnd
, EDITSTATE
*es
)
262 es
->undo_insert_count
= 0;
263 *es
->undo_text
= '\0';
267 /*********************************************************************
272 static __inline__
void EDIT_WM_Clear(WND
*wnd
, EDITSTATE
*es
)
274 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "");
278 /*********************************************************************
283 static __inline__
void EDIT_WM_Cut(WND
*wnd
, EDITSTATE
*es
)
285 EDIT_WM_Copy(wnd
, es
);
286 EDIT_WM_Clear(wnd
, es
);
290 /*********************************************************************
294 * The messages are in the order of the actual integer values
295 * (which can be found in include/windows.h)
296 * Whereever possible the 16 bit versions are converted to
297 * the 32 bit ones, so that we can 'fall through' to the
298 * helper functions. These are mostly 32 bit (with a few
299 * exceptions, clearly indicated by a '16' extension to their
303 LRESULT WINAPI
EditWndProc( HWND32 hwnd
, UINT32 msg
,
304 WPARAM32 wParam
, LPARAM lParam
)
306 WND
*wnd
= WIN_FindWndPtr(hwnd
);
307 EDITSTATE
*es
= *(EDITSTATE
**)((wnd
)->wExtra
);
312 DPRINTF_EDIT_MSG32("WM_DESTROY");
313 EDIT_WM_Destroy(wnd
, es
);
317 DPRINTF_EDIT_MSG32("WM_NCCREATE");
318 return EDIT_WM_NCCreate(wnd
, (LPCREATESTRUCT32A
)lParam
);
322 return DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
324 EDIT_LockBuffer(wnd
, es
);
327 DPRINTF_EDIT_MSG16("EM_GETSEL");
332 DPRINTF_EDIT_MSG32("EM_GETSEL");
333 result
= EDIT_EM_GetSel(wnd
, es
, (LPUINT32
)wParam
, (LPUINT32
)lParam
);
337 DPRINTF_EDIT_MSG16("EM_SETSEL");
338 if (SLOWORD(lParam
) == -1)
339 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
341 EDIT_EM_SetSel(wnd
, es
, LOWORD(lParam
), HIWORD(lParam
), FALSE
);
343 EDIT_EM_ScrollCaret(wnd
, es
);
347 DPRINTF_EDIT_MSG32("EM_SETSEL");
348 EDIT_EM_SetSel(wnd
, es
, wParam
, lParam
, FALSE
);
353 DPRINTF_EDIT_MSG16("EM_GETRECT");
355 CONV_RECT32TO16(&es
->format_rect
, (LPRECT16
)PTR_SEG_TO_LIN(lParam
));
358 DPRINTF_EDIT_MSG32("EM_GETRECT");
360 CopyRect32((LPRECT32
)lParam
, &es
->format_rect
);
364 DPRINTF_EDIT_MSG16("EM_SETRECT");
365 if ((es
->style
& ES_MULTILINE
) && lParam
) {
367 CONV_RECT16TO32((LPRECT16
)PTR_SEG_TO_LIN(lParam
), &rc
);
368 EDIT_SetRectNP(wnd
, es
, &rc
);
369 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
373 DPRINTF_EDIT_MSG32("EM_SETRECT");
374 if ((es
->style
& ES_MULTILINE
) && lParam
) {
375 EDIT_SetRectNP(wnd
, es
, (LPRECT32
)lParam
);
376 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
381 DPRINTF_EDIT_MSG16("EM_SETRECTNP");
382 if ((es
->style
& ES_MULTILINE
) && lParam
) {
384 CONV_RECT16TO32((LPRECT16
)PTR_SEG_TO_LIN(lParam
), &rc
);
385 EDIT_SetRectNP(wnd
, es
, &rc
);
389 DPRINTF_EDIT_MSG32("EM_SETRECTNP");
390 if ((es
->style
& ES_MULTILINE
) && lParam
)
391 EDIT_SetRectNP(wnd
, es
, (LPRECT32
)lParam
);
395 DPRINTF_EDIT_MSG16("EM_SCROLL");
398 DPRINTF_EDIT_MSG32("EM_SCROLL");
399 result
= EDIT_EM_Scroll(wnd
, es
, (INT32
)wParam
);
402 case EM_LINESCROLL16
:
403 DPRINTF_EDIT_MSG16("EM_LINESCROLL");
404 wParam
= (WPARAM32
)(INT32
)SHIWORD(lParam
);
405 lParam
= (LPARAM
)(INT32
)SLOWORD(lParam
);
407 case EM_LINESCROLL32
:
408 DPRINTF_EDIT_MSG32("EM_LINESCROLL");
409 result
= (LRESULT
)EDIT_EM_LineScroll(wnd
, es
, (INT32
)wParam
, (INT32
)lParam
);
412 case EM_SCROLLCARET16
:
413 DPRINTF_EDIT_MSG16("EM_SCROLLCARET");
415 case EM_SCROLLCARET32
:
416 DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
417 EDIT_EM_ScrollCaret(wnd
, es
);
422 DPRINTF_EDIT_MSG16("EM_GETMODIFY");
425 DPRINTF_EDIT_MSG32("EM_GETMODIFY");
426 return ((es
->flags
& EF_MODIFIED
) != 0);
430 DPRINTF_EDIT_MSG16("EM_SETMODIFY");
433 DPRINTF_EDIT_MSG32("EM_SETMODIFY");
435 es
->flags
|= EF_MODIFIED
;
437 es
->flags
&= ~EF_MODIFIED
;
440 case EM_GETLINECOUNT16
:
441 DPRINTF_EDIT_MSG16("EM_GETLINECOUNT");
443 case EM_GETLINECOUNT32
:
444 DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
445 result
= (es
->style
& ES_MULTILINE
) ? es
->line_count
: 1;
449 DPRINTF_EDIT_MSG16("EM_LINEINDEX");
450 if ((INT16
)wParam
== -1)
451 wParam
= (WPARAM32
)-1;
454 DPRINTF_EDIT_MSG32("EM_LINEINDEX");
455 result
= (LRESULT
)EDIT_EM_LineIndex(wnd
, es
, (INT32
)wParam
);
459 DPRINTF_EDIT_MSG16("EM_SETHANDLE");
460 EDIT_EM_SetHandle16(wnd
, es
, (HLOCAL16
)wParam
);
463 DPRINTF_EDIT_MSG32("EM_SETHANDLE");
464 EDIT_EM_SetHandle(wnd
, es
, (HLOCAL32
)wParam
);
468 DPRINTF_EDIT_MSG16("EM_GETHANDLE");
469 result
= (LRESULT
)EDIT_EM_GetHandle16(wnd
, es
);
472 DPRINTF_EDIT_MSG32("EM_GETHANDLE");
473 result
= (LRESULT
)EDIT_EM_GetHandle(wnd
, es
);
477 DPRINTF_EDIT_MSG16("EM_GETTHUMB");
480 DPRINTF_EDIT_MSG32("EM_GETTHUMB");
481 result
= EDIT_EM_GetThumb(wnd
, es
);
484 /* messages 0x00bf and 0x00c0 missing from specs */
487 DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
490 DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
491 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
495 DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
498 DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
499 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
502 case EM_LINELENGTH16
:
503 DPRINTF_EDIT_MSG16("EM_LINELENGTH");
505 case EM_LINELENGTH32
:
506 DPRINTF_EDIT_MSG32("EM_LINELENGTH");
507 result
= (LRESULT
)EDIT_EM_LineLength(wnd
, es
, (INT32
)wParam
);
510 case EM_REPLACESEL16
:
511 DPRINTF_EDIT_MSG16("EM_REPLACESEL");
512 lParam
= (LPARAM
)PTR_SEG_TO_LIN((SEGPTR
)lParam
);
514 case EM_REPLACESEL32
:
515 DPRINTF_EDIT_MSG32("EM_REPLACESEL");
516 EDIT_EM_ReplaceSel(wnd
, es
, (BOOL32
)wParam
, (LPCSTR
)lParam
);
520 /* message 0x00c3 missing from specs */
523 DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
526 DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
527 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
531 DPRINTF_EDIT_MSG16("EM_GETLINE");
532 lParam
= (LPARAM
)PTR_SEG_TO_LIN((SEGPTR
)lParam
);
535 DPRINTF_EDIT_MSG32("EM_GETLINE");
536 result
= (LRESULT
)EDIT_EM_GetLine(wnd
, es
, (INT32
)wParam
, (LPSTR
)lParam
);
540 DPRINTF_EDIT_MSG16("EM_LIMITTEXT");
542 case EM_SETLIMITTEXT32
:
543 DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
544 EDIT_EM_SetLimitText(wnd
, es
, (INT32
)wParam
);
548 DPRINTF_EDIT_MSG16("EM_CANUNDO");
551 DPRINTF_EDIT_MSG32("EM_CANUNDO");
552 result
= (LRESULT
)EDIT_EM_CanUndo(wnd
, es
);
556 DPRINTF_EDIT_MSG16("EM_UNDO");
561 DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
562 result
= (LRESULT
)EDIT_EM_Undo(wnd
, es
);
566 DPRINTF_EDIT_MSG16("EM_FMTLINES");
569 DPRINTF_EDIT_MSG32("EM_FMTLINES");
570 result
= (LRESULT
)EDIT_EM_FmtLines(wnd
, es
, (BOOL32
)wParam
);
573 case EM_LINEFROMCHAR16
:
574 DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR");
576 case EM_LINEFROMCHAR32
:
577 DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
578 result
= (LRESULT
)EDIT_EM_LineFromChar(wnd
, es
, (INT32
)wParam
);
581 /* message 0x00ca missing from specs */
584 DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
587 DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
588 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
591 case EM_SETTABSTOPS16
:
592 DPRINTF_EDIT_MSG16("EM_SETTABSTOPS");
593 result
= (LRESULT
)EDIT_EM_SetTabStops16(wnd
, es
, (INT32
)wParam
, (LPINT16
)PTR_SEG_TO_LIN((SEGPTR
)lParam
));
595 case EM_SETTABSTOPS32
:
596 DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
597 result
= (LRESULT
)EDIT_EM_SetTabStops(wnd
, es
, (INT32
)wParam
, (LPINT32
)lParam
);
600 case EM_SETPASSWORDCHAR16
:
601 DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR");
603 case EM_SETPASSWORDCHAR32
:
604 DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
605 EDIT_EM_SetPasswordChar(wnd
, es
, (CHAR
)wParam
);
608 case EM_EMPTYUNDOBUFFER16
:
609 DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER");
611 case EM_EMPTYUNDOBUFFER32
:
612 DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
613 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
616 case EM_GETFIRSTVISIBLELINE16
:
617 DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE");
618 result
= es
->y_offset
;
620 case EM_GETFIRSTVISIBLELINE32
:
621 DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
622 result
= (es
->style
& ES_MULTILINE
) ? es
->y_offset
: es
->x_offset
;
625 case EM_SETREADONLY16
:
626 DPRINTF_EDIT_MSG16("EM_SETREADONLY");
628 case EM_SETREADONLY32
:
629 DPRINTF_EDIT_MSG32("EM_SETREADONLY");
631 wnd
->dwStyle
|= ES_READONLY
;
632 es
->style
|= ES_READONLY
;
634 wnd
->dwStyle
&= ~ES_READONLY
;
635 es
->style
&= ~ES_READONLY
;
640 case EM_SETWORDBREAKPROC16
:
641 DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC");
642 EDIT_EM_SetWordBreakProc16(wnd
, es
, (EDITWORDBREAKPROC16
)lParam
);
644 case EM_SETWORDBREAKPROC32
:
645 DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
646 EDIT_EM_SetWordBreakProc(wnd
, es
, (EDITWORDBREAKPROC32A
)lParam
);
649 case EM_GETWORDBREAKPROC16
:
650 DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC");
651 result
= (LRESULT
)es
->word_break_proc16
;
653 case EM_GETWORDBREAKPROC32
:
654 DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
655 result
= (LRESULT
)es
->word_break_proc32A
;
658 case EM_GETPASSWORDCHAR16
:
659 DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR");
661 case EM_GETPASSWORDCHAR32
:
662 DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
663 result
= es
->password_char
;
666 /* The following EM_xxx are new to win95 and don't exist for 16 bit */
668 case EM_SETMARGINS32
:
669 DPRINTF_EDIT_MSG32("EM_SETMARGINS");
670 EDIT_EM_SetMargins(wnd
, es
, (INT32
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
673 case EM_GETMARGINS32
:
674 DPRINTF_EDIT_MSG32("EM_GETMARGINS");
675 result
= MAKELONG(es
->left_margin
, es
->right_margin
);
678 case EM_GETLIMITTEXT32
:
679 DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
680 result
= es
->buffer_limit
;
683 case EM_POSFROMCHAR32
:
684 DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
685 result
= EDIT_EM_PosFromChar(wnd
, es
, (INT32
)wParam
, FALSE
);
688 case EM_CHARFROMPOS32
:
689 DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
690 result
= EDIT_EM_CharFromPos(wnd
, es
, SLOWORD(lParam
), SHIWORD(lParam
));
694 DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
695 result
= (es
->style
& ES_MULTILINE
) ?
696 DLGC_WANTALLKEYS
| DLGC_HASSETSEL
| DLGC_WANTCHARS
| DLGC_WANTARROWS
:
697 DLGC_HASSETSEL
| DLGC_WANTCHARS
| DLGC_WANTARROWS
;
701 DPRINTF_EDIT_MSG32("WM_CHAR");
702 EDIT_WM_Char(wnd
, es
, (CHAR
)wParam
, (DWORD
)lParam
);
706 DPRINTF_EDIT_MSG32("WM_CLEAR");
707 EDIT_WM_Clear(wnd
, es
);
711 DPRINTF_EDIT_MSG32("WM_COMMAND");
712 EDIT_WM_Command(wnd
, es
, HIWORD(wParam
), LOWORD(wParam
), (HWND32
)lParam
);
716 DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
717 EDIT_WM_ContextMenu(wnd
, es
, (HWND32
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
721 DPRINTF_EDIT_MSG32("WM_COPY");
722 EDIT_WM_Copy(wnd
, es
);
726 DPRINTF_EDIT_MSG32("WM_CREATE");
727 result
= EDIT_WM_Create(wnd
, es
, (LPCREATESTRUCT32A
)lParam
);
731 DPRINTF_EDIT_MSG32("WM_CUT");
732 EDIT_WM_Cut(wnd
, es
);
736 DPRINTF_EDIT_MSG32("WM_ENABLE");
737 InvalidateRect32(hwnd
, NULL
, TRUE
);
741 DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
742 result
= EDIT_WM_EraseBkGnd(wnd
, es
, (HDC32
)wParam
);
746 DPRINTF_EDIT_MSG32("WM_GETFONT");
747 result
= (LRESULT
)es
->font
;
751 DPRINTF_EDIT_MSG32("WM_GETTEXT");
752 result
= (LRESULT
)EDIT_WM_GetText(wnd
, es
, (INT32
)wParam
, (LPSTR
)lParam
);
755 case WM_GETTEXTLENGTH
:
756 DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
757 result
= lstrlen32A(es
->text
);
761 DPRINTF_EDIT_MSG32("WM_HSCROLL");
762 result
= EDIT_WM_HScroll(wnd
, es
, LOWORD(wParam
), SHIWORD(wParam
), (HWND32
)lParam
);
766 DPRINTF_EDIT_MSG32("WM_KEYDOWN");
767 result
= EDIT_WM_KeyDown(wnd
, es
, (INT32
)wParam
, (DWORD
)lParam
);
771 DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
772 result
= EDIT_WM_KillFocus(wnd
, es
, (HWND32
)wParam
);
775 case WM_LBUTTONDBLCLK
:
776 DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
777 result
= EDIT_WM_LButtonDblClk(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
781 DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
782 result
= EDIT_WM_LButtonDown(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
786 DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
787 result
= EDIT_WM_LButtonUp(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
790 case WM_MOUSEACTIVATE
:
792 * FIXME: maybe DefWindowProc() screws up, but it seems that
793 * modalless dialog boxes need this. If we don't do this, the focus
794 * will _not_ be set by DefWindowProc() for edit controls in a
795 * modalless dialog box ???
797 DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
798 SetFocus32(wnd
->hwndSelf
);
799 result
= MA_ACTIVATE
;
804 * DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
806 result
= EDIT_WM_MouseMove(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
810 DPRINTF_EDIT_MSG32("WM_PAINT");
811 EDIT_WM_Paint(wnd
, es
);
815 DPRINTF_EDIT_MSG32("WM_PASTE");
816 EDIT_WM_Paste(wnd
, es
);
820 DPRINTF_EDIT_MSG32("WM_SETFOCUS");
821 EDIT_WM_SetFocus(wnd
, es
, (HWND32
)wParam
);
825 DPRINTF_EDIT_MSG32("WM_SETFONT");
826 EDIT_WM_SetFont(wnd
, es
, (HFONT32
)wParam
, LOWORD(lParam
) != 0);
830 DPRINTF_EDIT_MSG32("WM_SETTEXT");
831 EDIT_WM_SetText(wnd
, es
, (LPCSTR
)lParam
);
836 DPRINTF_EDIT_MSG32("WM_SIZE");
837 EDIT_WM_Size(wnd
, es
, (UINT32
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
841 DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
842 result
= EDIT_WM_SysKeyDown(wnd
, es
, (INT32
)wParam
, (DWORD
)lParam
);
846 DPRINTF_EDIT_MSG32("WM_TIMER");
847 EDIT_WM_Timer(wnd
, es
, (INT32
)wParam
, (TIMERPROC32
)lParam
);
851 DPRINTF_EDIT_MSG32("WM_VSCROLL");
852 result
= EDIT_WM_VScroll(wnd
, es
, LOWORD(wParam
), SHIWORD(wParam
), (HWND32
)(lParam
));
856 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
859 EDIT_UnlockBuffer(wnd
, es
, FALSE
);
864 /*********************************************************************
866 * EDIT_BuildLineDefs_ML
868 * Build linked list of text lines.
869 * Lines can end with '\0' (last line), a character (if it is wrapped),
870 * a soft return '\r\r\n' or a hard return '\r\n'
873 static void EDIT_BuildLineDefs_ML(WND
*wnd
, EDITSTATE
*es
)
876 HFONT32 old_font
= 0;
879 LINEDEF
*current_def
;
880 LINEDEF
**previous_next
;
882 current_def
= es
->first_line_def
;
884 LINEDEF
*next_def
= current_def
->next
;
885 HeapFree(es
->heap
, 0, current_def
);
886 current_def
= next_def
;
887 } while (current_def
);
891 dc
= GetDC32(wnd
->hwndSelf
);
893 old_font
= SelectObject32(dc
, es
->font
);
895 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
897 previous_next
= &es
->first_line_def
;
899 current_def
= HeapAlloc(es
->heap
, 0, sizeof(LINEDEF
));
900 current_def
->next
= NULL
;
903 if ((*cp
== '\r') && (*(cp
+ 1) == '\n'))
908 current_def
->ending
= END_0
;
909 current_def
->net_length
= lstrlen32A(start
);
910 } else if ((cp
> start
) && (*(cp
- 1) == '\r')) {
911 current_def
->ending
= END_SOFT
;
912 current_def
->net_length
= cp
- start
- 1;
914 current_def
->ending
= END_HARD
;
915 current_def
->net_length
= cp
- start
;
917 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
,
918 start
, current_def
->net_length
,
919 es
->tabs_count
, es
->tabs
));
920 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
921 if ((!(es
->style
& ES_AUTOHSCROLL
)) && (current_def
->width
> fw
)) {
926 next
= EDIT_CallWordBreakProc(wnd
, es
, start
- es
->text
,
927 prev
+ 1, current_def
->net_length
, WB_RIGHT
);
928 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
,
929 start
, next
, es
->tabs_count
, es
->tabs
));
930 } while (current_def
->width
<= fw
);
936 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
,
937 start
, next
, es
->tabs_count
, es
->tabs
));
938 } while (current_def
->width
<= fw
);
942 current_def
->net_length
= prev
;
943 current_def
->ending
= END_WRAP
;
944 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
, start
,
945 current_def
->net_length
, es
->tabs_count
, es
->tabs
));
947 switch (current_def
->ending
) {
949 current_def
->length
= current_def
->net_length
+ 3;
952 current_def
->length
= current_def
->net_length
+ 2;
956 current_def
->length
= current_def
->net_length
;
959 es
->text_width
= MAX(es
->text_width
, current_def
->width
);
960 start
+= current_def
->length
;
961 *previous_next
= current_def
;
962 previous_next
= ¤t_def
->next
;
964 } while (current_def
->ending
!= END_0
);
966 SelectObject32(dc
, old_font
);
967 ReleaseDC32(wnd
->hwndSelf
, dc
);
971 /*********************************************************************
973 * EDIT_CallWordBreakProc
975 * Call appropriate WordBreakProc (internal or external).
977 * Note: The "start" argument should always be an index refering
978 * to es->text. The actual wordbreak proc might be
979 * 16 bit, so we can't always pass any 32 bit LPSTR.
980 * Hence we assume that es->text is the buffer that holds
981 * the string under examination (we can decide this for ourselves).
984 static INT32
EDIT_CallWordBreakProc(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 index
, INT32 count
, INT32 action
)
986 if (es
->word_break_proc16
) {
987 HLOCAL16 hloc16
= EDIT_EM_GetHandle16(wnd
, es
);
988 SEGPTR segptr
= LocalLock16(hloc16
);
989 INT32 ret
= (INT32
)Callbacks
->CallWordBreakProc(es
->word_break_proc16
,
990 segptr
+ start
, index
, count
, action
);
991 LocalUnlock16(hloc16
);
994 else if (es
->word_break_proc32A
)
996 TRACE(relay
, "(wordbrk=%p,str='%s',idx=%d,cnt=%d,act=%d)\n",
997 es
->word_break_proc32A
, es
->text
+ start
, index
,
999 return (INT32
)es
->word_break_proc32A( es
->text
+ start
, index
,
1003 return EDIT_WordBreakProc(es
->text
+ start
, index
, count
, action
);
1007 /*********************************************************************
1011 * Beware: This is not the function called on EM_CHARFROMPOS
1012 * The position _can_ be outside the formatting / client
1014 * The return value is only the character index
1017 static INT32
EDIT_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
, LPBOOL32 after_wrap
)
1021 HFONT32 old_font
= 0;
1023 if (es
->style
& ES_MULTILINE
) {
1024 INT32 line
= (y
- es
->format_rect
.top
) / es
->line_height
+ es
->y_offset
;
1025 INT32 line_index
= 0;
1026 LINEDEF
*line_def
= es
->first_line_def
;
1028 while ((line
> 0) && line_def
->next
) {
1029 line_index
+= line_def
->length
;
1030 line_def
= line_def
->next
;
1033 x
+= es
->x_offset
- es
->format_rect
.left
;
1034 if (x
>= line_def
->width
) {
1036 *after_wrap
= (line_def
->ending
== END_WRAP
);
1037 return line_index
+ line_def
->net_length
;
1041 *after_wrap
= FALSE
;
1044 dc
= GetDC32(wnd
->hwndSelf
);
1046 old_font
= SelectObject32(dc
, es
->font
);
1047 low
= line_index
+ 1;
1048 high
= line_index
+ line_def
->net_length
+ 1;
1049 while (low
< high
- 1)
1051 INT32 mid
= (low
+ high
) / 2;
1052 if (LOWORD(GetTabbedTextExtent32A(dc
, es
->text
+ line_index
,mid
- line_index
, es
->tabs_count
, es
->tabs
)) > x
) high
= mid
;
1058 *after_wrap
= ((index
== line_index
+ line_def
->net_length
) &&
1059 (line_def
->ending
== END_WRAP
));
1064 *after_wrap
= FALSE
;
1065 x
-= es
->format_rect
.left
;
1067 return es
->x_offset
;
1068 text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
1069 dc
= GetDC32(wnd
->hwndSelf
);
1071 old_font
= SelectObject32(dc
, es
->font
);
1075 INT32 high
= es
->x_offset
;
1076 while (low
< high
- 1)
1078 INT32 mid
= (low
+ high
) / 2;
1079 GetTextExtentPoint32A( dc
, text
+ mid
,
1080 es
->x_offset
- mid
, &size
);
1081 if (size
.cx
> -x
) low
= mid
;
1088 INT32 low
= es
->x_offset
;
1089 INT32 high
= lstrlen32A(es
->text
) + 1;
1090 while (low
< high
- 1)
1092 INT32 mid
= (low
+ high
) / 2;
1093 GetTextExtentPoint32A( dc
, text
+ es
->x_offset
,
1094 mid
- es
->x_offset
, &size
);
1095 if (size
.cx
> x
) high
= mid
;
1100 if (es
->style
& ES_PASSWORD
)
1101 HeapFree(es
->heap
, 0 ,text
);
1104 SelectObject32(dc
, old_font
);
1105 ReleaseDC32(wnd
->hwndSelf
, dc
);
1110 /*********************************************************************
1114 * adjusts the point to be within the formatting rectangle
1115 * (so CharFromPos returns the nearest _visible_ character)
1118 static void EDIT_ConfinePoint(WND
*wnd
, EDITSTATE
*es
, LPINT32 x
, LPINT32 y
)
1120 *x
= MIN(MAX(*x
, es
->format_rect
.left
), es
->format_rect
.right
- 1);
1121 *y
= MIN(MAX(*y
, es
->format_rect
.top
), es
->format_rect
.bottom
- 1);
1125 /*********************************************************************
1129 * Calculates the bounding rectangle for a line from a starting
1130 * column to an ending column.
1133 static void EDIT_GetLineRect(WND
*wnd
, EDITSTATE
*es
, INT32 line
, INT32 scol
, INT32 ecol
, LPRECT32 rc
)
1135 INT32 line_index
= EDIT_EM_LineIndex(wnd
, es
, line
);
1137 if (es
->style
& ES_MULTILINE
)
1138 rc
->top
= es
->format_rect
.top
+ (line
- es
->y_offset
) * es
->line_height
;
1140 rc
->top
= es
->format_rect
.top
;
1141 rc
->bottom
= rc
->top
+ es
->line_height
;
1142 rc
->left
= (scol
== 0) ? es
->format_rect
.left
: SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, line_index
+ scol
, TRUE
));
1143 rc
->right
= (ecol
== -1) ? es
->format_rect
.right
: SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, line_index
+ ecol
, TRUE
));
1147 /*********************************************************************
1149 * EDIT_GetPasswordPointer_SL
1151 * note: caller should free the (optionally) allocated buffer
1154 static LPSTR
EDIT_GetPasswordPointer_SL(WND
*wnd
, EDITSTATE
*es
)
1156 if (es
->style
& ES_PASSWORD
) {
1157 INT32 len
= lstrlen32A(es
->text
);
1158 LPSTR text
= HeapAlloc(es
->heap
, 0, len
+ 1);
1159 RtlFillMemory(text
, len
, es
->password_char
);
1167 /*********************************************************************
1171 * This acts as a LOCAL_Lock(), but it locks only once. This way
1172 * you can call it whenever you like, without unlocking.
1175 static void EDIT_LockBuffer(WND
*wnd
, EDITSTATE
*es
)
1178 ERR(edit
, "no EDITSTATE ... please report\n");
1181 if (!(es
->style
& ES_MULTILINE
))
1185 es
->text
= LocalLock32(es
->hloc32
);
1186 else if (es
->hloc16
)
1187 es
->text
= LOCAL_Lock(wnd
->hInstance
, es
->hloc16
);
1189 ERR(edit
, "no buffer ... please report\n");
1197 /*********************************************************************
1199 * EDIT_SL_InvalidateText
1201 * Called from EDIT_InvalidateText().
1202 * Does the job for single-line controls only.
1205 static void EDIT_SL_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
)
1210 EDIT_GetLineRect(wnd
, es
, 0, start
, end
, &line_rect
);
1211 if (IntersectRect32(&rc
, &line_rect
, &es
->format_rect
))
1212 InvalidateRect32(wnd
->hwndSelf
, &rc
, FALSE
);
1216 /*********************************************************************
1218 * EDIT_ML_InvalidateText
1220 * Called from EDIT_InvalidateText().
1221 * Does the job for multi-line controls only.
1224 static void EDIT_ML_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
)
1226 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1227 INT32 sl
= EDIT_EM_LineFromChar(wnd
, es
, start
);
1228 INT32 el
= EDIT_EM_LineFromChar(wnd
, es
, end
);
1237 if ((el
< es
->y_offset
) || (sl
> es
->y_offset
+ vlc
))
1240 sc
= start
- EDIT_EM_LineIndex(wnd
, es
, sl
);
1241 ec
= end
- EDIT_EM_LineIndex(wnd
, es
, el
);
1242 if (sl
< es
->y_offset
) {
1246 if (el
> es
->y_offset
+ vlc
) {
1247 el
= es
->y_offset
+ vlc
;
1248 ec
= EDIT_EM_LineLength(wnd
, es
, EDIT_EM_LineIndex(wnd
, es
, el
));
1250 GetClientRect32(wnd
->hwndSelf
, &rc1
);
1251 IntersectRect32(&rcWnd
, &rc1
, &es
->format_rect
);
1253 EDIT_GetLineRect(wnd
, es
, sl
, sc
, ec
, &rcLine
);
1254 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1255 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1257 EDIT_GetLineRect(wnd
, es
, sl
, sc
,
1258 EDIT_EM_LineLength(wnd
, es
,
1259 EDIT_EM_LineIndex(wnd
, es
, sl
)),
1261 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1262 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1263 for (l
= sl
+ 1 ; l
< el
; l
++) {
1264 EDIT_GetLineRect(wnd
, es
, l
, 0,
1265 EDIT_EM_LineLength(wnd
, es
,
1266 EDIT_EM_LineIndex(wnd
, es
, l
)),
1268 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1269 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1271 EDIT_GetLineRect(wnd
, es
, el
, 0, ec
, &rcLine
);
1272 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1273 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1278 /*********************************************************************
1280 * EDIT_InvalidateText
1282 * Invalidate the text from offset start upto, but not including,
1283 * offset end. Useful for (re)painting the selection.
1284 * Regions outside the linewidth are not invalidated.
1285 * end == -1 means end == TextLength.
1286 * start and end need not be ordered.
1289 static void EDIT_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
)
1295 end
= lstrlen32A(es
->text
);
1297 ORDER_INT32(start
, end
);
1299 if (es
->style
& ES_MULTILINE
)
1300 EDIT_ML_InvalidateText(wnd
, es
, start
, end
);
1302 EDIT_SL_InvalidateText(wnd
, es
, start
, end
);
1306 /*********************************************************************
1310 * Try to fit size + 1 bytes in the buffer. Constrain to limits.
1313 static BOOL32
EDIT_MakeFit(WND
*wnd
, EDITSTATE
*es
, INT32 size
)
1318 if (size
<= es
->buffer_size
)
1320 if (size
> es
->buffer_limit
) {
1321 EDIT_NOTIFY_PARENT(wnd
, EN_MAXTEXT
, "EN_MAXTEXT");
1324 size
= ((size
/ GROWLENGTH
) + 1) * GROWLENGTH
;
1325 if (size
> es
->buffer_limit
)
1326 size
= es
->buffer_limit
;
1328 TRACE(edit
, "trying to ReAlloc to %d+1\n", size
);
1330 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
1332 if ((es
->text
= HeapReAlloc(es
->heap
, 0, es
->text
, size
+ 1)))
1333 es
->buffer_size
= MIN(HeapSize(es
->heap
, 0, es
->text
) - 1, es
->buffer_limit
);
1335 es
->buffer_size
= 0;
1336 } else if (es
->hloc32
) {
1337 if ((hNew32
= LocalReAlloc32(es
->hloc32
, size
+ 1, 0))) {
1338 TRACE(edit
, "Old 32 bit handle %08x, new handle %08x\n", es
->hloc32
, hNew32
);
1339 es
->hloc32
= hNew32
;
1340 es
->buffer_size
= MIN(LocalSize32(es
->hloc32
) - 1, es
->buffer_limit
);
1342 } else if (es
->hloc16
) {
1343 if ((hNew16
= LOCAL_ReAlloc(wnd
->hInstance
, es
->hloc16
, size
+ 1, LMEM_MOVEABLE
))) {
1344 TRACE(edit
, "Old 16 bit handle %08x, new handle %08x\n", es
->hloc16
, hNew16
);
1345 es
->hloc16
= hNew16
;
1346 es
->buffer_size
= MIN(LOCAL_Size(wnd
->hInstance
, es
->hloc16
) - 1, es
->buffer_limit
);
1349 if (es
->buffer_size
< size
) {
1350 EDIT_LockBuffer(wnd
, es
);
1351 WARN(edit
, "FAILED ! We now have %d+1\n", es
->buffer_size
);
1352 EDIT_NOTIFY_PARENT(wnd
, EN_ERRSPACE
, "EN_ERRSPACE");
1355 EDIT_LockBuffer(wnd
, es
);
1356 TRACE(edit
, "We now have %d+1\n", es
->buffer_size
);
1362 /*********************************************************************
1366 * Try to fit size + 1 bytes in the undo buffer.
1369 static BOOL32
EDIT_MakeUndoFit(WND
*wnd
, EDITSTATE
*es
, INT32 size
)
1371 if (size
<= es
->undo_buffer_size
)
1373 size
= ((size
/ GROWLENGTH
) + 1) * GROWLENGTH
;
1375 TRACE(edit
, "trying to ReAlloc to %d+1\n", size
);
1377 if ((es
->undo_text
= HeapReAlloc(es
->heap
, 0, es
->undo_text
, size
+ 1))) {
1378 es
->undo_buffer_size
= HeapSize(es
->heap
, 0, es
->undo_text
) - 1;
1379 if (es
->undo_buffer_size
< size
) {
1380 WARN(edit
, "FAILED ! We now have %d+1\n", es
->undo_buffer_size
);
1389 /*********************************************************************
1394 static void EDIT_MoveBackward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1396 INT32 e
= es
->selection_end
;
1400 if ((es
->style
& ES_MULTILINE
) && e
&&
1401 (es
->text
[e
- 1] == '\r') && (es
->text
[e
] == '\n')) {
1403 if (e
&& (es
->text
[e
- 1] == '\r'))
1407 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1408 EDIT_EM_ScrollCaret(wnd
, es
);
1412 /*********************************************************************
1416 * Only for multi line controls
1417 * Move the caret one line down, on a column with the nearest
1418 * x coordinate on the screen (might be a different column).
1421 static void EDIT_MoveDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1423 INT32 s
= es
->selection_start
;
1424 INT32 e
= es
->selection_end
;
1425 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1426 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1427 INT32 x
= SLOWORD(pos
);
1428 INT32 y
= SHIWORD(pos
);
1430 e
= EDIT_CharFromPos(wnd
, es
, x
, y
+ es
->line_height
, &after_wrap
);
1433 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1434 EDIT_EM_ScrollCaret(wnd
, es
);
1438 /*********************************************************************
1443 static void EDIT_MoveEnd(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1445 BOOL32 after_wrap
= FALSE
;
1448 if (es
->style
& ES_MULTILINE
)
1449 e
= EDIT_CharFromPos(wnd
, es
, 0x7fffffff,
1450 HIWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
)), &after_wrap
);
1452 e
= lstrlen32A(es
->text
);
1453 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, after_wrap
);
1454 EDIT_EM_ScrollCaret(wnd
, es
);
1458 /*********************************************************************
1463 static void EDIT_MoveForward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1465 INT32 e
= es
->selection_end
;
1469 if ((es
->style
& ES_MULTILINE
) && (es
->text
[e
- 1] == '\r')) {
1470 if (es
->text
[e
] == '\n')
1472 else if ((es
->text
[e
] == '\r') && (es
->text
[e
+ 1] == '\n'))
1476 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1477 EDIT_EM_ScrollCaret(wnd
, es
);
1481 /*********************************************************************
1485 * Home key: move to beginning of line.
1488 static void EDIT_MoveHome(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1492 if (es
->style
& ES_MULTILINE
)
1493 e
= EDIT_CharFromPos(wnd
, es
, 0x80000000,
1494 HIWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
)), NULL
);
1497 EDIT_EM_SetSel(wnd
, es
, e
, extend
? es
->selection_start
: e
, FALSE
);
1498 EDIT_EM_ScrollCaret(wnd
, es
);
1502 /*********************************************************************
1504 * EDIT_MovePageDown_ML
1506 * Only for multi line controls
1507 * Move the caret one page down, on a column with the nearest
1508 * x coordinate on the screen (might be a different column).
1511 static void EDIT_MovePageDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1513 INT32 s
= es
->selection_start
;
1514 INT32 e
= es
->selection_end
;
1515 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1516 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1517 INT32 x
= SLOWORD(pos
);
1518 INT32 y
= SHIWORD(pos
);
1520 e
= EDIT_CharFromPos(wnd
, es
, x
,
1521 y
+ (es
->format_rect
.bottom
- es
->format_rect
.top
),
1525 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1526 EDIT_EM_ScrollCaret(wnd
, es
);
1530 /*********************************************************************
1532 * EDIT_MovePageUp_ML
1534 * Only for multi line controls
1535 * Move the caret one page up, on a column with the nearest
1536 * x coordinate on the screen (might be a different column).
1539 static void EDIT_MovePageUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1541 INT32 s
= es
->selection_start
;
1542 INT32 e
= es
->selection_end
;
1543 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1544 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1545 INT32 x
= SLOWORD(pos
);
1546 INT32 y
= SHIWORD(pos
);
1548 e
= EDIT_CharFromPos(wnd
, es
, x
,
1549 y
- (es
->format_rect
.bottom
- es
->format_rect
.top
),
1553 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1554 EDIT_EM_ScrollCaret(wnd
, es
);
1558 /*********************************************************************
1562 * Only for multi line controls
1563 * Move the caret one line up, on a column with the nearest
1564 * x coordinate on the screen (might be a different column).
1567 static void EDIT_MoveUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1569 INT32 s
= es
->selection_start
;
1570 INT32 e
= es
->selection_end
;
1571 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1572 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1573 INT32 x
= SLOWORD(pos
);
1574 INT32 y
= SHIWORD(pos
);
1576 e
= EDIT_CharFromPos(wnd
, es
, x
, y
- es
->line_height
, &after_wrap
);
1579 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1580 EDIT_EM_ScrollCaret(wnd
, es
);
1584 /*********************************************************************
1586 * EDIT_MoveWordBackward
1589 static void EDIT_MoveWordBackward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1591 INT32 s
= es
->selection_start
;
1592 INT32 e
= es
->selection_end
;
1597 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
1598 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
1599 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1602 li
= EDIT_EM_LineIndex(wnd
, es
, l
- 1);
1603 e
= li
+ EDIT_EM_LineLength(wnd
, es
, li
);
1606 e
= li
+ (INT32
)EDIT_CallWordBreakProc(wnd
, es
,
1607 li
, e
- li
, ll
, WB_LEFT
);
1611 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
1612 EDIT_EM_ScrollCaret(wnd
, es
);
1616 /*********************************************************************
1618 * EDIT_MoveWordForward
1621 static void EDIT_MoveWordForward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1623 INT32 s
= es
->selection_start
;
1624 INT32 e
= es
->selection_end
;
1629 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
1630 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
1631 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1633 if ((es
->style
& ES_MULTILINE
) && (l
!= es
->line_count
- 1))
1634 e
= EDIT_EM_LineIndex(wnd
, es
, l
+ 1);
1636 e
= li
+ EDIT_CallWordBreakProc(wnd
, es
,
1637 li
, e
- li
+ 1, ll
, WB_RIGHT
);
1641 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
1642 EDIT_EM_ScrollCaret(wnd
, es
);
1646 /*********************************************************************
1651 static void EDIT_PaintLine(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
, INT32 line
, BOOL32 rev
)
1653 INT32 s
= es
->selection_start
;
1654 INT32 e
= es
->selection_end
;
1661 if (es
->style
& ES_MULTILINE
) {
1662 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1663 if ((line
< es
->y_offset
) || (line
> es
->y_offset
+ vlc
) || (line
>= es
->line_count
))
1668 TRACE(edit
, "line=%d\n", line
);
1670 pos
= EDIT_EM_PosFromChar(wnd
, es
, EDIT_EM_LineIndex(wnd
, es
, line
), FALSE
);
1673 li
= EDIT_EM_LineIndex(wnd
, es
, line
);
1674 ll
= EDIT_EM_LineLength(wnd
, es
, li
);
1675 s
= es
->selection_start
;
1676 e
= es
->selection_end
;
1678 s
= MIN(li
+ ll
, MAX(li
, s
));
1679 e
= MIN(li
+ ll
, MAX(li
, e
));
1680 if (rev
&& (s
!= e
) &&
1681 ((es
->flags
& EF_FOCUSED
) || (es
->style
& ES_NOHIDESEL
))) {
1682 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, 0, s
- li
, FALSE
);
1683 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, s
- li
, e
- s
, TRUE
);
1684 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, e
- li
, li
+ ll
- e
, FALSE
);
1686 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, 0, ll
, FALSE
);
1690 /*********************************************************************
1695 static INT32
EDIT_PaintText(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
, INT32 x
, INT32 y
, INT32 line
, INT32 col
, INT32 count
, BOOL32 rev
)
1705 BkColor
= GetBkColor32(dc
);
1706 TextColor
= GetTextColor32(dc
);
1708 SetBkColor32(dc
, GetSysColor32(COLOR_HIGHLIGHT
));
1709 SetTextColor32(dc
, GetSysColor32(COLOR_HIGHLIGHTTEXT
));
1711 li
= EDIT_EM_LineIndex(wnd
, es
, line
);
1712 if (es
->style
& ES_MULTILINE
) {
1713 ret
= (INT32
)LOWORD(TabbedTextOut32A(dc
, x
, y
, es
->text
+ li
+ col
, count
,
1714 es
->tabs_count
, es
->tabs
, es
->format_rect
.left
- es
->x_offset
));
1716 LPSTR text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
1717 TextOut32A(dc
, x
, y
, text
+ li
+ col
, count
);
1718 GetTextExtentPoint32A(dc
, text
+ li
+ col
, count
, &size
);
1720 if (es
->style
& ES_PASSWORD
)
1721 HeapFree(es
->heap
, 0, text
);
1724 SetBkColor32(dc
, BkColor
);
1725 SetTextColor32(dc
, TextColor
);
1731 /*********************************************************************
1736 static void EDIT_SetCaretPos(WND
*wnd
, EDITSTATE
*es
, INT32 pos
,
1739 LRESULT res
= EDIT_EM_PosFromChar(wnd
, es
, pos
, after_wrap
);
1740 INT32 x
= SLOWORD(res
);
1741 INT32 y
= SHIWORD(res
);
1743 if(x
< es
->format_rect
.left
)
1744 x
= es
->format_rect
.left
;
1745 if(x
> es
->format_rect
.right
- 2)
1746 x
= es
->format_rect
.right
- 2;
1747 if(y
> es
->format_rect
.bottom
)
1748 y
= es
->format_rect
.bottom
;
1749 if(y
< es
->format_rect
.top
)
1750 y
= es
->format_rect
.top
;
1751 SetCaretPos32(x
, y
);
1756 /*********************************************************************
1760 * note: this is not (exactly) the handler called on EM_SETRECTNP
1761 * it is also used to set the rect of a single line control
1764 static void EDIT_SetRectNP(WND
*wnd
, EDITSTATE
*es
, LPRECT32 rc
)
1766 CopyRect32(&es
->format_rect
, rc
);
1767 if (es
->style
& WS_BORDER
) {
1768 INT32 bw
= GetSystemMetrics32(SM_CXBORDER
) + 1;
1769 if(TWEAK_WineLook
== WIN31_LOOK
)
1771 es
->format_rect
.left
+= bw
;
1772 es
->format_rect
.top
+= bw
;
1773 es
->format_rect
.right
-= bw
;
1774 es
->format_rect
.bottom
-= bw
;
1776 es
->format_rect
.left
+= es
->left_margin
;
1777 es
->format_rect
.right
-= es
->right_margin
;
1778 es
->format_rect
.right
= MAX(es
->format_rect
.right
, es
->format_rect
.left
+ es
->char_width
);
1779 if (es
->style
& ES_MULTILINE
)
1780 es
->format_rect
.bottom
= es
->format_rect
.top
+
1781 MAX(1, (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
) * es
->line_height
;
1783 es
->format_rect
.bottom
= es
->format_rect
.top
+ es
->line_height
;
1784 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
))
1785 EDIT_BuildLineDefs_ML(wnd
, es
);
1789 /*********************************************************************
1794 static void EDIT_UnlockBuffer(WND
*wnd
, EDITSTATE
*es
, BOOL32 force
)
1797 ERR(edit
, "no EDITSTATE ... please report\n");
1800 if (!(es
->style
& ES_MULTILINE
))
1802 if (!es
->lock_count
) {
1803 ERR(edit
, "lock_count == 0 ... please report\n");
1807 ERR(edit
, "es->text == 0 ... please report\n");
1810 if (force
|| (es
->lock_count
== 1)) {
1812 LocalUnlock32(es
->hloc32
);
1814 } else if (es
->hloc16
) {
1815 LOCAL_Unlock(wnd
->hInstance
, es
->hloc16
);
1823 /*********************************************************************
1825 * EDIT_WordBreakProc
1827 * Find the beginning of words.
1828 * Note: unlike the specs for a WordBreakProc, this function only
1829 * allows to be called without linebreaks between s[0] upto
1830 * s[count - 1]. Remember it is only called
1831 * internally, so we can decide this for ourselves.
1834 static INT32
EDIT_WordBreakProc(LPSTR s
, INT32 index
, INT32 count
, INT32 action
)
1838 TRACE(edit
, "s=%p, index=%u, count=%u, action=%d\n",
1839 s
, index
, count
, action
);
1847 if (s
[index
] == ' ') {
1848 while (index
&& (s
[index
] == ' '))
1851 while (index
&& (s
[index
] != ' '))
1853 if (s
[index
] == ' ')
1857 while (index
&& (s
[index
] != ' '))
1859 if (s
[index
] == ' ')
1869 if (s
[index
] == ' ')
1870 while ((index
< count
) && (s
[index
] == ' ')) index
++;
1872 while (s
[index
] && (s
[index
] != ' ') && (index
< count
))
1874 while ((s
[index
] == ' ') && (index
< count
)) index
++;
1878 case WB_ISDELIMITER
:
1879 ret
= (s
[index
] == ' ');
1882 ERR(edit
, "unknown action code, please report !\n");
1889 /*********************************************************************
1893 * FIXME: do the specs mean to return LineIndex or LineNumber ???
1894 * Let's assume LineIndex is meant
1895 * FIXME: do the specs mean to return -1 if outside client area or
1896 * if outside formatting rectangle ???
1899 static LRESULT
EDIT_EM_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
)
1907 GetClientRect32(wnd
->hwndSelf
, &rc
);
1908 if (!PtInRect32(&rc
, pt
))
1911 index
= EDIT_CharFromPos(wnd
, es
, x
, y
, NULL
);
1912 return MAKELONG(index
, EDIT_EM_LineIndex(wnd
, es
,
1913 EDIT_EM_LineFromChar(wnd
, es
, index
)));
1917 /*********************************************************************
1921 * Enable or disable soft breaks.
1923 static BOOL32
EDIT_EM_FmtLines(WND
*wnd
, EDITSTATE
*es
, BOOL32 add_eol
)
1925 es
->flags
&= ~EF_USE_SOFTBRK
;
1927 es
->flags
|= EF_USE_SOFTBRK
;
1928 FIXME(edit
, "soft break enabled, not implemented\n");
1934 /*********************************************************************
1938 * Hopefully this won't fire back at us.
1939 * We always start with a fixed buffer in our own heap.
1940 * However, with this message a 32 bit application requests
1941 * a handle to 32 bit moveable local heap memory, where it expects
1943 * It's a pity that from this moment on we have to use this
1944 * local heap, because applications may rely on the handle
1947 * In this function we'll try to switch to local heap.
1950 static HLOCAL32
EDIT_EM_GetHandle(WND
*wnd
, EDITSTATE
*es
)
1956 if (!(es
->style
& ES_MULTILINE
))
1961 else if (es
->hloc16
)
1962 return (HLOCAL32
)es
->hloc16
;
1964 if (!(newBuf
= LocalAlloc32(LMEM_MOVEABLE
, lstrlen32A(es
->text
) + 1))) {
1965 ERR(edit
, "could not allocate new 32 bit buffer\n");
1968 newSize
= MIN(LocalSize32(newBuf
) - 1, es
->buffer_limit
);
1969 if (!(newText
= LocalLock32(newBuf
))) {
1970 ERR(edit
, "could not lock new 32 bit buffer\n");
1971 LocalFree32(newBuf
);
1974 lstrcpy32A(newText
, es
->text
);
1975 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
1977 HeapFree(es
->heap
, 0, es
->text
);
1978 es
->hloc32
= newBuf
;
1979 es
->hloc16
= (HLOCAL16
)NULL
;
1980 es
->buffer_size
= newSize
;
1982 EDIT_LockBuffer(wnd
, es
);
1983 TRACE(edit
, "switched to 32 bit local heap\n");
1989 /*********************************************************************
1993 * Hopefully this won't fire back at us.
1994 * We always start with a buffer in 32 bit linear memory.
1995 * However, with this message a 16 bit application requests
1996 * a handle of 16 bit local heap memory, where it expects to find
1998 * It's a pitty that from this moment on we have to use this
1999 * local heap, because applications may rely on the handle
2002 * In this function we'll try to switch to local heap.
2004 static HLOCAL16
EDIT_EM_GetHandle16(WND
*wnd
, EDITSTATE
*es
)
2010 if (!(es
->style
& ES_MULTILINE
))
2016 if (!LOCAL_HeapSize(wnd
->hInstance
)) {
2017 if (!LocalInit(wnd
->hInstance
, 0,
2018 GlobalSize16(wnd
->hInstance
))) {
2019 ERR(edit
, "could not initialize local heap\n");
2022 TRACE(edit
, "local heap initialized\n");
2024 if (!(newBuf
= LOCAL_Alloc(wnd
->hInstance
, LMEM_MOVEABLE
, lstrlen32A(es
->text
) + 1))) {
2025 ERR(edit
, "could not allocate new 16 bit buffer\n");
2028 newSize
= MIN(LOCAL_Size(wnd
->hInstance
, newBuf
) - 1, es
->buffer_limit
);
2029 if (!(newText
= LOCAL_Lock(wnd
->hInstance
, newBuf
))) {
2030 ERR(edit
, "could not lock new 16 bit buffer\n");
2031 LOCAL_Free(wnd
->hInstance
, newBuf
);
2034 lstrcpy32A(newText
, es
->text
);
2035 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2037 HeapFree(es
->heap
, 0, es
->text
);
2038 else if (es
->hloc32
) {
2039 while (LocalFree32(es
->hloc32
)) ;
2040 LocalFree32(es
->hloc32
);
2042 es
->hloc32
= (HLOCAL32
)NULL
;
2043 es
->hloc16
= newBuf
;
2044 es
->buffer_size
= newSize
;
2046 EDIT_LockBuffer(wnd
, es
);
2047 TRACE(edit
, "switched to 16 bit buffer\n");
2053 /*********************************************************************
2058 static INT32
EDIT_EM_GetLine(WND
*wnd
, EDITSTATE
*es
, INT32 line
, LPSTR lpch
)
2064 if (es
->style
& ES_MULTILINE
) {
2065 if (line
>= es
->line_count
)
2069 i
= EDIT_EM_LineIndex(wnd
, es
, line
);
2071 len
= MIN(*(WORD
*)lpch
, EDIT_EM_LineLength(wnd
, es
, i
));
2072 for (i
= 0 ; i
< len
; i
++) {
2077 return (LRESULT
)len
;
2081 /*********************************************************************
2086 static LRESULT
EDIT_EM_GetSel(WND
*wnd
, EDITSTATE
*es
, LPUINT32 start
, LPUINT32 end
)
2088 UINT32 s
= es
->selection_start
;
2089 UINT32 e
= es
->selection_end
;
2096 return MAKELONG(s
, e
);
2100 /*********************************************************************
2104 * FIXME: is this right ? (or should it be only VSCROLL)
2105 * (and maybe only for edit controls that really have their
2106 * own scrollbars) (and maybe only for multiline controls ?)
2107 * All in all: very poorly documented
2109 * FIXME: now it's also broken, because of the new WM_HSCROLL /
2110 * WM_VSCROLL handlers
2113 static LRESULT
EDIT_EM_GetThumb(WND
*wnd
, EDITSTATE
*es
)
2115 return MAKELONG(EDIT_WM_VScroll(wnd
, es
, EM_GETTHUMB16
, 0, 0),
2116 EDIT_WM_HScroll(wnd
, es
, EM_GETTHUMB16
, 0, 0));
2120 /*********************************************************************
2125 static INT32
EDIT_EM_LineFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
)
2130 if (!(es
->style
& ES_MULTILINE
))
2132 if (index
> lstrlen32A(es
->text
))
2133 return es
->line_count
- 1;
2135 index
= MIN(es
->selection_start
, es
->selection_end
);
2138 line_def
= es
->first_line_def
;
2139 index
-= line_def
->length
;
2140 while ((index
>= 0) && line_def
->next
) {
2142 line_def
= line_def
->next
;
2143 index
-= line_def
->length
;
2149 /*********************************************************************
2154 static INT32
EDIT_EM_LineIndex(WND
*wnd
, EDITSTATE
*es
, INT32 line
)
2159 if (!(es
->style
& ES_MULTILINE
))
2161 if (line
>= es
->line_count
)
2165 line_def
= es
->first_line_def
;
2167 INT32 index
= es
->selection_end
- line_def
->length
;
2168 while ((index
>= 0) && line_def
->next
) {
2169 line_index
+= line_def
->length
;
2170 line_def
= line_def
->next
;
2171 index
-= line_def
->length
;
2175 line_index
+= line_def
->length
;
2176 line_def
= line_def
->next
;
2184 /*********************************************************************
2189 static INT32
EDIT_EM_LineLength(WND
*wnd
, EDITSTATE
*es
, INT32 index
)
2193 if (!(es
->style
& ES_MULTILINE
))
2194 return lstrlen32A(es
->text
);
2198 INT32 sl = EDIT_EM_LineFromChar(wnd, es, es->selection_start);
2199 INT32 el = EDIT_EM_LineFromChar(wnd, es, es->selection_end);
2200 return es->selection_start - es->line_defs[sl].offset +
2201 es->line_defs[el].offset +
2202 es->line_defs[el].length - es->selection_end;
2206 line_def
= es
->first_line_def
;
2207 index
-= line_def
->length
;
2208 while ((index
>= 0) && line_def
->next
) {
2209 line_def
= line_def
->next
;
2210 index
-= line_def
->length
;
2212 return line_def
->net_length
;
2216 /*********************************************************************
2220 * FIXME: dx is in average character widths
2221 * However, we assume it is in pixels when we use this
2222 * function internally
2225 static BOOL32
EDIT_EM_LineScroll(WND
*wnd
, EDITSTATE
*es
, INT32 dx
, INT32 dy
)
2229 if (!(es
->style
& ES_MULTILINE
))
2232 if (-dx
> es
->x_offset
)
2234 if (dx
> es
->text_width
- es
->x_offset
)
2235 dx
= es
->text_width
- es
->x_offset
;
2236 nyoff
= MAX(0, es
->y_offset
+ dy
);
2237 if (nyoff
>= es
->line_count
)
2238 nyoff
= es
->line_count
- 1;
2239 dy
= (es
->y_offset
- nyoff
) * es
->line_height
;
2243 GetClientRect32(wnd
->hwndSelf
, &rc1
);
2244 IntersectRect32(&rc
, &rc1
, &es
->format_rect
);
2245 ScrollWindowEx32(wnd
->hwndSelf
, -dx
, dy
,
2246 NULL
, &rc
, (HRGN32
)NULL
, NULL
, SW_INVALIDATE
);
2247 es
->y_offset
= nyoff
;
2250 if (dx
&& !(es
->flags
& EF_HSCROLL_TRACK
))
2251 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
2252 if (dy
&& !(es
->flags
& EF_VSCROLL_TRACK
))
2253 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
2258 /*********************************************************************
2263 static LRESULT
EDIT_EM_PosFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
, BOOL32 after_wrap
)
2265 INT32 len
= lstrlen32A(es
->text
);
2271 HFONT32 old_font
= 0;
2274 index
= MIN(index
, len
);
2275 dc
= GetDC32(wnd
->hwndSelf
);
2277 old_font
= SelectObject32(dc
, es
->font
);
2278 if (es
->style
& ES_MULTILINE
) {
2279 l
= EDIT_EM_LineFromChar(wnd
, es
, index
);
2280 y
= (l
- es
->y_offset
) * es
->line_height
;
2281 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2282 if (after_wrap
&& (li
== index
) && l
) {
2284 LINEDEF
*line_def
= es
->first_line_def
;
2286 line_def
= line_def
->next
;
2289 if (line_def
->ending
== END_WRAP
) {
2291 y
-= es
->line_height
;
2292 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2295 x
= LOWORD(GetTabbedTextExtent32A(dc
, es
->text
+ li
, index
- li
,
2296 es
->tabs_count
, es
->tabs
)) - es
->x_offset
;
2298 LPSTR text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
2299 if (index
< es
->x_offset
) {
2300 GetTextExtentPoint32A(dc
, text
+ index
,
2301 es
->x_offset
- index
, &size
);
2304 GetTextExtentPoint32A(dc
, text
+ es
->x_offset
,
2305 index
- es
->x_offset
, &size
);
2309 if (es
->style
& ES_PASSWORD
)
2310 HeapFree(es
->heap
, 0 ,text
);
2312 x
+= es
->format_rect
.left
;
2313 y
+= es
->format_rect
.top
;
2315 SelectObject32(dc
, old_font
);
2316 ReleaseDC32(wnd
->hwndSelf
, dc
);
2317 return MAKELONG((INT16
)x
, (INT16
)y
);
2321 /*********************************************************************
2325 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here
2328 static void EDIT_EM_ReplaceSel(WND
*wnd
, EDITSTATE
*es
, BOOL32 can_undo
, LPCSTR lpsz_replace
)
2330 INT32 strl
= lstrlen32A(lpsz_replace
);
2331 INT32 tl
= lstrlen32A(es
->text
);
2338 s
= es
->selection_start
;
2339 e
= es
->selection_end
;
2341 if ((s
== e
) && !strl
)
2346 if (!EDIT_MakeFit(wnd
, es
, tl
- (e
- s
) + strl
))
2350 /* there is something to be deleted */
2352 utl
= lstrlen32A(es
->undo_text
);
2353 if (!es
->undo_insert_count
&& (*es
->undo_text
&& (s
== es
->undo_position
))) {
2354 /* undo-buffer is extended to the right */
2355 EDIT_MakeUndoFit(wnd
, es
, utl
+ e
- s
);
2356 lstrcpyn32A(es
->undo_text
+ utl
, es
->text
+ s
, e
- s
+ 1);
2357 } else if (!es
->undo_insert_count
&& (*es
->undo_text
&& (e
== es
->undo_position
))) {
2358 /* undo-buffer is extended to the left */
2359 EDIT_MakeUndoFit(wnd
, es
, utl
+ e
- s
);
2360 for (p
= es
->undo_text
+ utl
; p
>= es
->undo_text
; p
--)
2362 for (i
= 0 , p
= es
->undo_text
; i
< e
- s
; i
++)
2363 p
[i
] = (es
->text
+ s
)[i
];
2364 es
->undo_position
= s
;
2366 /* new undo-buffer */
2367 EDIT_MakeUndoFit(wnd
, es
, e
- s
);
2368 lstrcpyn32A(es
->undo_text
, es
->text
+ s
, e
- s
+ 1);
2369 es
->undo_position
= s
;
2371 /* any deletion makes the old insertion-undo invalid */
2372 es
->undo_insert_count
= 0;
2374 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2377 lstrcpy32A(es
->text
+ s
, es
->text
+ e
);
2380 /* there is an insertion */
2382 if ((s
== es
->undo_position
) ||
2383 ((es
->undo_insert_count
) &&
2384 (s
== es
->undo_position
+ es
->undo_insert_count
)))
2386 * insertion is new and at delete position or
2387 * an extension to either left or right
2389 es
->undo_insert_count
+= strl
;
2391 /* new insertion undo */
2392 es
->undo_position
= s
;
2393 es
->undo_insert_count
= strl
;
2394 /* new insertion makes old delete-buffer invalid */
2395 *es
->undo_text
= '\0';
2398 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2401 tl
= lstrlen32A(es
->text
);
2402 for (p
= es
->text
+ tl
; p
>= es
->text
+ s
; p
--)
2404 for (i
= 0 , p
= es
->text
+ s
; i
< strl
; i
++)
2405 p
[i
] = lpsz_replace
[i
];
2406 if(es
->style
& ES_UPPERCASE
)
2407 CharUpperBuff32A(p
, strl
);
2408 else if(es
->style
& ES_LOWERCASE
)
2409 CharLowerBuff32A(p
, strl
);
2412 /* FIXME: really inefficient */
2413 if (es
->style
& ES_MULTILINE
)
2414 EDIT_BuildLineDefs_ML(wnd
, es
);
2416 EDIT_EM_SetSel(wnd
, es
, s
, s
, FALSE
);
2417 es
->flags
|= EF_MODIFIED
;
2418 es
->flags
|= EF_UPDATE
;
2419 EDIT_EM_ScrollCaret(wnd
, es
);
2421 /* FIXME: really inefficient */
2422 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2426 /*********************************************************************
2431 static LRESULT
EDIT_EM_Scroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
)
2435 if (!(es
->style
& ES_MULTILINE
))
2436 return (LRESULT
)FALSE
;
2446 if (es
->y_offset
< es
->line_count
- 1)
2451 dy
= -(es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2454 if (es
->y_offset
< es
->line_count
- 1)
2455 dy
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2458 return (LRESULT
)FALSE
;
2461 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
2462 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
2464 return MAKELONG((INT16
)dy
, (BOOL16
)TRUE
);
2468 /*********************************************************************
2473 static void EDIT_EM_ScrollCaret(WND
*wnd
, EDITSTATE
*es
)
2475 if (es
->style
& ES_MULTILINE
) {
2480 INT32 cw
= es
->char_width
;
2485 l
= EDIT_EM_LineFromChar(wnd
, es
, es
->selection_end
);
2486 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2487 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
));
2488 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2489 if (l
>= es
->y_offset
+ vlc
)
2490 dy
= l
- vlc
+ 1 - es
->y_offset
;
2491 if (l
< es
->y_offset
)
2492 dy
= l
- es
->y_offset
;
2493 ww
= es
->format_rect
.right
- es
->format_rect
.left
;
2494 if (x
< es
->format_rect
.left
)
2495 dx
= x
- es
->format_rect
.left
- ww
/ HSCROLL_FRACTION
/ cw
* cw
;
2496 if (x
> es
->format_rect
.right
)
2497 dx
= x
- es
->format_rect
.left
- (HSCROLL_FRACTION
- 1) * ww
/ HSCROLL_FRACTION
/ cw
* cw
;
2499 EDIT_EM_LineScroll(wnd
, es
, dx
, dy
);
2505 if (!(es
->style
& ES_AUTOHSCROLL
))
2508 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
2509 format_width
= es
->format_rect
.right
- es
->format_rect
.left
;
2510 if (x
< es
->format_rect
.left
) {
2511 goal
= es
->format_rect
.left
+ format_width
/ HSCROLL_FRACTION
;
2514 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
2515 } while ((x
< goal
) && es
->x_offset
);
2516 /* FIXME: use ScrollWindow() somehow to improve performance */
2517 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2518 } else if (x
> es
->format_rect
.right
) {
2520 INT32 len
= lstrlen32A(es
->text
);
2521 goal
= es
->format_rect
.right
- format_width
/ HSCROLL_FRACTION
;
2524 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
2525 x_last
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, len
, FALSE
));
2526 } while ((x
> goal
) && (x_last
> es
->format_rect
.right
));
2527 /* FIXME: use ScrollWindow() somehow to improve performance */
2528 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2534 /*********************************************************************
2538 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2541 static void EDIT_EM_SetHandle(WND
*wnd
, EDITSTATE
*es
, HLOCAL32 hloc
)
2543 if (!(es
->style
& ES_MULTILINE
))
2547 WARN(edit
, "called with NULL handle\n");
2551 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2553 * old buffer is freed by caller, unless
2554 * it is still in our own heap. (in that case
2555 * we free it, correcting the buggy caller.)
2558 HeapFree(es
->heap
, 0, es
->text
);
2560 es
->hloc16
= (HLOCAL16
)NULL
;
2563 es
->buffer_size
= LocalSize32(es
->hloc32
) - 1;
2564 EDIT_LockBuffer(wnd
, es
);
2566 es
->x_offset
= es
->y_offset
= 0;
2567 es
->selection_start
= es
->selection_end
= 0;
2568 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2569 es
->flags
&= ~EF_MODIFIED
;
2570 es
->flags
&= ~EF_UPDATE
;
2571 EDIT_BuildLineDefs_ML(wnd
, es
);
2572 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2573 EDIT_EM_ScrollCaret(wnd
, es
);
2577 /*********************************************************************
2581 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2584 static void EDIT_EM_SetHandle16(WND
*wnd
, EDITSTATE
*es
, HLOCAL16 hloc
)
2586 if (!(es
->style
& ES_MULTILINE
))
2590 WARN(edit
, "called with NULL handle\n");
2594 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2596 * old buffer is freed by caller, unless
2597 * it is still in our own heap. (in that case
2598 * we free it, correcting the buggy caller.)
2601 HeapFree(es
->heap
, 0, es
->text
);
2604 es
->hloc32
= (HLOCAL32
)NULL
;
2606 es
->buffer_size
= LOCAL_Size(wnd
->hInstance
, es
->hloc16
) - 1;
2607 EDIT_LockBuffer(wnd
, es
);
2609 es
->x_offset
= es
->y_offset
= 0;
2610 es
->selection_start
= es
->selection_end
= 0;
2611 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2612 es
->flags
&= ~EF_MODIFIED
;
2613 es
->flags
&= ~EF_UPDATE
;
2614 EDIT_BuildLineDefs_ML(wnd
, es
);
2615 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2616 EDIT_EM_ScrollCaret(wnd
, es
);
2620 /*********************************************************************
2624 * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
2625 * However, the windows version is not complied to yet in all of edit.c
2628 static void EDIT_EM_SetLimitText(WND
*wnd
, EDITSTATE
*es
, INT32 limit
)
2630 if (es
->style
& ES_MULTILINE
) {
2632 es
->buffer_limit
= MIN(limit
, BUFLIMIT_MULTI
);
2634 es
->buffer_limit
= BUFLIMIT_MULTI
;
2637 es
->buffer_limit
= MIN(limit
, BUFLIMIT_SINGLE
);
2639 es
->buffer_limit
= BUFLIMIT_SINGLE
;
2644 /*********************************************************************
2648 * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
2649 * action wParam despite what the docs say. It also appears not to affect
2650 * multiline controls??
2653 static void EDIT_EM_SetMargins(WND
*wnd
, EDITSTATE
*es
, INT32 action
,
2654 INT32 left
, INT32 right
)
2656 if (action
& EC_LEFTMARGIN
) {
2657 if (left
!= EC_USEFONTINFO
)
2658 es
->left_margin
= left
;
2660 if (es
->style
& ES_MULTILINE
)
2661 es
->left_margin
= 0; /* ?? */
2663 es
->left_margin
= es
->char_width
;
2666 if (action
& EC_RIGHTMARGIN
) {
2667 if (right
!= EC_USEFONTINFO
)
2668 es
->right_margin
= right
;
2670 if (es
->style
& ES_MULTILINE
)
2671 es
->right_margin
= 0; /* ?? */
2673 es
->right_margin
= es
->char_width
;
2675 TRACE(edit
, "left=%d, right=%d\n", es
->left_margin
, es
->right_margin
);
2679 /*********************************************************************
2681 * EM_SETPASSWORDCHAR
2684 static void EDIT_EM_SetPasswordChar(WND
*wnd
, EDITSTATE
*es
, CHAR c
)
2686 if (es
->style
& ES_MULTILINE
)
2689 if (es
->password_char
== c
)
2692 es
->password_char
= c
;
2694 wnd
->dwStyle
|= ES_PASSWORD
;
2695 es
->style
|= ES_PASSWORD
;
2697 wnd
->dwStyle
&= ~ES_PASSWORD
;
2698 es
->style
&= ~ES_PASSWORD
;
2700 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2704 /*********************************************************************
2708 * note: unlike the specs say: the order of start and end
2709 * _is_ preserved in Windows. (i.e. start can be > end)
2710 * In other words: this handler is OK
2713 static void EDIT_EM_SetSel(WND
*wnd
, EDITSTATE
*es
, UINT32 start
, UINT32 end
, BOOL32 after_wrap
)
2715 UINT32 old_start
= es
->selection_start
;
2716 UINT32 old_end
= es
->selection_end
;
2717 UINT32 len
= lstrlen32A(es
->text
);
2720 start
= es
->selection_end
;
2721 end
= es
->selection_end
;
2723 start
= MIN(start
, len
);
2724 end
= MIN(end
, len
);
2726 es
->selection_start
= start
;
2727 es
->selection_end
= end
;
2729 es
->flags
|= EF_AFTER_WRAP
;
2731 es
->flags
&= ~EF_AFTER_WRAP
;
2732 if (es
->flags
& EF_FOCUSED
)
2733 EDIT_SetCaretPos(wnd
, es
, end
, after_wrap
);
2734 /* This is little bit more efficient than before, not sure if it can be improved. FIXME? */
2735 ORDER_UINT32(start
, end
);
2736 ORDER_UINT32(end
, old_end
);
2737 ORDER_UINT32(start
, old_start
);
2738 ORDER_UINT32(old_start
, old_end
);
2739 if (end
!= old_start
)
2743 * ORDER_UINT32(end, old_start);
2744 * EDIT_InvalidateText(wnd, es, start, end);
2745 * EDIT_InvalidateText(wnd, es, old_start, old_end);
2746 * in place of the following if statement.
2748 if (old_start
> end
)
2750 EDIT_InvalidateText(wnd
, es
, start
, end
);
2751 EDIT_InvalidateText(wnd
, es
, old_start
, old_end
);
2755 EDIT_InvalidateText(wnd
, es
, start
, old_start
);
2756 EDIT_InvalidateText(wnd
, es
, end
, old_end
);
2759 else EDIT_InvalidateText(wnd
, es
, start
, old_end
);
2763 /*********************************************************************
2768 static BOOL32
EDIT_EM_SetTabStops(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT32 tabs
)
2770 if (!(es
->style
& ES_MULTILINE
))
2773 HeapFree(es
->heap
, 0, es
->tabs
);
2774 es
->tabs_count
= count
;
2778 es
->tabs
= HeapAlloc(es
->heap
, 0, count
* sizeof(INT32
));
2779 memcpy(es
->tabs
, tabs
, count
* sizeof(INT32
));
2785 /*********************************************************************
2790 static BOOL32
EDIT_EM_SetTabStops16(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT16 tabs
)
2792 if (!(es
->style
& ES_MULTILINE
))
2795 HeapFree(es
->heap
, 0, es
->tabs
);
2796 es
->tabs_count
= count
;
2801 es
->tabs
= HeapAlloc(es
->heap
, 0, count
* sizeof(INT32
));
2802 for (i
= 0 ; i
< count
; i
++)
2803 es
->tabs
[i
] = *tabs
++;
2809 /*********************************************************************
2811 * EM_SETWORDBREAKPROC
2814 static void EDIT_EM_SetWordBreakProc(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC32A wbp
)
2816 if (es
->word_break_proc32A
== wbp
)
2819 es
->word_break_proc32A
= wbp
;
2820 es
->word_break_proc16
= NULL
;
2821 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
)) {
2822 EDIT_BuildLineDefs_ML(wnd
, es
);
2823 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2828 /*********************************************************************
2830 * EM_SETWORDBREAKPROC16
2833 static void EDIT_EM_SetWordBreakProc16(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC16 wbp
)
2835 if (es
->word_break_proc16
== wbp
)
2838 es
->word_break_proc32A
= NULL
;
2839 es
->word_break_proc16
= wbp
;
2840 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
)) {
2841 EDIT_BuildLineDefs_ML(wnd
, es
);
2842 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2847 /*********************************************************************
2852 static BOOL32
EDIT_EM_Undo(WND
*wnd
, EDITSTATE
*es
)
2854 INT32 ulength
= lstrlen32A(es
->undo_text
);
2855 LPSTR utext
= HeapAlloc(es
->heap
, 0, ulength
+ 1);
2857 lstrcpy32A(utext
, es
->undo_text
);
2859 TRACE(edit
, "before UNDO:insertion length = %d, deletion buffer = %s\n",
2860 es
->undo_insert_count
, utext
);
2862 EDIT_EM_SetSel(wnd
, es
, es
->undo_position
, es
->undo_position
+ es
->undo_insert_count
, FALSE
);
2863 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2864 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, utext
);
2865 EDIT_EM_SetSel(wnd
, es
, es
->undo_position
, es
->undo_position
+ es
->undo_insert_count
, FALSE
);
2866 HeapFree(es
->heap
, 0, utext
);
2868 TRACE(edit
, "after UNDO:insertion length = %d, deletion buffer = %s\n",
2869 es
->undo_insert_count
, es
->undo_text
);
2875 /*********************************************************************
2880 static void EDIT_WM_Char(WND
*wnd
, EDITSTATE
*es
, CHAR c
, DWORD key_data
)
2885 if (es
->style
& ES_MULTILINE
) {
2886 if (es
->style
& ES_READONLY
) {
2887 EDIT_MoveHome(wnd
, es
, FALSE
);
2888 EDIT_MoveDown_ML(wnd
, es
, FALSE
);
2890 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "\r\n");
2894 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_READONLY
))
2895 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "\t");
2898 if (!(es
->style
& ES_READONLY
) && ((BYTE
)c
>= ' ') && (c
!= 127)) {
2902 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, str
);
2909 /*********************************************************************
2914 static void EDIT_WM_Command(WND
*wnd
, EDITSTATE
*es
, INT32 code
, INT32 id
, HWND32 control
)
2916 if (code
|| control
)
2921 EDIT_EM_Undo(wnd
, es
);
2924 EDIT_WM_Cut(wnd
, es
);
2927 EDIT_WM_Copy(wnd
, es
);
2930 EDIT_WM_Paste(wnd
, es
);
2933 EDIT_WM_Clear(wnd
, es
);
2936 EDIT_EM_SetSel(wnd
, es
, 0, -1, FALSE
);
2937 EDIT_EM_ScrollCaret(wnd
, es
);
2940 ERR(edit
, "unknown menu item, please report\n");
2946 /*********************************************************************
2950 * Note: the resource files resource/sysres_??.rc cannot define a
2951 * single popup menu. Hence we use a (dummy) menubar
2952 * containing the single popup menu as its first item.
2954 * FIXME: the message identifiers have been chosen arbitrarily,
2955 * hence we use MF_BYPOSITION.
2956 * We might as well use the "real" values (anybody knows ?)
2957 * The menu definition is in resources/sysres_??.rc.
2958 * Once these are OK, we better use MF_BYCOMMAND here
2959 * (as we do in EDIT_WM_Command()).
2962 static void EDIT_WM_ContextMenu(WND
*wnd
, EDITSTATE
*es
, HWND32 hwnd
, INT32 x
, INT32 y
)
2964 HMENU32 menu
= LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_EDITMENU
));
2965 HMENU32 popup
= GetSubMenu32(menu
, 0);
2966 UINT32 start
= es
->selection_start
;
2967 UINT32 end
= es
->selection_end
;
2969 ORDER_UINT32(start
, end
);
2972 EnableMenuItem32(popup
, 0, MF_BYPOSITION
| (EDIT_EM_CanUndo(wnd
, es
) ? MF_ENABLED
: MF_GRAYED
));
2974 EnableMenuItem32(popup
, 2, MF_BYPOSITION
| ((end
- start
) && !(es
->style
& ES_PASSWORD
) ? MF_ENABLED
: MF_GRAYED
));
2976 EnableMenuItem32(popup
, 3, MF_BYPOSITION
| ((end
- start
) && !(es
->style
& ES_PASSWORD
) ? MF_ENABLED
: MF_GRAYED
));
2978 EnableMenuItem32(popup
, 4, MF_BYPOSITION
| (IsClipboardFormatAvailable32(CF_TEXT
) ? MF_ENABLED
: MF_GRAYED
));
2980 EnableMenuItem32(popup
, 5, MF_BYPOSITION
| ((end
- start
) ? MF_ENABLED
: MF_GRAYED
));
2982 EnableMenuItem32(popup
, 7, MF_BYPOSITION
| (start
|| (end
!= lstrlen32A(es
->text
)) ? MF_ENABLED
: MF_GRAYED
));
2984 TrackPopupMenu32(popup
, TPM_LEFTALIGN
| TPM_RIGHTBUTTON
, x
, y
, 0, wnd
->hwndSelf
, NULL
);
2985 DestroyMenu32(menu
);
2989 /*********************************************************************
2994 static void EDIT_WM_Copy(WND
*wnd
, EDITSTATE
*es
)
2996 INT32 s
= es
->selection_start
;
2997 INT32 e
= es
->selection_end
;
3004 hdst
= GlobalAlloc32(GMEM_MOVEABLE
, (DWORD
)(e
- s
+ 1));
3005 dst
= GlobalLock32(hdst
);
3006 lstrcpyn32A(dst
, es
->text
+ s
, e
- s
+ 1);
3007 GlobalUnlock32(hdst
);
3008 OpenClipboard32(wnd
->hwndSelf
);
3010 SetClipboardData32(CF_TEXT
, hdst
);
3015 /*********************************************************************
3020 static LRESULT
EDIT_WM_Create(WND
*wnd
, EDITSTATE
*es
, LPCREATESTRUCT32A cs
)
3023 * To initialize some final structure members, we call some helper
3024 * functions. However, since the EDITSTATE is not consistent (i.e.
3025 * not fully initialized), we should be very careful which
3026 * functions can be called, and in what order.
3028 EDIT_WM_SetFont(wnd
, es
, 0, FALSE
);
3029 if (cs
->lpszName
&& *(cs
->lpszName
) != '\0') {
3030 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, cs
->lpszName
);
3031 /* if we insert text to the editline, the text scrolls out of the window, as the caret is placed after the insert pos normally; thus we reset es->selection... to 0 and update caret */
3032 es
->selection_start
= es
->selection_end
= 0;
3033 EDIT_EM_ScrollCaret(wnd
, es
);
3039 /*********************************************************************
3044 static void EDIT_WM_Destroy(WND
*wnd
, EDITSTATE
*es
)
3047 while (LocalUnlock32(es
->hloc32
)) ;
3048 LocalFree32(es
->hloc32
);
3051 while (LOCAL_Unlock(wnd
->hInstance
, es
->hloc16
)) ;
3052 LOCAL_Free(wnd
->hInstance
, es
->hloc16
);
3054 HeapDestroy(es
->heap
);
3055 HeapFree(GetProcessHeap(), 0, es
);
3056 *(EDITSTATE
**)wnd
->wExtra
= NULL
;
3060 /*********************************************************************
3065 static LRESULT
EDIT_WM_EraseBkGnd(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
)
3070 if (!(brush
= (HBRUSH32
)EDIT_SEND_CTLCOLOR(wnd
, dc
)))
3071 brush
= (HBRUSH32
)GetStockObject32(WHITE_BRUSH
);
3073 GetClientRect32(wnd
->hwndSelf
, &rc
);
3074 IntersectClipRect32(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3075 GetClipBox32(dc
, &rc
);
3077 * FIXME: specs say that we should UnrealizeObject() the brush,
3078 * but the specs of UnrealizeObject() say that we shouldn't
3079 * unrealize a stock object. The default brush that
3080 * DefWndProc() returns is ... a stock object.
3082 FillRect32(dc
, &rc
, brush
);
3087 /*********************************************************************
3092 static INT32
EDIT_WM_GetText(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPSTR text
)
3094 INT32 len
= lstrlen32A(es
->text
);
3097 lstrcpy32A(text
, es
->text
);
3104 /*********************************************************************
3108 * 16 bit notepad needs this. Actually it is not _our_ hack,
3109 * it is notepad's. Notepad is sending us scrollbar messages with
3110 * undocumented parameters without us even having a scrollbar ... !?!?
3113 static LRESULT
EDIT_HScroll_Hack(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3116 INT32 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3119 if (!(es
->flags
& EF_HSCROLL_HACK
)) {
3120 ERR(edit
, "hacked WM_HSCROLL handler invoked\n");
3121 ERR(edit
, " if you are _not_ running 16 bit notepad, please report\n");
3122 ERR(edit
, " (this message is only displayed once per edit control)\n");
3123 es
->flags
|= EF_HSCROLL_HACK
;
3129 dx
= -es
->char_width
;
3132 if (es
->x_offset
< es
->text_width
)
3133 dx
= es
->char_width
;
3137 dx
= -fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3140 if (es
->x_offset
< es
->text_width
)
3141 dx
= fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3148 if (es
->x_offset
< es
->text_width
)
3149 dx
= es
->text_width
- es
->x_offset
;
3152 es
->flags
|= EF_HSCROLL_TRACK
;
3153 dx
= pos
* es
->text_width
/ 100 - es
->x_offset
;
3155 case SB_THUMBPOSITION
:
3156 es
->flags
&= ~EF_HSCROLL_TRACK
;
3157 if (!(dx
= pos
* es
->text_width
/ 100 - es
->x_offset
))
3158 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
3164 * FIXME : the next two are undocumented !
3165 * Are we doing the right thing ?
3166 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
3167 * although it's also a regular control message.
3170 ret
= es
->text_width
? es
->x_offset
* 100 / es
->text_width
: 0;
3172 case EM_LINESCROLL16
:
3177 ERR(edit
, "undocumented (hacked) WM_HSCROLL parameter, please report\n");
3181 EDIT_EM_LineScroll(wnd
, es
, dx
, 0);
3186 /*********************************************************************
3191 static LRESULT
EDIT_WM_HScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3196 if (!(es
->style
& ES_MULTILINE
))
3199 if (!(es
->style
& ES_AUTOHSCROLL
))
3202 if (!(es
->style
& WS_HSCROLL
))
3203 return EDIT_HScroll_Hack(wnd
, es
, action
, pos
, scroll_bar
);
3206 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3210 dx
= -es
->char_width
;
3213 if (es
->x_offset
< es
->text_width
)
3214 dx
= es
->char_width
;
3218 dx
= -fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3221 if (es
->x_offset
< es
->text_width
)
3222 dx
= fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3229 if (es
->x_offset
< es
->text_width
)
3230 dx
= es
->text_width
- es
->x_offset
;
3233 es
->flags
|= EF_HSCROLL_TRACK
;
3234 dx
= pos
- es
->x_offset
;
3236 case SB_THUMBPOSITION
:
3237 es
->flags
&= ~EF_HSCROLL_TRACK
;
3238 if (!(dx
= pos
- es
->x_offset
)) {
3239 SetScrollPos32(wnd
->hwndSelf
, SB_HORZ
, pos
, TRUE
);
3240 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
3247 ERR(edit
, "undocumented WM_HSCROLL parameter, please report\n");
3251 EDIT_EM_LineScroll(wnd
, es
, dx
, 0);
3256 /*********************************************************************
3261 static BOOL32
EDIT_CheckCombo(WND
*wnd
, UINT32 msg
, INT32 key
, DWORD key_data
)
3265 if (WIDGETS_IsControl32(wnd
->parent
, BIC32_COMBO
) &&
3266 (hLBox
= COMBO_GetLBWindow(wnd
->parent
))) {
3267 HWND32 hCombo
= wnd
->parent
->hwndSelf
;
3268 BOOL32 bUIFlip
= TRUE
;
3270 TRACE(combo
, "[%04x]: handling msg %04x (%04x)\n",
3271 wnd
->hwndSelf
, (UINT16
)msg
, (UINT16
)key
);
3274 case WM_KEYDOWN
: /* Handle F4 and arrow keys */
3276 bUIFlip
= (BOOL32
)SendMessage32A(hCombo
, CB_GETEXTENDEDUI32
, 0, 0);
3277 if (SendMessage32A(hCombo
, CB_GETDROPPEDSTATE32
, 0, 0))
3281 SendMessage32A(hLBox
, WM_KEYDOWN
, (WPARAM32
)key
, 0);
3283 /* make sure ComboLBox pops up */
3284 SendMessage32A(hCombo
, CB_SETEXTENDEDUI32
, 0, 0);
3285 SendMessage32A(hLBox
, WM_KEYDOWN
, VK_F4
, 0);
3286 SendMessage32A(hCombo
, CB_SETEXTENDEDUI32
, 1, 0);
3289 case WM_SYSKEYDOWN
: /* Handle Alt+up/down arrows */
3290 bUIFlip
= (BOOL32
)SendMessage32A(hCombo
, CB_GETEXTENDEDUI32
, 0, 0);
3292 bUIFlip
= (BOOL32
)SendMessage32A(hCombo
, CB_GETDROPPEDSTATE32
, 0, 0);
3293 SendMessage32A(hCombo
, CB_SHOWDROPDOWN32
, (bUIFlip
) ? FALSE
: TRUE
, 0);
3295 SendMessage32A(hLBox
, WM_KEYDOWN
, VK_F4
, 0);
3304 /*********************************************************************
3308 * Handling of special keys that don't produce a WM_CHAR
3309 * (i.e. non-printable keys) & Backspace & Delete
3312 static LRESULT
EDIT_WM_KeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
)
3317 if (GetKeyState32(VK_MENU
) & 0x8000)
3320 shift
= GetKeyState32(VK_SHIFT
) & 0x8000;
3321 control
= GetKeyState32(VK_CONTROL
) & 0x8000;
3326 if (EDIT_CheckCombo(wnd
, WM_KEYDOWN
, key
, key_data
))
3332 if ((es
->style
& ES_MULTILINE
) && (key
== VK_UP
))
3333 EDIT_MoveUp_ML(wnd
, es
, shift
);
3336 EDIT_MoveWordBackward(wnd
, es
, shift
);
3338 EDIT_MoveBackward(wnd
, es
, shift
);
3341 if (EDIT_CheckCombo(wnd
, WM_KEYDOWN
, key
, key_data
))
3345 if ((es
->style
& ES_MULTILINE
) && (key
== VK_DOWN
))
3346 EDIT_MoveDown_ML(wnd
, es
, shift
);
3348 EDIT_MoveWordForward(wnd
, es
, shift
);
3350 EDIT_MoveForward(wnd
, es
, shift
);
3353 EDIT_MoveHome(wnd
, es
, shift
);
3356 EDIT_MoveEnd(wnd
, es
, shift
);
3359 if (es
->style
& ES_MULTILINE
)
3360 EDIT_MovePageUp_ML(wnd
, es
, shift
);
3363 if (es
->style
& ES_MULTILINE
)
3364 EDIT_MovePageDown_ML(wnd
, es
, shift
);
3367 if (!(es
->style
& ES_READONLY
) && !control
) {
3368 if (es
->selection_start
!= es
->selection_end
)
3369 EDIT_WM_Clear(wnd
, es
);
3371 /* delete character left of caret */
3372 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3373 EDIT_MoveBackward(wnd
, es
, TRUE
);
3374 EDIT_WM_Clear(wnd
, es
);
3379 if (!(es
->style
& ES_READONLY
) && !(shift
&& control
)) {
3380 if (es
->selection_start
!= es
->selection_end
) {
3382 EDIT_WM_Cut(wnd
, es
);
3384 EDIT_WM_Clear(wnd
, es
);
3387 /* delete character left of caret */
3388 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3389 EDIT_MoveBackward(wnd
, es
, TRUE
);
3390 EDIT_WM_Clear(wnd
, es
);
3391 } else if (control
) {
3392 /* delete to end of line */
3393 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3394 EDIT_MoveEnd(wnd
, es
, TRUE
);
3395 EDIT_WM_Clear(wnd
, es
);
3397 /* delete character right of caret */
3398 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3399 EDIT_MoveForward(wnd
, es
, TRUE
);
3400 EDIT_WM_Clear(wnd
, es
);
3407 if (!(es
->style
& ES_READONLY
))
3408 EDIT_WM_Paste(wnd
, es
);
3410 EDIT_WM_Copy(wnd
, es
);
3417 /*********************************************************************
3422 static LRESULT
EDIT_WM_KillFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_getting_focus
)
3424 es
->flags
&= ~EF_FOCUSED
;
3426 if(!(es
->style
& ES_NOHIDESEL
))
3427 EDIT_InvalidateText(wnd
, es
, es
->selection_start
, es
->selection_end
);
3428 EDIT_NOTIFY_PARENT(wnd
, EN_KILLFOCUS
, "EN_KILLFOCUS");
3433 /*********************************************************************
3437 * The caret position has been set on the WM_LBUTTONDOWN message
3440 static LRESULT
EDIT_WM_LButtonDblClk(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3443 INT32 e
= es
->selection_end
;
3448 if (!(es
->flags
& EF_FOCUSED
))
3451 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
3452 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
3453 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
3454 s
= li
+ EDIT_CallWordBreakProc (wnd
, es
, li
, e
- li
, ll
, WB_LEFT
);
3455 e
= li
+ EDIT_CallWordBreakProc(wnd
, es
, li
, e
- li
, ll
, WB_RIGHT
);
3456 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
3457 EDIT_EM_ScrollCaret(wnd
, es
);
3462 /*********************************************************************
3467 static LRESULT
EDIT_WM_LButtonDown(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3472 if (!(es
->flags
& EF_FOCUSED
))
3475 SetCapture32(wnd
->hwndSelf
);
3476 EDIT_ConfinePoint(wnd
, es
, &x
, &y
);
3477 e
= EDIT_CharFromPos(wnd
, es
, x
, y
, &after_wrap
);
3478 EDIT_EM_SetSel(wnd
, es
, (keys
& MK_SHIFT
) ? es
->selection_start
: e
, e
, after_wrap
);
3479 EDIT_EM_ScrollCaret(wnd
, es
);
3480 es
->region_posx
= es
->region_posy
= 0;
3481 SetTimer32(wnd
->hwndSelf
, 0, 100, NULL
);
3486 /*********************************************************************
3491 static LRESULT
EDIT_WM_LButtonUp(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3493 if (GetCapture32() == wnd
->hwndSelf
) {
3494 KillTimer32(wnd
->hwndSelf
, 0);
3501 /*********************************************************************
3506 static LRESULT
EDIT_WM_MouseMove(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3512 if (GetCapture32() != wnd
->hwndSelf
)
3516 * FIXME: gotta do some scrolling if outside client
3517 * area. Maybe reset the timer ?
3520 EDIT_ConfinePoint(wnd
, es
, &x
, &y
);
3521 es
->region_posx
= (prex
< x
) ? -1 : ((prex
> x
) ? 1 : 0);
3522 es
->region_posy
= (prey
< y
) ? -1 : ((prey
> y
) ? 1 : 0);
3523 e
= EDIT_CharFromPos(wnd
, es
, x
, y
, &after_wrap
);
3524 EDIT_EM_SetSel(wnd
, es
, es
->selection_start
, e
, after_wrap
);
3529 /*********************************************************************
3534 static LRESULT
EDIT_WM_NCCreate(WND
*wnd
, LPCREATESTRUCT32A cs
)
3538 if (!(es
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*es
))))
3540 *(EDITSTATE
**)wnd
->wExtra
= es
;
3543 * Note: since the EDITSTATE has not been fully initialized yet,
3544 * we can't use any API calls that may send
3545 * WM_XXX messages before WM_NCCREATE is completed.
3548 if (!(es
->heap
= HeapCreate(0, 0x10000, 0)))
3550 es
->style
= cs
->style
;
3552 if ((es
->style
& WS_BORDER
) && !(es
->style
& WS_DLGFRAME
))
3553 wnd
->dwStyle
&= ~WS_BORDER
;
3555 if (es
->style
& ES_MULTILINE
) {
3556 es
->buffer_size
= BUFSTART_MULTI
;
3557 es
->buffer_limit
= BUFLIMIT_MULTI
;
3558 if (es
->style
& WS_VSCROLL
)
3559 es
->style
|= ES_AUTOVSCROLL
;
3560 if (es
->style
& WS_HSCROLL
)
3561 es
->style
|= ES_AUTOHSCROLL
;
3562 es
->style
&= ~ES_PASSWORD
;
3563 if ((es
->style
& ES_CENTER
) || (es
->style
& ES_RIGHT
)) {
3564 if (es
->style
& ES_RIGHT
)
3565 es
->style
&= ~ES_CENTER
;
3566 es
->style
&= ~WS_HSCROLL
;
3567 es
->style
&= ~ES_AUTOHSCROLL
;
3570 /* FIXME: for now, all multi line controls are AUTOVSCROLL */
3571 es
->style
|= ES_AUTOVSCROLL
;
3573 es
->buffer_size
= BUFSTART_SINGLE
;
3574 es
->buffer_limit
= BUFLIMIT_SINGLE
;
3575 es
->style
&= ~ES_CENTER
;
3576 es
->style
&= ~ES_RIGHT
;
3577 es
->style
&= ~WS_HSCROLL
;
3578 es
->style
&= ~WS_VSCROLL
;
3579 es
->style
&= ~ES_AUTOVSCROLL
;
3580 es
->style
&= ~ES_WANTRETURN
;
3581 if (es
->style
& ES_UPPERCASE
) {
3582 es
->style
&= ~ES_LOWERCASE
;
3583 es
->style
&= ~ES_NUMBER
;
3584 } else if (es
->style
& ES_LOWERCASE
)
3585 es
->style
&= ~ES_NUMBER
;
3586 if (es
->style
& ES_PASSWORD
)
3587 es
->password_char
= '*';
3589 /* FIXME: for now, all single line controls are AUTOHSCROLL */
3590 es
->style
|= ES_AUTOHSCROLL
;
3592 if (!(es
->text
= HeapAlloc(es
->heap
, 0, es
->buffer_size
+ 1)))
3594 es
->buffer_size
= HeapSize(es
->heap
, 0, es
->text
) - 1;
3595 if (!(es
->undo_text
= HeapAlloc(es
->heap
, 0, es
->buffer_size
+ 1)))
3597 es
->undo_buffer_size
= HeapSize(es
->heap
, 0, es
->undo_text
) - 1;
3599 if (es
->style
& ES_MULTILINE
)
3600 if (!(es
->first_line_def
= HeapAlloc(es
->heap
, HEAP_ZERO_MEMORY
, sizeof(LINEDEF
))))
3607 /*********************************************************************
3612 static void EDIT_WM_Paint(WND
*wnd
, EDITSTATE
*es
)
3617 HFONT32 old_font
= 0;
3621 BOOL32 rev
= IsWindowEnabled32(wnd
->hwndSelf
) &&
3622 ((es
->flags
& EF_FOCUSED
) ||
3623 (es
->style
& ES_NOHIDESEL
));
3625 if (es
->flags
& EF_UPDATE
)
3626 EDIT_NOTIFY_PARENT(wnd
, EN_UPDATE
, "EN_UPDATE");
3628 dc
= BeginPaint32(wnd
->hwndSelf
, &ps
);
3629 if(es
->style
& WS_BORDER
) {
3630 GetClientRect32(wnd
->hwndSelf
, &rc
);
3631 if(es
->style
& ES_MULTILINE
) {
3632 if(es
->style
& WS_HSCROLL
) rc
.bottom
++;
3633 if(es
->style
& WS_VSCROLL
) rc
.right
++;
3635 Rectangle32(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3637 IntersectClipRect32(dc
, es
->format_rect
.left
,
3638 es
->format_rect
.top
,
3639 es
->format_rect
.right
,
3640 es
->format_rect
.bottom
);
3641 if (es
->style
& ES_MULTILINE
) {
3642 GetClientRect32(wnd
->hwndSelf
, &rc
);
3643 IntersectClipRect32(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3646 old_font
= SelectObject32(dc
, es
->font
);
3647 EDIT_SEND_CTLCOLOR(wnd
, dc
);
3648 if (!IsWindowEnabled32(wnd
->hwndSelf
))
3649 SetTextColor32(dc
, GetSysColor32(COLOR_GRAYTEXT
));
3650 GetClipBox32(dc
, &rcRgn
);
3651 if (es
->style
& ES_MULTILINE
) {
3652 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
3653 for (i
= es
->y_offset
; i
<= MIN(es
->y_offset
+ vlc
, es
->y_offset
+ es
->line_count
- 1) ; i
++) {
3654 EDIT_GetLineRect(wnd
, es
, i
, 0, -1, &rcLine
);
3655 if (IntersectRect32(&rc
, &rcRgn
, &rcLine
))
3656 EDIT_PaintLine(wnd
, es
, dc
, i
, rev
);
3659 EDIT_GetLineRect(wnd
, es
, 0, 0, -1, &rcLine
);
3660 if (IntersectRect32(&rc
, &rcRgn
, &rcLine
))
3661 EDIT_PaintLine(wnd
, es
, dc
, 0, rev
);
3664 SelectObject32(dc
, old_font
);
3665 if (es
->flags
& EF_FOCUSED
)
3666 EDIT_SetCaretPos(wnd
, es
, es
->selection_end
,
3667 es
->flags
& EF_AFTER_WRAP
);
3668 EndPaint32(wnd
->hwndSelf
, &ps
);
3669 if ((es
->style
& WS_VSCROLL
) && !(es
->flags
& EF_VSCROLL_TRACK
)) {
3670 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
3672 si
.cbSize
= sizeof(SCROLLINFO
);
3673 si
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
3675 si
.nMax
= es
->line_count
+ vlc
- 2;
3677 si
.nPos
= es
->y_offset
;
3678 SetScrollInfo32(wnd
->hwndSelf
, SB_VERT
, &si
, TRUE
);
3680 if ((es
->style
& WS_HSCROLL
) && !(es
->flags
& EF_HSCROLL_TRACK
)) {
3682 INT32 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3683 si
.cbSize
= sizeof(SCROLLINFO
);
3684 si
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
3686 si
.nMax
= es
->text_width
+ fw
- 1;
3688 si
.nPos
= es
->x_offset
;
3689 SetScrollInfo32(wnd
->hwndSelf
, SB_HORZ
, &si
, TRUE
);
3692 if (es
->flags
& EF_UPDATE
) {
3693 es
->flags
&= ~EF_UPDATE
;
3694 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3699 /*********************************************************************
3704 static void EDIT_WM_Paste(WND
*wnd
, EDITSTATE
*es
)
3709 OpenClipboard32(wnd
->hwndSelf
);
3710 if ((hsrc
= GetClipboardData32(CF_TEXT
))) {
3711 src
= (LPSTR
)GlobalLock32(hsrc
);
3712 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, src
);
3713 GlobalUnlock32(hsrc
);
3719 /*********************************************************************
3724 static void EDIT_WM_SetFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_losing_focus
)
3726 es
->flags
|= EF_FOCUSED
;
3727 CreateCaret32(wnd
->hwndSelf
, 0, 2, es
->line_height
);
3728 EDIT_SetCaretPos(wnd
, es
, es
->selection_end
,
3729 es
->flags
& EF_AFTER_WRAP
);
3730 if(!(es
->style
& ES_NOHIDESEL
))
3731 EDIT_InvalidateText(wnd
, es
, es
->selection_start
, es
->selection_end
);
3732 ShowCaret32(wnd
->hwndSelf
);
3733 EDIT_NOTIFY_PARENT(wnd
, EN_SETFOCUS
, "EN_SETFOCUS");
3737 /*********************************************************************
3741 * With Win95 look the margins are set to default font value unless
3742 * the system font (font == 0) is being set, in which case they are left
3746 static void EDIT_WM_SetFont(WND
*wnd
, EDITSTATE
*es
, HFONT32 font
, BOOL32 redraw
)
3750 HFONT32 old_font
= 0;
3753 dc
= GetDC32(wnd
->hwndSelf
);
3755 old_font
= SelectObject32(dc
, font
);
3756 GetTextMetrics32A(dc
, &tm
);
3757 es
->line_height
= tm
.tmHeight
;
3758 es
->char_width
= tm
.tmAveCharWidth
;
3760 SelectObject32(dc
, old_font
);
3761 ReleaseDC32(wnd
->hwndSelf
, dc
);
3762 if (font
&& (TWEAK_WineLook
> WIN31_LOOK
))
3763 EDIT_EM_SetMargins(wnd
, es
, EC_LEFTMARGIN
| EC_RIGHTMARGIN
,
3764 EC_USEFONTINFO
, EC_USEFONTINFO
);
3765 if (es
->style
& ES_MULTILINE
)
3766 EDIT_BuildLineDefs_ML(wnd
, es
);
3769 GetClientRect32(wnd
->hwndSelf
, &r
);
3770 EDIT_SetRectNP(wnd
, es
, &r
);
3773 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
3774 if (es
->flags
& EF_FOCUSED
) {
3776 CreateCaret32(wnd
->hwndSelf
, 0, 2, es
->line_height
);
3777 EDIT_SetCaretPos(wnd
, es
, es
->selection_end
,
3778 es
->flags
& EF_AFTER_WRAP
);
3779 ShowCaret32(wnd
->hwndSelf
);
3784 /*********************************************************************
3789 * For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
3790 * The modified flag is reset. No notifications are sent.
3792 * For single-line controls, reception of WM_SETTEXT triggers:
3793 * The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
3796 static void EDIT_WM_SetText(WND
*wnd
, EDITSTATE
*es
, LPCSTR text
)
3798 EDIT_EM_SetSel(wnd
, es
, 0, -1, FALSE
);
3800 TRACE(edit
, "\t'%s'\n", text
);
3801 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, text
);
3803 TRACE(edit
, "\t<NULL>\n");
3804 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, "");
3807 if (es
->style
& ES_MULTILINE
) {
3808 es
->flags
&= ~EF_UPDATE
;
3810 es
->flags
|= EF_UPDATE
;
3812 es
->flags
&= ~EF_MODIFIED
;
3813 EDIT_EM_SetSel(wnd
, es
, 0, 0, FALSE
);
3814 EDIT_EM_ScrollCaret(wnd
, es
);
3818 /*********************************************************************
3823 static void EDIT_WM_Size(WND
*wnd
, EDITSTATE
*es
, UINT32 action
, INT32 width
, INT32 height
)
3825 if ((action
== SIZE_MAXIMIZED
) || (action
== SIZE_RESTORED
)) {
3827 SetRect32(&rc
, 0, 0, width
, height
);
3828 EDIT_SetRectNP(wnd
, es
, &rc
);
3829 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
3834 /*********************************************************************
3839 static LRESULT
EDIT_WM_SysKeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
)
3841 if ((key
== VK_BACK
) && (key_data
& 0x2000)) {
3842 if (EDIT_EM_CanUndo(wnd
, es
))
3843 EDIT_EM_Undo(wnd
, es
);
3845 } else if (key
== VK_UP
|| key
== VK_DOWN
)
3846 if (EDIT_CheckCombo(wnd
, WM_SYSKEYDOWN
, key
, key_data
))
3848 return DefWindowProc32A(wnd
->hwndSelf
, WM_SYSKEYDOWN
, (WPARAM32
)key
, (LPARAM
)key_data
);
3852 /*********************************************************************
3857 static void EDIT_WM_Timer(WND
*wnd
, EDITSTATE
*es
, INT32 id
, TIMERPROC32 timer_proc
)
3859 if (es
->region_posx
< 0) {
3860 EDIT_MoveBackward(wnd
, es
, TRUE
);
3861 } else if (es
->region_posx
> 0) {
3862 EDIT_MoveForward(wnd
, es
, TRUE
);
3865 * FIXME: gotta do some vertical scrolling here, like
3866 * EDIT_EM_LineScroll(wnd, 0, 1);
3871 /*********************************************************************
3875 * 16 bit notepad needs this. Actually it is not _our_ hack,
3876 * it is notepad's. Notepad is sending us scrollbar messages with
3877 * undocumented parameters without us even having a scrollbar ... !?!?
3880 static LRESULT
EDIT_VScroll_Hack(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3885 if (!(es
->flags
& EF_VSCROLL_HACK
)) {
3886 ERR(edit
, "hacked WM_VSCROLL handler invoked\n");
3887 ERR(edit
, " if you are _not_ running 16 bit notepad, please report\n");
3888 ERR(edit
, " (this message is only displayed once per edit control)\n");
3889 es
->flags
|= EF_VSCROLL_HACK
;
3897 EDIT_EM_Scroll(wnd
, es
, action
);
3903 dy
= es
->line_count
- 1 - es
->y_offset
;
3906 es
->flags
|= EF_VSCROLL_TRACK
;
3907 dy
= (pos
* (es
->line_count
- 1) + 50) / 100 - es
->y_offset
;
3909 case SB_THUMBPOSITION
:
3910 es
->flags
&= ~EF_VSCROLL_TRACK
;
3911 if (!(dy
= (pos
* (es
->line_count
- 1) + 50) / 100 - es
->y_offset
))
3912 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
3918 * FIXME : the next two are undocumented !
3919 * Are we doing the right thing ?
3920 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
3921 * although it's also a regular control message.
3924 ret
= (es
->line_count
> 1) ? es
->y_offset
* 100 / (es
->line_count
- 1) : 0;
3926 case EM_LINESCROLL16
:
3931 ERR(edit
, "undocumented (hacked) WM_VSCROLL parameter, please report\n");
3935 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
3940 /*********************************************************************
3945 static LRESULT
EDIT_WM_VScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3949 if (!(es
->style
& ES_MULTILINE
))
3952 if (!(es
->style
& ES_AUTOVSCROLL
))
3955 if (!(es
->style
& WS_VSCROLL
))
3956 return EDIT_VScroll_Hack(wnd
, es
, action
, pos
, scroll_bar
);
3964 EDIT_EM_Scroll(wnd
, es
, action
);
3971 dy
= es
->line_count
- 1 - es
->y_offset
;
3974 es
->flags
|= EF_VSCROLL_TRACK
;
3975 dy
= pos
- es
->y_offset
;
3977 case SB_THUMBPOSITION
:
3978 es
->flags
&= ~EF_VSCROLL_TRACK
;
3979 if (!(dy
= pos
- es
->y_offset
)) {
3980 SetScrollPos32(wnd
->hwndSelf
, SB_VERT
, pos
, TRUE
);
3981 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
3988 ERR(edit
, "undocumented WM_VSCROLL action %d, please report\n",
3993 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);