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)
25 #define BUFLIMIT_MULTI 65534 /* maximum buffer size (not including '\0')
26 FIXME: BTW, new specs say 65535 (do you dare ???) */
27 #define BUFLIMIT_SINGLE 32766 /* maximum buffer size (not including '\0') */
28 #define BUFSTART_MULTI 1024 /* starting size */
29 #define BUFSTART_SINGLE 256 /* starting size */
30 #define GROWLENGTH 64 /* buffers grow by this much */
31 #define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */
34 * extra flags for EDITSTATE.flags field
36 #define EF_MODIFIED 0x0001 /* text has been modified */
37 #define EF_FOCUSED 0x0002 /* we have input focus */
38 #define EF_UPDATE 0x0004 /* notify parent of changed state on next WM_PAINT */
39 #define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */
40 #define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */
41 #define EF_VSCROLL_HACK 0x0020 /* we already have informed the user of the hacked handler */
42 #define EF_HSCROLL_HACK 0x0040 /* we already have informed the user of the hacked handler */
43 #define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a
44 wrapped line, instead of in front of the next character */
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 EDITWORDBREAKPROC16 word_break_proc16
;
88 EDITWORDBREAKPROC32A word_break_proc32A
;
89 INT32 line_count
; /* number of lines */
90 INT32 y_offset
; /* scroll offset in number of lines */
92 * only for multi line controls
94 INT32 lock_count
; /* amount of re-entries in the EditWndProc */
97 INT32 text_width
; /* width of the widest line in pixels */
98 LINEDEF
*first_line_def
; /* linked list of (soft) linebreaks */
99 HLOCAL16 hloc16
; /* for controls receiving EM_GETHANDLE16 */
100 HLOCAL32 hloc32
; /* for controls receiving EM_GETHANDLE */
104 #define SWAP_INT32(x,y) do { INT32 temp = (INT32)(x); (x) = (INT32)(y); (y) = temp; } while(0)
105 #define ORDER_INT32(x,y) do { if ((INT32)(y) < (INT32)(x)) SWAP_INT32((x),(y)); } while(0)
107 #define SWAP_UINT32(x,y) do { UINT32 temp = (UINT32)(x); (x) = (UINT32)(y); (y) = temp; } while(0)
108 #define ORDER_UINT32(x,y) do { if ((UINT32)(y) < (UINT32)(x)) SWAP_UINT32((x),(y)); } while(0)
110 #define DPRINTF_EDIT_NOTIFY(hwnd, str) \
111 ({dprintf_edit(stddeb, \
112 "edit: notification " str " sent to hwnd=%08x\n", \
115 #define EDIT_SEND_CTLCOLOR(wnd,hdc) \
116 (SendMessage32A((wnd)->parent->hwndSelf, WM_CTLCOLOREDIT, \
117 (WPARAM32)(hdc), (LPARAM)(wnd)->hwndSelf))
118 #define EDIT_NOTIFY_PARENT(wnd, wNotifyCode, str) \
119 (DPRINTF_EDIT_NOTIFY((wnd)->parent->hwndSelf, str), \
120 SendMessage32A((wnd)->parent->hwndSelf, WM_COMMAND, \
121 MAKEWPARAM((wnd)->wIDmenu, wNotifyCode), \
122 (LPARAM)(wnd)->hwndSelf))
123 #define DPRINTF_EDIT_MSG16(str) \
124 dprintf_edit(stddeb, \
125 "edit: 16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
126 (UINT32)hwnd, (UINT32)wParam, (UINT32)lParam)
127 #define DPRINTF_EDIT_MSG32(str) \
128 dprintf_edit(stddeb, \
129 "edit: 32 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
130 (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_SetRectNP(WND
*wnd
, EDITSTATE
*es
, LPRECT32 lprc
);
182 static void EDIT_UnlockBuffer(WND
*wnd
, EDITSTATE
*es
, BOOL32 force
);
183 static INT32
EDIT_WordBreakProc(LPSTR s
, INT32 index
, INT32 count
, INT32 action
);
185 * EM_XXX message handlers
187 static LRESULT
EDIT_EM_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
);
188 static BOOL32
EDIT_EM_FmtLines(WND
*wnd
, EDITSTATE
*es
, BOOL32 add_eol
);
189 static HLOCAL32
EDIT_EM_GetHandle(WND
*wnd
, EDITSTATE
*es
);
190 static HLOCAL16
EDIT_EM_GetHandle16(WND
*wnd
, EDITSTATE
*es
);
191 static INT32
EDIT_EM_GetLine(WND
*wnd
, EDITSTATE
*es
, INT32 line
, LPSTR lpch
);
192 static LRESULT
EDIT_EM_GetSel(WND
*wnd
, EDITSTATE
*es
, LPUINT32 start
, LPUINT32 end
);
193 static LRESULT
EDIT_EM_GetThumb(WND
*wnd
, EDITSTATE
*es
);
194 static INT32
EDIT_EM_LineFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
);
195 static INT32
EDIT_EM_LineIndex(WND
*wnd
, EDITSTATE
*es
, INT32 line
);
196 static INT32
EDIT_EM_LineLength(WND
*wnd
, EDITSTATE
*es
, INT32 index
);
197 static BOOL32
EDIT_EM_LineScroll(WND
*wnd
, EDITSTATE
*es
, INT32 dx
, INT32 dy
);
198 static LRESULT
EDIT_EM_PosFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
, BOOL32 after_wrap
);
199 static void EDIT_EM_ReplaceSel(WND
*wnd
, EDITSTATE
*es
, BOOL32 can_undo
, LPCSTR lpsz_replace
);
200 static LRESULT
EDIT_EM_Scroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
);
201 static void EDIT_EM_ScrollCaret(WND
*wnd
, EDITSTATE
*es
);
202 static void EDIT_EM_SetHandle(WND
*wnd
, EDITSTATE
*es
, HLOCAL32 hloc
);
203 static void EDIT_EM_SetHandle16(WND
*wnd
, EDITSTATE
*es
, HLOCAL16 hloc
);
204 static void EDIT_EM_SetLimitText(WND
*wnd
, EDITSTATE
*es
, INT32 limit
);
205 static void EDIT_EM_SetMargins(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 left
, INT32 right
);
206 static void EDIT_EM_SetPasswordChar(WND
*wnd
, EDITSTATE
*es
, CHAR c
);
207 static void EDIT_EM_SetSel(WND
*wnd
, EDITSTATE
*es
, UINT32 start
, UINT32 end
, BOOL32 after_wrap
);
208 static BOOL32
EDIT_EM_SetTabStops(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT32 tabs
);
209 static BOOL32
EDIT_EM_SetTabStops16(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT16 tabs
);
210 static void EDIT_EM_SetWordBreakProc(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC32A wbp
);
211 static void EDIT_EM_SetWordBreakProc16(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC16 wbp
);
212 static BOOL32
EDIT_EM_Undo(WND
*wnd
, EDITSTATE
*es
);
214 * WM_XXX message handlers
216 static void EDIT_WM_Char(WND
*wnd
, EDITSTATE
*es
, CHAR c
, DWORD key_data
);
217 static void EDIT_WM_Command(WND
*wnd
, EDITSTATE
*es
, INT32 code
, INT32 id
, HWND32 conrtol
);
218 static void EDIT_WM_ContextMenu(WND
*wnd
, EDITSTATE
*es
, HWND32 hwnd
, INT32 x
, INT32 y
);
219 static void EDIT_WM_Copy(WND
*wnd
, EDITSTATE
*es
);
220 static LRESULT
EDIT_WM_Create(WND
*wnd
, LPCREATESTRUCT32A cs
);
221 static void EDIT_WM_Destroy(WND
*wnd
, EDITSTATE
*es
);
222 static LRESULT
EDIT_WM_EraseBkGnd(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
);
223 static INT32
EDIT_WM_GetText(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPSTR text
);
224 static LRESULT
EDIT_WM_HScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
);
225 static LRESULT
EDIT_WM_KeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
);
226 static LRESULT
EDIT_WM_KillFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_getting_focus
);
227 static LRESULT
EDIT_WM_LButtonDblClk(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
228 static LRESULT
EDIT_WM_LButtonDown(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
229 static LRESULT
EDIT_WM_LButtonUp(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
230 static LRESULT
EDIT_WM_MouseMove(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
);
231 static void EDIT_WM_Paint(WND
*wnd
, EDITSTATE
*es
);
232 static void EDIT_WM_Paste(WND
*wnd
, EDITSTATE
*es
);
233 static void EDIT_WM_SetFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_losing_focus
);
234 static void EDIT_WM_SetFont(WND
*wnd
, EDITSTATE
*es
, HFONT32 font
, BOOL32 redraw
);
235 static void EDIT_WM_SetText(WND
*wnd
, EDITSTATE
*es
, LPCSTR text
);
236 static void EDIT_WM_Size(WND
*wnd
, EDITSTATE
*es
, UINT32 action
, INT32 width
, INT32 height
);
237 static LRESULT
EDIT_WM_SysKeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
);
238 static void EDIT_WM_Timer(WND
*wnd
, EDITSTATE
*es
, INT32 id
, TIMERPROC32 timer_proc
);
239 static LRESULT
EDIT_WM_VScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
);
242 /*********************************************************************
247 static __inline__ BOOL32
EDIT_EM_CanUndo(WND
*wnd
, EDITSTATE
*es
)
249 return (es
->undo_insert_count
|| lstrlen32A(es
->undo_text
));
253 /*********************************************************************
258 static __inline__
void EDIT_EM_EmptyUndoBuffer(WND
*wnd
, EDITSTATE
*es
)
260 es
->undo_insert_count
= 0;
261 *es
->undo_text
= '\0';
265 /*********************************************************************
270 static __inline__
void EDIT_WM_Clear(WND
*wnd
, EDITSTATE
*es
)
272 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "");
276 /*********************************************************************
281 static __inline__
void EDIT_WM_Cut(WND
*wnd
, EDITSTATE
*es
)
283 EDIT_WM_Copy(wnd
, es
);
284 EDIT_WM_Clear(wnd
, es
);
288 /*********************************************************************
292 * The messages are in the order of the actual integer values
293 * (which can be found in include/windows.h)
294 * Whereever possible the 16 bit versions are converted to
295 * the 32 bit ones, so that we can 'fall through' to the
296 * helper functions. These are mostly 32 bit (with a few
297 * exceptions, clearly indicated by a '16' extension to their
301 LRESULT WINAPI
EditWndProc( HWND32 hwnd
, UINT32 msg
,
302 WPARAM32 wParam
, LPARAM lParam
)
304 WND
*wnd
= WIN_FindWndPtr(hwnd
);
305 EDITSTATE
*es
= *(EDITSTATE
**)((wnd
)->wExtra
);
310 DPRINTF_EDIT_MSG32("WM_CREATE");
311 return EDIT_WM_Create(wnd
, (LPCREATESTRUCT32A
)lParam
);
314 DPRINTF_EDIT_MSG32("WM_DESTROY");
315 EDIT_WM_Destroy(wnd
, es
);
320 return DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
322 EDIT_LockBuffer(wnd
, es
);
325 DPRINTF_EDIT_MSG16("EM_GETSEL");
330 DPRINTF_EDIT_MSG32("EM_GETSEL");
331 result
= EDIT_EM_GetSel(wnd
, es
, (LPUINT32
)wParam
, (LPUINT32
)lParam
);
335 DPRINTF_EDIT_MSG16("EM_SETSEL");
336 if (SLOWORD(lParam
) == -1)
337 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
339 EDIT_EM_SetSel(wnd
, es
, LOWORD(lParam
), HIWORD(lParam
), FALSE
);
341 EDIT_EM_ScrollCaret(wnd
, es
);
345 DPRINTF_EDIT_MSG32("EM_SETSEL");
346 EDIT_EM_SetSel(wnd
, es
, wParam
, lParam
, FALSE
);
351 DPRINTF_EDIT_MSG16("EM_GETRECT");
353 CONV_RECT32TO16(&es
->format_rect
, (LPRECT16
)PTR_SEG_TO_LIN(lParam
));
356 DPRINTF_EDIT_MSG32("EM_GETRECT");
358 CopyRect32((LPRECT32
)lParam
, &es
->format_rect
);
362 DPRINTF_EDIT_MSG16("EM_SETRECT");
363 if ((es
->style
& ES_MULTILINE
) && lParam
) {
365 CONV_RECT16TO32((LPRECT16
)PTR_SEG_TO_LIN(lParam
), &rc
);
366 EDIT_SetRectNP(wnd
, es
, &rc
);
367 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
371 DPRINTF_EDIT_MSG32("EM_SETRECT");
372 if ((es
->style
& ES_MULTILINE
) && lParam
) {
373 EDIT_SetRectNP(wnd
, es
, (LPRECT32
)lParam
);
374 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
379 DPRINTF_EDIT_MSG16("EM_SETRECTNP");
380 if ((es
->style
& ES_MULTILINE
) && lParam
) {
382 CONV_RECT16TO32((LPRECT16
)PTR_SEG_TO_LIN(lParam
), &rc
);
383 EDIT_SetRectNP(wnd
, es
, &rc
);
387 DPRINTF_EDIT_MSG32("EM_SETRECTNP");
388 if ((es
->style
& ES_MULTILINE
) && lParam
)
389 EDIT_SetRectNP(wnd
, es
, (LPRECT32
)lParam
);
393 DPRINTF_EDIT_MSG16("EM_SCROLL");
396 DPRINTF_EDIT_MSG32("EM_SCROLL");
397 result
= EDIT_EM_Scroll(wnd
, es
, (INT32
)wParam
);
400 case EM_LINESCROLL16
:
401 DPRINTF_EDIT_MSG16("EM_LINESCROLL");
402 wParam
= (WPARAM32
)(INT32
)SHIWORD(lParam
);
403 lParam
= (LPARAM
)(INT32
)SLOWORD(lParam
);
405 case EM_LINESCROLL32
:
406 DPRINTF_EDIT_MSG32("EM_LINESCROLL");
407 result
= (LRESULT
)EDIT_EM_LineScroll(wnd
, es
, (INT32
)wParam
, (INT32
)lParam
);
410 case EM_SCROLLCARET16
:
411 DPRINTF_EDIT_MSG16("EM_SCROLLCARET");
413 case EM_SCROLLCARET32
:
414 DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
415 EDIT_EM_ScrollCaret(wnd
, es
);
420 DPRINTF_EDIT_MSG16("EM_GETMODIFY");
423 DPRINTF_EDIT_MSG32("EM_GETMODIFY");
424 return ((es
->flags
& EF_MODIFIED
) != 0);
428 DPRINTF_EDIT_MSG16("EM_SETMODIFY");
431 DPRINTF_EDIT_MSG32("EM_SETMODIFY");
433 es
->flags
|= EF_MODIFIED
;
435 es
->flags
&= ~EF_MODIFIED
;
438 case EM_GETLINECOUNT16
:
439 DPRINTF_EDIT_MSG16("EM_GETLINECOUNT");
441 case EM_GETLINECOUNT32
:
442 DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
443 result
= (es
->style
& ES_MULTILINE
) ? es
->line_count
: 1;
447 DPRINTF_EDIT_MSG16("EM_LINEINDEX");
448 if ((INT16
)wParam
== -1)
449 wParam
= (WPARAM32
)-1;
452 DPRINTF_EDIT_MSG32("EM_LINEINDEX");
453 result
= (LRESULT
)EDIT_EM_LineIndex(wnd
, es
, (INT32
)wParam
);
457 DPRINTF_EDIT_MSG16("EM_SETHANDLE");
458 EDIT_EM_SetHandle16(wnd
, es
, (HLOCAL16
)wParam
);
461 DPRINTF_EDIT_MSG32("EM_SETHANDLE");
462 EDIT_EM_SetHandle(wnd
, es
, (HLOCAL32
)wParam
);
466 DPRINTF_EDIT_MSG16("EM_GETHANDLE");
467 result
= (LRESULT
)EDIT_EM_GetHandle16(wnd
, es
);
470 DPRINTF_EDIT_MSG32("EM_GETHANDLE");
471 result
= (LRESULT
)EDIT_EM_GetHandle(wnd
, es
);
475 DPRINTF_EDIT_MSG16("EM_GETTHUMB");
478 DPRINTF_EDIT_MSG32("EM_GETTHUMB");
479 result
= EDIT_EM_GetThumb(wnd
, es
);
482 /* messages 0x00bf and 0x00c0 missing from specs */
485 DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
488 DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
489 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
493 DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
496 DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
497 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
500 case EM_LINELENGTH16
:
501 DPRINTF_EDIT_MSG16("EM_LINELENGTH");
503 case EM_LINELENGTH32
:
504 DPRINTF_EDIT_MSG32("EM_LINELENGTH");
505 result
= (LRESULT
)EDIT_EM_LineLength(wnd
, es
, (INT32
)wParam
);
508 case EM_REPLACESEL16
:
509 DPRINTF_EDIT_MSG16("EM_REPLACESEL");
510 lParam
= (LPARAM
)PTR_SEG_TO_LIN((SEGPTR
)lParam
);
512 case EM_REPLACESEL32
:
513 DPRINTF_EDIT_MSG32("EM_REPLACESEL");
514 EDIT_EM_ReplaceSel(wnd
, es
, (BOOL32
)wParam
, (LPCSTR
)lParam
);
517 /* message 0x00c3 missing from specs */
520 DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
523 DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
524 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
528 DPRINTF_EDIT_MSG16("EM_GETLINE");
529 lParam
= (LPARAM
)PTR_SEG_TO_LIN((SEGPTR
)lParam
);
532 DPRINTF_EDIT_MSG32("EM_GETLINE");
533 result
= (LRESULT
)EDIT_EM_GetLine(wnd
, es
, (INT32
)wParam
, (LPSTR
)lParam
);
537 DPRINTF_EDIT_MSG16("EM_LIMITTEXT");
539 case EM_SETLIMITTEXT32
:
540 DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
541 EDIT_EM_SetLimitText(wnd
, es
, (INT32
)wParam
);
545 DPRINTF_EDIT_MSG16("EM_CANUNDO");
548 DPRINTF_EDIT_MSG32("EM_CANUNDO");
549 result
= (LRESULT
)EDIT_EM_CanUndo(wnd
, es
);
553 DPRINTF_EDIT_MSG16("EM_UNDO");
558 DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
559 result
= (LRESULT
)EDIT_EM_Undo(wnd
, es
);
563 DPRINTF_EDIT_MSG16("EM_FMTLINES");
566 DPRINTF_EDIT_MSG32("EM_FMTLINES");
567 result
= (LRESULT
)EDIT_EM_FmtLines(wnd
, es
, (BOOL32
)wParam
);
570 case EM_LINEFROMCHAR16
:
571 DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR");
573 case EM_LINEFROMCHAR32
:
574 DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
575 result
= (LRESULT
)EDIT_EM_LineFromChar(wnd
, es
, (INT32
)wParam
);
578 /* message 0x00ca missing from specs */
581 DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
584 DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
585 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
588 case EM_SETTABSTOPS16
:
589 DPRINTF_EDIT_MSG16("EM_SETTABSTOPS");
590 result
= (LRESULT
)EDIT_EM_SetTabStops16(wnd
, es
, (INT32
)wParam
, (LPINT16
)PTR_SEG_TO_LIN((SEGPTR
)lParam
));
592 case EM_SETTABSTOPS32
:
593 DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
594 result
= (LRESULT
)EDIT_EM_SetTabStops(wnd
, es
, (INT32
)wParam
, (LPINT32
)lParam
);
597 case EM_SETPASSWORDCHAR16
:
598 DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR");
600 case EM_SETPASSWORDCHAR32
:
601 DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
602 EDIT_EM_SetPasswordChar(wnd
, es
, (CHAR
)wParam
);
605 case EM_EMPTYUNDOBUFFER16
:
606 DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER");
608 case EM_EMPTYUNDOBUFFER32
:
609 DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
610 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
613 case EM_GETFIRSTVISIBLELINE16
:
614 DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE");
615 result
= es
->y_offset
;
617 case EM_GETFIRSTVISIBLELINE32
:
618 DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
619 result
= (es
->style
& ES_MULTILINE
) ? es
->y_offset
: es
->x_offset
;
622 case EM_SETREADONLY16
:
623 DPRINTF_EDIT_MSG16("EM_SETREADONLY");
625 case EM_SETREADONLY32
:
626 DPRINTF_EDIT_MSG32("EM_SETREADONLY");
628 wnd
->dwStyle
|= ES_READONLY
;
629 es
->style
|= ES_READONLY
;
631 wnd
->dwStyle
&= ~ES_READONLY
;
632 es
->style
&= ~ES_READONLY
;
637 case EM_SETWORDBREAKPROC16
:
638 DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC");
639 EDIT_EM_SetWordBreakProc16(wnd
, es
, (EDITWORDBREAKPROC16
)lParam
);
641 case EM_SETWORDBREAKPROC32
:
642 DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
643 EDIT_EM_SetWordBreakProc(wnd
, es
, (EDITWORDBREAKPROC32A
)lParam
);
646 case EM_GETWORDBREAKPROC16
:
647 DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC");
648 result
= (LRESULT
)es
->word_break_proc16
;
650 case EM_GETWORDBREAKPROC32
:
651 DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
652 result
= (LRESULT
)es
->word_break_proc32A
;
655 case EM_GETPASSWORDCHAR16
:
656 DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR");
658 case EM_GETPASSWORDCHAR32
:
659 DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
660 result
= es
->password_char
;
663 /* The following EM_xxx are new to win95 and don't exist for 16 bit */
665 case EM_SETMARGINS32
:
666 DPRINTF_EDIT_MSG32("EM_SETMARGINS");
667 EDIT_EM_SetMargins(wnd
, es
, (INT32
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
670 case EM_GETMARGINS32
:
671 DPRINTF_EDIT_MSG32("EM_GETMARGINS");
672 result
= MAKELONG(es
->left_margin
, es
->right_margin
);
675 case EM_GETLIMITTEXT32
:
676 DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
677 result
= es
->buffer_limit
;
680 case EM_POSFROMCHAR32
:
681 DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
682 result
= EDIT_EM_PosFromChar(wnd
, es
, (INT32
)wParam
, FALSE
);
685 case EM_CHARFROMPOS32
:
686 DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
687 result
= EDIT_EM_CharFromPos(wnd
, es
, SLOWORD(lParam
), SHIWORD(lParam
));
691 DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
692 result
= (es
->style
& ES_MULTILINE
) ?
693 DLGC_WANTALLKEYS
| DLGC_HASSETSEL
| DLGC_WANTCHARS
| DLGC_WANTARROWS
:
694 DLGC_HASSETSEL
| DLGC_WANTCHARS
| DLGC_WANTARROWS
;
698 DPRINTF_EDIT_MSG32("WM_CHAR");
699 EDIT_WM_Char(wnd
, es
, (CHAR
)wParam
, (DWORD
)lParam
);
703 DPRINTF_EDIT_MSG32("WM_CLEAR");
704 EDIT_WM_Clear(wnd
, es
);
708 DPRINTF_EDIT_MSG32("WM_COMMAND");
709 EDIT_WM_Command(wnd
, es
, HIWORD(wParam
), LOWORD(wParam
), (HWND32
)lParam
);
713 DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
714 EDIT_WM_ContextMenu(wnd
, es
, (HWND32
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
718 DPRINTF_EDIT_MSG32("WM_COPY");
719 EDIT_WM_Copy(wnd
, es
);
723 DPRINTF_EDIT_MSG32("WM_CUT");
724 EDIT_WM_Cut(wnd
, es
);
728 DPRINTF_EDIT_MSG32("WM_ENABLE");
729 InvalidateRect32(hwnd
, NULL
, TRUE
);
733 DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
734 result
= EDIT_WM_EraseBkGnd(wnd
, es
, (HDC32
)wParam
);
738 DPRINTF_EDIT_MSG32("WM_GETFONT");
739 result
= (LRESULT
)es
->font
;
743 DPRINTF_EDIT_MSG32("WM_GETTEXT");
744 result
= (LRESULT
)EDIT_WM_GetText(wnd
, es
, (INT32
)wParam
, (LPSTR
)lParam
);
747 case WM_GETTEXTLENGTH
:
748 DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
749 result
= lstrlen32A(es
->text
);
753 DPRINTF_EDIT_MSG32("WM_HSCROLL");
754 result
= EDIT_WM_HScroll(wnd
, es
, LOWORD(wParam
), SHIWORD(wParam
), (HWND32
)lParam
);
758 DPRINTF_EDIT_MSG32("WM_KEYDOWN");
759 result
= EDIT_WM_KeyDown(wnd
, es
, (INT32
)wParam
, (DWORD
)lParam
);
763 DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
764 result
= EDIT_WM_KillFocus(wnd
, es
, (HWND32
)wParam
);
767 case WM_LBUTTONDBLCLK
:
768 DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
769 result
= EDIT_WM_LButtonDblClk(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
773 DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
774 result
= EDIT_WM_LButtonDown(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
778 DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
779 result
= EDIT_WM_LButtonUp(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
782 case WM_MOUSEACTIVATE
:
784 * FIXME: maybe DefWindowProc() screws up, but it seems that
785 * modalless dialog boxes need this. If we don't do this, the focus
786 * will _not_ be set by DefWindowProc() for edit controls in a
787 * modalless dialog box ???
789 DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
790 SetFocus32(wnd
->hwndSelf
);
791 result
= MA_ACTIVATE
;
796 * DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
798 result
= EDIT_WM_MouseMove(wnd
, es
, (DWORD
)wParam
, SLOWORD(lParam
), SHIWORD(lParam
));
802 DPRINTF_EDIT_MSG32("WM_PAINT");
803 EDIT_WM_Paint(wnd
, es
);
807 DPRINTF_EDIT_MSG32("WM_PASTE");
808 EDIT_WM_Paste(wnd
, es
);
812 DPRINTF_EDIT_MSG32("WM_SETFOCUS");
813 EDIT_WM_SetFocus(wnd
, es
, (HWND32
)wParam
);
817 DPRINTF_EDIT_MSG32("WM_SETFONT");
818 EDIT_WM_SetFont(wnd
, es
, (HFONT32
)wParam
, LOWORD(lParam
) != 0);
822 DPRINTF_EDIT_MSG32("WM_SETTEXT");
823 EDIT_WM_SetText(wnd
, es
, (LPCSTR
)lParam
);
828 DPRINTF_EDIT_MSG32("WM_SIZE");
829 EDIT_WM_Size(wnd
, es
, (UINT32
)wParam
, LOWORD(lParam
), HIWORD(lParam
));
833 DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
834 result
= EDIT_WM_SysKeyDown(wnd
, es
, (INT32
)wParam
, (DWORD
)lParam
);
838 DPRINTF_EDIT_MSG32("WM_TIMER");
839 EDIT_WM_Timer(wnd
, es
, (INT32
)wParam
, (TIMERPROC32
)lParam
);
843 DPRINTF_EDIT_MSG32("WM_VSCROLL");
844 result
= EDIT_WM_VScroll(wnd
, es
, LOWORD(wParam
), SHIWORD(wParam
), (HWND32
)(lParam
));
848 result
= DefWindowProc32A(hwnd
, msg
, wParam
, lParam
);
851 EDIT_UnlockBuffer(wnd
, es
, FALSE
);
856 /*********************************************************************
858 * EDIT_BuildLineDefs_ML
860 * Build linked list of text lines.
861 * Lines can end with '\0' (last line), a character (if it is wrapped),
862 * a soft return '\r\r\n' or a hard return '\r\n'
865 static void EDIT_BuildLineDefs_ML(WND
*wnd
, EDITSTATE
*es
)
868 HFONT32 old_font
= 0;
871 LINEDEF
*current_def
;
872 LINEDEF
**previous_next
;
874 current_def
= es
->first_line_def
;
876 LINEDEF
*next_def
= current_def
->next
;
877 HeapFree(es
->heap
, 0, current_def
);
878 current_def
= next_def
;
879 } while (current_def
);
883 dc
= GetDC32(wnd
->hwndSelf
);
885 old_font
= SelectObject32(dc
, es
->font
);
887 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
889 previous_next
= &es
->first_line_def
;
891 current_def
= HeapAlloc(es
->heap
, 0, sizeof(LINEDEF
));
892 current_def
->next
= NULL
;
895 if ((*cp
== '\r') && (*(cp
+ 1) == '\n'))
900 current_def
->ending
= END_0
;
901 current_def
->net_length
= lstrlen32A(start
);
902 } else if ((cp
> start
) && (*(cp
- 1) == '\r')) {
903 current_def
->ending
= END_SOFT
;
904 current_def
->net_length
= cp
- start
- 1;
906 current_def
->ending
= END_HARD
;
907 current_def
->net_length
= cp
- start
;
909 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
,
910 start
, current_def
->net_length
,
911 es
->tabs_count
, es
->tabs
));
912 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
913 if ((!(es
->style
& ES_AUTOHSCROLL
)) && (current_def
->width
> fw
)) {
918 next
= EDIT_CallWordBreakProc(wnd
, es
, start
- es
->text
,
919 prev
+ 1, current_def
->net_length
, WB_RIGHT
);
920 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
,
921 start
, next
, es
->tabs_count
, es
->tabs
));
922 } while (current_def
->width
<= fw
);
928 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
,
929 start
, next
, es
->tabs_count
, es
->tabs
));
930 } while (current_def
->width
<= fw
);
934 current_def
->net_length
= prev
;
935 current_def
->ending
= END_WRAP
;
936 current_def
->width
= (INT32
)LOWORD(GetTabbedTextExtent32A(dc
, start
,
937 current_def
->net_length
, es
->tabs_count
, es
->tabs
));
939 switch (current_def
->ending
) {
941 current_def
->length
= current_def
->net_length
+ 3;
944 current_def
->length
= current_def
->net_length
+ 2;
948 current_def
->length
= current_def
->net_length
;
951 es
->text_width
= MAX(es
->text_width
, current_def
->width
);
952 start
+= current_def
->length
;
953 *previous_next
= current_def
;
954 previous_next
= ¤t_def
->next
;
956 } while (current_def
->ending
!= END_0
);
958 SelectObject32(dc
, old_font
);
959 ReleaseDC32(wnd
->hwndSelf
, dc
);
963 /*********************************************************************
965 * EDIT_CallWordBreakProc
967 * Call appropriate WordBreakProc (internal or external).
969 * Note: The "start" argument should always be an index refering
970 * to es->text. The actual wordbreak proc might be
971 * 16 bit, so we can't always pass any 32 bit LPSTR.
972 * Hence we assume that es->text is the buffer that holds
973 * the string under examination (we can decide this for ourselves).
976 static INT32
EDIT_CallWordBreakProc(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 index
, INT32 count
, INT32 action
)
978 if (es
->word_break_proc16
) {
979 HLOCAL16 hloc16
= EDIT_EM_GetHandle16(wnd
, es
);
980 SEGPTR segptr
= LocalLock16(hloc16
);
981 INT32 ret
= (INT32
)CallWordBreakProc16((FARPROC16
)es
->word_break_proc16
,
982 segptr
+ start
, index
, count
, action
);
983 LocalUnlock16(hloc16
);
985 } else if (es
->word_break_proc32A
)
986 return (INT32
)CallWordBreakProc32A((FARPROC32
)es
->word_break_proc32A
,
987 es
->text
+ start
, index
, count
, action
);
989 return EDIT_WordBreakProc(es
->text
+ start
, index
, count
, action
);
993 /*********************************************************************
997 * Beware: This is not the function called on EM_CHARFROMPOS
998 * The position _can_ be outside the formatting / client
1000 * The return value is only the character index
1003 static INT32
EDIT_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
, LPBOOL32 after_wrap
)
1007 HFONT32 old_font
= 0;
1009 if (es
->style
& ES_MULTILINE
) {
1010 INT32 line
= (y
- es
->format_rect
.top
) / es
->line_height
+ es
->y_offset
;
1011 INT32 line_index
= 0;
1012 LINEDEF
*line_def
= es
->first_line_def
;
1013 while ((line
> 0) && line_def
->next
) {
1014 line_index
+= line_def
->length
;
1015 line_def
= line_def
->next
;
1018 x
+= es
->x_offset
- es
->format_rect
.left
;
1019 if (x
>= line_def
->width
) {
1021 *after_wrap
= (line_def
->ending
== END_WRAP
);
1022 return line_index
+ line_def
->net_length
;
1026 *after_wrap
= FALSE
;
1029 dc
= GetDC32(wnd
->hwndSelf
);
1031 old_font
= SelectObject32(dc
, es
->font
);
1032 /* FIXME: inefficient algorithm */
1033 for (index
= line_index
+ 1 ; index
< line_index
+ line_def
->net_length
; index
++)
1034 if (LOWORD(GetTabbedTextExtent32A(dc
, es
->text
+ line_index
,
1035 index
- line_index
, es
->tabs_count
, es
->tabs
)) >= x
)
1038 *after_wrap
= ((index
== line_index
+ line_def
->net_length
) &&
1039 (line_def
->ending
== END_WRAP
));
1044 *after_wrap
= FALSE
;
1045 x
-= es
->format_rect
.left
;
1047 return es
->x_offset
;
1048 text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
1049 dc
= GetDC32(wnd
->hwndSelf
);
1051 old_font
= SelectObject32(dc
, es
->font
);
1054 /* FIXME: inefficient algorithm */
1055 for (index
= es
->x_offset
; index
; index
--) {
1056 GetTextExtentPoint32A(dc
, text
+ index
,
1057 es
->x_offset
- index
, &size
);
1062 INT32 len
= lstrlen32A(es
->text
);
1063 /* FIXME: inefficient algorithm */
1064 for (index
= es
->x_offset
; index
< len
; index
++) {
1065 GetTextExtentPoint32A(dc
, text
+ es
->x_offset
,
1066 index
- es
->x_offset
, &size
);
1071 if (es
->style
& ES_PASSWORD
)
1072 HeapFree(es
->heap
, 0 ,text
);
1075 SelectObject32(dc
, old_font
);
1076 ReleaseDC32(wnd
->hwndSelf
, dc
);
1081 /*********************************************************************
1085 * adjusts the point to be within the formatting rectangle
1086 * (so CharFromPos returns the nearest _visible_ character)
1089 static void EDIT_ConfinePoint(WND
*wnd
, EDITSTATE
*es
, LPINT32 x
, LPINT32 y
)
1091 *x
= MIN(MAX(*x
, es
->format_rect
.left
), es
->format_rect
.right
- 1);
1092 *y
= MIN(MAX(*y
, es
->format_rect
.top
), es
->format_rect
.bottom
- 1);
1096 /*********************************************************************
1100 * Calculates the bounding rectangle for a line from a starting
1101 * column to an ending column.
1104 static void EDIT_GetLineRect(WND
*wnd
, EDITSTATE
*es
, INT32 line
, INT32 scol
, INT32 ecol
, LPRECT32 rc
)
1106 INT32 line_index
= EDIT_EM_LineIndex(wnd
, es
, line
);
1108 if (es
->style
& ES_MULTILINE
)
1109 rc
->top
= es
->format_rect
.top
+ (line
- es
->y_offset
) * es
->line_height
;
1111 rc
->top
= es
->format_rect
.top
;
1112 rc
->bottom
= rc
->top
+ es
->line_height
;
1113 rc
->left
= (scol
== 0) ? es
->format_rect
.left
: SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, line_index
+ scol
, TRUE
));
1114 rc
->right
= (ecol
== -1) ? es
->format_rect
.right
: SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, line_index
+ ecol
, TRUE
));
1118 /*********************************************************************
1120 * EDIT_GetPasswordPointer_SL
1122 * note: caller should free the (optionally) allocated buffer
1125 static LPSTR
EDIT_GetPasswordPointer_SL(WND
*wnd
, EDITSTATE
*es
)
1127 if (es
->style
& ES_PASSWORD
) {
1128 INT32 len
= lstrlen32A(es
->text
);
1129 LPSTR text
= HeapAlloc(es
->heap
, 0, len
+ 1);
1130 RtlFillMemory(text
, len
, es
->password_char
);
1138 /*********************************************************************
1142 * This acts as a LOCAL_Lock(), but it locks only once. This way
1143 * you can call it whenever you like, without unlocking.
1146 static void EDIT_LockBuffer(WND
*wnd
, EDITSTATE
*es
)
1149 fprintf(stderr
, "edit: LockBuffer() without an EDITSTATE ... please report\n");
1152 if (!(es
->style
& ES_MULTILINE
))
1156 es
->text
= LocalLock32(es
->hloc32
);
1157 else if (es
->hloc16
)
1158 es
->text
= LOCAL_Lock(wnd
->hInstance
, es
->hloc16
);
1160 fprintf(stderr
, "edit: LockBuffer() without a buffer ... please report\n");
1168 /*********************************************************************
1170 * EDIT_SL_InvalidateText
1172 * Called from EDIT_InvalidateText().
1173 * Does the job for single-line controls only.
1176 static void EDIT_SL_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
)
1181 EDIT_GetLineRect(wnd
, es
, 0, start
, end
, &line_rect
);
1182 if (IntersectRect32(&rc
, &line_rect
, &es
->format_rect
))
1183 InvalidateRect32(wnd
->hwndSelf
, &rc
, FALSE
);
1187 /*********************************************************************
1189 * EDIT_ML_InvalidateText
1191 * Called from EDIT_InvalidateText().
1192 * Does the job for multi-line controls only.
1195 static void EDIT_ML_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
)
1197 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1198 INT32 sl
= EDIT_EM_LineFromChar(wnd
, es
, start
);
1199 INT32 el
= EDIT_EM_LineFromChar(wnd
, es
, end
);
1208 if ((el
< es
->y_offset
) || (sl
> es
->y_offset
+ vlc
))
1211 sc
= start
- EDIT_EM_LineIndex(wnd
, es
, sl
);
1212 ec
= end
- EDIT_EM_LineIndex(wnd
, es
, el
);
1213 if (sl
< es
->y_offset
) {
1217 if (el
> es
->y_offset
+ vlc
) {
1218 el
= es
->y_offset
+ vlc
;
1219 ec
= EDIT_EM_LineLength(wnd
, es
, EDIT_EM_LineIndex(wnd
, es
, el
));
1221 GetClientRect32(wnd
->hwndSelf
, &rc1
);
1222 IntersectRect32(&rcWnd
, &rc1
, &es
->format_rect
);
1224 EDIT_GetLineRect(wnd
, es
, sl
, sc
, ec
, &rcLine
);
1225 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1226 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1228 EDIT_GetLineRect(wnd
, es
, sl
, sc
,
1229 EDIT_EM_LineLength(wnd
, es
,
1230 EDIT_EM_LineIndex(wnd
, es
, sl
)),
1232 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1233 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1234 for (l
= sl
+ 1 ; l
< el
; l
++) {
1235 EDIT_GetLineRect(wnd
, es
, l
, 0,
1236 EDIT_EM_LineLength(wnd
, es
,
1237 EDIT_EM_LineIndex(wnd
, es
, l
)),
1239 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1240 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1242 EDIT_GetLineRect(wnd
, es
, el
, 0, ec
, &rcLine
);
1243 if (IntersectRect32(&rcUpdate
, &rcWnd
, &rcLine
))
1244 InvalidateRect32(wnd
->hwndSelf
, &rcUpdate
, FALSE
);
1249 /*********************************************************************
1251 * EDIT_InvalidateText
1253 * Invalidate the text from offset start upto, but not including,
1254 * offset end. Useful for (re)painting the selection.
1255 * Regions outside the linewidth are not invalidated.
1256 * end == -1 means end == TextLength.
1257 * start and end need not be ordered.
1260 static void EDIT_InvalidateText(WND
*wnd
, EDITSTATE
*es
, INT32 start
, INT32 end
)
1266 end
= lstrlen32A(es
->text
);
1268 ORDER_INT32(start
, end
);
1270 if (es
->style
& ES_MULTILINE
)
1271 EDIT_ML_InvalidateText(wnd
, es
, start
, end
);
1273 EDIT_SL_InvalidateText(wnd
, es
, start
, end
);
1277 /*********************************************************************
1281 * Try to fit size + 1 bytes in the buffer. Constrain to limits.
1284 static BOOL32
EDIT_MakeFit(WND
*wnd
, EDITSTATE
*es
, INT32 size
)
1289 if (size
<= es
->buffer_size
)
1291 if (size
> es
->buffer_limit
) {
1292 EDIT_NOTIFY_PARENT(wnd
, EN_MAXTEXT
, "EN_MAXTEXT");
1295 size
= ((size
/ GROWLENGTH
) + 1) * GROWLENGTH
;
1296 if (size
> es
->buffer_limit
)
1297 size
= es
->buffer_limit
;
1299 dprintf_edit(stddeb
, "edit: EDIT_MakeFit: trying to ReAlloc to %d+1\n", size
);
1301 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
1303 if ((es
->text
= HeapReAlloc(es
->heap
, 0, es
->text
, size
+ 1)))
1304 es
->buffer_size
= MIN(HeapSize(es
->heap
, 0, es
->text
) - 1, es
->buffer_limit
);
1306 es
->buffer_size
= 0;
1307 } else if (es
->hloc32
) {
1308 if ((hNew32
= LocalReAlloc32(es
->hloc32
, size
+ 1, 0))) {
1309 dprintf_edit(stddeb
, "edit: EDIT_MakeFit: Old 32 bit handle %08x, new handle %08x\n", es
->hloc32
, hNew32
);
1310 es
->hloc32
= hNew32
;
1311 es
->buffer_size
= MIN(LocalSize32(es
->hloc32
) - 1, es
->buffer_limit
);
1313 } else if (es
->hloc16
) {
1314 if ((hNew16
= LOCAL_ReAlloc(wnd
->hInstance
, es
->hloc16
, size
+ 1, LMEM_MOVEABLE
))) {
1315 dprintf_edit(stddeb
, "edit: EDIT_MakeFit: Old 16 bit handle %08x, new handle %08x\n", es
->hloc16
, hNew16
);
1316 es
->hloc16
= hNew16
;
1317 es
->buffer_size
= MIN(LOCAL_Size(wnd
->hInstance
, es
->hloc16
) - 1, es
->buffer_limit
);
1320 if (es
->buffer_size
< size
) {
1321 EDIT_LockBuffer(wnd
, es
);
1322 dprintf_edit(stddeb
, "edit: EDIT_MakeFit: FAILED ! We now have %d+1\n", es
->buffer_size
);
1323 EDIT_NOTIFY_PARENT(wnd
, EN_ERRSPACE
, "EN_ERRSPACE");
1326 EDIT_LockBuffer(wnd
, es
);
1327 dprintf_edit(stddeb
, "edit: EDIT_MakeFit: We now have %d+1\n", es
->buffer_size
);
1333 /*********************************************************************
1337 * Try to fit size + 1 bytes in the undo buffer.
1340 static BOOL32
EDIT_MakeUndoFit(WND
*wnd
, EDITSTATE
*es
, INT32 size
)
1342 if (size
<= es
->undo_buffer_size
)
1344 size
= ((size
/ GROWLENGTH
) + 1) * GROWLENGTH
;
1346 dprintf_edit(stddeb
, "edit: EDIT_MakeUndoFit: trying to ReAlloc to %d+1\n", size
);
1348 if ((es
->undo_text
= HeapReAlloc(es
->heap
, 0, es
->undo_text
, size
+ 1))) {
1349 es
->undo_buffer_size
= HeapSize(es
->heap
, 0, es
->undo_text
) - 1;
1350 if (es
->undo_buffer_size
< size
) {
1351 dprintf_edit(stddeb
, "edit: EDIT_MakeUndoFit: FAILED ! We now have %d+1\n", es
->undo_buffer_size
);
1360 /*********************************************************************
1365 static void EDIT_MoveBackward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1367 INT32 e
= es
->selection_end
;
1371 if ((es
->style
& ES_MULTILINE
) && e
&&
1372 (es
->text
[e
- 1] == '\r') && (es
->text
[e
] == '\n')) {
1374 if (e
&& (es
->text
[e
- 1] == '\r'))
1378 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1379 EDIT_EM_ScrollCaret(wnd
, es
);
1383 /*********************************************************************
1387 * Only for multi line controls
1388 * Move the caret one line down, on a column with the nearest
1389 * x coordinate on the screen (might be a different column).
1392 static void EDIT_MoveDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1394 INT32 s
= es
->selection_start
;
1395 INT32 e
= es
->selection_end
;
1396 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1397 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1398 INT32 x
= SLOWORD(pos
);
1399 INT32 y
= SHIWORD(pos
);
1401 e
= EDIT_CharFromPos(wnd
, es
, x
, y
+ es
->line_height
, &after_wrap
);
1404 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1405 EDIT_EM_ScrollCaret(wnd
, es
);
1409 /*********************************************************************
1414 static void EDIT_MoveEnd(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1416 BOOL32 after_wrap
= FALSE
;
1419 if (es
->style
& ES_MULTILINE
)
1420 e
= EDIT_CharFromPos(wnd
, es
, 0x7fffffff,
1421 HIWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
)), &after_wrap
);
1423 e
= lstrlen32A(es
->text
);
1424 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, after_wrap
);
1425 EDIT_EM_ScrollCaret(wnd
, es
);
1429 /*********************************************************************
1434 static void EDIT_MoveForward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1436 INT32 e
= es
->selection_end
;
1440 if ((es
->style
& ES_MULTILINE
) && (es
->text
[e
- 1] == '\r')) {
1441 if (es
->text
[e
] == '\n')
1443 else if ((es
->text
[e
] == '\r') && (es
->text
[e
+ 1] == '\n'))
1447 EDIT_EM_SetSel(wnd
, es
, extend
? es
->selection_start
: e
, e
, FALSE
);
1448 EDIT_EM_ScrollCaret(wnd
, es
);
1452 /*********************************************************************
1456 * Home key: move to beginning of line.
1459 static void EDIT_MoveHome(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1463 if (es
->style
& ES_MULTILINE
)
1464 e
= EDIT_CharFromPos(wnd
, es
, 0x80000000,
1465 HIWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
)), NULL
);
1468 EDIT_EM_SetSel(wnd
, es
, e
, extend
? es
->selection_start
: e
, FALSE
);
1469 EDIT_EM_ScrollCaret(wnd
, es
);
1473 /*********************************************************************
1475 * EDIT_MovePageDown_ML
1477 * Only for multi line controls
1478 * Move the caret one page down, on a column with the nearest
1479 * x coordinate on the screen (might be a different column).
1482 static void EDIT_MovePageDown_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1484 INT32 s
= es
->selection_start
;
1485 INT32 e
= es
->selection_end
;
1486 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1487 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1488 INT32 x
= SLOWORD(pos
);
1489 INT32 y
= SHIWORD(pos
);
1491 e
= EDIT_CharFromPos(wnd
, es
, x
,
1492 y
+ (es
->format_rect
.bottom
- es
->format_rect
.top
),
1496 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1497 EDIT_EM_ScrollCaret(wnd
, es
);
1501 /*********************************************************************
1503 * EDIT_MovePageUp_ML
1505 * Only for multi line controls
1506 * Move the caret one page up, on a column with the nearest
1507 * x coordinate on the screen (might be a different column).
1510 static void EDIT_MovePageUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1512 INT32 s
= es
->selection_start
;
1513 INT32 e
= es
->selection_end
;
1514 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1515 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1516 INT32 x
= SLOWORD(pos
);
1517 INT32 y
= SHIWORD(pos
);
1519 e
= EDIT_CharFromPos(wnd
, es
, x
,
1520 y
- (es
->format_rect
.bottom
- es
->format_rect
.top
),
1524 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1525 EDIT_EM_ScrollCaret(wnd
, es
);
1529 /*********************************************************************
1533 * Only for multi line controls
1534 * Move the caret one line up, on a column with the nearest
1535 * x coordinate on the screen (might be a different column).
1538 static void EDIT_MoveUp_ML(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1540 INT32 s
= es
->selection_start
;
1541 INT32 e
= es
->selection_end
;
1542 BOOL32 after_wrap
= (es
->flags
& EF_AFTER_WRAP
);
1543 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, e
, after_wrap
);
1544 INT32 x
= SLOWORD(pos
);
1545 INT32 y
= SHIWORD(pos
);
1547 e
= EDIT_CharFromPos(wnd
, es
, x
, y
- es
->line_height
, &after_wrap
);
1550 EDIT_EM_SetSel(wnd
, es
, s
, e
, after_wrap
);
1551 EDIT_EM_ScrollCaret(wnd
, es
);
1555 /*********************************************************************
1557 * EDIT_MoveWordBackward
1560 static void EDIT_MoveWordBackward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1562 INT32 s
= es
->selection_start
;
1563 INT32 e
= es
->selection_end
;
1568 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
1569 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
1570 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1573 li
= EDIT_EM_LineIndex(wnd
, es
, l
- 1);
1574 e
= li
+ EDIT_EM_LineLength(wnd
, es
, li
);
1577 e
= li
+ (INT32
)EDIT_CallWordBreakProc(wnd
, es
,
1578 li
, e
- li
, ll
, WB_LEFT
);
1582 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
1583 EDIT_EM_ScrollCaret(wnd
, es
);
1587 /*********************************************************************
1589 * EDIT_MoveWordForward
1592 static void EDIT_MoveWordForward(WND
*wnd
, EDITSTATE
*es
, BOOL32 extend
)
1594 INT32 s
= es
->selection_start
;
1595 INT32 e
= es
->selection_end
;
1600 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
1601 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
1602 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1604 if ((es
->style
& ES_MULTILINE
) && (l
!= es
->line_count
- 1))
1605 e
= EDIT_EM_LineIndex(wnd
, es
, l
+ 1);
1607 e
= li
+ EDIT_CallWordBreakProc(wnd
, es
,
1608 li
, e
- li
+ 1, ll
, WB_RIGHT
);
1612 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
1613 EDIT_EM_ScrollCaret(wnd
, es
);
1617 /*********************************************************************
1622 static void EDIT_PaintLine(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
, INT32 line
, BOOL32 rev
)
1624 INT32 s
= es
->selection_start
;
1625 INT32 e
= es
->selection_end
;
1632 if (es
->style
& ES_MULTILINE
) {
1633 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1634 if ((line
< es
->y_offset
) || (line
> es
->y_offset
+ vlc
) || (line
>= es
->line_count
))
1639 dprintf_edit(stddeb
, "edit: EDIT_PaintLine: line=%d\n", line
);
1641 pos
= EDIT_EM_PosFromChar(wnd
, es
, EDIT_EM_LineIndex(wnd
, es
, line
), FALSE
);
1644 li
= EDIT_EM_LineIndex(wnd
, es
, line
);
1645 ll
= EDIT_EM_LineLength(wnd
, es
, li
);
1646 s
= es
->selection_start
;
1647 e
= es
->selection_end
;
1649 s
= MIN(li
+ ll
, MAX(li
, s
));
1650 e
= MIN(li
+ ll
, MAX(li
, e
));
1651 if (rev
&& (s
!= e
) &&
1652 ((es
->flags
& EF_FOCUSED
) || (es
->style
& ES_NOHIDESEL
))) {
1653 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, 0, s
- li
, FALSE
);
1654 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, s
- li
, e
- s
, TRUE
);
1655 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, e
- li
, li
+ ll
- e
, FALSE
);
1657 x
+= EDIT_PaintText(wnd
, es
, dc
, x
, y
, line
, 0, ll
, FALSE
);
1661 /*********************************************************************
1666 static INT32
EDIT_PaintText(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
, INT32 x
, INT32 y
, INT32 line
, INT32 col
, INT32 count
, BOOL32 rev
)
1676 BkColor
= GetBkColor32(dc
);
1677 TextColor
= GetTextColor32(dc
);
1679 SetBkColor32(dc
, GetSysColor32(COLOR_HIGHLIGHT
));
1680 SetTextColor32(dc
, GetSysColor32(COLOR_HIGHLIGHTTEXT
));
1682 li
= EDIT_EM_LineIndex(wnd
, es
, line
);
1683 if (es
->style
& ES_MULTILINE
) {
1684 ret
= (INT32
)LOWORD(TabbedTextOut32A(dc
, x
, y
, es
->text
+ li
+ col
, count
,
1685 es
->tabs_count
, es
->tabs
, es
->format_rect
.left
- es
->x_offset
));
1687 LPSTR text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
1688 TextOut32A(dc
, x
, y
, text
+ li
+ col
, count
);
1689 GetTextExtentPoint32A(dc
, text
+ li
+ col
, count
, &size
);
1691 if (es
->style
& ES_PASSWORD
)
1692 HeapFree(es
->heap
, 0, text
);
1695 SetBkColor32(dc
, BkColor
);
1696 SetTextColor32(dc
, TextColor
);
1702 /*********************************************************************
1707 static void EDIT_EM_ScrollCaret(WND
*wnd
, EDITSTATE
*es
)
1709 if (es
->style
& ES_MULTILINE
) {
1714 INT32 cw
= es
->char_width
;
1719 l
= EDIT_EM_LineFromChar(wnd
, es
, es
->selection_end
);
1720 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
1721 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
));
1722 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
1723 if (l
>= es
->y_offset
+ vlc
)
1724 dy
= l
- vlc
+ 1 - es
->y_offset
;
1725 if (l
< es
->y_offset
)
1726 dy
= l
- es
->y_offset
;
1727 ww
= es
->format_rect
.right
- es
->format_rect
.left
;
1728 if (x
< es
->format_rect
.left
)
1729 dx
= x
- es
->format_rect
.left
- ww
/ HSCROLL_FRACTION
/ cw
* cw
;
1730 if (x
> es
->format_rect
.right
)
1731 dx
= x
- es
->format_rect
.left
- (HSCROLL_FRACTION
- 1) * ww
/ HSCROLL_FRACTION
/ cw
* cw
;
1733 EDIT_EM_LineScroll(wnd
, es
, dx
, dy
);
1739 if (!(es
->style
& ES_AUTOHSCROLL
))
1742 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
1743 format_width
= es
->format_rect
.right
- es
->format_rect
.left
;
1744 if (x
< es
->format_rect
.left
) {
1745 goal
= es
->format_rect
.left
+ format_width
/ HSCROLL_FRACTION
;
1748 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
1749 } while ((x
< goal
) && es
->x_offset
);
1750 /* FIXME: use ScrollWindow() somehow to improve performance */
1751 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
1752 } else if (x
> es
->format_rect
.right
) {
1754 INT32 len
= lstrlen32A(es
->text
);
1755 goal
= es
->format_rect
.right
- format_width
/ HSCROLL_FRACTION
;
1758 x
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, FALSE
));
1759 x_last
= SLOWORD(EDIT_EM_PosFromChar(wnd
, es
, len
, FALSE
));
1760 } while ((x
> goal
) && (x_last
> es
->format_rect
.right
));
1761 /* FIXME: use ScrollWindow() somehow to improve performance */
1762 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
1768 /*********************************************************************
1772 * note: this is not (exactly) the handler called on EM_SETRECTNP
1773 * it is also used to set the rect of a single line control
1776 static void EDIT_SetRectNP(WND
*wnd
, EDITSTATE
*es
, LPRECT32 rc
)
1778 CopyRect32(&es
->format_rect
, rc
);
1779 if (es
->style
& WS_BORDER
) {
1780 INT32 bw
= GetSystemMetrics32(SM_CXBORDER
) + 1;
1781 es
->format_rect
.left
+= bw
;
1782 es
->format_rect
.top
+= bw
;
1783 es
->format_rect
.right
-= bw
;
1784 es
->format_rect
.bottom
-= bw
;
1786 es
->format_rect
.left
+= es
->left_margin
;
1787 es
->format_rect
.right
-= es
->right_margin
;
1788 es
->format_rect
.right
= MAX(es
->format_rect
.right
, es
->format_rect
.left
+ es
->char_width
);
1789 if (es
->style
& ES_MULTILINE
)
1790 es
->format_rect
.bottom
= es
->format_rect
.top
+
1791 MAX(1, (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
) * es
->line_height
;
1793 es
->format_rect
.bottom
= es
->format_rect
.top
+ es
->line_height
;
1794 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
))
1795 EDIT_BuildLineDefs_ML(wnd
, es
);
1799 /*********************************************************************
1804 static void EDIT_UnlockBuffer(WND
*wnd
, EDITSTATE
*es
, BOOL32 force
)
1807 fprintf(stderr
, "edit: UnlockBuffer() without an EDITSTATE ... please report\n");
1810 if (!(es
->style
& ES_MULTILINE
))
1812 if (!es
->lock_count
) {
1813 fprintf(stderr
, "edit: UnlockBuffer() with lock_count == 0 ... please report\n");
1817 fprintf(stderr
, "edit: UnlockBuffer() with es->text == 0 ... please report\n");
1820 if (force
|| (es
->lock_count
== 1)) {
1822 LocalUnlock32(es
->hloc32
);
1824 } else if (es
->hloc16
) {
1825 LOCAL_Unlock(wnd
->hInstance
, es
->hloc16
);
1833 /*********************************************************************
1835 * EDIT_WordBreakProc
1837 * Find the beginning of words.
1838 * Note: unlike the specs for a WordBreakProc, this function only
1839 * allows to be called without linebreaks between s[0] upto
1840 * s[count - 1]. Remember it is only called
1841 * internally, so we can decide this for ourselves.
1844 static INT32
EDIT_WordBreakProc(LPSTR s
, INT32 index
, INT32 count
, INT32 action
)
1848 dprintf_edit(stddeb
, "edit: EDIT_WordBreakProc: s=%p, index=%u"
1849 ", count=%u, action=%d\n", s
, index
, count
, action
);
1857 if (s
[index
] == ' ') {
1858 while (index
&& (s
[index
] == ' '))
1861 while (index
&& (s
[index
] != ' '))
1863 if (s
[index
] == ' ')
1867 while (index
&& (s
[index
] != ' '))
1869 if (s
[index
] == ' ')
1879 if (s
[index
] == ' ')
1880 while ((index
< count
) && (s
[index
] == ' ')) index
++;
1882 while (s
[index
] && (s
[index
] != ' ') && (index
< count
))
1884 while ((s
[index
] == ' ') && (index
< count
)) index
++;
1888 case WB_ISDELIMITER
:
1889 ret
= (s
[index
] == ' ');
1892 fprintf(stderr
, "edit: EDIT_WordBreakProc: unknown action code, please report !\n");
1899 /*********************************************************************
1903 * FIXME: do the specs mean to return LineIndex or LineNumber ???
1904 * Let's assume LineIndex is meant
1905 * FIXME: do the specs mean to return -1 if outside client area or
1906 * if outside formatting rectangle ???
1909 static LRESULT
EDIT_EM_CharFromPos(WND
*wnd
, EDITSTATE
*es
, INT32 x
, INT32 y
)
1917 GetClientRect32(wnd
->hwndSelf
, &rc
);
1918 if (!PtInRect32(&rc
, pt
))
1921 index
= EDIT_CharFromPos(wnd
, es
, x
, y
, NULL
);
1922 return MAKELONG(index
, EDIT_EM_LineIndex(wnd
, es
,
1923 EDIT_EM_LineFromChar(wnd
, es
, index
)));
1927 /*********************************************************************
1932 static BOOL32
EDIT_EM_FmtLines(WND
*wnd
, EDITSTATE
*es
, BOOL32 add_eol
)
1934 fprintf(stdnimp
, "edit: EM_FMTLINES: message not implemented\n");
1939 /*********************************************************************
1943 * Hopefully this won't fire back at us.
1944 * We always start with a fixed buffer in our own heap.
1945 * However, with this message a 32 bit application requests
1946 * a handle to 32 bit moveable local heap memory, where it expects
1948 * It's a pitty that from this moment on we have to use this
1949 * local heap, because applications may rely on the handle
1952 * In this function we'll try to switch to local heap.
1955 static HLOCAL32
EDIT_EM_GetHandle(WND
*wnd
, EDITSTATE
*es
)
1961 if (!(es
->style
& ES_MULTILINE
))
1966 else if (es
->hloc16
)
1967 return (HLOCAL32
)es
->hloc16
;
1969 if (!(newBuf
= LocalAlloc32(LMEM_MOVEABLE
, lstrlen32A(es
->text
) + 1))) {
1970 fprintf(stderr
, "edit: EM_GETHANDLE: could not allocate new 32 bit buffer\n");
1973 newSize
= MIN(LocalSize32(newBuf
) - 1, es
->buffer_limit
);
1974 if (!(newText
= LocalLock32(newBuf
))) {
1975 fprintf(stderr
, "edit: EM_GETHANDLE: could not lock new 32 bit buffer\n");
1976 LocalFree32(newBuf
);
1979 lstrcpy32A(newText
, es
->text
);
1980 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
1982 HeapFree(es
->heap
, 0, es
->text
);
1983 es
->hloc32
= newBuf
;
1984 es
->hloc16
= (HLOCAL16
)NULL
;
1985 es
->buffer_size
= newSize
;
1987 EDIT_LockBuffer(wnd
, es
);
1988 dprintf_edit(stddeb
, "edit: EM_GETHANDLE: switched to 32 bit local heap\n");
1994 /*********************************************************************
1998 * Hopefully this won't fire back at us.
1999 * We always start with a buffer in 32 bit linear memory.
2000 * However, with this message a 16 bit application requests
2001 * a handle of 16 bit local heap memory, where it expects to find
2003 * It's a pitty that from this moment on we have to use this
2004 * local heap, because applications may rely on the handle
2007 * In this function we'll try to switch to local heap.
2009 static HLOCAL16
EDIT_EM_GetHandle16(WND
*wnd
, EDITSTATE
*es
)
2015 if (!(es
->style
& ES_MULTILINE
))
2021 if (!LOCAL_HeapSize(wnd
->hInstance
)) {
2022 if (!LocalInit(wnd
->hInstance
, 0,
2023 GlobalSize16(wnd
->hInstance
))) {
2024 fprintf(stderr
, "edit: EM_GETHANDLE: could not initialize local heap\n");
2027 dprintf_edit(stddeb
, "edit: EM_GETHANDLE: local heap initialized\n");
2029 if (!(newBuf
= LOCAL_Alloc(wnd
->hInstance
, LMEM_MOVEABLE
, lstrlen32A(es
->text
) + 1))) {
2030 fprintf(stderr
, "edit: EM_GETHANDLE: could not allocate new 16 bit buffer\n");
2033 newSize
= MIN(LOCAL_Size(wnd
->hInstance
, newBuf
) - 1, es
->buffer_limit
);
2034 if (!(newText
= LOCAL_Lock(wnd
->hInstance
, newBuf
))) {
2035 fprintf(stderr
, "edit: EM_GETHANDLE: could not lock new 16 bit buffer\n");
2036 LOCAL_Free(wnd
->hInstance
, newBuf
);
2039 lstrcpy32A(newText
, es
->text
);
2040 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2042 HeapFree(es
->heap
, 0, es
->text
);
2043 else if (es
->hloc32
) {
2044 while (LocalFree32(es
->hloc32
)) ;
2045 LocalFree32(es
->hloc32
);
2047 es
->hloc32
= (HLOCAL32
)NULL
;
2048 es
->hloc16
= newBuf
;
2049 es
->buffer_size
= newSize
;
2051 EDIT_LockBuffer(wnd
, es
);
2052 dprintf_edit(stddeb
, "edit: EM_GETHANDLE: switched to 16 bit buffer\n");
2058 /*********************************************************************
2063 static INT32
EDIT_EM_GetLine(WND
*wnd
, EDITSTATE
*es
, INT32 line
, LPSTR lpch
)
2069 if (es
->style
& ES_MULTILINE
) {
2070 if (line
>= es
->line_count
)
2074 src
= es
->text
+ EDIT_EM_LineIndex(wnd
, es
, line
);
2075 len
= MIN(*(WORD
*)lpch
, EDIT_EM_LineLength(wnd
, es
, line
));
2076 for (i
= 0 ; i
< len
; i
++) {
2081 return (LRESULT
)len
;
2085 /*********************************************************************
2090 static LRESULT
EDIT_EM_GetSel(WND
*wnd
, EDITSTATE
*es
, LPUINT32 start
, LPUINT32 end
)
2092 UINT32 s
= es
->selection_start
;
2093 UINT32 e
= es
->selection_end
;
2100 return MAKELONG(s
, e
);
2104 /*********************************************************************
2108 * FIXME: is this right ? (or should it be only VSCROLL)
2109 * (and maybe only for edit controls that really have their
2110 * own scrollbars) (and maybe only for multiline controls ?)
2111 * All in all: very poorly documented
2113 * FIXME: now it's also broken, because of the new WM_HSCROLL /
2114 * WM_VSCROLL handlers
2117 static LRESULT
EDIT_EM_GetThumb(WND
*wnd
, EDITSTATE
*es
)
2119 return MAKELONG(EDIT_WM_VScroll(wnd
, es
, EM_GETTHUMB16
, 0, 0),
2120 EDIT_WM_HScroll(wnd
, es
, EM_GETTHUMB16
, 0, 0));
2124 /*********************************************************************
2129 static INT32
EDIT_EM_LineFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
)
2134 if (!(es
->style
& ES_MULTILINE
))
2136 if (index
> lstrlen32A(es
->text
))
2137 return es
->line_count
- 1;
2139 index
= MIN(es
->selection_start
, es
->selection_end
);
2142 line_def
= es
->first_line_def
;
2143 index
-= line_def
->length
;
2144 while ((index
>= 0) && line_def
->next
) {
2146 line_def
= line_def
->next
;
2147 index
-= line_def
->length
;
2153 /*********************************************************************
2158 static INT32
EDIT_EM_LineIndex(WND
*wnd
, EDITSTATE
*es
, INT32 line
)
2163 if (!(es
->style
& ES_MULTILINE
))
2165 if (line
>= es
->line_count
)
2169 line_def
= es
->first_line_def
;
2171 INT32 index
= es
->selection_end
- line_def
->length
;
2172 while ((index
>= 0) && line_def
->next
) {
2173 line_index
+= line_def
->length
;
2174 line_def
= line_def
->next
;
2175 index
-= line_def
->length
;
2179 line_index
+= line_def
->length
;
2180 line_def
= line_def
->next
;
2188 /*********************************************************************
2193 static INT32
EDIT_EM_LineLength(WND
*wnd
, EDITSTATE
*es
, INT32 index
)
2197 if (!(es
->style
& ES_MULTILINE
))
2198 return lstrlen32A(es
->text
);
2202 INT32 sl = EDIT_EM_LineFromChar(wnd, es, es->selection_start);
2203 INT32 el = EDIT_EM_LineFromChar(wnd, es, es->selection_end);
2204 return es->selection_start - es->line_defs[sl].offset +
2205 es->line_defs[el].offset +
2206 es->line_defs[el].length - es->selection_end;
2210 line_def
= es
->first_line_def
;
2211 index
-= line_def
->length
;
2212 while ((index
>= 0) && line_def
->next
) {
2213 line_def
= line_def
->next
;
2214 index
-= line_def
->length
;
2216 return line_def
->net_length
;
2220 /*********************************************************************
2224 * FIXME: dx is in average character widths
2225 * However, we assume it is in pixels when we use this
2226 * function internally
2229 static BOOL32
EDIT_EM_LineScroll(WND
*wnd
, EDITSTATE
*es
, INT32 dx
, INT32 dy
)
2233 if (!(es
->style
& ES_MULTILINE
))
2236 if (-dx
> es
->x_offset
)
2238 if (dx
> es
->text_width
- es
->x_offset
)
2239 dx
= es
->text_width
- es
->x_offset
;
2240 nyoff
= MAX(0, es
->y_offset
+ dy
);
2241 if (nyoff
>= es
->line_count
)
2242 nyoff
= es
->line_count
- 1;
2243 dy
= (es
->y_offset
- nyoff
) * es
->line_height
;
2245 if (!(wnd
->flags
& WIN_NO_REDRAW
)) {
2248 GetClientRect32(wnd
->hwndSelf
, &rc1
);
2249 IntersectRect32(&rc
, &rc1
, &es
->format_rect
);
2250 ScrollWindowEx32(wnd
->hwndSelf
, -dx
, dy
,
2251 NULL
, &rc
, (HRGN32
)NULL
, NULL
, SW_INVALIDATE
);
2253 es
->y_offset
= nyoff
;
2256 if (dx
&& !(es
->flags
& EF_HSCROLL_TRACK
))
2257 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
2258 if (dy
&& !(es
->flags
& EF_VSCROLL_TRACK
))
2259 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
2264 /*********************************************************************
2269 static LRESULT
EDIT_EM_PosFromChar(WND
*wnd
, EDITSTATE
*es
, INT32 index
, BOOL32 after_wrap
)
2271 INT32 len
= lstrlen32A(es
->text
);
2277 HFONT32 old_font
= 0;
2280 index
= MIN(index
, len
);
2281 dc
= GetDC32(wnd
->hwndSelf
);
2283 old_font
= SelectObject32(dc
, es
->font
);
2284 if (es
->style
& ES_MULTILINE
) {
2285 l
= EDIT_EM_LineFromChar(wnd
, es
, index
);
2286 y
= (l
- es
->y_offset
) * es
->line_height
;
2287 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2288 if (after_wrap
&& (li
== index
) && l
) {
2290 LINEDEF
*line_def
= es
->first_line_def
;
2292 line_def
= line_def
->next
;
2295 if (line_def
->ending
== END_WRAP
) {
2297 y
-= es
->line_height
;
2298 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
2301 x
= LOWORD(GetTabbedTextExtent32A(dc
, es
->text
+ li
, index
- li
,
2302 es
->tabs_count
, es
->tabs
)) - es
->x_offset
;
2304 LPSTR text
= EDIT_GetPasswordPointer_SL(wnd
, es
);
2305 if (index
< es
->x_offset
) {
2306 GetTextExtentPoint32A(dc
, text
+ index
,
2307 es
->x_offset
- index
, &size
);
2310 GetTextExtentPoint32A(dc
, text
+ es
->x_offset
,
2311 index
- es
->x_offset
, &size
);
2315 if (es
->style
& ES_PASSWORD
)
2316 HeapFree(es
->heap
, 0 ,text
);
2318 x
+= es
->format_rect
.left
;
2319 y
+= es
->format_rect
.top
;
2321 SelectObject32(dc
, old_font
);
2322 ReleaseDC32(wnd
->hwndSelf
, dc
);
2323 return MAKELONG((INT16
)x
, (INT16
)y
);
2327 /*********************************************************************
2331 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here
2334 static void EDIT_EM_ReplaceSel(WND
*wnd
, EDITSTATE
*es
, BOOL32 can_undo
, LPCSTR lpsz_replace
)
2336 INT32 strl
= lstrlen32A(lpsz_replace
);
2337 INT32 tl
= lstrlen32A(es
->text
);
2344 s
= es
->selection_start
;
2345 e
= es
->selection_end
;
2347 if ((s
== e
) && !strl
)
2352 if (!EDIT_MakeFit(wnd
, es
, tl
- (e
- s
) + strl
))
2356 /* there is something to be deleted */
2358 utl
= lstrlen32A(es
->undo_text
);
2359 if (!es
->undo_insert_count
&& (*es
->undo_text
&& (s
== es
->undo_position
))) {
2360 /* undo-buffer is extended to the right */
2361 EDIT_MakeUndoFit(wnd
, es
, utl
+ e
- s
);
2362 lstrcpyn32A(es
->undo_text
+ utl
, es
->text
+ s
, e
- s
+ 1);
2363 } else if (!es
->undo_insert_count
&& (*es
->undo_text
&& (e
== es
->undo_position
))) {
2364 /* undo-buffer is extended to the left */
2365 EDIT_MakeUndoFit(wnd
, es
, utl
+ e
- s
);
2366 for (p
= es
->undo_text
+ utl
; p
>= es
->undo_text
; p
--)
2368 for (i
= 0 , p
= es
->undo_text
; i
< e
- s
; i
++)
2369 p
[i
] = (es
->text
+ s
)[i
];
2370 es
->undo_position
= s
;
2372 /* new undo-buffer */
2373 EDIT_MakeUndoFit(wnd
, es
, e
- s
);
2374 lstrcpyn32A(es
->undo_text
, es
->text
+ s
, e
- s
+ 1);
2375 es
->undo_position
= s
;
2377 /* any deletion makes the old insertion-undo invalid */
2378 es
->undo_insert_count
= 0;
2380 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2383 lstrcpy32A(es
->text
+ s
, es
->text
+ e
);
2386 /* there is an insertion */
2388 if ((s
== es
->undo_position
) ||
2389 ((es
->undo_insert_count
) &&
2390 (s
== es
->undo_position
+ es
->undo_insert_count
)))
2392 * insertion is new and at delete position or
2393 * an extension to either left or right
2395 es
->undo_insert_count
+= strl
;
2397 /* new insertion undo */
2398 es
->undo_position
= s
;
2399 es
->undo_insert_count
= strl
;
2400 /* new insertion makes old delete-buffer invalid */
2401 *es
->undo_text
= '\0';
2404 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2407 tl
= lstrlen32A(es
->text
);
2408 for (p
= es
->text
+ tl
; p
>= es
->text
+ s
; p
--)
2410 for (i
= 0 , p
= es
->text
+ s
; i
< strl
; i
++)
2411 p
[i
] = lpsz_replace
[i
];
2412 if(es
->style
& ES_UPPERCASE
)
2413 CharUpperBuff32A(p
, strl
);
2414 else if(es
->style
& ES_LOWERCASE
)
2415 CharLowerBuff32A(p
, strl
);
2418 /* FIXME: really inefficient */
2419 if (es
->style
& ES_MULTILINE
)
2420 EDIT_BuildLineDefs_ML(wnd
, es
);
2422 EDIT_EM_SetSel(wnd
, es
, s
, s
, FALSE
);
2423 es
->flags
|= EF_MODIFIED
;
2424 es
->flags
|= EF_UPDATE
;
2425 EDIT_EM_ScrollCaret(wnd
, es
);
2427 /* FIXME: really inefficient */
2428 if (!(wnd
->flags
& WIN_NO_REDRAW
))
2429 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2433 /*********************************************************************
2438 static LRESULT
EDIT_EM_Scroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
)
2442 if (!(es
->style
& ES_MULTILINE
))
2443 return (LRESULT
)FALSE
;
2453 if (es
->y_offset
< es
->line_count
- 1)
2458 dy
= -(es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2461 if (es
->y_offset
< es
->line_count
- 1)
2462 dy
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
2465 return (LRESULT
)FALSE
;
2468 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
2469 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
2471 return MAKELONG((INT16
)dy
, (BOOL16
)TRUE
);
2475 /*********************************************************************
2479 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2482 static void EDIT_EM_SetHandle(WND
*wnd
, EDITSTATE
*es
, HLOCAL32 hloc
)
2484 if (!(es
->style
& ES_MULTILINE
))
2488 fprintf(stderr
, "edit: EM_SETHANDLE called with NULL handle\n");
2492 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2494 * old buffer is freed by caller, unless
2495 * it is still in our own heap. (in that case
2496 * we free it, correcting the buggy caller.)
2499 HeapFree(es
->heap
, 0, es
->text
);
2501 es
->hloc16
= (HLOCAL16
)NULL
;
2504 es
->buffer_size
= LocalSize32(es
->hloc32
) - 1;
2505 EDIT_LockBuffer(wnd
, es
);
2507 es
->x_offset
= es
->y_offset
= 0;
2508 es
->selection_start
= es
->selection_end
= 0;
2509 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2510 es
->flags
&= ~EF_MODIFIED
;
2511 es
->flags
&= ~EF_UPDATE
;
2512 EDIT_BuildLineDefs_ML(wnd
, es
);
2513 if (!(wnd
->flags
& WIN_NO_REDRAW
))
2514 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2515 EDIT_EM_ScrollCaret(wnd
, es
);
2519 /*********************************************************************
2523 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2526 static void EDIT_EM_SetHandle16(WND
*wnd
, EDITSTATE
*es
, HLOCAL16 hloc
)
2528 if (!(es
->style
& ES_MULTILINE
))
2532 fprintf(stderr
, "edit: EM_SETHANDLE called with NULL handle\n");
2536 EDIT_UnlockBuffer(wnd
, es
, TRUE
);
2538 * old buffer is freed by caller, unless
2539 * it is still in our own heap. (in that case
2540 * we free it, correcting the buggy caller.)
2543 HeapFree(es
->heap
, 0, es
->text
);
2546 es
->hloc32
= (HLOCAL32
)NULL
;
2548 es
->buffer_size
= LOCAL_Size(wnd
->hInstance
, es
->hloc16
) - 1;
2549 EDIT_LockBuffer(wnd
, es
);
2551 es
->x_offset
= es
->y_offset
= 0;
2552 es
->selection_start
= es
->selection_end
= 0;
2553 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2554 es
->flags
&= ~EF_MODIFIED
;
2555 es
->flags
&= ~EF_UPDATE
;
2556 EDIT_BuildLineDefs_ML(wnd
, es
);
2557 if (!(wnd
->flags
& WIN_NO_REDRAW
))
2558 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2559 EDIT_EM_ScrollCaret(wnd
, es
);
2563 /*********************************************************************
2567 * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
2568 * However, the windows version is not complied to yet in all of edit.c
2571 static void EDIT_EM_SetLimitText(WND
*wnd
, EDITSTATE
*es
, INT32 limit
)
2573 if (es
->style
& ES_MULTILINE
) {
2575 es
->buffer_limit
= MIN(limit
, BUFLIMIT_MULTI
);
2577 es
->buffer_limit
= BUFLIMIT_MULTI
;
2580 es
->buffer_limit
= MIN(limit
, BUFLIMIT_SINGLE
);
2582 es
->buffer_limit
= BUFLIMIT_SINGLE
;
2587 /*********************************************************************
2592 static void EDIT_EM_SetMargins(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 left
, INT32 right
)
2594 if (action
& EC_USEFONTINFO
) {
2595 if (es
->style
& ES_MULTILINE
) {
2597 * FIXME: do some GetABCCharWidth, or so
2598 * This is just preliminary
2600 es
->left_margin
= es
->right_margin
= es
->char_width
;
2602 es
->left_margin
= es
->right_margin
= es
->char_width
;
2605 if (action
& EC_LEFTMARGIN
)
2606 es
->left_margin
= left
;
2607 if (action
& EC_RIGHTMARGIN
)
2608 es
->right_margin
= right
;
2613 /*********************************************************************
2615 * EM_SETPASSWORDCHAR
2618 static void EDIT_EM_SetPasswordChar(WND
*wnd
, EDITSTATE
*es
, CHAR c
)
2620 if (es
->style
& ES_MULTILINE
)
2623 if (es
->password_char
== c
)
2626 es
->password_char
= c
;
2628 wnd
->dwStyle
|= ES_PASSWORD
;
2629 es
->style
|= ES_PASSWORD
;
2631 wnd
->dwStyle
&= ~ES_PASSWORD
;
2632 es
->style
&= ~ES_PASSWORD
;
2634 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2638 /*********************************************************************
2642 * note: unlike the specs say: the order of start and end
2643 * _is_ preserved in Windows. (i.e. start can be > end)
2644 * In other words: this handler is OK
2647 static void EDIT_EM_SetSel(WND
*wnd
, EDITSTATE
*es
, UINT32 start
, UINT32 end
, BOOL32 after_wrap
)
2649 UINT32 old_start
= es
->selection_start
;
2650 UINT32 old_end
= es
->selection_end
;
2651 UINT32 len
= lstrlen32A(es
->text
);
2654 start
= es
->selection_end
;
2655 end
= es
->selection_end
;
2657 start
= MIN(start
, len
);
2658 end
= MIN(end
, len
);
2660 es
->selection_start
= start
;
2661 es
->selection_end
= end
;
2663 es
->flags
|= EF_AFTER_WRAP
;
2665 es
->flags
&= ~EF_AFTER_WRAP
;
2666 if (!(wnd
->flags
& WIN_NO_REDRAW
)) {
2667 if (es
->flags
& EF_FOCUSED
) {
2668 LRESULT pos
= EDIT_EM_PosFromChar(wnd
, es
, end
, after_wrap
);
2669 SetCaretPos32(SLOWORD(pos
), SHIWORD(pos
));
2671 /* FIXME: little efficiency, could be better */
2672 ORDER_UINT32(start
, end
);
2673 ORDER_UINT32(start
, old_start
);
2674 ORDER_UINT32(start
, old_end
);
2675 ORDER_UINT32(end
, old_start
);
2676 ORDER_UINT32(end
, old_end
);
2677 ORDER_UINT32(old_start
, old_end
);
2678 if (end
!= old_start
) {
2679 EDIT_InvalidateText(wnd
, es
, start
, end
);
2680 EDIT_InvalidateText(wnd
, es
, old_start
, old_end
);
2682 EDIT_InvalidateText(wnd
, es
, start
, old_end
);
2687 /*********************************************************************
2692 static BOOL32
EDIT_EM_SetTabStops(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT32 tabs
)
2694 if (!(es
->style
& ES_MULTILINE
))
2697 HeapFree(es
->heap
, 0, es
->tabs
);
2698 es
->tabs_count
= count
;
2702 es
->tabs
= HeapAlloc(es
->heap
, 0, count
* sizeof(INT32
));
2703 memcpy(es
->tabs
, tabs
, count
* sizeof(INT32
));
2709 /*********************************************************************
2714 static BOOL32
EDIT_EM_SetTabStops16(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPINT16 tabs
)
2716 if (!(es
->style
& ES_MULTILINE
))
2719 HeapFree(es
->heap
, 0, es
->tabs
);
2720 es
->tabs_count
= count
;
2725 es
->tabs
= HeapAlloc(es
->heap
, 0, count
* sizeof(INT32
));
2726 for (i
= 0 ; i
< count
; i
++)
2727 es
->tabs
[i
] = *tabs
++;
2733 /*********************************************************************
2735 * EM_SETWORDBREAKPROC
2738 static void EDIT_EM_SetWordBreakProc(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC32A wbp
)
2740 if (es
->word_break_proc32A
== wbp
)
2743 es
->word_break_proc32A
= wbp
;
2744 es
->word_break_proc16
= NULL
;
2745 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
)) {
2746 EDIT_BuildLineDefs_ML(wnd
, es
);
2747 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2752 /*********************************************************************
2754 * EM_SETWORDBREAKPROC16
2757 static void EDIT_EM_SetWordBreakProc16(WND
*wnd
, EDITSTATE
*es
, EDITWORDBREAKPROC16 wbp
)
2759 if (es
->word_break_proc16
== wbp
)
2762 es
->word_break_proc32A
= NULL
;
2763 es
->word_break_proc16
= wbp
;
2764 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_AUTOHSCROLL
)) {
2765 EDIT_BuildLineDefs_ML(wnd
, es
);
2766 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
2771 /*********************************************************************
2776 static BOOL32
EDIT_EM_Undo(WND
*wnd
, EDITSTATE
*es
)
2778 INT32 ulength
= lstrlen32A(es
->undo_text
);
2779 LPSTR utext
= HeapAlloc(es
->heap
, 0, ulength
+ 1);
2781 lstrcpy32A(utext
, es
->undo_text
);
2783 dprintf_edit(stddeb
, "edit: before UNDO:insertion length = %d, deletion buffer = %s\n",
2784 es
->undo_insert_count
, utext
);
2786 EDIT_EM_SetSel(wnd
, es
, es
->undo_position
, es
->undo_position
+ es
->undo_insert_count
, FALSE
);
2787 EDIT_EM_EmptyUndoBuffer(wnd
, es
);
2788 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, utext
);
2789 EDIT_EM_SetSel(wnd
, es
, es
->undo_position
, es
->undo_position
+ es
->undo_insert_count
, FALSE
);
2790 HeapFree(es
->heap
, 0, utext
);
2792 dprintf_edit(stddeb
, "edit: after UNDO: insertion length = %d, deletion buffer = %s\n",
2793 es
->undo_insert_count
, es
->undo_text
);
2799 /*********************************************************************
2804 static void EDIT_WM_Char(WND
*wnd
, EDITSTATE
*es
, CHAR c
, DWORD key_data
)
2809 if (es
->style
& ES_MULTILINE
) {
2810 if (es
->style
& ES_READONLY
) {
2811 EDIT_MoveHome(wnd
, es
, FALSE
);
2812 EDIT_MoveDown_ML(wnd
, es
, FALSE
);
2814 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "\r\n");
2818 if ((es
->style
& ES_MULTILINE
) && !(es
->style
& ES_READONLY
))
2819 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, "\t");
2822 if (!(es
->style
& ES_READONLY
) && (c
>= ' ') && (c
!= 127)) {
2826 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, str
);
2833 /*********************************************************************
2838 static void EDIT_WM_Command(WND
*wnd
, EDITSTATE
*es
, INT32 code
, INT32 id
, HWND32 control
)
2840 if (code
|| control
)
2845 EDIT_EM_Undo(wnd
, es
);
2848 EDIT_WM_Cut(wnd
, es
);
2851 EDIT_WM_Copy(wnd
, es
);
2854 EDIT_WM_Paste(wnd
, es
);
2857 EDIT_WM_Clear(wnd
, es
);
2860 EDIT_EM_SetSel(wnd
, es
, 0, -1, FALSE
);
2861 EDIT_EM_ScrollCaret(wnd
, es
);
2864 dprintf_edit(stddeb
, "edit: unknown menu item, please report\n");
2870 /*********************************************************************
2874 * Note: the resource files resource/sysres_??.rc cannot define a
2875 * single popup menu. Hence we use a (dummy) menubar
2876 * containing the single popup menu as its first item.
2878 * FIXME: the message identifiers have been chosen arbitrarily,
2879 * hence we use MF_BYPOSITION.
2880 * We might as well use the "real" values (anybody knows ?)
2881 * The menu definition is in resources/sysres_??.rc.
2882 * Once these are OK, we better use MF_BYCOMMAND here
2883 * (as we do in EDIT_WM_Command()).
2886 static void EDIT_WM_ContextMenu(WND
*wnd
, EDITSTATE
*es
, HWND32 hwnd
, INT32 x
, INT32 y
)
2888 HMENU32 menu
= LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_EDITMENU
));
2889 HMENU32 popup
= GetSubMenu32(menu
, 0);
2890 UINT32 start
= es
->selection_start
;
2891 UINT32 end
= es
->selection_end
;
2893 ORDER_UINT32(start
, end
);
2896 EnableMenuItem32(popup
, 0, MF_BYPOSITION
| (EDIT_EM_CanUndo(wnd
, es
) ? MF_ENABLED
: MF_GRAYED
));
2898 EnableMenuItem32(popup
, 2, MF_BYPOSITION
| ((end
- start
) && !(es
->style
& ES_PASSWORD
) ? MF_ENABLED
: MF_GRAYED
));
2900 EnableMenuItem32(popup
, 3, MF_BYPOSITION
| ((end
- start
) && !(es
->style
& ES_PASSWORD
) ? MF_ENABLED
: MF_GRAYED
));
2902 EnableMenuItem32(popup
, 4, MF_BYPOSITION
| (IsClipboardFormatAvailable32(CF_TEXT
) ? MF_ENABLED
: MF_GRAYED
));
2904 EnableMenuItem32(popup
, 5, MF_BYPOSITION
| ((end
- start
) ? MF_ENABLED
: MF_GRAYED
));
2906 EnableMenuItem32(popup
, 7, MF_BYPOSITION
| (start
|| (end
!= lstrlen32A(es
->text
)) ? MF_ENABLED
: MF_GRAYED
));
2908 TrackPopupMenu32(popup
, TPM_LEFTALIGN
| TPM_RIGHTBUTTON
, x
, y
, 0, wnd
->hwndSelf
, NULL
);
2909 DestroyMenu32(menu
);
2913 /*********************************************************************
2917 * FIXME: replace with 32 bit calls as soon as they are implemented
2918 * in the clipboard code
2921 static void EDIT_WM_Copy(WND
*wnd
, EDITSTATE
*es
)
2923 INT32 s
= es
->selection_start
;
2924 INT32 e
= es
->selection_end
;
2931 hdst
= GlobalAlloc16(GMEM_MOVEABLE
, (DWORD
)(e
- s
+ 1));
2932 dst
= GlobalLock16(hdst
);
2933 lstrcpyn32A(dst
, es
->text
+ s
, e
- s
+ 1);
2934 GlobalUnlock16(hdst
);
2935 OpenClipboard32(wnd
->hwndSelf
);
2937 SetClipboardData16(CF_TEXT
, hdst
);
2942 /*********************************************************************
2947 static LRESULT
EDIT_WM_Create(WND
*wnd
, LPCREATESTRUCT32A cs
)
2951 if (!(es
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*es
))))
2953 *(EDITSTATE
**)wnd
->wExtra
= es
;
2954 if (!(es
->heap
= HeapCreate(0, 0x10000, 0)))
2956 es
->style
= cs
->style
;
2958 /* remove the WS_CAPTION style if it has been set - this is really a */
2959 /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
2960 if ((es
->style
& WS_BORDER
) && (es
->style
& WS_DLGFRAME
))
2961 es
->style
^= WS_DLGFRAME
;
2963 if (es
->style
& ES_MULTILINE
) {
2964 es
->buffer_size
= BUFSTART_MULTI
;
2965 es
->buffer_limit
= BUFLIMIT_MULTI
;
2966 if (es
->style
& WS_VSCROLL
)
2967 es
->style
|= ES_AUTOVSCROLL
;
2968 if (es
->style
& WS_HSCROLL
)
2969 es
->style
|= ES_AUTOHSCROLL
;
2970 es
->style
&= ~ES_PASSWORD
;
2971 if ((es
->style
& ES_CENTER
) || (es
->style
& ES_RIGHT
)) {
2972 if (es
->style
& ES_RIGHT
)
2973 es
->style
&= ~ES_CENTER
;
2974 es
->style
&= ~WS_HSCROLL
;
2975 es
->style
&= ~ES_AUTOHSCROLL
;
2978 /* FIXME: for now, all multi line controls are AUTOVSCROLL */
2979 es
->style
|= ES_AUTOVSCROLL
;
2981 es
->buffer_size
= BUFSTART_SINGLE
;
2982 es
->buffer_limit
= BUFLIMIT_SINGLE
;
2983 es
->style
&= ~ES_CENTER
;
2984 es
->style
&= ~ES_RIGHT
;
2985 es
->style
&= ~WS_HSCROLL
;
2986 es
->style
&= ~WS_VSCROLL
;
2987 es
->style
&= ~ES_AUTOVSCROLL
;
2988 es
->style
&= ~ES_WANTRETURN
;
2989 if (es
->style
& ES_UPPERCASE
) {
2990 es
->style
&= ~ES_LOWERCASE
;
2991 es
->style
&= ~ES_NUMBER
;
2992 } else if (es
->style
& ES_LOWERCASE
)
2993 es
->style
&= ~ES_NUMBER
;
2994 if (es
->style
& ES_PASSWORD
)
2995 es
->password_char
= '*';
2997 /* FIXME: for now, all single line controls are AUTOHSCROLL */
2998 es
->style
|= ES_AUTOHSCROLL
;
3000 if (!(es
->text
= HeapAlloc(es
->heap
, 0, es
->buffer_size
+ 1)))
3002 es
->buffer_size
= HeapSize(es
->heap
, 0, es
->text
) - 1;
3003 if (!(es
->undo_text
= HeapAlloc(es
->heap
, 0, es
->buffer_size
+ 1)))
3005 es
->undo_buffer_size
= HeapSize(es
->heap
, 0, es
->undo_text
) - 1;
3007 if (es
->style
& ES_MULTILINE
)
3008 if (!(es
->first_line_def
= HeapAlloc(es
->heap
, HEAP_ZERO_MEMORY
, sizeof(LINEDEF
))))
3012 * To initialize some final structure members, we call some helper
3013 * functions. However, since the EDITSTATE is not consistent (i.e.
3014 * not fully initialized), we should be very careful which
3015 * functions can be called, and in what order.
3017 EDIT_WM_SetFont(wnd
, es
, 0, FALSE
);
3018 if (cs
->lpszName
&& *(cs
->lpszName
) != '\0') {
3019 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, cs
->lpszName
);
3020 /* 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 */
3021 es
->selection_start
= es
->selection_end
= 0;
3022 EDIT_EM_ScrollCaret(wnd
, es
);
3028 /*********************************************************************
3033 static void EDIT_WM_Destroy(WND
*wnd
, EDITSTATE
*es
)
3036 while (LocalUnlock32(es
->hloc32
)) ;
3037 LocalFree32(es
->hloc32
);
3040 while (LOCAL_Unlock(wnd
->hInstance
, es
->hloc16
)) ;
3041 LOCAL_Free(wnd
->hInstance
, es
->hloc16
);
3043 HeapDestroy(es
->heap
);
3044 HeapFree(GetProcessHeap(), 0, es
);
3045 *(EDITSTATE
**)wnd
->wExtra
= NULL
;
3049 /*********************************************************************
3054 static LRESULT
EDIT_WM_EraseBkGnd(WND
*wnd
, EDITSTATE
*es
, HDC32 dc
)
3059 if (!(brush
= (HBRUSH32
)EDIT_SEND_CTLCOLOR(wnd
, dc
)))
3060 brush
= (HBRUSH32
)GetStockObject32(WHITE_BRUSH
);
3062 GetClientRect32(wnd
->hwndSelf
, &rc
);
3063 IntersectClipRect32(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3064 GetClipBox32(dc
, &rc
);
3066 * FIXME: specs say that we should UnrealizeObject() the brush,
3067 * but the specs of UnrealizeObject() say that we shouldn't
3068 * unrealize a stock object. The default brush that
3069 * DefWndProc() returns is ... a stock object.
3071 FillRect32(dc
, &rc
, brush
);
3076 /*********************************************************************
3081 static INT32
EDIT_WM_GetText(WND
*wnd
, EDITSTATE
*es
, INT32 count
, LPSTR text
)
3083 INT32 len
= lstrlen32A(es
->text
);
3086 lstrcpy32A(text
, es
->text
);
3093 /*********************************************************************
3097 * 16 bit notepad needs this. Actually it is not _our_ hack,
3098 * it is notepad's. Notepad is sending us scrollbar messages with
3099 * undocumented parameters without us even having a scrollbar ... !?!?
3102 static LRESULT
EDIT_HScroll_Hack(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3105 INT32 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3108 if (!(es
->flags
& EF_HSCROLL_HACK
)) {
3109 fprintf(stderr
, "edit: hacked WM_HSCROLL handler invoked\n");
3110 fprintf(stderr
, " if you are _not_ running 16 bit notepad, please report\n");
3111 fprintf(stderr
, " (this message is only displayed once per edit control)\n");
3112 es
->flags
|= EF_HSCROLL_HACK
;
3118 dx
= -es
->char_width
;
3121 if (es
->x_offset
< es
->text_width
)
3122 dx
= es
->char_width
;
3126 dx
= -fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3129 if (es
->x_offset
< es
->text_width
)
3130 dx
= fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3137 if (es
->x_offset
< es
->text_width
)
3138 dx
= es
->text_width
- es
->x_offset
;
3141 es
->flags
|= EF_HSCROLL_TRACK
;
3142 dx
= pos
* es
->text_width
/ 100 - es
->x_offset
;
3144 case SB_THUMBPOSITION
:
3145 es
->flags
&= ~EF_HSCROLL_TRACK
;
3146 if (!(dx
= pos
* es
->text_width
/ 100 - es
->x_offset
))
3147 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
3153 * FIXME : the next two are undocumented !
3154 * Are we doing the right thing ?
3155 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
3156 * although it's also a regular control message.
3159 ret
= es
->text_width
? es
->x_offset
* 100 / es
->text_width
: 0;
3161 case EM_LINESCROLL16
:
3166 dprintf_edit(stddeb
, "edit: undocumented (hacked) WM_HSCROLL parameter, please report\n");
3170 EDIT_EM_LineScroll(wnd
, es
, dx
, 0);
3175 /*********************************************************************
3180 static LRESULT
EDIT_WM_HScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3185 if (!(es
->style
& ES_MULTILINE
))
3188 if (!(es
->style
& ES_AUTOHSCROLL
))
3191 if (!(es
->style
& WS_HSCROLL
))
3192 return EDIT_HScroll_Hack(wnd
, es
, action
, pos
, scroll_bar
);
3195 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3199 dx
= -es
->char_width
;
3202 if (es
->x_offset
< es
->text_width
)
3203 dx
= es
->char_width
;
3207 dx
= -fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3210 if (es
->x_offset
< es
->text_width
)
3211 dx
= fw
/ HSCROLL_FRACTION
/ es
->char_width
* es
->char_width
;
3218 if (es
->x_offset
< es
->text_width
)
3219 dx
= es
->text_width
- es
->x_offset
;
3222 es
->flags
|= EF_HSCROLL_TRACK
;
3223 dx
= pos
- es
->x_offset
;
3225 case SB_THUMBPOSITION
:
3226 es
->flags
&= ~EF_HSCROLL_TRACK
;
3227 if (!(dx
= pos
- es
->x_offset
)) {
3228 SetScrollPos32(wnd
->hwndSelf
, SB_HORZ
, pos
, TRUE
);
3229 EDIT_NOTIFY_PARENT(wnd
, EN_HSCROLL
, "EN_HSCROLL");
3236 fprintf(stderr
, "edit: undocumented WM_HSCROLL parameter, please report\n");
3240 EDIT_EM_LineScroll(wnd
, es
, dx
, 0);
3245 /*********************************************************************
3250 static BOOL32
EDIT_CheckCombo(WND
*wnd
, UINT32 msg
, INT32 key
, DWORD key_data
)
3254 if (WIDGETS_IsControl32(wnd
->parent
, BIC32_COMBO
) &&
3255 (hLBox
= COMBO_GetLBWindow(wnd
->parent
))) {
3256 HWND32 hCombo
= wnd
->parent
->hwndSelf
;
3257 BOOL32 bUIFlip
= TRUE
;
3259 dprintf_combo(stddeb
, "EDIT_CheckCombo [%04x]: handling msg %04x (%04x)\n",
3260 wnd
->hwndSelf
, (UINT16
)msg
, (UINT16
)key
);
3263 case WM_KEYDOWN
: /* Handle F4 and arrow keys */
3265 bUIFlip
= (BOOL32
)SendMessage32A(hCombo
, CB_GETEXTENDEDUI32
, 0, 0);
3266 if (SendMessage32A(hCombo
, CB_GETDROPPEDSTATE32
, 0, 0))
3270 SendMessage32A(hLBox
, WM_KEYDOWN
, (WPARAM32
)key
, 0);
3272 /* make sure ComboLBox pops up */
3273 SendMessage32A(hCombo
, CB_SETEXTENDEDUI32
, 0, 0);
3274 SendMessage32A(hLBox
, WM_KEYDOWN
, VK_F4
, 0);
3275 SendMessage32A(hCombo
, CB_SETEXTENDEDUI32
, 1, 0);
3278 case WM_SYSKEYDOWN
: /* Handle Alt+up/down arrows */
3279 bUIFlip
= (BOOL32
)SendMessage32A(hCombo
, CB_GETEXTENDEDUI32
, 0, 0);
3281 bUIFlip
= (BOOL32
)SendMessage32A(hCombo
, CB_GETDROPPEDSTATE32
, 0, 0);
3282 SendMessage32A(hCombo
, CB_SHOWDROPDOWN32
, (bUIFlip
) ? FALSE
: TRUE
, 0);
3284 SendMessage32A(hLBox
, WM_KEYDOWN
, VK_F4
, 0);
3293 /*********************************************************************
3297 * Handling of special keys that don't produce a WM_CHAR
3298 * (i.e. non-printable keys) & Backspace & Delete
3301 static LRESULT
EDIT_WM_KeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
)
3306 if (GetKeyState32(VK_MENU
) & 0x8000)
3309 shift
= GetKeyState32(VK_SHIFT
) & 0x8000;
3310 control
= GetKeyState32(VK_CONTROL
) & 0x8000;
3315 if (EDIT_CheckCombo(wnd
, WM_KEYDOWN
, key
, key_data
))
3321 if ((es
->style
& ES_MULTILINE
) && (key
== VK_UP
))
3322 EDIT_MoveUp_ML(wnd
, es
, shift
);
3325 EDIT_MoveWordBackward(wnd
, es
, shift
);
3327 EDIT_MoveBackward(wnd
, es
, shift
);
3330 if (EDIT_CheckCombo(wnd
, WM_KEYDOWN
, key
, key_data
))
3334 if ((es
->style
& ES_MULTILINE
) && (key
== VK_DOWN
))
3335 EDIT_MoveDown_ML(wnd
, es
, shift
);
3337 EDIT_MoveWordForward(wnd
, es
, shift
);
3339 EDIT_MoveForward(wnd
, es
, shift
);
3342 EDIT_MoveHome(wnd
, es
, shift
);
3345 EDIT_MoveEnd(wnd
, es
, shift
);
3348 if (es
->style
& ES_MULTILINE
)
3349 EDIT_MovePageUp_ML(wnd
, es
, shift
);
3352 if (es
->style
& ES_MULTILINE
)
3353 EDIT_MovePageDown_ML(wnd
, es
, shift
);
3356 if (!(es
->style
& ES_READONLY
) && !control
)
3357 if (es
->selection_start
!= es
->selection_end
)
3358 EDIT_WM_Clear(wnd
, es
);
3360 /* delete character left of caret */
3361 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3362 EDIT_MoveBackward(wnd
, es
, TRUE
);
3363 EDIT_WM_Clear(wnd
, es
);
3367 if (!(es
->style
& ES_READONLY
) && !(shift
&& control
))
3368 if (es
->selection_start
!= es
->selection_end
) {
3370 EDIT_WM_Cut(wnd
, es
);
3372 EDIT_WM_Clear(wnd
, es
);
3375 /* delete character left of caret */
3376 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3377 EDIT_MoveBackward(wnd
, es
, TRUE
);
3378 EDIT_WM_Clear(wnd
, es
);
3379 } else if (control
) {
3380 /* delete to end of line */
3381 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3382 EDIT_MoveEnd(wnd
, es
, TRUE
);
3383 EDIT_WM_Clear(wnd
, es
);
3385 /* delete character right of caret */
3386 EDIT_EM_SetSel(wnd
, es
, -1, 0, FALSE
);
3387 EDIT_MoveForward(wnd
, es
, TRUE
);
3388 EDIT_WM_Clear(wnd
, es
);
3394 if (!(es
->style
& ES_READONLY
))
3395 EDIT_WM_Paste(wnd
, es
);
3397 EDIT_WM_Copy(wnd
, es
);
3404 /*********************************************************************
3409 static LRESULT
EDIT_WM_KillFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_getting_focus
)
3411 es
->flags
&= ~EF_FOCUSED
;
3413 if(!(es
->style
& ES_NOHIDESEL
))
3414 EDIT_InvalidateText(wnd
, es
, es
->selection_start
, es
->selection_end
);
3415 EDIT_NOTIFY_PARENT(wnd
, EN_KILLFOCUS
, "EN_KILLFOCUS");
3420 /*********************************************************************
3424 * The caret position has been set on the WM_LBUTTONDOWN message
3427 static LRESULT
EDIT_WM_LButtonDblClk(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3430 INT32 e
= es
->selection_end
;
3435 if (!(es
->flags
& EF_FOCUSED
))
3438 l
= EDIT_EM_LineFromChar(wnd
, es
, e
);
3439 li
= EDIT_EM_LineIndex(wnd
, es
, l
);
3440 ll
= EDIT_EM_LineLength(wnd
, es
, e
);
3441 s
= li
+ EDIT_CallWordBreakProc (wnd
, es
, li
, e
- li
, ll
, WB_LEFT
);
3442 e
= li
+ EDIT_CallWordBreakProc(wnd
, es
, li
, e
- li
, ll
, WB_RIGHT
);
3443 EDIT_EM_SetSel(wnd
, es
, s
, e
, FALSE
);
3444 EDIT_EM_ScrollCaret(wnd
, es
);
3449 /*********************************************************************
3454 static LRESULT
EDIT_WM_LButtonDown(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3459 if (!(es
->flags
& EF_FOCUSED
))
3462 SetCapture32(wnd
->hwndSelf
);
3463 EDIT_ConfinePoint(wnd
, es
, &x
, &y
);
3464 e
= EDIT_CharFromPos(wnd
, es
, x
, y
, &after_wrap
);
3465 EDIT_EM_SetSel(wnd
, es
, (keys
& MK_SHIFT
) ? es
->selection_start
: e
, e
, after_wrap
);
3466 EDIT_EM_ScrollCaret(wnd
, es
);
3467 SetTimer32(wnd
->hwndSelf
, 0, 100, NULL
);
3472 /*********************************************************************
3477 static LRESULT
EDIT_WM_LButtonUp(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3479 if (GetCapture32() == wnd
->hwndSelf
) {
3480 KillTimer32(wnd
->hwndSelf
, 0);
3487 /*********************************************************************
3492 static LRESULT
EDIT_WM_MouseMove(WND
*wnd
, EDITSTATE
*es
, DWORD keys
, INT32 x
, INT32 y
)
3497 if (GetCapture32() != wnd
->hwndSelf
)
3501 * FIXME: gotta do some scrolling if outside client
3502 * area. Maybe reset the timer ?
3504 EDIT_ConfinePoint(wnd
, es
, &x
, &y
);
3505 e
= EDIT_CharFromPos(wnd
, es
, x
, y
, &after_wrap
);
3506 EDIT_EM_SetSel(wnd
, es
, es
->selection_start
, e
, after_wrap
);
3511 /*********************************************************************
3516 static void EDIT_WM_Paint(WND
*wnd
, EDITSTATE
*es
)
3521 HFONT32 old_font
= 0;
3526 BOOL32 rev
= IsWindowEnabled32(wnd
->hwndSelf
) &&
3527 ((es
->flags
& EF_FOCUSED
) ||
3528 (es
->style
& ES_NOHIDESEL
));
3530 if (es
->flags
& EF_UPDATE
)
3531 EDIT_NOTIFY_PARENT(wnd
, EN_UPDATE
, "EN_UPDATE");
3533 dc
= BeginPaint32(wnd
->hwndSelf
, &ps
);
3534 IntersectClipRect32(dc
, es
->format_rect
.left
,
3535 es
->format_rect
.top
,
3536 es
->format_rect
.right
,
3537 es
->format_rect
.bottom
);
3538 if (es
->style
& ES_MULTILINE
) {
3539 GetClientRect32(wnd
->hwndSelf
, &rc
);
3540 IntersectClipRect32(dc
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
3543 old_font
= SelectObject32(dc
, es
->font
);
3544 EDIT_SEND_CTLCOLOR(wnd
, dc
);
3545 if (!IsWindowEnabled32(wnd
->hwndSelf
))
3546 SetTextColor32(dc
, GetSysColor32(COLOR_GRAYTEXT
));
3547 GetClipBox32(dc
, &rcRgn
);
3548 if (es
->style
& ES_MULTILINE
) {
3549 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
3550 for (i
= es
->y_offset
; i
<= MIN(es
->y_offset
+ vlc
, es
->y_offset
+ es
->line_count
- 1) ; i
++) {
3551 EDIT_GetLineRect(wnd
, es
, i
, 0, -1, &rcLine
);
3552 if (IntersectRect32(&rc
, &rcRgn
, &rcLine
))
3553 EDIT_PaintLine(wnd
, es
, dc
, i
, rev
);
3556 EDIT_GetLineRect(wnd
, es
, 0, 0, -1, &rcLine
);
3557 if (IntersectRect32(&rc
, &rcRgn
, &rcLine
))
3558 EDIT_PaintLine(wnd
, es
, dc
, 0, rev
);
3561 SelectObject32(dc
, old_font
);
3562 if (es
->flags
& EF_FOCUSED
) {
3563 pos
= EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
);
3564 SetCaretPos32(SLOWORD(pos
), SHIWORD(pos
));
3566 EndPaint32(wnd
->hwndSelf
, &ps
);
3567 if ((es
->style
& WS_VSCROLL
) && !(es
->flags
& EF_VSCROLL_TRACK
)) {
3568 INT32 vlc
= (es
->format_rect
.bottom
- es
->format_rect
.top
) / es
->line_height
;
3570 si
.cbSize
= sizeof(SCROLLINFO
);
3571 si
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
3573 si
.nMax
= es
->line_count
+ vlc
- 2;
3575 si
.nPos
= es
->y_offset
;
3576 SetScrollInfo32(wnd
->hwndSelf
, SB_VERT
, &si
, TRUE
);
3578 if ((es
->style
& WS_HSCROLL
) && !(es
->flags
& EF_HSCROLL_TRACK
)) {
3580 INT32 fw
= es
->format_rect
.right
- es
->format_rect
.left
;
3581 si
.cbSize
= sizeof(SCROLLINFO
);
3582 si
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
3584 si
.nMax
= es
->text_width
+ fw
- 1;
3586 si
.nPos
= es
->x_offset
;
3587 SetScrollInfo32(wnd
->hwndSelf
, SB_HORZ
, &si
, TRUE
);
3590 if (es
->flags
& EF_UPDATE
) {
3591 es
->flags
&= ~EF_UPDATE
;
3592 EDIT_NOTIFY_PARENT(wnd
, EN_CHANGE
, "EN_CHANGE");
3597 /*********************************************************************
3601 * FIXME: replace with 32 bit handler once GetClipboardData32() is
3602 * implemented in misc/clipboard.c
3605 static void EDIT_WM_Paste(WND
*wnd
, EDITSTATE
*es
)
3610 OpenClipboard32(wnd
->hwndSelf
);
3611 if ((hsrc
= GetClipboardData16(CF_TEXT
))) {
3612 src
= (LPSTR
)GlobalLock16(hsrc
);
3613 EDIT_EM_ReplaceSel(wnd
, es
, TRUE
, src
);
3614 GlobalUnlock16(hsrc
);
3620 /*********************************************************************
3625 static void EDIT_WM_SetFocus(WND
*wnd
, EDITSTATE
*es
, HWND32 window_losing_focus
)
3629 es
->flags
|= EF_FOCUSED
;
3630 CreateCaret32(wnd
->hwndSelf
, 0, 2, es
->line_height
);
3631 pos
= EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
);
3632 SetCaretPos32(SLOWORD(pos
), SHIWORD(pos
));
3633 if(!(es
->style
& ES_NOHIDESEL
))
3634 EDIT_InvalidateText(wnd
, es
, es
->selection_start
, es
->selection_end
);
3635 ShowCaret32(wnd
->hwndSelf
);
3636 EDIT_NOTIFY_PARENT(wnd
, EN_SETFOCUS
, "EN_SETFOCUS");
3640 /*********************************************************************
3645 static void EDIT_WM_SetFont(WND
*wnd
, EDITSTATE
*es
, HFONT32 font
, BOOL32 redraw
)
3649 HFONT32 old_font
= 0;
3652 dc
= GetDC32(wnd
->hwndSelf
);
3654 old_font
= SelectObject32(dc
, font
);
3655 GetTextMetrics32A(dc
, &tm
);
3656 es
->line_height
= tm
.tmHeight
;
3657 es
->char_width
= tm
.tmAveCharWidth
;
3659 SelectObject32(dc
, old_font
);
3660 ReleaseDC32(wnd
->hwndSelf
, dc
);
3661 if (wnd
->flags
& WIN_ISWIN32
)
3662 EDIT_EM_SetMargins(wnd
, es
, EC_USEFONTINFO
, 0, 0);
3663 if (es
->style
& ES_MULTILINE
)
3664 EDIT_BuildLineDefs_ML(wnd
, es
);
3665 if (redraw
&& !(wnd
->flags
& WIN_NO_REDRAW
))
3666 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
3667 if (es
->flags
& EF_FOCUSED
) {
3670 CreateCaret32(wnd
->hwndSelf
, 0, 2, es
->line_height
);
3671 pos
= EDIT_EM_PosFromChar(wnd
, es
, es
->selection_end
, es
->flags
& EF_AFTER_WRAP
);
3672 SetCaretPos32(SLOWORD(pos
), SHIWORD(pos
));
3673 ShowCaret32(wnd
->hwndSelf
);
3678 /*********************************************************************
3683 static void EDIT_WM_SetText(WND
*wnd
, EDITSTATE
*es
, LPCSTR text
)
3685 EDIT_EM_SetSel(wnd
, es
, 0, -1, FALSE
);
3687 dprintf_edit(stddeb
, "\t'%s'\n", text
);
3688 EDIT_EM_ReplaceSel(wnd
, es
, FALSE
, text
);
3690 es
->flags
|= EF_MODIFIED
;
3691 es
->flags
|= EF_UPDATE
;
3692 EDIT_EM_ScrollCaret(wnd
, es
);
3696 /*********************************************************************
3701 static void EDIT_WM_Size(WND
*wnd
, EDITSTATE
*es
, UINT32 action
, INT32 width
, INT32 height
)
3703 if ((action
== SIZE_MAXIMIZED
) || (action
== SIZE_RESTORED
)) {
3705 SetRect32(&rc
, 0, 0, width
, height
);
3706 EDIT_SetRectNP(wnd
, es
, &rc
);
3707 InvalidateRect32(wnd
->hwndSelf
, NULL
, TRUE
);
3712 /*********************************************************************
3717 static LRESULT
EDIT_WM_SysKeyDown(WND
*wnd
, EDITSTATE
*es
, INT32 key
, DWORD key_data
)
3719 if ((key
== VK_BACK
) && (key_data
& 0x2000)) {
3720 if (EDIT_EM_CanUndo(wnd
, es
))
3721 EDIT_EM_Undo(wnd
, es
);
3723 } else if (key
== VK_UP
|| key
== VK_DOWN
)
3724 if (EDIT_CheckCombo(wnd
, WM_SYSKEYDOWN
, key
, key_data
))
3726 return DefWindowProc32A(wnd
->hwndSelf
, WM_SYSKEYDOWN
, (WPARAM32
)key
, (LPARAM
)key_data
);
3730 /*********************************************************************
3735 static void EDIT_WM_Timer(WND
*wnd
, EDITSTATE
*es
, INT32 id
, TIMERPROC32 timer_proc
)
3738 * FIXME: gotta do some scrolling here, like
3739 * EDIT_EM_LineScroll(wnd, 0, 1);
3744 /*********************************************************************
3748 * 16 bit notepad needs this. Actually it is not _our_ hack,
3749 * it is notepad's. Notepad is sending us scrollbar messages with
3750 * undocumented parameters without us even having a scrollbar ... !?!?
3753 static LRESULT
EDIT_VScroll_Hack(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3758 if (!(es
->flags
& EF_VSCROLL_HACK
)) {
3759 fprintf(stderr
, "edit: hacked WM_VSCROLL handler invoked\n");
3760 fprintf(stderr
, " if you are _not_ running 16 bit notepad, please report\n");
3761 fprintf(stderr
, " (this message is only displayed once per edit control)\n");
3762 es
->flags
|= EF_VSCROLL_HACK
;
3770 EDIT_EM_Scroll(wnd
, es
, action
);
3776 dy
= es
->line_count
- 1 - es
->y_offset
;
3779 es
->flags
|= EF_VSCROLL_TRACK
;
3780 dy
= (pos
* (es
->line_count
- 1) + 50) / 100 - es
->y_offset
;
3782 case SB_THUMBPOSITION
:
3783 es
->flags
&= ~EF_VSCROLL_TRACK
;
3784 if (!(dy
= (pos
* (es
->line_count
- 1) + 50) / 100 - es
->y_offset
))
3785 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
3791 * FIXME : the next two are undocumented !
3792 * Are we doing the right thing ?
3793 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
3794 * although it's also a regular control message.
3797 ret
= (es
->line_count
> 1) ? es
->y_offset
* 100 / (es
->line_count
- 1) : 0;
3799 case EM_LINESCROLL16
:
3804 fprintf(stderr
, "edit: undocumented (hacked) WM_VSCROLL parameter, please report\n");
3808 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);
3813 /*********************************************************************
3818 static LRESULT
EDIT_WM_VScroll(WND
*wnd
, EDITSTATE
*es
, INT32 action
, INT32 pos
, HWND32 scroll_bar
)
3822 if (!(es
->style
& ES_MULTILINE
))
3825 if (!(es
->style
& ES_AUTOVSCROLL
))
3828 if (!(es
->style
& WS_VSCROLL
))
3829 return EDIT_VScroll_Hack(wnd
, es
, action
, pos
, scroll_bar
);
3837 EDIT_EM_Scroll(wnd
, es
, action
);
3844 dy
= es
->line_count
- 1 - es
->y_offset
;
3847 es
->flags
|= EF_VSCROLL_TRACK
;
3848 dy
= pos
- es
->y_offset
;
3850 case SB_THUMBPOSITION
:
3851 es
->flags
&= ~EF_VSCROLL_TRACK
;
3852 if (!(dy
= pos
- es
->y_offset
)) {
3853 SetScrollPos32(wnd
->hwndSelf
, SB_VERT
, pos
, TRUE
);
3854 EDIT_NOTIFY_PARENT(wnd
, EN_VSCROLL
, "EN_VSCROLL");
3861 fprintf(stderr
, "edit: undocumented WM_VSCROLL parameter, please report\n");
3865 EDIT_EM_LineScroll(wnd
, es
, 0, dy
);