source: trunk/src/user32/edit.cpp@ 1368

Last change on this file since 1368 was 1368, checked in by sandervl, 26 years ago

compile fixes

File size: 129.1 KB
Line 
1/* $Id: edit.cpp,v 1.6 1999-10-20 06:38:09 sandervl Exp $ */
2/*
3 * Edit control
4 *
5 * Copyright David W. Metcalfe, 1994
6 * Copyright William Magro, 1995, 1996
7 * Copyright Frans van Dorsselaer, 1996, 1997
8 *
9 * Copyright 1999 Christoph Bratschi (ported from WINE)
10 *
11 * WINE version: 990923
12 */
13
14/*
15 * please read EDIT.TODO (and update it when you change things)
16 CB:
17 - OS/2 menu not implemented (WM_CONTEXTMENU)
18 */
19
20#include <os2win.h>
21#include <string.h>
22#include "controls.h"
23#include "combo.h"
24
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 */
32
33/*
34 * extra flags for EDITSTATE.flags field
35 */
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 */
45#define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */
46
47typedef enum
48{
49 END_0 = 0, /* line ends with terminating '\0' character */
50 END_WRAP, /* line is wrapped */
51 END_HARD, /* line ends with a hard return '\r\n' */
52 END_SOFT /* line ends with a soft return '\r\r\n' */
53} LINE_END;
54
55typedef struct tagLINEDEF {
56 INT length; /* bruto length of a line in bytes */
57 INT net_length; /* netto length of a line in visible characters */
58 LINE_END ending;
59 INT width; /* width of the line in pixels */
60 struct tagLINEDEF *next;
61} LINEDEF;
62
63typedef struct
64{
65 HANDLE heap; /* our own heap */
66 LPSTR text; /* the actual contents of the control */
67 INT buffer_size; /* the size of the buffer */
68 INT buffer_limit; /* the maximum size to which the buffer may grow */
69 HFONT font; /* NULL means standard system font */
70 INT x_offset; /* scroll offset for multi lines this is in pixels
71 for single lines it's in characters */
72 INT line_height; /* height of a screen line in pixels */
73 INT char_width; /* average character width in pixels */
74 DWORD style; /* sane version of wnd->dwStyle */
75 WORD flags; /* flags that are not in es->style or wnd->flags (EF_XXX) */
76 INT undo_insert_count; /* number of characters inserted in sequence */
77 INT undo_position; /* character index of the insertion and deletion */
78 LPSTR undo_text; /* deleted text */
79 INT undo_buffer_size; /* size of the deleted text buffer */
80 INT selection_start; /* == selection_end if no selection */
81 INT selection_end; /* == current caret position */
82 CHAR password_char; /* == 0 if no password char, and for multi line controls */
83 INT left_margin; /* in pixels */
84 INT right_margin; /* in pixels */
85 RECT format_rect;
86 INT region_posx; /* Position of cursor relative to region: */
87 INT region_posy; /* -1: to left, 0: within, 1: to right */
88 EDITWORDBREAKPROCA word_break_procA;
89 INT line_count; /* number of lines */
90 INT y_offset; /* scroll offset in number of lines */
91 BOOL bCaptureState; /* flag indicating whether mouse was captured */
92 BOOL bEnableState; /* flag keeping the enable state */
93 /*
94 * only for multi line controls
95 */
96 INT lock_count; /* amount of re-entries in the EditWndProc */
97 INT tabs_count;
98 LPINT tabs;
99 INT text_width; /* width of the widest line in pixels */
100 LINEDEF *first_line_def; /* linked list of (soft) linebreaks */
101 HLOCAL hloc; /* for controls receiving EM_GETHANDLE */
102} EDITSTATE;
103
104
105#define SWAP_INT32(x,y) do { INT temp = (INT)(x); (x) = (INT)(y); (y) = temp; } while(0)
106#define ORDER_INT(x,y) do { if ((INT)(y) < (INT)(x)) SWAP_INT32((x),(y)); } while(0)
107
108#define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
109#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
110
111/* used for disabled or read-only edit control */
112#define EDIT_SEND_CTLCOLORSTATIC(hwnd,hdc) \
113 (SendMessageA(GetParent(hwnd), WM_CTLCOLORSTATIC, \
114 (WPARAM)(hdc), (LPARAM)hwnd))
115#define EDIT_SEND_CTLCOLOR(hwnd,hdc) \
116 (SendMessageA(GetParent(hwnd), WM_CTLCOLOREDIT, \
117 (WPARAM)(hdc), (LPARAM)hwnd))
118#define EDIT_NOTIFY_PARENT(hwnd, wNotifyCode, str) \
119 do { \
120 SendMessageA(GetParent(hwnd), WM_COMMAND, \
121 MAKEWPARAM(GetWindowLongA(hwnd,GWL_ID), wNotifyCode), \
122 (LPARAM)hwnd);} while(0)
123
124/*********************************************************************
125 *
126 * Declarations
127 *
128 */
129
130/*
131 * These functions have trivial implementations
132 * We still like to call them internally
133 * "static inline" makes them more like macro's
134 */
135static inline BOOL EDIT_EM_CanUndo(HWND hwnd, EDITSTATE *es);
136static inline void EDIT_EM_EmptyUndoBuffer(HWND hwnd, EDITSTATE *es);
137static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es);
138static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es);
139
140/*
141 * Helper functions only valid for one type of control
142 */
143static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es);
144static LPSTR EDIT_GetPasswordPointer_SL(HWND hwnd, EDITSTATE *es);
145static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
146static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
147static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
148static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
149/*
150 * Helper functions valid for both single line _and_ multi line controls
151 */
152static INT EDIT_CallWordBreakProc(HWND hwnd, EDITSTATE *es, INT start, INT index, INT count, INT action);
153static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap);
154static void EDIT_ConfinePoint(HWND hwnd, EDITSTATE *es, LPINT x, LPINT y);
155static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc);
156static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end);
157static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es);
158static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, INT size);
159static BOOL EDIT_MakeUndoFit(HWND hwnd, EDITSTATE *es, INT size);
160static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
161static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend);
162static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend);
163static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend);
164static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
165static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend);
166static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev);
167static INT EDIT_PaintText(HWND hwnd, EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
168static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos, BOOL after_wrap);
169static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT lprc);
170static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force);
171static INT EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action);
172/*
173 * EM_XXX message handlers
174 */
175static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y);
176static BOOL EDIT_EM_FmtLines(HWND hwnd, EDITSTATE *es, BOOL add_eol);
177static HLOCAL EDIT_EM_GetHandle(HWND hwnd, EDITSTATE *es);
178static HLOCAL16 EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es);
179static INT EDIT_EM_GetLine(HWND hwnd, EDITSTATE *es, INT line, LPSTR lpch);
180static LRESULT EDIT_EM_GetSel(HWND hwnd, EDITSTATE *es, LPUINT start, LPUINT end);
181static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es);
182static INT EDIT_EM_LineFromChar(HWND hwnd, EDITSTATE *es, INT index);
183static INT EDIT_EM_LineIndex(HWND hwnd, EDITSTATE *es, INT line);
184static INT EDIT_EM_LineLength(HWND hwnd, EDITSTATE *es, INT index);
185static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy);
186static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap);
187static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace);
188static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action);
189static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es);
190static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc);
191static void EDIT_EM_SetLimitText(HWND hwnd, EDITSTATE *es, INT limit);
192static void EDIT_EM_SetMargins(HWND hwnd, EDITSTATE *es, INT action, INT left, INT right);
193static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, CHAR c);
194static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
195static BOOL EDIT_EM_SetTabStops(HWND hwnd, EDITSTATE *es, INT count, LPINT tabs);
196static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp);
197static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es);
198/*
199 * WM_XXX message handlers
200 */
201static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, CHAR c, DWORD key_data);
202static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND conrtol);
203static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, HWND hwndBtn, INT x, INT y);
204static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es);
205static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCREATESTRUCTA cs);
206static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es);
207static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc);
208static INT EDIT_WM_GetText(HWND hwnd, EDITSTATE *es, INT count, LPSTR text);
209static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar);
210static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data);
211static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es, HWND window_getting_focus);
212static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
213static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
214static LRESULT EDIT_WM_LButtonUp(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
215static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
216static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTA cs);
217static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es,WPARAM wParam);
218static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es);
219static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es, HWND window_losing_focus);
220static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw);
221static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPCSTR text);
222static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height);
223static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data);
224static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es, INT id, TIMERPROC timer_proc);
225static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar);
226
227
228/*********************************************************************
229 *
230 * EM_CANUNDO
231 *
232 */
233static inline BOOL EDIT_EM_CanUndo(HWND hwnd, EDITSTATE *es)
234{
235 return (es->undo_insert_count || lstrlenA(es->undo_text));
236}
237
238
239/*********************************************************************
240 *
241 * EM_EMPTYUNDOBUFFER
242 *
243 */
244static inline void EDIT_EM_EmptyUndoBuffer(HWND hwnd, EDITSTATE *es)
245{
246 es->undo_insert_count = 0;
247 *es->undo_text = '\0';
248}
249
250
251/*********************************************************************
252 *
253 * WM_CLEAR
254 *
255 */
256static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es)
257{
258 EDIT_EM_ReplaceSel(hwnd, es, TRUE, "");
259}
260
261
262/*********************************************************************
263 *
264 * WM_CUT
265 *
266 */
267static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es)
268{
269 EDIT_WM_Copy(hwnd, es);
270 EDIT_WM_Clear(hwnd, es);
271}
272
273
274/*********************************************************************
275 *
276 * EditWndProc()
277 *
278 * The messages are in the order of the actual integer values
279 * (which can be found in include/windows.h)
280 * Whereever possible the 16 bit versions are converted to
281 * the 32 bit ones, so that we can 'fall through' to the
282 * helper functions. These are mostly 32 bit (with a few
283 * exceptions, clearly indicated by a '16' extension to their
284 * names).
285 *
286 */
287LRESULT WINAPI EditWndProc( HWND hwnd, UINT msg,
288 WPARAM wParam, LPARAM lParam )
289{
290 EDITSTATE *es = (EDITSTATE*)GetInfoPtr(hwnd);
291 LRESULT result = 0;
292
293 switch (msg) {
294 case WM_DESTROY:
295 //DPRINTF_EDIT_MSG32("WM_DESTROY");
296 EDIT_WM_Destroy(hwnd, es);
297 result = 0;
298 goto END;
299
300 case WM_NCCREATE:
301 //DPRINTF_EDIT_MSG32("WM_NCCREATE");
302 result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTA)lParam);
303 goto END;
304 }
305
306 if (!es)
307 {
308 result = DefWindowProcA(hwnd, msg, wParam, lParam);
309 goto END;
310 }
311
312
313 EDIT_LockBuffer(hwnd, es);
314 switch (msg) {
315 case EM_GETSEL:
316 //DPRINTF_EDIT_MSG32("EM_GETSEL");
317 result = EDIT_EM_GetSel(hwnd, es, (LPUINT)wParam, (LPUINT)lParam);
318 break;
319
320 case EM_SETSEL:
321 //DPRINTF_EDIT_MSG32("EM_SETSEL");
322 EDIT_EM_SetSel(hwnd, es, wParam, lParam, FALSE);
323 EDIT_EM_ScrollCaret(hwnd,es);
324 result = 1;
325 break;
326
327 case EM_GETRECT:
328 //DPRINTF_EDIT_MSG32("EM_GETRECT");
329 if (lParam)
330 CopyRect((LPRECT)lParam, &es->format_rect);
331 break;
332
333 case EM_SETRECT:
334 //DPRINTF_EDIT_MSG32("EM_SETRECT");
335 if ((es->style & ES_MULTILINE) && lParam) {
336 EDIT_SetRectNP(hwnd, es, (LPRECT)lParam);
337 InvalidateRect(hwnd, NULL, TRUE);
338 }
339 break;
340
341 case EM_SETRECTNP:
342 //DPRINTF_EDIT_MSG32("EM_SETRECTNP");
343 if ((es->style & ES_MULTILINE) && lParam)
344 EDIT_SetRectNP(hwnd, es, (LPRECT)lParam);
345 break;
346
347 case EM_SCROLL:
348 //DPRINTF_EDIT_MSG32("EM_SCROLL");
349 result = EDIT_EM_Scroll(hwnd, es, (INT)wParam);
350 break;
351
352 case EM_LINESCROLL:
353 //DPRINTF_EDIT_MSG32("EM_LINESCROLL");
354 result = (LRESULT)EDIT_EM_LineScroll(hwnd, es, (INT)wParam, (INT)lParam);
355 break;
356
357 case EM_SCROLLCARET:
358 //DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
359 EDIT_EM_ScrollCaret(hwnd, es);
360 result = 1;
361 break;
362
363 case EM_GETMODIFY:
364 //DPRINTF_EDIT_MSG32("EM_GETMODIFY");
365 result = ((es->flags & EF_MODIFIED) != 0);
366 break;
367
368 case EM_SETMODIFY:
369 //DPRINTF_EDIT_MSG32("EM_SETMODIFY");
370 if (wParam)
371 es->flags |= EF_MODIFIED;
372 else
373 es->flags &= ~(EF_MODIFIED | EF_UPDATE); /* reset pending updates */
374 break;
375
376 case EM_GETLINECOUNT:
377 //DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
378 result = (es->style & ES_MULTILINE) ? es->line_count : 1;
379 break;
380
381 case EM_LINEINDEX:
382 //DPRINTF_EDIT_MSG32("EM_LINEINDEX");
383 result = (LRESULT)EDIT_EM_LineIndex(hwnd, es, (INT)wParam);
384 break;
385
386 case EM_SETHANDLE:
387 //DPRINTF_EDIT_MSG32("EM_SETHANDLE");
388 EDIT_EM_SetHandle(hwnd, es, (HLOCAL)wParam);
389 break;
390
391 case EM_GETHANDLE:
392 //DPRINTF_EDIT_MSG32("EM_GETHANDLE");
393 result = (LRESULT)EDIT_EM_GetHandle(hwnd, es);
394 break;
395
396 case EM_GETTHUMB:
397 //DPRINTF_EDIT_MSG32("EM_GETTHUMB");
398 result = EDIT_EM_GetThumb(hwnd, es);
399 break;
400
401 /* messages 0x00bf and 0x00c0 missing from specs */
402
403 case WM_USER+15:
404 //DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
405 /* fall through */
406 case 0x00bf:
407 //DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
408 result = DefWindowProcA(hwnd, msg, wParam, lParam);
409 break;
410
411 case WM_USER+16:
412 //DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
413 /* fall through */
414 case 0x00c0:
415 //DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
416 result = DefWindowProcA(hwnd, msg, wParam, lParam);
417 break;
418
419 case EM_LINELENGTH:
420 //DPRINTF_EDIT_MSG32("EM_LINELENGTH");
421 result = (LRESULT)EDIT_EM_LineLength(hwnd, es, (INT)wParam);
422 break;
423
424 case EM_REPLACESEL:
425 //DPRINTF_EDIT_MSG32("EM_REPLACESEL");
426 EDIT_EM_ReplaceSel(hwnd, es, (BOOL)wParam, (LPCSTR)lParam);
427 result = 1;
428 break;
429
430 /* message 0x00c3 missing from specs */
431
432 case WM_USER+19:
433 //DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
434 /* fall through */
435 case 0x00c3:
436 //DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
437 result = DefWindowProcA(hwnd, msg, wParam, lParam);
438 break;
439
440 case EM_GETLINE:
441 //DPRINTF_EDIT_MSG32("EM_GETLINE");
442 result = (LRESULT)EDIT_EM_GetLine(hwnd, es, (INT)wParam, (LPSTR)lParam);
443 break;
444
445 case EM_SETLIMITTEXT:
446 //DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
447 EDIT_EM_SetLimitText(hwnd, es, (INT)wParam);
448 break;
449
450 case EM_CANUNDO:
451 //DPRINTF_EDIT_MSG32("EM_CANUNDO");
452 result = (LRESULT)EDIT_EM_CanUndo(hwnd, es);
453 break;
454
455 case EM_UNDO:
456 /* fall through */
457 case WM_UNDO:
458 //DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
459 result = (LRESULT)EDIT_EM_Undo(hwnd, es);
460 break;
461
462 case EM_FMTLINES:
463 //DPRINTF_EDIT_MSG32("EM_FMTLINES");
464 result = (LRESULT)EDIT_EM_FmtLines(hwnd, es, (BOOL)wParam);
465 break;
466
467 case EM_LINEFROMCHAR:
468 //DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
469 result = (LRESULT)EDIT_EM_LineFromChar(hwnd, es, (INT)wParam);
470 break;
471
472 /* message 0x00ca missing from specs */
473
474 case WM_USER+26:
475 //DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
476 /* fall through */
477 case 0x00ca:
478 //DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
479 result = DefWindowProcA(hwnd, msg, wParam, lParam);
480 break;
481
482 case EM_SETTABSTOPS:
483 //DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
484 result = (LRESULT)EDIT_EM_SetTabStops(hwnd, es, (INT)wParam, (LPINT)lParam);
485 break;
486
487 case EM_SETPASSWORDCHAR:
488 //DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
489 EDIT_EM_SetPasswordChar(hwnd, es, (CHAR)wParam);
490 break;
491
492 case EM_EMPTYUNDOBUFFER:
493 //DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
494 EDIT_EM_EmptyUndoBuffer(hwnd, es);
495 break;
496
497 case EM_GETFIRSTVISIBLELINE:
498 //DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
499 result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
500 break;
501
502 case EM_SETREADONLY:
503 //DPRINTF_EDIT_MSG32("EM_SETREADONLY");
504 if (wParam)
505 {
506 SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) | ES_READONLY);
507 es->style |= ES_READONLY;
508 } else
509 {
510 SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) & ~ES_READONLY);
511 es->style &= ~ES_READONLY;
512 }
513 result = 1;
514 break;
515
516 case EM_SETWORDBREAKPROC:
517 //DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
518 EDIT_EM_SetWordBreakProc(hwnd, es, (EDITWORDBREAKPROCA)lParam);
519 break;
520
521 case EM_GETWORDBREAKPROC:
522 //DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
523 result = (LRESULT)es->word_break_procA;
524 break;
525
526 case EM_GETPASSWORDCHAR:
527 //DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
528 result = es->password_char;
529 break;
530
531 /* The following EM_xxx are new to win95 and don't exist for 16 bit */
532
533 case EM_SETMARGINS:
534 //DPRINTF_EDIT_MSG32("EM_SETMARGINS");
535 EDIT_EM_SetMargins(hwnd, es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam));
536 break;
537
538 case EM_GETMARGINS:
539 //DPRINTF_EDIT_MSG32("EM_GETMARGINS");
540 result = MAKELONG(es->left_margin, es->right_margin);
541 break;
542
543 case EM_GETLIMITTEXT:
544 //DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
545 result = es->buffer_limit;
546 break;
547
548 case EM_POSFROMCHAR:
549 //DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
550 result = EDIT_EM_PosFromChar(hwnd, es, (INT)wParam, FALSE);
551 break;
552
553 case EM_CHARFROMPOS:
554 //DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
555 result = EDIT_EM_CharFromPos(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
556 break;
557
558 case WM_GETDLGCODE:
559 //DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
560 result = (es->style & ES_MULTILINE) ?
561 DLGC_WANTALLKEYS | DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS :
562 DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
563 break;
564
565 case WM_CHAR:
566 //DPRINTF_EDIT_MSG32("WM_CHAR");
567 EDIT_WM_Char(hwnd, es, (CHAR)wParam, (DWORD)lParam);
568 break;
569
570 case WM_CLEAR:
571 //DPRINTF_EDIT_MSG32("WM_CLEAR");
572 EDIT_WM_Clear(hwnd, es);
573 break;
574
575 case WM_COMMAND:
576 //DPRINTF_EDIT_MSG32("WM_COMMAND");
577 EDIT_WM_Command(hwnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
578 break;
579
580 case WM_CONTEXTMENU:
581 //DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
582 EDIT_WM_ContextMenu(hwnd, es, (HWND)wParam, SLOWORD(lParam), SHIWORD(lParam));
583 break;
584
585 case WM_COPY:
586 //DPRINTF_EDIT_MSG32("WM_COPY");
587 EDIT_WM_Copy(hwnd, es);
588 break;
589
590 case WM_CREATE:
591 //DPRINTF_EDIT_MSG32("WM_CREATE");
592 result = EDIT_WM_Create(hwnd, es, (LPCREATESTRUCTA)lParam);
593 break;
594
595 case WM_CUT:
596 //DPRINTF_EDIT_MSG32("WM_CUT");
597 EDIT_WM_Cut(hwnd, es);
598 break;
599
600 case WM_ENABLE:
601 //DPRINTF_EDIT_MSG32("WM_ENABLE");
602 es->bEnableState = (BOOL)wParam;
603 InvalidateRect(hwnd, NULL, TRUE);
604 break;
605
606 case WM_ERASEBKGND:
607 //DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
608 result = EDIT_WM_EraseBkGnd(hwnd, es, (HDC)wParam);
609 break;
610
611 case WM_GETFONT:
612 //DPRINTF_EDIT_MSG32("WM_GETFONT");
613 result = (LRESULT)es->font;
614 break;
615
616 case WM_GETTEXT:
617 //DPRINTF_EDIT_MSG32("WM_GETTEXT");
618 result = (LRESULT)EDIT_WM_GetText(hwnd, es, (INT)wParam, (LPSTR)lParam);
619 break;
620
621 case WM_GETTEXTLENGTH:
622 //DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
623 result = lstrlenA(es->text);
624 break;
625
626 case WM_HSCROLL:
627 //DPRINTF_EDIT_MSG32("WM_HSCROLL");
628 result = EDIT_WM_HScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)lParam);
629 break;
630
631 case WM_KEYDOWN:
632 //DPRINTF_EDIT_MSG32("WM_KEYDOWN");
633 result = EDIT_WM_KeyDown(hwnd, es, (INT)wParam, (DWORD)lParam);
634 break;
635
636 case WM_KILLFOCUS:
637 //DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
638 result = EDIT_WM_KillFocus(hwnd, es, (HWND)wParam);
639 break;
640
641 case WM_LBUTTONDBLCLK:
642 //DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
643 result = EDIT_WM_LButtonDblClk(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
644 break;
645
646 case WM_LBUTTONDOWN:
647 //DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
648 result = EDIT_WM_LButtonDown(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
649 break;
650
651 case WM_LBUTTONUP:
652 //DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
653 result = EDIT_WM_LButtonUp(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
654 break;
655
656 case WM_MOUSEACTIVATE:
657 /*
658 * FIXME: maybe DefWindowProc() screws up, but it seems that
659 * modalless dialog boxes need this. If we don't do this, the focus
660 * will _not_ be set by DefWindowProc() for edit controls in a
661 * modalless dialog box ???
662 */
663 //DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
664 SetFocus(hwnd);
665 result = MA_ACTIVATE;
666 break;
667
668 case WM_MOUSEMOVE:
669 /*
670 * DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
671 */
672 result = EDIT_WM_MouseMove(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
673 break;
674
675 case WM_PAINT:
676 //DPRINTF_EDIT_MSG32("WM_PAINT");
677 EDIT_WM_Paint(hwnd, es,wParam);
678 break;
679
680 case WM_PASTE:
681 //DPRINTF_EDIT_MSG32("WM_PASTE");
682 EDIT_WM_Paste(hwnd, es);
683 break;
684
685 case WM_SETFOCUS:
686 //DPRINTF_EDIT_MSG32("WM_SETFOCUS");
687 EDIT_WM_SetFocus(hwnd, es, (HWND)wParam);
688 break;
689
690 case WM_SETFONT:
691 //DPRINTF_EDIT_MSG32("WM_SETFONT");
692 EDIT_WM_SetFont(hwnd, es, (HFONT)wParam, LOWORD(lParam) != 0);
693 break;
694
695 case WM_SETTEXT:
696 //DPRINTF_EDIT_MSG32("WM_SETTEXT");
697 EDIT_WM_SetText(hwnd, es, (LPCSTR)lParam);
698 result = TRUE;
699 break;
700
701 case WM_SIZE:
702 //DPRINTF_EDIT_MSG32("WM_SIZE");
703 EDIT_WM_Size(hwnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
704 break;
705
706 case WM_SYSKEYDOWN:
707 //DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
708 result = EDIT_WM_SysKeyDown(hwnd, es, (INT)wParam, (DWORD)lParam);
709 break;
710
711 case WM_TIMER:
712 //DPRINTF_EDIT_MSG32("WM_TIMER");
713 EDIT_WM_Timer(hwnd, es, (INT)wParam, (TIMERPROC)lParam);
714 break;
715
716 case WM_VSCROLL:
717 //DPRINTF_EDIT_MSG32("WM_VSCROLL");
718 result = EDIT_WM_VScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam), (HWND)(lParam));
719 break;
720
721 default:
722 result = DefWindowProcA(hwnd, msg, wParam, lParam);
723 break;
724 }
725 EDIT_UnlockBuffer(hwnd, es, FALSE);
726 END:
727 return result;
728
729}
730
731
732/*********************************************************************
733 *
734 * EDIT_BuildLineDefs_ML
735 *
736 * Build linked list of text lines.
737 * Lines can end with '\0' (last line), a character (if it is wrapped),
738 * a soft return '\r\r\n' or a hard return '\r\n'
739 *
740 */
741static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es)
742{
743 HDC dc;
744 HFONT old_font = 0;
745 LPSTR start, cp;
746 INT fw;
747 LINEDEF *current_def;
748 LINEDEF **previous_next;
749
750 current_def = es->first_line_def;
751 do {
752 LINEDEF *next_def = current_def->next;
753 HeapFree(es->heap, 0, current_def);
754 current_def = next_def;
755 } while (current_def);
756 es->line_count = 0;
757 es->text_width = 0;
758
759 dc = GetDC(hwnd);
760 if (es->font)
761 old_font = SelectObject(dc, es->font);
762
763 fw = es->format_rect.right - es->format_rect.left;
764 start = es->text;
765 previous_next = &es->first_line_def;
766 do {
767 current_def = (LINEDEF*)HeapAlloc(es->heap, 0, sizeof(LINEDEF));
768 current_def->next = NULL;
769 cp = start;
770 while (*cp) {
771 if ((*cp == '\r') && (*(cp + 1) == '\n'))
772 break;
773 cp++;
774 }
775 if (!(*cp)) {
776 current_def->ending = END_0;
777 current_def->net_length = lstrlenA(start);
778 } else if ((cp > start) && (*(cp - 1) == '\r')) {
779 current_def->ending = END_SOFT;
780 current_def->net_length = cp - start - 1;
781 } else {
782 current_def->ending = END_HARD;
783 current_def->net_length = cp - start;
784 }
785 current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc,
786 start, current_def->net_length,
787 es->tabs_count, es->tabs));
788 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
789 if ((!(es->style & ES_AUTOHSCROLL)) && (current_def->width > fw)) {
790 INT next = 0;
791 INT prev;
792 do {
793 prev = next;
794 next = EDIT_CallWordBreakProc(hwnd, es, start - es->text,
795 prev + 1, current_def->net_length, WB_RIGHT);
796 current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc,
797 start, next, es->tabs_count, es->tabs));
798 } while (current_def->width <= fw);
799 if (!prev) {
800 next = 0;
801 do {
802 prev = next;
803 next++;
804 current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc,
805 start, next, es->tabs_count, es->tabs));
806 } while (current_def->width <= fw);
807 if (!prev)
808 prev = 1;
809 }
810 current_def->net_length = prev;
811 current_def->ending = END_WRAP;
812 current_def->width = (INT)LOWORD(GetTabbedTextExtentA(dc, start,
813 current_def->net_length, es->tabs_count, es->tabs));
814 }
815 switch (current_def->ending) {
816 case END_SOFT:
817 current_def->length = current_def->net_length + 3;
818 break;
819 case END_HARD:
820 current_def->length = current_def->net_length + 2;
821 break;
822 case END_WRAP:
823 case END_0:
824 current_def->length = current_def->net_length;
825 break;
826 }
827 es->text_width = MAX(es->text_width, current_def->width);
828 start += current_def->length;
829 *previous_next = current_def;
830 previous_next = &current_def->next;
831 es->line_count++;
832 } while (current_def->ending != END_0);
833 if (es->font)
834 SelectObject(dc, old_font);
835 ReleaseDC(hwnd, dc);
836}
837
838
839/*********************************************************************
840 *
841 * EDIT_CallWordBreakProc
842 *
843 * Call appropriate WordBreakProc (internal or external).
844 *
845 * Note: The "start" argument should always be an index refering
846 * to es->text. The actual wordbreak proc might be
847 * 16 bit, so we can't always pass any 32 bit LPSTR.
848 * Hence we assume that es->text is the buffer that holds
849 * the string under examination (we can decide this for ourselves).
850 *
851 */
852static INT EDIT_CallWordBreakProc(HWND hwnd, EDITSTATE *es, INT start, INT index, INT count, INT action)
853{
854 if (es->word_break_procA)
855 {
856 //TRACE_(relay)("(wordbrk=%p,str='%s',idx=%d,cnt=%d,act=%d)\n",
857 // es->word_break_proc32A, es->text + start, index,
858 // count, action );
859 return (INT)es->word_break_procA( es->text + start, index,
860 count, action );
861 }
862 else
863 return EDIT_WordBreakProc(es->text + start, index, count, action);
864}
865
866
867/*********************************************************************
868 *
869 * EDIT_CharFromPos
870 *
871 * Beware: This is not the function called on EM_CHARFROMPOS
872 * The position _can_ be outside the formatting / client
873 * rectangle
874 * The return value is only the character index
875 *
876 */
877static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
878{
879 INT index;
880 HDC dc;
881 HFONT old_font = 0;
882
883 if (es->style & ES_MULTILINE) {
884 INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
885 INT line_index = 0;
886 LINEDEF *line_def = es->first_line_def;
887 INT low, high;
888 while ((line > 0) && line_def->next) {
889 line_index += line_def->length;
890 line_def = line_def->next;
891 line--;
892 }
893 x += es->x_offset - es->format_rect.left;
894 if (x >= line_def->width) {
895 if (after_wrap)
896 *after_wrap = (line_def->ending == END_WRAP);
897 return line_index + line_def->net_length;
898 }
899 if (x <= 0) {
900 if (after_wrap)
901 *after_wrap = FALSE;
902 return line_index;
903 }
904 dc = GetDC(hwnd);
905 if (es->font)
906 old_font = SelectObject(dc, es->font);
907 low = line_index + 1;
908 high = line_index + line_def->net_length + 1;
909 while (low < high - 1)
910 {
911 INT mid = (low + high) / 2;
912 if (LOWORD(GetTabbedTextExtentA(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid;
913 else low = mid;
914 }
915 index = low;
916
917 if (after_wrap)
918 *after_wrap = ((index == line_index + line_def->net_length) &&
919 (line_def->ending == END_WRAP));
920 } else {
921 LPSTR text;
922 SIZE size;
923 if (after_wrap)
924 *after_wrap = FALSE;
925 x -= es->format_rect.left;
926 if (!x)
927 return es->x_offset;
928 text = EDIT_GetPasswordPointer_SL(hwnd, es);
929 dc = GetDC(hwnd);
930 if (es->font)
931 old_font = SelectObject(dc, es->font);
932 if (x < 0)
933 {
934 INT low = 0;
935 INT high = es->x_offset;
936 while (low < high - 1)
937 {
938 INT mid = (low + high) / 2;
939 GetTextExtentPoint32A( dc, text + mid,
940 es->x_offset - mid, &size );
941 if (size.cx > -x) low = mid;
942 else high = mid;
943 }
944 index = low;
945 }
946 else
947 {
948 INT low = es->x_offset;
949 INT high = lstrlenA(es->text) + 1;
950 while (low < high - 1)
951 {
952 INT mid = (low + high) / 2;
953 GetTextExtentPoint32A( dc, text + es->x_offset,
954 mid - es->x_offset, &size );
955 if (size.cx > x) high = mid;
956 else low = mid;
957 }
958 index = low;
959 }
960 if (es->style & ES_PASSWORD)
961 HeapFree(es->heap, 0 ,text);
962 }
963 if (es->font)
964 SelectObject(dc, old_font);
965 ReleaseDC(hwnd, dc);
966 return index;
967}
968
969
970/*********************************************************************
971 *
972 * EDIT_ConfinePoint
973 *
974 * adjusts the point to be within the formatting rectangle
975 * (so CharFromPos returns the nearest _visible_ character)
976 *
977 */
978static void EDIT_ConfinePoint(HWND hwnd, EDITSTATE *es, LPINT x, LPINT y)
979{
980 *x = MIN(MAX(*x, es->format_rect.left), es->format_rect.right - 1);
981 *y = MIN(MAX(*y, es->format_rect.top), es->format_rect.bottom - 1);
982}
983
984
985/*********************************************************************
986 *
987 * EDIT_GetLineRect
988 *
989 * Calculates the bounding rectangle for a line from a starting
990 * column to an ending column.
991 *
992 */
993static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
994{
995 INT line_index = EDIT_EM_LineIndex(hwnd, es, line);
996
997 if (es->style & ES_MULTILINE)
998 rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
999 else
1000 rc->top = es->format_rect.top;
1001 rc->bottom = rc->top + es->line_height;
1002 rc->left = (scol == 0) ? es->format_rect.left : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + scol, TRUE));
1003 rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + ecol, TRUE));
1004}
1005
1006
1007/*********************************************************************
1008 *
1009 * EDIT_GetPasswordPointer_SL
1010 *
1011 * note: caller should free the (optionally) allocated buffer
1012 *
1013 */
1014static LPSTR EDIT_GetPasswordPointer_SL(HWND hwnd, EDITSTATE *es)
1015{
1016 if (es->style & ES_PASSWORD) {
1017 INT len = lstrlenA(es->text);
1018 LPSTR text = (LPSTR)HeapAlloc(es->heap, 0, len + 1);
1019 RtlFillMemory(text, len, es->password_char);
1020 text[len] = '\0';
1021 return text;
1022 } else
1023 return es->text;
1024}
1025
1026
1027/*********************************************************************
1028 *
1029 * EDIT_LockBuffer
1030 *
1031 * This acts as a LOCAL_Lock(), but it locks only once. This way
1032 * you can call it whenever you like, without unlocking.
1033 *
1034 */
1035static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es)
1036{
1037 if (!es) {
1038 //ERR_(edit)("no EDITSTATE ... please report\n");
1039 return;
1040 }
1041 if (!(es->style & ES_MULTILINE))
1042 return;
1043 if (!es->text) {
1044 if (es->hloc)
1045 es->text = (char*)LocalLock(es->hloc);
1046 else {
1047 //ERR_(edit)("no buffer ... please report\n");
1048 return;
1049 }
1050 }
1051 es->lock_count++;
1052}
1053
1054
1055/*********************************************************************
1056 *
1057 * EDIT_SL_InvalidateText
1058 *
1059 * Called from EDIT_InvalidateText().
1060 * Does the job for single-line controls only.
1061 *
1062 */
1063static void EDIT_SL_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
1064{
1065 RECT line_rect;
1066 RECT rc;
1067
1068 EDIT_GetLineRect(hwnd, es, 0, start, end, &line_rect);
1069 if (IntersectRect(&rc, &line_rect, &es->format_rect))
1070 InvalidateRect(hwnd, &rc, FALSE);
1071}
1072
1073
1074/*********************************************************************
1075 *
1076 * EDIT_ML_InvalidateText
1077 *
1078 * Called from EDIT_InvalidateText().
1079 * Does the job for multi-line controls only.
1080 *
1081 */
1082static void EDIT_ML_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
1083{
1084 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
1085 INT sl = EDIT_EM_LineFromChar(hwnd, es, start);
1086 INT el = EDIT_EM_LineFromChar(hwnd, es, end);
1087 INT sc;
1088 INT ec;
1089 RECT rc1;
1090 RECT rcWnd;
1091 RECT rcLine;
1092 RECT rcUpdate;
1093 INT l;
1094
1095 if ((el < es->y_offset) || (sl > es->y_offset + vlc))
1096 return;
1097
1098 sc = start - EDIT_EM_LineIndex(hwnd, es, sl);
1099 ec = end - EDIT_EM_LineIndex(hwnd, es, el);
1100 if (sl < es->y_offset) {
1101 sl = es->y_offset;
1102 sc = 0;
1103 }
1104 if (el > es->y_offset + vlc) {
1105 el = es->y_offset + vlc;
1106 ec = EDIT_EM_LineLength(hwnd, es, EDIT_EM_LineIndex(hwnd, es, el));
1107 }
1108 GetClientRect(hwnd, &rc1);
1109 IntersectRect(&rcWnd, &rc1, &es->format_rect);
1110 if (sl == el) {
1111 EDIT_GetLineRect(hwnd, es, sl, sc, ec, &rcLine);
1112 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1113 InvalidateRect(hwnd, &rcUpdate, FALSE);
1114 } else {
1115 EDIT_GetLineRect(hwnd, es, sl, sc,
1116 EDIT_EM_LineLength(hwnd, es,
1117 EDIT_EM_LineIndex(hwnd, es, sl)),
1118 &rcLine);
1119 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1120 InvalidateRect(hwnd, &rcUpdate, FALSE);
1121 for (l = sl + 1 ; l < el ; l++) {
1122 EDIT_GetLineRect(hwnd, es, l, 0,
1123 EDIT_EM_LineLength(hwnd, es,
1124 EDIT_EM_LineIndex(hwnd, es, l)),
1125 &rcLine);
1126 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1127 InvalidateRect(hwnd, &rcUpdate, FALSE);
1128 }
1129 EDIT_GetLineRect(hwnd, es, el, 0, ec, &rcLine);
1130 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
1131 InvalidateRect(hwnd, &rcUpdate, FALSE);
1132 }
1133}
1134
1135
1136/*********************************************************************
1137 *
1138 * EDIT_InvalidateText
1139 *
1140 * Invalidate the text from offset start upto, but not including,
1141 * offset end. Useful for (re)painting the selection.
1142 * Regions outside the linewidth are not invalidated.
1143 * end == -1 means end == TextLength.
1144 * start and end need not be ordered.
1145 *
1146 */
1147static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
1148{
1149 if (end == start)
1150 return;
1151
1152 if (end == -1)
1153 end = lstrlenA(es->text);
1154
1155 ORDER_INT(start, end);
1156
1157 if (es->style & ES_MULTILINE)
1158 EDIT_ML_InvalidateText(hwnd, es, start, end);
1159 else
1160 EDIT_SL_InvalidateText(hwnd, es, start, end);
1161}
1162
1163
1164/*********************************************************************
1165 *
1166 * EDIT_MakeFit
1167 *
1168 * Try to fit size + 1 bytes in the buffer. Constrain to limits.
1169 *
1170 */
1171static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, INT size)
1172{
1173 HLOCAL hNew32;
1174 HLOCAL16 hNew16;
1175
1176 if (size <= es->buffer_size)
1177 return TRUE;
1178 if (size > es->buffer_limit) {
1179 EDIT_NOTIFY_PARENT(hwnd, EN_MAXTEXT, "EN_MAXTEXT");
1180 return FALSE;
1181 }
1182 size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
1183 if (size > es->buffer_limit)
1184 size = es->buffer_limit;
1185
1186 //TRACE_(edit)("trying to ReAlloc to %d+1\n", size);
1187
1188 EDIT_UnlockBuffer(hwnd, es, TRUE);
1189 if (es->text) {
1190 es->text = (char*)HeapReAlloc(es->heap, 0, es->text, size + 1);
1191 if (es->text)
1192 es->buffer_size = MIN(HeapSize(es->heap, 0, es->text) - 1, es->buffer_limit);
1193 else
1194 es->buffer_size = 0;
1195 } else if (es->hloc) {
1196 hNew32 = LocalReAlloc(es->hloc, size + 1, 0);
1197 if (hNew32) {
1198 //TRACE_(edit)("Old 32 bit handle %08x, new handle %08x\n", es->hloc32, hNew32);
1199 es->hloc = hNew32;
1200 es->buffer_size = MIN(LocalSize(es->hloc) - 1, es->buffer_limit);
1201 }
1202 }
1203 if (es->buffer_size < size) {
1204 EDIT_LockBuffer(hwnd, es);
1205 //WARN_(edit)("FAILED ! We now have %d+1\n", es->buffer_size);
1206 EDIT_NOTIFY_PARENT(hwnd, EN_ERRSPACE, "EN_ERRSPACE");
1207 return FALSE;
1208 } else {
1209 EDIT_LockBuffer(hwnd, es);
1210 //TRACE_(edit)("We now have %d+1\n", es->buffer_size);
1211 return TRUE;
1212 }
1213}
1214
1215
1216/*********************************************************************
1217 *
1218 * EDIT_MakeUndoFit
1219 *
1220 * Try to fit size + 1 bytes in the undo buffer.
1221 *
1222 */
1223static BOOL EDIT_MakeUndoFit(HWND hwnd, EDITSTATE *es, INT size)
1224{
1225 if (size <= es->undo_buffer_size)
1226 return TRUE;
1227 size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
1228
1229 //TRACE_(edit)("trying to ReAlloc to %d+1\n", size);
1230 es->undo_text = (char*)HeapReAlloc(es->heap, 0, es->undo_text, size + 1);
1231 if (es->undo_text) {
1232 es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1;
1233 if (es->undo_buffer_size < size) {
1234 //WARN_(edit)("FAILED ! We now have %d+1\n", es->undo_buffer_size);
1235 return FALSE;
1236 }
1237 return TRUE;
1238 }
1239 return FALSE;
1240}
1241
1242
1243/*********************************************************************
1244 *
1245 * EDIT_MoveBackward
1246 *
1247 */
1248static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
1249{
1250 INT e = es->selection_end;
1251
1252 if (e) {
1253 e--;
1254 if ((es->style & ES_MULTILINE) && e &&
1255 (es->text[e - 1] == '\r') && (es->text[e] == '\n')) {
1256 e--;
1257 if (e && (es->text[e - 1] == '\r'))
1258 e--;
1259 }
1260 }
1261 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
1262 EDIT_EM_ScrollCaret(hwnd, es);
1263}
1264
1265
1266/*********************************************************************
1267 *
1268 * EDIT_MoveDown_ML
1269 *
1270 * Only for multi line controls
1271 * Move the caret one line down, on a column with the nearest
1272 * x coordinate on the screen (might be a different column).
1273 *
1274 */
1275static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
1276{
1277 INT s = es->selection_start;
1278 INT e = es->selection_end;
1279 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
1280 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
1281 INT x = SLOWORD(pos);
1282 INT y = SHIWORD(pos);
1283
1284 e = EDIT_CharFromPos(hwnd, es, x, y + es->line_height, &after_wrap);
1285 if (!extend)
1286 s = e;
1287 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
1288 EDIT_EM_ScrollCaret(hwnd, es);
1289}
1290
1291
1292/*********************************************************************
1293 *
1294 * EDIT_MoveEnd
1295 *
1296 */
1297static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend)
1298{
1299 BOOL after_wrap = FALSE;
1300 INT e;
1301
1302 /* Pass a high value in x to make sure of receiving the en of the line */
1303 if (es->style & ES_MULTILINE)
1304 e = EDIT_CharFromPos(hwnd, es, 0x3fffffff,
1305 HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
1306 else
1307 e = lstrlenA(es->text);
1308 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, after_wrap);
1309 EDIT_EM_ScrollCaret(hwnd, es);
1310}
1311
1312
1313/*********************************************************************
1314 *
1315 * EDIT_MoveForward
1316 *
1317 */
1318static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend)
1319{
1320 INT e = es->selection_end;
1321
1322 if (es->text[e]) {
1323 e++;
1324 if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) {
1325 if (es->text[e] == '\n')
1326 e++;
1327 else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n'))
1328 e += 2;
1329 }
1330 }
1331 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
1332 EDIT_EM_ScrollCaret(hwnd, es);
1333}
1334
1335
1336/*********************************************************************
1337 *
1338 * EDIT_MoveHome
1339 *
1340 * Home key: move to beginning of line.
1341 *
1342 */
1343static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend)
1344{
1345 INT e;
1346
1347 /* Pass the x_offset in x to make sure of receiving the first position of the line */
1348 if (es->style & ES_MULTILINE)
1349 e = EDIT_CharFromPos(hwnd, es, -es->x_offset,
1350 HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
1351 else
1352 e = 0;
1353 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
1354 EDIT_EM_ScrollCaret(hwnd, es);
1355}
1356
1357
1358/*********************************************************************
1359 *
1360 * EDIT_MovePageDown_ML
1361 *
1362 * Only for multi line controls
1363 * Move the caret one page down, on a column with the nearest
1364 * x coordinate on the screen (might be a different column).
1365 *
1366 */
1367static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
1368{
1369 INT s = es->selection_start;
1370 INT e = es->selection_end;
1371 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
1372 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
1373 INT x = SLOWORD(pos);
1374 INT y = SHIWORD(pos);
1375
1376 e = EDIT_CharFromPos(hwnd, es, x,
1377 y + (es->format_rect.bottom - es->format_rect.top),
1378 &after_wrap);
1379 if (!extend)
1380 s = e;
1381 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
1382 EDIT_EM_ScrollCaret(hwnd, es);
1383}
1384
1385
1386/*********************************************************************
1387 *
1388 * EDIT_MovePageUp_ML
1389 *
1390 * Only for multi line controls
1391 * Move the caret one page up, on a column with the nearest
1392 * x coordinate on the screen (might be a different column).
1393 *
1394 */
1395static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
1396{
1397 INT s = es->selection_start;
1398 INT e = es->selection_end;
1399 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
1400 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
1401 INT x = SLOWORD(pos);
1402 INT y = SHIWORD(pos);
1403
1404 e = EDIT_CharFromPos(hwnd, es, x,
1405 y - (es->format_rect.bottom - es->format_rect.top),
1406 &after_wrap);
1407 if (!extend)
1408 s = e;
1409 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
1410 EDIT_EM_ScrollCaret(hwnd, es);
1411}
1412
1413
1414/*********************************************************************
1415 *
1416 * EDIT_MoveUp_ML
1417 *
1418 * Only for multi line controls
1419 * Move the caret one line up, on a column with the nearest
1420 * x coordinate on the screen (might be a different column).
1421 *
1422 */
1423static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
1424{
1425 INT s = es->selection_start;
1426 INT e = es->selection_end;
1427 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
1428 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
1429 INT x = SLOWORD(pos);
1430 INT y = SHIWORD(pos);
1431
1432 e = EDIT_CharFromPos(hwnd, es, x, y - es->line_height, &after_wrap);
1433 if (!extend)
1434 s = e;
1435 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
1436 EDIT_EM_ScrollCaret(hwnd, es);
1437}
1438
1439
1440/*********************************************************************
1441 *
1442 * EDIT_MoveWordBackward
1443 *
1444 */
1445static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
1446{
1447 INT s = es->selection_start;
1448 INT e = es->selection_end;
1449 INT l;
1450 INT ll;
1451 INT li;
1452
1453 l = EDIT_EM_LineFromChar(hwnd, es, e);
1454 ll = EDIT_EM_LineLength(hwnd, es, e);
1455 li = EDIT_EM_LineIndex(hwnd, es, l);
1456 if (e - li == 0) {
1457 if (l) {
1458 li = EDIT_EM_LineIndex(hwnd, es, l - 1);
1459 e = li + EDIT_EM_LineLength(hwnd, es, li);
1460 }
1461 } else {
1462 e = li + (INT)EDIT_CallWordBreakProc(hwnd, es,
1463 li, e - li, ll, WB_LEFT);
1464 }
1465 if (!extend)
1466 s = e;
1467 EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
1468 EDIT_EM_ScrollCaret(hwnd, es);
1469}
1470
1471
1472/*********************************************************************
1473 *
1474 * EDIT_MoveWordForward
1475 *
1476 */
1477static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend)
1478{
1479 INT s = es->selection_start;
1480 INT e = es->selection_end;
1481 INT l;
1482 INT ll;
1483 INT li;
1484
1485 l = EDIT_EM_LineFromChar(hwnd, es, e);
1486 ll = EDIT_EM_LineLength(hwnd, es, e);
1487 li = EDIT_EM_LineIndex(hwnd, es, l);
1488 if (e - li == ll) {
1489 if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
1490 e = EDIT_EM_LineIndex(hwnd, es, l + 1);
1491 } else {
1492 e = li + EDIT_CallWordBreakProc(hwnd, es,
1493 li, e - li + 1, ll, WB_RIGHT);
1494 }
1495 if (!extend)
1496 s = e;
1497 EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
1498 EDIT_EM_ScrollCaret(hwnd, es);
1499}
1500
1501
1502/*********************************************************************
1503 *
1504 * EDIT_PaintLine
1505 *
1506 */
1507static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC dc, INT line, BOOL rev)
1508{
1509 INT s = es->selection_start;
1510 INT e = es->selection_end;
1511 INT li;
1512 INT ll;
1513 INT x;
1514 INT y;
1515 LRESULT pos;
1516
1517 if (es->style & ES_MULTILINE) {
1518 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
1519 if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
1520 return;
1521 } else if (line)
1522 return;
1523
1524 //TRACE_(edit)("line=%d\n", line);
1525
1526 pos = EDIT_EM_PosFromChar(hwnd, es, EDIT_EM_LineIndex(hwnd, es, line), FALSE);
1527 x = SLOWORD(pos);
1528 y = SHIWORD(pos);
1529 li = EDIT_EM_LineIndex(hwnd, es, line);
1530 ll = EDIT_EM_LineLength(hwnd, es, li);
1531 s = es->selection_start;
1532 e = es->selection_end;
1533 ORDER_INT(s, e);
1534 s = MIN(li + ll, MAX(li, s));
1535 e = MIN(li + ll, MAX(li, e));
1536 if (rev && (s != e) &&
1537 ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
1538 x += EDIT_PaintText(hwnd, es, dc, x, y, line, 0, s - li, FALSE);
1539 x += EDIT_PaintText(hwnd, es, dc, x, y, line, s - li, e - s, TRUE);
1540 x += EDIT_PaintText(hwnd, es, dc, x, y, line, e - li, li + ll - e, FALSE);
1541 } else
1542 x += EDIT_PaintText(hwnd, es, dc, x, y, line, 0, ll, FALSE);
1543}
1544
1545
1546/*********************************************************************
1547 *
1548 * EDIT_PaintText
1549 *
1550 */
1551static INT EDIT_PaintText(HWND hwnd, EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev)
1552{
1553 COLORREF BkColor;
1554 COLORREF TextColor;
1555 INT ret;
1556 INT li;
1557 SIZE size;
1558
1559 if (!count)
1560 return 0;
1561 BkColor = GetBkColor(dc);
1562 TextColor = GetTextColor(dc);
1563 if (rev) {
1564 SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
1565 SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1566 }
1567 li = EDIT_EM_LineIndex(hwnd, es, line);
1568 if (es->style & ES_MULTILINE) {
1569 ret = (INT)LOWORD(TabbedTextOutA(dc, x, y, es->text + li + col, count,
1570 es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
1571 } else {
1572 LPSTR text = EDIT_GetPasswordPointer_SL(hwnd, es);
1573 TextOutA(dc, x, y, text + li + col, count);
1574 GetTextExtentPoint32A(dc, text + li + col, count, &size);
1575 ret = size.cx;
1576 if (es->style & ES_PASSWORD)
1577 HeapFree(es->heap, 0, text);
1578 }
1579 if (rev) {
1580 SetBkColor(dc, BkColor);
1581 SetTextColor(dc, TextColor);
1582 }
1583 return ret;
1584}
1585
1586
1587/*********************************************************************
1588 *
1589 * EDIT_SetCaretPos
1590 *
1591 */
1592static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos,
1593 BOOL after_wrap)
1594{
1595 LRESULT res = EDIT_EM_PosFromChar(hwnd, es, pos, after_wrap);
1596 INT x = SLOWORD(res);
1597 INT y = SHIWORD(res);
1598
1599 if(x < es->format_rect.left)
1600 x = es->format_rect.left;
1601 if(x > es->format_rect.right - 2)
1602 x = es->format_rect.right - 2;
1603 if(y > es->format_rect.bottom)
1604 y = es->format_rect.bottom;
1605 if(y < es->format_rect.top)
1606 y = es->format_rect.top;
1607 SetCaretPos(x, y);
1608 return;
1609}
1610
1611
1612/*********************************************************************
1613 *
1614 * EDIT_SetRectNP
1615 *
1616 * note: this is not (exactly) the handler called on EM_SETRECTNP
1617 * it is also used to set the rect of a single line control
1618 *
1619 */
1620static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT rc)
1621{
1622 CopyRect(&es->format_rect, rc);
1623 if (es->style & WS_BORDER) {
1624 INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
1625 es->format_rect.left += bw;
1626 es->format_rect.top += bw;
1627 es->format_rect.right -= bw;
1628 es->format_rect.bottom -= bw;
1629 }
1630 es->format_rect.left += es->left_margin;
1631 es->format_rect.right -= es->right_margin;
1632 es->format_rect.right = MAX(es->format_rect.right, es->format_rect.left + es->char_width);
1633 if (es->style & ES_MULTILINE)
1634 es->format_rect.bottom = es->format_rect.top +
1635 MAX(1, (es->format_rect.bottom - es->format_rect.top) / es->line_height) * es->line_height;
1636 else
1637 es->format_rect.bottom = es->format_rect.top + es->line_height;
1638 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
1639 EDIT_BuildLineDefs_ML(hwnd, es);
1640}
1641
1642
1643/*********************************************************************
1644 *
1645 * EDIT_UnlockBuffer
1646 *
1647 */
1648static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force)
1649{
1650 if (!es) {
1651 //ERR_(edit)("no EDITSTATE ... please report\n");
1652 return;
1653 }
1654 if (!(es->style & ES_MULTILINE))
1655 return;
1656 if (!es->lock_count) {
1657 //ERR_(edit)("lock_count == 0 ... please report\n");
1658 return;
1659 }
1660 if (!es->text) {
1661 //ERR_(edit)("es->text == 0 ... please report\n");
1662 return;
1663 }
1664 if (force || (es->lock_count == 1)) {
1665 if (es->hloc) {
1666 LocalUnlock(es->hloc);
1667 es->text = NULL;
1668 }
1669 }
1670 es->lock_count--;
1671}
1672
1673
1674/*********************************************************************
1675 *
1676 * EDIT_WordBreakProc
1677 *
1678 * Find the beginning of words.
1679 * Note: unlike the specs for a WordBreakProc, this function only
1680 * allows to be called without linebreaks between s[0] upto
1681 * s[count - 1]. Remember it is only called
1682 * internally, so we can decide this for ourselves.
1683 *
1684 */
1685static INT EDIT_WordBreakProc(LPSTR s, INT index, INT count, INT action)
1686{
1687 INT ret = 0;
1688
1689 //TRACE_(edit)("s=%p, index=%u, count=%u, action=%d\n",
1690 // s, index, count, action);
1691
1692 switch (action) {
1693 case WB_LEFT:
1694 if (!count)
1695 break;
1696 if (index)
1697 index--;
1698 if (s[index] == ' ') {
1699 while (index && (s[index] == ' '))
1700 index--;
1701 if (index) {
1702 while (index && (s[index] != ' '))
1703 index--;
1704 if (s[index] == ' ')
1705 index++;
1706 }
1707 } else {
1708 while (index && (s[index] != ' '))
1709 index--;
1710 if (s[index] == ' ')
1711 index++;
1712 }
1713 ret = index;
1714 break;
1715 case WB_RIGHT:
1716 if (!count)
1717 break;
1718 if (index)
1719 index--;
1720 if (s[index] == ' ')
1721 while ((index < count) && (s[index] == ' ')) index++;
1722 else {
1723 while (s[index] && (s[index] != ' ') && (index < count))
1724 index++;
1725 while ((s[index] == ' ') && (index < count)) index++;
1726 }
1727 ret = index;
1728 break;
1729 case WB_ISDELIMITER:
1730 ret = (s[index] == ' ');
1731 break;
1732 default:
1733 //ERR_(edit)("unknown action code, please report !\n");
1734 break;
1735 }
1736 return ret;
1737}
1738
1739
1740/*********************************************************************
1741 *
1742 * EM_CHARFROMPOS
1743 *
1744 * returns line number (not index) in high-order word of result.
1745 * NB : Q137805 is unclear about this. POINT * pointer in lParam apply
1746 * to Richedit, not to the edit control. Original documentation is valid.
1747 * FIXME: do the specs mean to return -1 if outside client area or
1748 * if outside formatting rectangle ???
1749 *
1750 */
1751static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y)
1752{
1753 POINT pt;
1754 RECT rc;
1755 INT index;
1756
1757 pt.x = x;
1758 pt.y = y;
1759 GetClientRect(hwnd, &rc);
1760 if (!PtInRect(&rc, pt))
1761 return -1;
1762
1763 index = EDIT_CharFromPos(hwnd, es, x, y, NULL);
1764 return MAKELONG(index, EDIT_EM_LineFromChar(hwnd, es, index));
1765}
1766
1767
1768/*********************************************************************
1769 *
1770 * EM_FMTLINES
1771 *
1772 * Enable or disable soft breaks.
1773 */
1774static BOOL EDIT_EM_FmtLines(HWND hwnd, EDITSTATE *es, BOOL add_eol)
1775{
1776 es->flags &= ~EF_USE_SOFTBRK;
1777 if (add_eol) {
1778 es->flags |= EF_USE_SOFTBRK;
1779 //FIXME_(edit)("soft break enabled, not implemented\n");
1780 }
1781 return add_eol;
1782}
1783
1784
1785/*********************************************************************
1786 *
1787 * EM_GETHANDLE
1788 *
1789 * Hopefully this won't fire back at us.
1790 * We always start with a fixed buffer in our own heap.
1791 * However, with this message a 32 bit application requests
1792 * a handle to 32 bit moveable local heap memory, where it expects
1793 * to find the text.
1794 * It's a pity that from this moment on we have to use this
1795 * local heap, because applications may rely on the handle
1796 * in the future.
1797 *
1798 * In this function we'll try to switch to local heap.
1799 *
1800 */
1801static HLOCAL EDIT_EM_GetHandle(HWND hwnd, EDITSTATE *es)
1802{
1803 HLOCAL newBuf;
1804 LPSTR newText;
1805 INT newSize;
1806
1807 if (!(es->style & ES_MULTILINE))
1808 return 0;
1809
1810 if (es->hloc)
1811 return es->hloc;
1812
1813 if (!(newBuf = LocalAlloc(LMEM_MOVEABLE, lstrlenA(es->text) + 1))) {
1814 //ERR_(edit)("could not allocate new 32 bit buffer\n");
1815 return 0;
1816 }
1817 newSize = MIN(LocalSize(newBuf) - 1, es->buffer_limit);
1818 if (!(newText = (char*)LocalLock(newBuf))) {
1819 //ERR_(edit)("could not lock new 32 bit buffer\n");
1820 LocalFree(newBuf);
1821 return 0;
1822 }
1823 lstrcpyA(newText, es->text);
1824 EDIT_UnlockBuffer(hwnd, es, TRUE);
1825 if (es->text)
1826 HeapFree(es->heap, 0, es->text);
1827 es->hloc = newBuf;
1828 es->buffer_size = newSize;
1829 es->text = newText;
1830 EDIT_LockBuffer(hwnd, es);
1831 //TRACE_(edit)("switched to 32 bit local heap\n");
1832
1833 return es->hloc;
1834}
1835
1836/*********************************************************************
1837 *
1838 * EM_GETLINE
1839 *
1840 */
1841static INT EDIT_EM_GetLine(HWND hwnd, EDITSTATE *es, INT line, LPSTR lpch)
1842{
1843 LPSTR src;
1844 INT len;
1845 INT i;
1846
1847 if (es->style & ES_MULTILINE) {
1848 if (line >= es->line_count)
1849 return 0;
1850 } else
1851 line = 0;
1852 i = EDIT_EM_LineIndex(hwnd, es, line);
1853 src = es->text + i;
1854 //SvL: Shouldn't this be *lpch-1? For terminating 0
1855 //len = MIN(*(WORD *)lpch-1, EDIT_EM_LineLength(hwnd, es, i));
1856 len = MIN(*(WORD *)lpch, EDIT_EM_LineLength(hwnd, es, i));
1857 for (i = 0 ; i < len ; i++) {
1858 *lpch = *src;
1859 src++;
1860 lpch++;
1861 }
1862 //SvL: Terminate string
1863 //*lpch = 0;
1864 return (LRESULT)len;
1865}
1866
1867
1868/*********************************************************************
1869 *
1870 * EM_GETSEL
1871 *
1872 */
1873static LRESULT EDIT_EM_GetSel(HWND hwnd, EDITSTATE *es, LPUINT start, LPUINT end)
1874{
1875 UINT s = es->selection_start;
1876 UINT e = es->selection_end;
1877
1878 ORDER_UINT(s, e);
1879 if (start)
1880 *start = s;
1881 if (end)
1882 *end = e;
1883 return MAKELONG(s, e);
1884}
1885
1886
1887/*********************************************************************
1888 *
1889 * EM_GETTHUMB
1890 *
1891 * FIXME: is this right ? (or should it be only VSCROLL)
1892 * (and maybe only for edit controls that really have their
1893 * own scrollbars) (and maybe only for multiline controls ?)
1894 * All in all: very poorly documented
1895 *
1896 * FIXME: now it's also broken, because of the new WM_HSCROLL /
1897 * WM_VSCROLL handlers
1898 *
1899 */
1900static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es)
1901{
1902 return MAKELONG(EDIT_WM_VScroll(hwnd, es, EM_GETTHUMB, 0, 0),
1903 EDIT_WM_HScroll(hwnd, es, EM_GETTHUMB, 0, 0));
1904}
1905
1906
1907/*********************************************************************
1908 *
1909 * EM_LINEFROMCHAR
1910 *
1911 */
1912static INT EDIT_EM_LineFromChar(HWND hwnd, EDITSTATE *es, INT index)
1913{
1914 INT line;
1915 LINEDEF *line_def;
1916
1917 if (!(es->style & ES_MULTILINE))
1918 return 0;
1919 if (index > lstrlenA(es->text))
1920 return es->line_count - 1;
1921 if (index == -1)
1922 index = MIN(es->selection_start, es->selection_end);
1923
1924 line = 0;
1925 line_def = es->first_line_def;
1926 index -= line_def->length;
1927 while ((index >= 0) && line_def->next) {
1928 line++;
1929 line_def = line_def->next;
1930 index -= line_def->length;
1931 }
1932 return line;
1933}
1934
1935
1936/*********************************************************************
1937 *
1938 * EM_LINEINDEX
1939 *
1940 */
1941static INT EDIT_EM_LineIndex(HWND hwnd, EDITSTATE *es, INT line)
1942{
1943 INT line_index;
1944 LINEDEF *line_def;
1945
1946 if (!(es->style & ES_MULTILINE))
1947 return 0;
1948 if (line >= es->line_count)
1949 return -1;
1950
1951 line_index = 0;
1952 line_def = es->first_line_def;
1953 if (line == -1) {
1954 INT index = es->selection_end - line_def->length;
1955 while ((index >= 0) && line_def->next) {
1956 line_index += line_def->length;
1957 line_def = line_def->next;
1958 index -= line_def->length;
1959 }
1960 } else {
1961 while (line > 0) {
1962 line_index += line_def->length;
1963 line_def = line_def->next;
1964 line--;
1965 }
1966 }
1967 return line_index;
1968}
1969
1970
1971/*********************************************************************
1972 *
1973 * EM_LINELENGTH
1974 *
1975 */
1976static INT EDIT_EM_LineLength(HWND hwnd, EDITSTATE *es, INT index)
1977{
1978 LINEDEF *line_def;
1979
1980 if (!(es->style & ES_MULTILINE))
1981 return lstrlenA(es->text);
1982
1983 if (index == -1) {
1984 /* FIXME: broken
1985 INT32 sl = EDIT_EM_LineFromChar(wnd, es, es->selection_start);
1986 INT32 el = EDIT_EM_LineFromChar(wnd, es, es->selection_end);
1987 return es->selection_start - es->line_defs[sl].offset +
1988 es->line_defs[el].offset +
1989 es->line_defs[el].length - es->selection_end;
1990 */
1991 return 0;
1992 }
1993 line_def = es->first_line_def;
1994 index -= line_def->length;
1995 while ((index >= 0) && line_def->next) {
1996 line_def = line_def->next;
1997 index -= line_def->length;
1998 }
1999 return line_def->net_length;
2000}
2001
2002
2003/*********************************************************************
2004 *
2005 * EM_LINESCROLL
2006 *
2007 * FIXME: dx is in average character widths
2008 * However, we assume it is in pixels when we use this
2009 * function internally
2010 *
2011 */
2012static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy)
2013{
2014 INT nyoff;
2015
2016 if (!(es->style & ES_MULTILINE))
2017 return FALSE;
2018
2019 if (-dx > es->x_offset)
2020 dx = -es->x_offset;
2021 if (dx > es->text_width - es->x_offset)
2022 dx = es->text_width - es->x_offset;
2023 nyoff = MAX(0, es->y_offset + dy);
2024 if (nyoff >= es->line_count)
2025 nyoff = es->line_count - 1;
2026 dy = (es->y_offset - nyoff) * es->line_height;
2027 if (dx || dy) {
2028 RECT rc1;
2029 RECT rc;
2030 GetClientRect(hwnd, &rc1);
2031 IntersectRect(&rc, &rc1, &es->format_rect);
2032 ScrollWindowEx(hwnd, -dx, dy,
2033 NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE);
2034 es->y_offset = nyoff;
2035 es->x_offset += dx;
2036 }
2037 if (dx && !(es->flags & EF_HSCROLL_TRACK))
2038 EDIT_NOTIFY_PARENT(hwnd, EN_HSCROLL, "EN_HSCROLL");
2039 if (dy && !(es->flags & EF_VSCROLL_TRACK))
2040 EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL, "EN_VSCROLL");
2041 return TRUE;
2042}
2043
2044
2045/*********************************************************************
2046 *
2047 * EM_POSFROMCHAR
2048 *
2049 */
2050static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap)
2051{
2052 INT len = lstrlenA(es->text);
2053 INT l;
2054 INT li;
2055 INT x;
2056 INT y = 0;
2057 HDC dc;
2058 HFONT old_font = 0;
2059 SIZE size;
2060
2061 index = MIN(index, len);
2062 dc = GetDC(hwnd);
2063 if (es->font)
2064 old_font = SelectObject(dc, es->font);
2065 if (es->style & ES_MULTILINE) {
2066 l = EDIT_EM_LineFromChar(hwnd, es, index);
2067 y = (l - es->y_offset) * es->line_height;
2068 li = EDIT_EM_LineIndex(hwnd, es, l);
2069 if (after_wrap && (li == index) && l) {
2070 INT l2 = l - 1;
2071 LINEDEF *line_def = es->first_line_def;
2072 while (l2) {
2073 line_def = line_def->next;
2074 l2--;
2075 }
2076 if (line_def->ending == END_WRAP) {
2077 l--;
2078 y -= es->line_height;
2079 li = EDIT_EM_LineIndex(hwnd, es, l);
2080 }
2081 }
2082 x = LOWORD(GetTabbedTextExtentA(dc, es->text + li, index - li,
2083 es->tabs_count, es->tabs)) - es->x_offset;
2084 } else {
2085 LPSTR text = EDIT_GetPasswordPointer_SL(hwnd, es);
2086 if (index < es->x_offset) {
2087 GetTextExtentPoint32A(dc, text + index,
2088 es->x_offset - index, &size);
2089 x = -size.cx;
2090 } else {
2091 GetTextExtentPoint32A(dc, text + es->x_offset,
2092 index - es->x_offset, &size);
2093 x = size.cx;
2094 }
2095 y = 0;
2096 if (es->style & ES_PASSWORD)
2097 HeapFree(es->heap, 0 ,text);
2098 }
2099 x += es->format_rect.left;
2100 y += es->format_rect.top;
2101 if (es->font)
2102 SelectObject(dc, old_font);
2103 ReleaseDC(hwnd, dc);
2104 return MAKELONG((INT16)x, (INT16)y);
2105}
2106
2107
2108/*********************************************************************
2109 *
2110 * EM_REPLACESEL
2111 *
2112 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here
2113 *
2114 */
2115static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCSTR lpsz_replace)
2116{
2117 INT strl = lstrlenA(lpsz_replace);
2118 INT tl = lstrlenA(es->text);
2119 INT utl;
2120 UINT s;
2121 UINT e;
2122 INT i;
2123 LPSTR p;
2124
2125 s = es->selection_start;
2126 e = es->selection_end;
2127
2128 if ((s == e) && !strl)
2129 return;
2130
2131 ORDER_UINT(s, e);
2132
2133 if (!EDIT_MakeFit(hwnd, es, tl - (e - s) + strl))
2134 return;
2135
2136 if (e != s) {
2137 /* there is something to be deleted */
2138 if (can_undo) {
2139 utl = lstrlenA(es->undo_text);
2140 if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
2141 /* undo-buffer is extended to the right */
2142 EDIT_MakeUndoFit(hwnd, es, utl + e - s);
2143 lstrcpynA(es->undo_text + utl, es->text + s, e - s + 1);
2144 } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
2145 /* undo-buffer is extended to the left */
2146 EDIT_MakeUndoFit(hwnd, es, utl + e - s);
2147 for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
2148 p[e - s] = p[0];
2149 for (i = 0 , p = es->undo_text ; i < e - s ; i++)
2150 p[i] = (es->text + s)[i];
2151 es->undo_position = s;
2152 } else {
2153 /* new undo-buffer */
2154 EDIT_MakeUndoFit(hwnd, es, e - s);
2155 lstrcpynA(es->undo_text, es->text + s, e - s + 1);
2156 es->undo_position = s;
2157 }
2158 /* any deletion makes the old insertion-undo invalid */
2159 es->undo_insert_count = 0;
2160 } else
2161 EDIT_EM_EmptyUndoBuffer(hwnd, es);
2162
2163 /* now delete */
2164 lstrcpyA(es->text + s, es->text + e);
2165 }
2166 if (strl) {
2167 /* there is an insertion */
2168 if (can_undo) {
2169 if ((s == es->undo_position) ||
2170 ((es->undo_insert_count) &&
2171 (s == es->undo_position + es->undo_insert_count)))
2172 /*
2173 * insertion is new and at delete position or
2174 * an extension to either left or right
2175 */
2176 es->undo_insert_count += strl;
2177 else {
2178 /* new insertion undo */
2179 es->undo_position = s;
2180 es->undo_insert_count = strl;
2181 /* new insertion makes old delete-buffer invalid */
2182 *es->undo_text = '\0';
2183 }
2184 } else
2185 EDIT_EM_EmptyUndoBuffer(hwnd, es);
2186
2187 /* now insert */
2188 tl = lstrlenA(es->text);
2189 for (p = es->text + tl ; p >= es->text + s ; p--)
2190 p[strl] = p[0];
2191 for (i = 0 , p = es->text + s ; i < strl ; i++)
2192 p[i] = lpsz_replace[i];
2193 if(es->style & ES_UPPERCASE)
2194 CharUpperBuffA(p, strl);
2195 else if(es->style & ES_LOWERCASE)
2196 CharLowerBuffA(p, strl);
2197 s += strl;
2198 }
2199 /* FIXME: really inefficient */
2200 if (es->style & ES_MULTILINE)
2201 EDIT_BuildLineDefs_ML(hwnd, es);
2202
2203 EDIT_EM_SetSel(hwnd, es, s, s, FALSE);
2204 es->flags |= EF_MODIFIED;
2205 es->flags |= EF_UPDATE;
2206 EDIT_EM_ScrollCaret(hwnd, es);
2207
2208 /* FIXME: really inefficient */
2209 InvalidateRect(hwnd, NULL, TRUE);
2210}
2211
2212
2213/*********************************************************************
2214 *
2215 * EM_SCROLL
2216 *
2217 */
2218static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action)
2219{
2220 INT dy;
2221
2222 if (!(es->style & ES_MULTILINE))
2223 return (LRESULT)FALSE;
2224
2225 dy = 0;
2226
2227 switch (action) {
2228 case SB_LINEUP:
2229 if (es->y_offset)
2230 dy = -1;
2231 break;
2232 case SB_LINEDOWN:
2233 if (es->y_offset < es->line_count - 1)
2234 dy = 1;
2235 break;
2236 case SB_PAGEUP:
2237 if (es->y_offset)
2238 dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
2239 break;
2240 case SB_PAGEDOWN:
2241 if (es->y_offset < es->line_count - 1)
2242 dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2243 break;
2244 default:
2245 return (LRESULT)FALSE;
2246 }
2247 if (dy) {
2248 EDIT_EM_LineScroll(hwnd, es, 0, dy);
2249 EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL, "EN_VSCROLL");
2250 }
2251 return MAKELONG((INT16)dy, (BOOL16)TRUE);
2252}
2253
2254
2255/*********************************************************************
2256 *
2257 * EM_SCROLLCARET
2258 *
2259 */
2260static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es)
2261{
2262 if (es->style & ES_MULTILINE) {
2263 INT l;
2264 INT li;
2265 INT vlc;
2266 INT ww;
2267 INT cw = es->char_width;
2268 INT x;
2269 INT dy = 0;
2270 INT dx = 0;
2271
2272 l = EDIT_EM_LineFromChar(hwnd, es, es->selection_end);
2273 li = EDIT_EM_LineIndex(hwnd, es, l);
2274 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP));
2275 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2276 if (l >= es->y_offset + vlc)
2277 dy = l - vlc + 1 - es->y_offset;
2278 if (l < es->y_offset)
2279 dy = l - es->y_offset;
2280 ww = es->format_rect.right - es->format_rect.left;
2281 if (x < es->format_rect.left)
2282 dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
2283 if (x > es->format_rect.right)
2284 dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
2285 if (dy || dx)
2286 EDIT_EM_LineScroll(hwnd, es, dx, dy);
2287 } else {
2288 INT x;
2289 INT goal;
2290 INT format_width;
2291
2292 if (!(es->style & ES_AUTOHSCROLL))
2293 return;
2294
2295 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
2296 format_width = es->format_rect.right - es->format_rect.left;
2297 if (x < es->format_rect.left) {
2298 goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
2299 do {
2300 es->x_offset--;
2301 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
2302 } while ((x < goal) && es->x_offset);
2303 /* FIXME: use ScrollWindow() somehow to improve performance */
2304 InvalidateRect(hwnd, NULL, TRUE);
2305 } else if (x > es->format_rect.right) {
2306 INT x_last;
2307 INT len = lstrlenA(es->text);
2308 goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
2309 do {
2310 es->x_offset++;
2311 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
2312 x_last = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, len, FALSE));
2313 } while ((x > goal) && (x_last > es->format_rect.right));
2314 /* FIXME: use ScrollWindow() somehow to improve performance */
2315 InvalidateRect(hwnd, NULL, TRUE);
2316 }
2317 }
2318}
2319
2320
2321/*********************************************************************
2322 *
2323 * EM_SETHANDLE
2324 *
2325 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2326 *
2327 */
2328static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc)
2329{
2330 if (!(es->style & ES_MULTILINE))
2331 return;
2332
2333 if (!hloc) {
2334 //WARN_(edit)("called with NULL handle\n");
2335 return;
2336 }
2337
2338 EDIT_UnlockBuffer(hwnd, es, TRUE);
2339 /*
2340 * old buffer is freed by caller, unless
2341 * it is still in our own heap. (in that case
2342 * we free it, correcting the buggy caller.)
2343 */
2344 if (es->text)
2345 HeapFree(es->heap, 0, es->text);
2346
2347 es->hloc = hloc;
2348 es->text = NULL;
2349 es->buffer_size = LocalSize(es->hloc) - 1;
2350 EDIT_LockBuffer(hwnd, es);
2351
2352 es->x_offset = es->y_offset = 0;
2353 es->selection_start = es->selection_end = 0;
2354 EDIT_EM_EmptyUndoBuffer(hwnd, es);
2355 es->flags &= ~EF_MODIFIED;
2356 es->flags &= ~EF_UPDATE;
2357 EDIT_BuildLineDefs_ML(hwnd, es);
2358 InvalidateRect(hwnd, NULL, TRUE);
2359 EDIT_EM_ScrollCaret(hwnd, es);
2360}
2361
2362/*********************************************************************
2363 *
2364 * EM_SETLIMITTEXT
2365 *
2366 * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
2367 * However, the windows version is not complied to yet in all of edit.c
2368 *
2369 */
2370static void EDIT_EM_SetLimitText(HWND hwnd, EDITSTATE *es, INT limit)
2371{
2372 if (es->style & ES_MULTILINE) {
2373 if (limit)
2374 es->buffer_limit = MIN(limit, BUFLIMIT_MULTI);
2375 else
2376 es->buffer_limit = BUFLIMIT_MULTI;
2377 } else {
2378 if (limit)
2379 es->buffer_limit = MIN(limit, BUFLIMIT_SINGLE);
2380 else
2381 es->buffer_limit = BUFLIMIT_SINGLE;
2382 }
2383}
2384
2385
2386/*********************************************************************
2387 *
2388 * EM_SETMARGINS
2389 *
2390 * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
2391 * action wParam despite what the docs say. EC_USEFONTINFO means one third
2392 * of the char's width, according to the new docs.
2393 *
2394 */
2395static void EDIT_EM_SetMargins(HWND hwnd, EDITSTATE *es, INT action,
2396 INT left, INT right)
2397{
2398 if (action & EC_LEFTMARGIN) {
2399 if (left != EC_USEFONTINFO)
2400 es->left_margin = left;
2401 else
2402 es->left_margin = es->char_width / 3;
2403 }
2404
2405 if (action & EC_RIGHTMARGIN) {
2406 if (right != EC_USEFONTINFO)
2407 es->right_margin = right;
2408 else
2409 es->right_margin = es->char_width / 3;
2410 }
2411 //TRACE_(edit)("left=%d, right=%d\n", es->left_margin, es->right_margin);
2412}
2413
2414
2415/*********************************************************************
2416 *
2417 * EM_SETPASSWORDCHAR
2418 *
2419 */
2420static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, CHAR c)
2421{
2422 if (es->style & ES_MULTILINE)
2423 return;
2424
2425 if (es->password_char == c)
2426 return;
2427
2428 es->password_char = c;
2429 if (c) {
2430 SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) | ES_PASSWORD);
2431 es->style |= ES_PASSWORD;
2432 } else {
2433 SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) & ~ES_PASSWORD);
2434 es->style &= ~ES_PASSWORD;
2435 }
2436 InvalidateRect(hwnd, NULL, TRUE);
2437}
2438
2439
2440/*********************************************************************
2441 *
2442 * EDIT_EM_SetSel
2443 *
2444 * note: unlike the specs say: the order of start and end
2445 * _is_ preserved in Windows. (i.e. start can be > end)
2446 * In other words: this handler is OK
2447 *
2448 */
2449static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
2450{
2451 UINT old_start = es->selection_start;
2452 UINT old_end = es->selection_end;
2453 UINT len = lstrlenA(es->text);
2454
2455 if (start == -1) {
2456 start = es->selection_end;
2457 end = es->selection_end;
2458 } else {
2459 start = MIN(start, len);
2460 end = MIN(end, len);
2461 }
2462 es->selection_start = start;
2463 es->selection_end = end;
2464 if (after_wrap)
2465 es->flags |= EF_AFTER_WRAP;
2466 else
2467 es->flags &= ~EF_AFTER_WRAP;
2468 if (es->flags & EF_FOCUSED)
2469 EDIT_SetCaretPos(hwnd, es, end, after_wrap);
2470/* This is little bit more efficient than before, not sure if it can be improved. FIXME? */
2471 ORDER_UINT(start, end);
2472 ORDER_UINT(end, old_end);
2473 ORDER_UINT(start, old_start);
2474 ORDER_UINT(old_start, old_end);
2475 if (end != old_start)
2476 {
2477/*
2478 * One can also do
2479 * ORDER_UINT32(end, old_start);
2480 * EDIT_InvalidateText(wnd, es, start, end);
2481 * EDIT_InvalidateText(wnd, es, old_start, old_end);
2482 * in place of the following if statement.
2483 */
2484 if (old_start > end )
2485 {
2486 EDIT_InvalidateText(hwnd, es, start, end);
2487 EDIT_InvalidateText(hwnd, es, old_start, old_end);
2488 }
2489 else
2490 {
2491 EDIT_InvalidateText(hwnd, es, start, old_start);
2492 EDIT_InvalidateText(hwnd, es, end, old_end);
2493 }
2494 }
2495 else EDIT_InvalidateText(hwnd, es, start, old_end);
2496}
2497
2498
2499/*********************************************************************
2500 *
2501 * EM_SETTABSTOPS
2502 *
2503 */
2504static BOOL EDIT_EM_SetTabStops(HWND hwnd, EDITSTATE *es, INT count, LPINT tabs)
2505{
2506 if (!(es->style & ES_MULTILINE))
2507 return FALSE;
2508 if (es->tabs)
2509 HeapFree(es->heap, 0, es->tabs);
2510 es->tabs_count = count;
2511 if (!count)
2512 es->tabs = NULL;
2513 else {
2514 es->tabs = (INT*)HeapAlloc(es->heap, 0, count * sizeof(INT));
2515 memcpy(es->tabs, tabs, count * sizeof(INT));
2516 }
2517 return TRUE;
2518}
2519
2520
2521/*********************************************************************
2522 *
2523 * EM_SETWORDBREAKPROC
2524 *
2525 */
2526static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROCA wbp)
2527{
2528 if (es->word_break_procA == wbp)
2529 return;
2530
2531 es->word_break_procA = wbp;
2532 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
2533 EDIT_BuildLineDefs_ML(hwnd, es);
2534 InvalidateRect(hwnd, NULL, TRUE);
2535 }
2536}
2537
2538
2539/*********************************************************************
2540 *
2541 * EM_UNDO / WM_UNDO
2542 *
2543 */
2544static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es)
2545{
2546 INT ulength = lstrlenA(es->undo_text);
2547 LPSTR utext = (LPSTR)HeapAlloc(es->heap, 0, ulength + 1);
2548
2549 lstrcpyA(utext, es->undo_text);
2550
2551 //TRACE_(edit)("before UNDO:insertion length = %d, deletion buffer = %s\n",
2552 // es->undo_insert_count, utext);
2553
2554 EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
2555 EDIT_EM_EmptyUndoBuffer(hwnd, es);
2556 EDIT_EM_ReplaceSel(hwnd, es, TRUE, utext);
2557 EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
2558 HeapFree(es->heap, 0, utext);
2559
2560 //TRACE_(edit)("after UNDO:insertion length = %d, deletion buffer = %s\n",
2561 // es->undo_insert_count, es->undo_text);
2562
2563 return TRUE;
2564}
2565
2566
2567/*********************************************************************
2568 *
2569 * WM_CHAR
2570 *
2571 */
2572static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, CHAR c, DWORD key_data)
2573{
2574 BOOL control = GetKeyState(VK_CONTROL) & 0x8000;
2575 switch (c) {
2576 case '\r':
2577 /* If the edit doesn't want the return, do nothing */
2578 if(!(es->style & ES_WANTRETURN))
2579 break;
2580 case '\n':
2581 if (es->style & ES_MULTILINE) {
2582 if (es->style & ES_READONLY) {
2583 EDIT_MoveHome(hwnd, es, FALSE);
2584 EDIT_MoveDown_ML(hwnd, es, FALSE);
2585 } else
2586 EDIT_EM_ReplaceSel(hwnd, es, TRUE, "\r\n");
2587 }
2588 break;
2589 case '\t':
2590 if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
2591 EDIT_EM_ReplaceSel(hwnd, es, TRUE, "\t");
2592 break;
2593 case VK_BACK:
2594 if (!(es->style & ES_READONLY) && !control) {
2595 if (es->selection_start != es->selection_end)
2596 EDIT_WM_Clear(hwnd, es);
2597 else {
2598 /* delete character left of caret */
2599 EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
2600 EDIT_MoveBackward(hwnd, es, TRUE);
2601 EDIT_WM_Clear(hwnd, es);
2602 }
2603 }
2604 break;
2605 default:
2606 if (!(es->style & ES_READONLY) && ((BYTE)c >= ' ') && (c != 127)) {
2607 char str[2];
2608 str[0] = c;
2609 str[1] = '\0';
2610 EDIT_EM_ReplaceSel(hwnd, es, TRUE, str);
2611 }
2612 break;
2613 }
2614}
2615
2616
2617/*********************************************************************
2618 *
2619 * WM_COMMAND
2620 *
2621 */
2622static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND control)
2623{
2624 if (code || control)
2625 return;
2626
2627 switch (id) {
2628 case EM_UNDO:
2629 EDIT_EM_Undo(hwnd, es);
2630 break;
2631 case WM_CUT:
2632 EDIT_WM_Cut(hwnd, es);
2633 break;
2634 case WM_COPY:
2635 EDIT_WM_Copy(hwnd, es);
2636 break;
2637 case WM_PASTE:
2638 EDIT_WM_Paste(hwnd, es);
2639 break;
2640 case WM_CLEAR:
2641 EDIT_WM_Clear(hwnd, es);
2642 break;
2643 case EM_SETSEL:
2644 EDIT_EM_SetSel(hwnd, es, 0, -1, FALSE);
2645 EDIT_EM_ScrollCaret(hwnd, es);
2646 break;
2647 default:
2648 //ERR_(edit)("unknown menu item, please report\n");
2649 break;
2650 }
2651}
2652
2653
2654/*********************************************************************
2655 *
2656 * WM_CONTEXTMENU
2657 *
2658 * Note: the resource files resource/sysres_??.rc cannot define a
2659 * single popup menu. Hence we use a (dummy) menubar
2660 * containing the single popup menu as its first item.
2661 *
2662 * FIXME: the message identifiers have been chosen arbitrarily,
2663 * hence we use MF_BYPOSITION.
2664 * We might as well use the "real" values (anybody knows ?)
2665 * The menu definition is in resources/sysres_??.rc.
2666 * Once these are OK, we better use MF_BYCOMMAND here
2667 * (as we do in EDIT_WM_Command()).
2668 *
2669 */
2670static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, HWND hwndBtn, INT x, INT y)
2671{
2672//CB: implement native menu!
2673 HMENU menu = LoadMenuA(GetModuleHandleA("USER32"), "EDITMENU");
2674 HMENU popup = GetSubMenu(menu, 0);
2675 UINT start = es->selection_start;
2676 UINT end = es->selection_end;
2677
2678 ORDER_UINT(start, end);
2679
2680 /* undo */
2681 EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(hwnd, es) ? MF_ENABLED : MF_GRAYED));
2682 /* cut */
2683 EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
2684 /* copy */
2685 EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
2686 /* paste */
2687 EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED));
2688 /* delete */
2689 EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) ? MF_ENABLED : MF_GRAYED));
2690 /* select all */
2691 EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != lstrlenA(es->text)) ? MF_ENABLED : MF_GRAYED));
2692
2693 TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, hwnd, NULL);
2694 DestroyMenu(menu);
2695}
2696
2697
2698/*********************************************************************
2699 *
2700 * WM_COPY
2701 *
2702 */
2703static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es)
2704{
2705 INT s = es->selection_start;
2706 INT e = es->selection_end;
2707 HGLOBAL hdst;
2708 LPSTR dst;
2709
2710 if (e == s)
2711 return;
2712 ORDER_INT(s, e);
2713 hdst = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(e - s + 1));
2714 dst = (LPSTR)GlobalLock(hdst);
2715 lstrcpynA(dst, es->text + s, e - s + 1);
2716 GlobalUnlock(hdst);
2717 OpenClipboard(hwnd);
2718 EmptyClipboard();
2719 SetClipboardData(CF_TEXT, hdst);
2720 CloseClipboard();
2721}
2722
2723
2724/*********************************************************************
2725 *
2726 * WM_CREATE
2727 *
2728 */
2729static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCREATESTRUCTA cs)
2730{
2731 /*
2732 * To initialize some final structure members, we call some helper
2733 * functions. However, since the EDITSTATE is not consistent (i.e.
2734 * not fully initialized), we should be very careful which
2735 * functions can be called, and in what order.
2736 */
2737 EDIT_WM_SetFont(hwnd, es, 0, FALSE);
2738 EDIT_EM_EmptyUndoBuffer(hwnd, es);
2739 if (cs->lpszName && *(cs->lpszName) != '\0') {
2740 EDIT_EM_ReplaceSel(hwnd, es, FALSE, cs->lpszName);
2741 /* if we insert text to the editline, the text scrolls out
2742 * of the window, as the caret is placed after the insert
2743 * pos normally; thus we reset es->selection... to 0 and
2744 * update caret
2745 */
2746 es->selection_start = es->selection_end = 0;
2747 EDIT_EM_ScrollCaret(hwnd, es);
2748 }
2749 return 0;
2750}
2751
2752
2753/*********************************************************************
2754 *
2755 * WM_DESTROY
2756 *
2757 */
2758static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es)
2759{
2760 if (es->hloc) {
2761 while (LocalUnlock(es->hloc)) ;
2762 LocalFree(es->hloc);
2763 }
2764
2765 HeapDestroy(es->heap);
2766 HeapFree(GetProcessHeap(), 0, es);
2767 SetInfoPtr(hwnd,0);
2768}
2769
2770
2771/*********************************************************************
2772 *
2773 * WM_ERASEBKGND
2774 *
2775 */
2776static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc)
2777{
2778 HBRUSH brush;
2779 RECT rc;
2780
2781 if (!es->bEnableState || (es->style & ES_READONLY))
2782 brush = (HBRUSH)EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
2783 else
2784 brush = (HBRUSH)EDIT_SEND_CTLCOLOR(hwnd, dc);
2785
2786 if (!brush)
2787 brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
2788
2789 GetClientRect(hwnd, &rc);
2790 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
2791 GetClipBox(dc, &rc);
2792 /*
2793 * FIXME: specs say that we should UnrealizeObject() the brush,
2794 * but the specs of UnrealizeObject() say that we shouldn't
2795 * unrealize a stock object. The default brush that
2796 * DefWndProc() returns is ... a stock object.
2797 */
2798 FillRect(dc, &rc, brush);
2799 return -1;
2800}
2801
2802
2803/*********************************************************************
2804 *
2805 * WM_GETTEXT
2806 *
2807 */
2808static INT EDIT_WM_GetText(HWND hwnd, EDITSTATE *es, INT count, LPSTR text)
2809{
2810 INT len;
2811
2812 if (es->text == NULL) // the only case of failure i can imagine
2813 return 0;
2814
2815 len = min(count, lstrlenA(es->text)); // determine length
2816 lstrcpynA(text, es->text, len); // copy as much as possible
2817 return len;
2818}
2819
2820
2821/*********************************************************************
2822 *
2823 * EDIT_HScroll_Hack
2824 *
2825 * 16 bit notepad needs this. Actually it is not _our_ hack,
2826 * it is notepad's. Notepad is sending us scrollbar messages with
2827 * undocumented parameters without us even having a scrollbar ... !?!?
2828 *
2829 */
2830static LRESULT EDIT_HScroll_Hack(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
2831{
2832 INT dx = 0;
2833 INT fw = es->format_rect.right - es->format_rect.left;
2834 LRESULT ret = 0;
2835
2836 if (!(es->flags & EF_HSCROLL_HACK)) {
2837 //ERR_(edit)("hacked WM_HSCROLL handler invoked\n");
2838 //ERR_(edit)(" if you are _not_ running 16 bit notepad, please report\n");
2839 //ERR_(edit)(" (this message is only displayed once per edit control)\n");
2840 es->flags |= EF_HSCROLL_HACK;
2841 }
2842
2843 switch (action) {
2844 case SB_LINELEFT:
2845 if (es->x_offset)
2846 dx = -es->char_width;
2847 break;
2848 case SB_LINERIGHT:
2849 if (es->x_offset < es->text_width)
2850 dx = es->char_width;
2851 break;
2852 case SB_PAGELEFT:
2853 if (es->x_offset)
2854 dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
2855 break;
2856 case SB_PAGERIGHT:
2857 if (es->x_offset < es->text_width)
2858 dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
2859 break;
2860 case SB_LEFT:
2861 if (es->x_offset)
2862 dx = -es->x_offset;
2863 break;
2864 case SB_RIGHT:
2865 if (es->x_offset < es->text_width)
2866 dx = es->text_width - es->x_offset;
2867 break;
2868 case SB_THUMBTRACK:
2869 es->flags |= EF_HSCROLL_TRACK;
2870 dx = pos * es->text_width / 100 - es->x_offset;
2871 break;
2872 case SB_THUMBPOSITION:
2873 es->flags &= ~EF_HSCROLL_TRACK;
2874 if (!(dx = pos * es->text_width / 100 - es->x_offset))
2875 EDIT_NOTIFY_PARENT(hwnd, EN_HSCROLL, "EN_HSCROLL");
2876 break;
2877 case SB_ENDSCROLL:
2878 break;
2879
2880 default:
2881 //ERR_(edit)("undocumented (hacked) WM_HSCROLL parameter, please report\n");
2882 return 0;
2883 }
2884 if (dx)
2885 EDIT_EM_LineScroll(hwnd, es, dx, 0);
2886 return ret;
2887}
2888
2889
2890/*********************************************************************
2891 *
2892 * WM_HSCROLL
2893 *
2894 */
2895static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
2896{
2897 INT dx;
2898 INT fw;
2899
2900 if (!(es->style & ES_MULTILINE))
2901 return 0;
2902
2903 if (!(es->style & ES_AUTOHSCROLL))
2904 return 0;
2905
2906 if (!(es->style & WS_HSCROLL))
2907 return EDIT_HScroll_Hack(hwnd, es, action, pos, scroll_bar);
2908
2909 dx = 0;
2910 fw = es->format_rect.right - es->format_rect.left;
2911 switch (action) {
2912 case SB_LINELEFT:
2913 if (es->x_offset)
2914 dx = -es->char_width;
2915 break;
2916 case SB_LINERIGHT:
2917 if (es->x_offset < es->text_width)
2918 dx = es->char_width;
2919 break;
2920 case SB_PAGELEFT:
2921 if (es->x_offset)
2922 dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
2923 break;
2924 case SB_PAGERIGHT:
2925 if (es->x_offset < es->text_width)
2926 dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
2927 break;
2928 case SB_LEFT:
2929 if (es->x_offset)
2930 dx = -es->x_offset;
2931 break;
2932 case SB_RIGHT:
2933 if (es->x_offset < es->text_width)
2934 dx = es->text_width - es->x_offset;
2935 break;
2936 case SB_THUMBTRACK:
2937 es->flags |= EF_HSCROLL_TRACK;
2938 dx = pos - es->x_offset;
2939 break;
2940 case SB_THUMBPOSITION:
2941 es->flags &= ~EF_HSCROLL_TRACK;
2942 if (!(dx = pos - es->x_offset)) {
2943 SetScrollPos(hwnd, SB_HORZ, pos, TRUE);
2944 EDIT_NOTIFY_PARENT(hwnd, EN_HSCROLL, "EN_HSCROLL");
2945 }
2946 break;
2947 case SB_ENDSCROLL:
2948 break;
2949
2950 default:
2951 //ERR_(edit)("undocumented WM_HSCROLL parameter, please report\n");
2952 return 0;
2953 }
2954 if (dx)
2955 EDIT_EM_LineScroll(hwnd, es, dx, 0);
2956 return 0;
2957}
2958
2959
2960/*********************************************************************
2961 *
2962 * EDIT_CheckCombo
2963 *
2964 */
2965static BOOL EDIT_CheckCombo(HWND hwnd, UINT msg, INT key, DWORD key_data)
2966{
2967 HWND hLBox;
2968
2969 if (GetClassWord(GetParent(hwnd),GCW_ATOM) == GlobalFindAtomA(COMBOBOXCLASSNAME) &&
2970 (hLBox = COMBO_GetLBWindow(GetParent(hwnd)))) {
2971 HWND hCombo = GetParent(hwnd);
2972 BOOL bUIFlip = TRUE;
2973
2974 //TRACE_(combo)("[%04x]: handling msg %04x (%04x)\n",
2975 // wnd->hwndSelf, (UINT16)msg, (UINT16)key);
2976
2977 switch (msg) {
2978 case WM_KEYDOWN: /* Handle F4 and arrow keys */
2979 if (key != VK_F4) {
2980 bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0);
2981 if (SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0))
2982 bUIFlip = FALSE;
2983 }
2984 if (!bUIFlip)
2985 SendMessageA(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
2986 else {
2987 /* make sure ComboLBox pops up */
2988 SendMessageA(hCombo, CB_SETEXTENDEDUI, 0, 0);
2989 SendMessageA(hLBox, WM_KEYDOWN, VK_F4, 0);
2990 SendMessageA(hCombo, CB_SETEXTENDEDUI, 1, 0);
2991 }
2992 break;
2993 case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
2994 bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETEXTENDEDUI, 0, 0);
2995 if (bUIFlip) {
2996 bUIFlip = (BOOL)SendMessageA(hCombo, CB_GETDROPPEDSTATE, 0, 0);
2997 SendMessageA(hCombo, CB_SHOWDROPDOWN, (bUIFlip) ? FALSE : TRUE, 0);
2998 } else
2999 SendMessageA(hLBox, WM_KEYDOWN, VK_F4, 0);
3000 break;
3001 }
3002 return TRUE;
3003 }
3004 return FALSE;
3005}
3006
3007
3008/*********************************************************************
3009 *
3010 * WM_KEYDOWN
3011 *
3012 * Handling of special keys that don't produce a WM_CHAR
3013 * (i.e. non-printable keys) & Backspace & Delete
3014 *
3015 */
3016static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data)
3017{
3018 BOOL shift;
3019 BOOL control;
3020
3021 if (GetKeyState(VK_MENU) & 0x8000)
3022 return 0;
3023
3024 shift = GetKeyState(VK_SHIFT) & 0x8000;
3025 control = GetKeyState(VK_CONTROL) & 0x8000;
3026
3027 switch (key) {
3028 case VK_F4:
3029 case VK_UP:
3030 if (EDIT_CheckCombo(hwnd, WM_KEYDOWN, key, key_data))
3031 break;
3032 if (key == VK_F4)
3033 break;
3034 /* fall through */
3035 case VK_LEFT:
3036 if ((es->style & ES_MULTILINE) && (key == VK_UP))
3037 EDIT_MoveUp_ML(hwnd, es, shift);
3038 else
3039 if (control)
3040 EDIT_MoveWordBackward(hwnd, es, shift);
3041 else
3042 EDIT_MoveBackward(hwnd, es, shift);
3043 break;
3044 case VK_DOWN:
3045 if (EDIT_CheckCombo(hwnd, WM_KEYDOWN, key, key_data))
3046 break;
3047 /* fall through */
3048 case VK_RIGHT:
3049 if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
3050 EDIT_MoveDown_ML(hwnd, es, shift);
3051 else if (control)
3052 EDIT_MoveWordForward(hwnd, es, shift);
3053 else
3054 EDIT_MoveForward(hwnd, es, shift);
3055 break;
3056 case VK_HOME:
3057 EDIT_MoveHome(hwnd, es, shift);
3058 break;
3059 case VK_END:
3060 EDIT_MoveEnd(hwnd, es, shift);
3061 break;
3062 case VK_PRIOR:
3063 if (es->style & ES_MULTILINE)
3064 EDIT_MovePageUp_ML(hwnd, es, shift);
3065 break;
3066 case VK_NEXT:
3067 if (es->style & ES_MULTILINE)
3068 EDIT_MovePageDown_ML(hwnd, es, shift);
3069 break;
3070 case VK_DELETE:
3071 if (!(es->style & ES_READONLY) && !(shift && control)) {
3072 if (es->selection_start != es->selection_end) {
3073 if (shift)
3074 EDIT_WM_Cut(hwnd, es);
3075 else
3076 EDIT_WM_Clear(hwnd, es);
3077 } else {
3078 if (shift) {
3079 /* delete character left of caret */
3080 EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
3081 EDIT_MoveBackward(hwnd, es, TRUE);
3082 EDIT_WM_Clear(hwnd, es);
3083 } else if (control) {
3084 /* delete to end of line */
3085 EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
3086 EDIT_MoveEnd(hwnd, es, TRUE);
3087 EDIT_WM_Clear(hwnd, es);
3088 } else {
3089 /* delete character right of caret */
3090 EDIT_EM_SetSel(hwnd, es, -1, 0, FALSE);
3091 EDIT_MoveForward(hwnd, es, TRUE);
3092 EDIT_WM_Clear(hwnd, es);
3093 }
3094 }
3095 }
3096 break;
3097 case VK_INSERT:
3098 if (shift) {
3099 if (!(es->style & ES_READONLY))
3100 EDIT_WM_Paste(hwnd, es);
3101 } else if (control)
3102 EDIT_WM_Copy(hwnd, es);
3103 break;
3104 case VK_RETURN:
3105 /* If the edit doesn't want the return send a message to the default object */
3106 if(!(es->style & ES_WANTRETURN))
3107 {
3108 HWND hwndParent = GetParent(hwnd);
3109 DWORD dw = SendMessageA( hwndParent, DM_GETDEFID, 0, 0 );
3110 if (HIWORD(dw) == DC_HASDEFID)
3111 {
3112 SendMessageA( hwndParent, WM_COMMAND,
3113 MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
3114 (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) );
3115 }
3116 }
3117 break;
3118 }
3119 return 0;
3120}
3121
3122
3123/*********************************************************************
3124 *
3125 * WM_KILLFOCUS
3126 *
3127 */
3128static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es, HWND window_getting_focus)
3129{
3130 es->flags &= ~EF_FOCUSED;
3131 DestroyCaret();
3132 if(!(es->style & ES_NOHIDESEL))
3133 EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
3134 EDIT_NOTIFY_PARENT(hwnd, EN_KILLFOCUS, "EN_KILLFOCUS");
3135 return 0;
3136}
3137
3138
3139/*********************************************************************
3140 *
3141 * WM_LBUTTONDBLCLK
3142 *
3143 * The caret position has been set on the WM_LBUTTONDOWN message
3144 *
3145 */
3146static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
3147{
3148 INT s;
3149 INT e = es->selection_end;
3150 INT l;
3151 INT li;
3152 INT ll;
3153
3154 if (!(es->flags & EF_FOCUSED))
3155 return 0;
3156
3157 l = EDIT_EM_LineFromChar(hwnd, es, e);
3158 li = EDIT_EM_LineIndex(hwnd, es, l);
3159 ll = EDIT_EM_LineLength(hwnd, es, e);
3160 s = li + EDIT_CallWordBreakProc (hwnd, es, li, e - li, ll, WB_LEFT);
3161 e = li + EDIT_CallWordBreakProc(hwnd, es, li, e - li, ll, WB_RIGHT);
3162 EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
3163 EDIT_EM_ScrollCaret(hwnd, es);
3164 return 0;
3165}
3166
3167
3168/*********************************************************************
3169 *
3170 * WM_LBUTTONDOWN
3171 *
3172 */
3173static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
3174{
3175 INT e;
3176 BOOL after_wrap;
3177
3178 //SvL: Set focus
3179 SetFocus(hwnd);
3180
3181 if (!(es->flags & EF_FOCUSED))
3182 return 0;
3183
3184 es->bCaptureState = TRUE;
3185 SetCapture(hwnd);
3186 EDIT_ConfinePoint(hwnd, es, &x, &y);
3187 e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
3188 EDIT_EM_SetSel(hwnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
3189 EDIT_EM_ScrollCaret(hwnd, es);
3190 es->region_posx = es->region_posy = 0;
3191 SetTimer(hwnd, 0, 100, NULL);
3192 return 0;
3193}
3194
3195
3196/*********************************************************************
3197 *
3198 * WM_LBUTTONUP
3199 *
3200 */
3201static LRESULT EDIT_WM_LButtonUp(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
3202{
3203 if (es->bCaptureState && GetCapture() == hwnd) {
3204 KillTimer(hwnd, 0);
3205 ReleaseCapture();
3206 }
3207 es->bCaptureState = FALSE;
3208
3209 return 0;
3210}
3211
3212
3213/*********************************************************************
3214 *
3215 * WM_MOUSEMOVE
3216 *
3217 */
3218static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
3219{
3220 INT e;
3221 BOOL after_wrap;
3222 INT prex, prey;
3223
3224 if (GetCapture() != hwnd)
3225 return 1; //SvL: Bugfix
3226
3227 /*
3228 * FIXME: gotta do some scrolling if outside client
3229 * area. Maybe reset the timer ?
3230 */
3231 prex = x; prey = y;
3232 EDIT_ConfinePoint(hwnd, es, &x, &y);
3233 es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
3234 es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
3235 e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
3236 EDIT_EM_SetSel(hwnd, es, es->selection_start, e, after_wrap);
3237
3238 return 1; //SvL: Bugfix -> PMWINDOW expects non-zero return value if
3239 // we want to restore the default mouse cursor
3240}
3241
3242
3243/*********************************************************************
3244 *
3245 * WM_NCCREATE
3246 *
3247 */
3248static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTA cs)
3249{
3250 EDITSTATE *es;
3251
3252 if (!(es = (EDITSTATE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
3253 return FALSE;
3254 SetInfoPtr(hwnd,(DWORD)es);
3255
3256 /*
3257 * Note: since the EDITSTATE has not been fully initialized yet,
3258 * we can't use any API calls that may send
3259 * WM_XXX messages before WM_NCCREATE is completed.
3260 */
3261
3262 if (!(es->heap = HeapCreate(0, 0x10000, 0)))
3263 return FALSE;
3264 es->style = cs->style;
3265
3266 es->bEnableState = !(cs->style & WS_DISABLED);
3267
3268 /*
3269 * In Win95 look and feel, the WS_BORDER style is replaced by the
3270 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
3271 * control a non client area.
3272 */
3273 if (es->style & WS_BORDER)
3274 {
3275 es->style &= ~WS_BORDER;
3276 SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE) & ~WS_BORDER);
3277 SetWindowLongA(hwnd,GWL_EXSTYLE,GetWindowLongA(hwnd,GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
3278 }
3279
3280 if (es->style & ES_MULTILINE) {
3281 es->buffer_size = BUFSTART_MULTI;
3282 es->buffer_limit = BUFLIMIT_MULTI;
3283 if (es->style & WS_VSCROLL)
3284 es->style |= ES_AUTOVSCROLL;
3285 if (es->style & WS_HSCROLL)
3286 es->style |= ES_AUTOHSCROLL;
3287 es->style &= ~ES_PASSWORD;
3288 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
3289 if (es->style & ES_RIGHT)
3290 es->style &= ~ES_CENTER;
3291 es->style &= ~WS_HSCROLL;
3292 es->style &= ~ES_AUTOHSCROLL;
3293 }
3294
3295 /* FIXME: for now, all multi line controls are AUTOVSCROLL */
3296 es->style |= ES_AUTOVSCROLL;
3297 } else {
3298 es->buffer_size = BUFSTART_SINGLE;
3299 es->buffer_limit = BUFLIMIT_SINGLE;
3300 es->style &= ~ES_CENTER;
3301 es->style &= ~ES_RIGHT;
3302 es->style &= ~WS_HSCROLL;
3303 es->style &= ~WS_VSCROLL;
3304 es->style &= ~ES_AUTOVSCROLL;
3305 es->style &= ~ES_WANTRETURN;
3306 if (es->style & ES_UPPERCASE) {
3307 es->style &= ~ES_LOWERCASE;
3308 es->style &= ~ES_NUMBER;
3309 } else if (es->style & ES_LOWERCASE)
3310 es->style &= ~ES_NUMBER;
3311 if (es->style & ES_PASSWORD)
3312 es->password_char = '*';
3313
3314 /* FIXME: for now, all single line controls are AUTOHSCROLL */
3315 es->style |= ES_AUTOHSCROLL;
3316 }
3317 if (!(es->text = (char*)HeapAlloc(es->heap, 0, es->buffer_size + 1)))
3318 return FALSE;
3319 es->buffer_size = HeapSize(es->heap, 0, es->text) - 1;
3320 if (!(es->undo_text = (char*)HeapAlloc(es->heap, 0, es->buffer_size + 1)))
3321 return FALSE;
3322 es->undo_buffer_size = HeapSize(es->heap, 0, es->undo_text) - 1;
3323 *es->text = '\0';
3324 if (es->style & ES_MULTILINE)
3325 if (!(es->first_line_def = (LINEDEF*)HeapAlloc(es->heap, HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
3326 return FALSE;
3327 es->line_count = 1;
3328
3329 return TRUE;
3330}
3331
3332/*********************************************************************
3333 *
3334 * WM_PAINT
3335 *
3336 */
3337static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es,WPARAM wParam)
3338{
3339 PAINTSTRUCT ps;
3340 INT i;
3341 HDC dc;
3342 HFONT old_font = 0;
3343 RECT rc;
3344 RECT rcLine;
3345 RECT rcRgn;
3346 BOOL rev = es->bEnableState &&
3347 ((es->flags & EF_FOCUSED) ||
3348 (es->style & ES_NOHIDESEL));
3349
3350 if (es->flags & EF_UPDATE)
3351 EDIT_NOTIFY_PARENT(hwnd, EN_UPDATE, "EN_UPDATE");
3352
3353 if (!wParam)
3354 dc = BeginPaint(hwnd, &ps);
3355 else
3356 dc = (HDC) wParam;
3357
3358 if(es->style & WS_BORDER) {
3359 GetClientRect(hwnd, &rc);
3360 if(es->style & ES_MULTILINE) {
3361 if(es->style & WS_HSCROLL) rc.bottom++;
3362 if(es->style & WS_VSCROLL) rc.right++;
3363 }
3364 Rectangle(dc, rc.left, rc.top, rc.right, rc.bottom);
3365 }
3366 IntersectClipRect(dc, es->format_rect.left,
3367 es->format_rect.top,
3368 es->format_rect.right,
3369 es->format_rect.bottom);
3370 if (es->style & ES_MULTILINE) {
3371 GetClientRect(hwnd, &rc);
3372 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
3373 }
3374 if (es->font)
3375 old_font = SelectObject(dc, es->font);
3376 if (!es->bEnableState || (es->style & ES_READONLY))
3377 EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
3378 else
3379 EDIT_SEND_CTLCOLOR(hwnd, dc);
3380 if (!es->bEnableState)
3381 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
3382 GetClipBox(dc, &rcRgn);
3383 if (es->style & ES_MULTILINE) {
3384 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3385 for (i = es->y_offset ; i <= MIN(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
3386 EDIT_GetLineRect(hwnd, es, i, 0, -1, &rcLine);
3387 if (IntersectRect(&rc, &rcRgn, &rcLine))
3388 EDIT_PaintLine(hwnd, es, dc, i, rev);
3389 }
3390 } else {
3391 EDIT_GetLineRect(hwnd, es, 0, 0, -1, &rcLine);
3392 if (IntersectRect(&rc, &rcRgn, &rcLine))
3393 EDIT_PaintLine(hwnd, es, dc, 0, rev);
3394 }
3395 if (es->font)
3396 SelectObject(dc, old_font);
3397 if (es->flags & EF_FOCUSED)
3398 EDIT_SetCaretPos(hwnd, es, es->selection_end,
3399 es->flags & EF_AFTER_WRAP);
3400 if (!wParam) EndPaint(hwnd, &ps);
3401 if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK)) {
3402 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3403 SCROLLINFO si;
3404 si.cbSize = sizeof(SCROLLINFO);
3405 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
3406 si.nMin = 0;
3407 si.nMax = es->line_count + vlc - 2;
3408 si.nPage = vlc;
3409 si.nPos = es->y_offset;
3410 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
3411 }
3412 if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK)) {
3413 SCROLLINFO si;
3414 INT fw = es->format_rect.right - es->format_rect.left;
3415 si.cbSize = sizeof(SCROLLINFO);
3416 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
3417 si.nMin = 0;
3418 si.nMax = es->text_width + fw - 1;
3419 si.nPage = fw;
3420 si.nPos = es->x_offset;
3421 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
3422 }
3423
3424 if (es->flags & EF_UPDATE) {
3425 es->flags &= ~EF_UPDATE;
3426 EDIT_NOTIFY_PARENT(hwnd, EN_CHANGE, "EN_CHANGE");
3427 }
3428}
3429
3430
3431/*********************************************************************
3432 *
3433 * WM_PASTE
3434 *
3435 */
3436static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es)
3437{
3438 HGLOBAL hsrc;
3439 LPSTR src;
3440
3441 OpenClipboard(hwnd);
3442 hsrc = GetClipboardData(CF_TEXT);
3443 if (hsrc) {
3444 src = (LPSTR)GlobalLock(hsrc);
3445 EDIT_EM_ReplaceSel(hwnd, es, TRUE, src);
3446 GlobalUnlock(hsrc);
3447 }
3448 CloseClipboard();
3449}
3450
3451
3452/*********************************************************************
3453 *
3454 * WM_SETFOCUS
3455 *
3456 */
3457static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es, HWND window_losing_focus)
3458{
3459 es->flags |= EF_FOCUSED;
3460 CreateCaret(hwnd, 0, 2, es->line_height);
3461 EDIT_SetCaretPos(hwnd, es, es->selection_end,
3462 es->flags & EF_AFTER_WRAP);
3463 if(!(es->style & ES_NOHIDESEL))
3464 EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
3465 ShowCaret(hwnd);
3466//SvL: TEST
3467// EDIT_NOTIFY_PARENT(hwnd, EN_SETFOCUS, "EN_SETFOCUS");
3468}
3469
3470
3471/*********************************************************************
3472 *
3473 * WM_SETFONT
3474 *
3475 * With Win95 look the margins are set to default font value unless
3476 * the system font (font == 0) is being set, in which case they are left
3477 * unchanged.
3478 *
3479 */
3480static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw)
3481{
3482 TEXTMETRICA tm;
3483 HDC dc;
3484 HFONT old_font = 0;
3485 RECT r;
3486
3487 es->font = font;
3488 dc = GetDC(hwnd);
3489 if (font)
3490 old_font = SelectObject(dc, font);
3491 GetTextMetricsA(dc, &tm);
3492 es->line_height = tm.tmHeight;
3493 es->char_width = tm.tmAveCharWidth;
3494 if (font)
3495 SelectObject(dc, old_font);
3496 ReleaseDC(hwnd, dc);
3497 if (font)
3498 EDIT_EM_SetMargins(hwnd, es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
3499 EC_USEFONTINFO, EC_USEFONTINFO);
3500 /* Force the recalculation of the format rect for each font change */
3501 GetClientRect(hwnd, &r);
3502 EDIT_SetRectNP(hwnd, es, &r);
3503 if (es->style & ES_MULTILINE)
3504 EDIT_BuildLineDefs_ML(hwnd, es);
3505
3506 if (redraw)
3507 InvalidateRect(hwnd, NULL, TRUE);
3508 if (es->flags & EF_FOCUSED) {
3509 DestroyCaret();
3510 CreateCaret(hwnd, 0, 2, es->line_height);
3511 EDIT_SetCaretPos(hwnd, es, es->selection_end,
3512 es->flags & EF_AFTER_WRAP);
3513 ShowCaret(hwnd);
3514 }
3515}
3516
3517
3518/*********************************************************************
3519 *
3520 * WM_SETTEXT
3521 *
3522 * NOTES
3523 * For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
3524 * The modified flag is reset. No notifications are sent.
3525 *
3526 * For single-line controls, reception of WM_SETTEXT triggers:
3527 * The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
3528 *
3529 */
3530static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPCSTR text)
3531{
3532 EDIT_EM_SetSel(hwnd, es, 0, -1, FALSE);
3533 if (text) {
3534 //TRACE_(edit)("\t'%s'\n", text);
3535 EDIT_EM_ReplaceSel(hwnd, es, FALSE, text);
3536 } else {
3537 //TRACE_(edit)("\t<NULL>\n");
3538 EDIT_EM_ReplaceSel(hwnd, es, FALSE, "");
3539 }
3540 es->x_offset = 0;
3541 if (es->style & ES_MULTILINE) {
3542 es->flags &= ~EF_UPDATE;
3543 } else {
3544 es->flags |= EF_UPDATE;
3545 }
3546 es->flags &= ~EF_MODIFIED;
3547 EDIT_EM_SetSel(hwnd, es, 0, 0, FALSE);
3548 EDIT_EM_ScrollCaret(hwnd, es);
3549}
3550
3551
3552/*********************************************************************
3553 *
3554 * WM_SIZE
3555 *
3556 */
3557static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height)
3558{
3559 if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
3560 RECT rc;
3561 SetRect(&rc, 0, 0, width, height);
3562 EDIT_SetRectNP(hwnd, es, &rc);
3563 InvalidateRect(hwnd, NULL, TRUE);
3564 }
3565}
3566
3567
3568/*********************************************************************
3569 *
3570 * WM_SYSKEYDOWN
3571 *
3572 */
3573static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data)
3574{
3575 if ((key == VK_BACK) && (key_data & 0x2000)) {
3576 if (EDIT_EM_CanUndo(hwnd, es))
3577 EDIT_EM_Undo(hwnd, es);
3578 return 0;
3579 } else if (key == VK_UP || key == VK_DOWN)
3580 if (EDIT_CheckCombo(hwnd, WM_SYSKEYDOWN, key, key_data))
3581 return 0;
3582 return DefWindowProcA(hwnd, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
3583}
3584
3585
3586/*********************************************************************
3587 *
3588 * WM_TIMER
3589 *
3590 */
3591static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es, INT id, TIMERPROC timer_proc)
3592{
3593 if (es->region_posx < 0) {
3594 EDIT_MoveBackward(hwnd, es, TRUE);
3595 } else if (es->region_posx > 0) {
3596 EDIT_MoveForward(hwnd, es, TRUE);
3597 }
3598/*
3599 * FIXME: gotta do some vertical scrolling here, like
3600 * EDIT_EM_LineScroll(wnd, 0, 1);
3601 */
3602}
3603
3604
3605/*********************************************************************
3606 *
3607 * EDIT_VScroll_Hack
3608 *
3609 * 16 bit notepad needs this. Actually it is not _our_ hack,
3610 * it is notepad's. Notepad is sending us scrollbar messages with
3611 * undocumented parameters without us even having a scrollbar ... !?!?
3612 *
3613 */
3614static LRESULT EDIT_VScroll_Hack(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
3615{
3616 INT dy = 0;
3617 LRESULT ret = 0;
3618
3619 if (!(es->flags & EF_VSCROLL_HACK)) {
3620 //ERR_(edit)("hacked WM_VSCROLL handler invoked\n");
3621 //ERR_(edit)(" if you are _not_ running 16 bit notepad, please report\n");
3622 //ERR_(edit)(" (this message is only displayed once per edit control)\n");
3623 es->flags |= EF_VSCROLL_HACK;
3624 }
3625
3626 switch (action) {
3627 case SB_LINEUP:
3628 case SB_LINEDOWN:
3629 case SB_PAGEUP:
3630 case SB_PAGEDOWN:
3631 EDIT_EM_Scroll(hwnd, es, action);
3632 return 0;
3633 case SB_TOP:
3634 dy = -es->y_offset;
3635 break;
3636 case SB_BOTTOM:
3637 dy = es->line_count - 1 - es->y_offset;
3638 break;
3639 case SB_THUMBTRACK:
3640 es->flags |= EF_VSCROLL_TRACK;
3641 dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset;
3642 break;
3643 case SB_THUMBPOSITION:
3644 es->flags &= ~EF_VSCROLL_TRACK;
3645 if (!(dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset))
3646 EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL, "EN_VSCROLL");
3647 break;
3648 case SB_ENDSCROLL:
3649 break;
3650
3651 default:
3652 //ERR_(edit)("undocumented (hacked) WM_VSCROLL parameter, please report\n");
3653 return 0;
3654 }
3655 if (dy)
3656 EDIT_EM_LineScroll(hwnd, es, 0, dy);
3657 return ret;
3658}
3659
3660
3661/*********************************************************************
3662 *
3663 * WM_VSCROLL
3664 *
3665 */
3666static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos, HWND scroll_bar)
3667{
3668 INT dy;
3669
3670 if (!(es->style & ES_MULTILINE))
3671 return 0;
3672
3673 if (!(es->style & ES_AUTOVSCROLL))
3674 return 0;
3675
3676 if (!(es->style & WS_VSCROLL))
3677 return EDIT_VScroll_Hack(hwnd, es, action, pos, scroll_bar);
3678
3679 dy = 0;
3680 switch (action) {
3681 case SB_LINEUP:
3682 case SB_LINEDOWN:
3683 case SB_PAGEUP:
3684 case SB_PAGEDOWN:
3685 EDIT_EM_Scroll(hwnd, es, action);
3686 return 0;
3687
3688 case SB_TOP:
3689 dy = -es->y_offset;
3690 break;
3691 case SB_BOTTOM:
3692 dy = es->line_count - 1 - es->y_offset;
3693 break;
3694 case SB_THUMBTRACK:
3695 es->flags |= EF_VSCROLL_TRACK;
3696 dy = pos - es->y_offset;
3697 break;
3698 case SB_THUMBPOSITION:
3699 es->flags &= ~EF_VSCROLL_TRACK;
3700 if (!(dy = pos - es->y_offset)) {
3701 SetScrollPos(hwnd, SB_VERT, pos, TRUE);
3702 EDIT_NOTIFY_PARENT(hwnd, EN_VSCROLL, "EN_VSCROLL");
3703 }
3704 break;
3705 case SB_ENDSCROLL:
3706 break;
3707
3708 default:
3709 //ERR_(edit)("undocumented WM_VSCROLL action %d, please report\n",
3710 // action);
3711 return 0;
3712 }
3713 if (dy)
3714 EDIT_EM_LineScroll(hwnd, es, 0, dy);
3715 return 0;
3716}
3717
3718BOOL EDIT_Register()
3719{
3720 WNDCLASSA wndClass;
3721
3722 if (GlobalFindAtomA(EDITCLASSNAME)) return FALSE;
3723
3724 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
3725 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3726 wndClass.lpfnWndProc = (WNDPROC)EditWndProc;
3727 wndClass.cbClsExtra = 0;
3728 wndClass.cbWndExtra = sizeof(VOID*);
3729 wndClass.hCursor = LoadCursorA(0,IDC_IBEAMA);
3730 wndClass.hbrBackground = (HBRUSH)0;
3731 wndClass.lpszClassName = EDITCLASSNAME;
3732
3733 return RegisterClassA(&wndClass);
3734}
3735
3736BOOL EDIT_Unregister()
3737{
3738 if (GlobalFindAtomA(EDITCLASSNAME))
3739 return UnregisterClassA(EDITCLASSNAME,(HINSTANCE)NULL);
3740 else return FALSE;
3741}
Note: See TracBrowser for help on using the repository browser.