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

Last change on this file since 1705 was 1705, checked in by cbratschi, 26 years ago

some edit fixes

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