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

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

Bugfix for SetPos bugfix, Edit controls now work, experimental fix in Edit control for VPBuddy

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