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

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

class changes

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