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

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

Combobox + windowpos changes + fixes

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