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

Last change on this file since 6496 was 6272, checked in by sandervl, 24 years ago

single line edit control selection drawing fix

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