blob: 36a387ce1d950c594438e4fa5b80cf1454083cd9 [file] [log] [blame]
Alexandre Julliard58199531994-04-21 01:20:00 +00001/*
Alexandre Julliard329f0681996-04-14 13:21:20 +00002 * Edit control
Alexandre Julliard58199531994-04-21 01:20:00 +00003 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004 * Copyright David W. Metcalfe, 1994
5 * Copyright William Magro, 1995, 1996
Alexandre Julliardc6c09441997-01-12 18:32:19 +00006 * Copyright Frans van Dorsselaer, 1996, 1997
Alexandre Julliard58199531994-04-21 01:20:00 +00007 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard329f0681996-04-14 13:21:20 +000022 */
23
24/*
Alexandre Julliardc6c09441997-01-12 18:32:19 +000025 * please read EDIT.TODO (and update it when you change things)
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +000026 */
Alexandre Julliard58199531994-04-21 01:20:00 +000027
Patrik Stridvall1bb94031999-05-08 15:47:44 +000028#include "config.h"
29
Jeff Garzikc3e1f721999-02-19 15:42:11 +000030#include <string.h>
Alexandre Julliard908464d2000-11-01 03:11:12 +000031#include <stdlib.h>
Patrik Stridvall6cc47d42000-03-08 18:26:56 +000032
33#include "winbase.h"
Alexandre Julliard889f7421997-04-15 17:19:52 +000034#include "winnt.h"
Alexandre Julliard58199531994-04-21 01:20:00 +000035#include "win.h"
Marcus Meissner317af321999-02-17 13:51:06 +000036#include "wine/winbase16.h"
Alexandre Julliard198746d2000-08-14 14:29:22 +000037#include "wine/winuser16.h"
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +000038#include "wine/unicode.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000039#include "controls.h"
Alexandre Julliard329f0681996-04-14 13:21:20 +000040#include "local.h"
Alexandre Julliarda41b2cf2001-01-15 20:12:55 +000041#include "user.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000042#include "wine/debug.h"
Alexandre Julliard58199531994-04-21 01:20:00 +000043
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000044WINE_DEFAULT_DEBUG_CHANNEL(edit);
45WINE_DECLARE_DEBUG_CHANNEL(combo);
46WINE_DECLARE_DEBUG_CHANNEL(relay);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000047
Alexandre Julliard889f7421997-04-15 17:19:52 +000048#define BUFLIMIT_MULTI 65534 /* maximum buffer size (not including '\0')
49 FIXME: BTW, new specs say 65535 (do you dare ???) */
50#define BUFLIMIT_SINGLE 32766 /* maximum buffer size (not including '\0') */
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +000051#define GROWLENGTH 32 /* buffers granularity in bytes: must be power of 2 */
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +000052#define ROUND_TO_GROW(size) (((size) + (GROWLENGTH - 1)) & ~(GROWLENGTH - 1))
Alexandre Julliard329f0681996-04-14 13:21:20 +000053#define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */
Alexandre Julliard58199531994-04-21 01:20:00 +000054
Alexandre Julliard889f7421997-04-15 17:19:52 +000055/*
56 * extra flags for EDITSTATE.flags field
57 */
58#define EF_MODIFIED 0x0001 /* text has been modified */
59#define EF_FOCUSED 0x0002 /* we have input focus */
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +000060#define EF_UPDATE 0x0004 /* notify parent of changed state */
Alexandre Julliard889f7421997-04-15 17:19:52 +000061#define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */
62#define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */
Alexandre Julliard889f7421997-04-15 17:19:52 +000063#define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a
64 wrapped line, instead of in front of the next character */
Alexandre Julliarda845b881998-06-01 10:44:35 +000065#define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */
Alexandre Julliard889f7421997-04-15 17:19:52 +000066
Alexandre Julliard329f0681996-04-14 13:21:20 +000067typedef enum
68{
Alexandre Julliard889f7421997-04-15 17:19:52 +000069 END_0 = 0, /* line ends with terminating '\0' character */
70 END_WRAP, /* line is wrapped */
71 END_HARD, /* line ends with a hard return '\r\n' */
Chuck Craynece2024c2002-04-22 23:08:19 +000072 END_SOFT, /* line ends with a soft return '\r\r\n' */
73 END_RICH /* line ends with a single '\n' */
Alexandre Julliard329f0681996-04-14 13:21:20 +000074} LINE_END;
75
Alexandre Julliard889f7421997-04-15 17:19:52 +000076typedef struct tagLINEDEF {
Alexandre Julliarda3960291999-02-26 11:11:13 +000077 INT length; /* bruto length of a line in bytes */
78 INT net_length; /* netto length of a line in visible characters */
Alexandre Julliard329f0681996-04-14 13:21:20 +000079 LINE_END ending;
Alexandre Julliarda3960291999-02-26 11:11:13 +000080 INT width; /* width of the line in pixels */
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +000081 INT index; /* line index into the buffer */
Alexandre Julliard889f7421997-04-15 17:19:52 +000082 struct tagLINEDEF *next;
Alexandre Julliard329f0681996-04-14 13:21:20 +000083} LINEDEF;
Alexandre Julliard58199531994-04-21 01:20:00 +000084
Alexandre Julliard58199531994-04-21 01:20:00 +000085typedef struct
86{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +000087 BOOL is_unicode; /* how the control was created */
88 LPWSTR text; /* the actual contents of the control */
89 UINT buffer_size; /* the size of the buffer in characters */
90 UINT buffer_limit; /* the maximum size to which the buffer may grow in characters */
Alexandre Julliarda3960291999-02-26 11:11:13 +000091 HFONT font; /* NULL means standard system font */
92 INT x_offset; /* scroll offset for multi lines this is in pixels
Alexandre Julliard889f7421997-04-15 17:19:52 +000093 for single lines it's in characters */
Alexandre Julliarda3960291999-02-26 11:11:13 +000094 INT line_height; /* height of a screen line in pixels */
95 INT char_width; /* average character width in pixels */
Alexandre Julliard889f7421997-04-15 17:19:52 +000096 DWORD style; /* sane version of wnd->dwStyle */
97 WORD flags; /* flags that are not in es->style or wnd->flags (EF_XXX) */
Alexandre Julliarda3960291999-02-26 11:11:13 +000098 INT undo_insert_count; /* number of characters inserted in sequence */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +000099 UINT undo_position; /* character index of the insertion and deletion */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000100 LPWSTR undo_text; /* deleted text */
Dmitry Timoshkov366c0a12000-12-22 20:28:05 +0000101 UINT undo_buffer_size; /* size of the deleted text buffer */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000102 INT selection_start; /* == selection_end if no selection */
103 INT selection_end; /* == current caret position */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000104 WCHAR password_char; /* == 0 if no password char, and for multi line controls */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000105 INT left_margin; /* in pixels */
106 INT right_margin; /* in pixels */
107 RECT format_rect;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +0000108 INT text_width; /* width of the widest line in pixels for multi line controls
109 and just line width for single line controls */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000110 INT region_posx; /* Position of cursor relative to region: */
111 INT region_posy; /* -1: to left, 0: within, 1: to right */
Alexandre Julliard889f7421997-04-15 17:19:52 +0000112 EDITWORDBREAKPROC16 word_break_proc16;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000113 void *word_break_proc; /* 32-bit word break proc: ANSI or Unicode */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000114 INT line_count; /* number of lines */
115 INT y_offset; /* scroll offset in number of lines */
Abey George6e013e51999-07-27 17:08:26 +0000116 BOOL bCaptureState; /* flag indicating whether mouse was captured */
Stephane Lussier93805341999-09-03 16:37:00 +0000117 BOOL bEnableState; /* flag keeping the enable state */
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +0000118 HWND hwndParent; /* Handle of parent for sending EN_* messages.
119 Even if parent will change, EN_* messages
120 should be sent to the first parent. */
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000121 HWND hwndListBox; /* handle of ComboBox's listbox or NULL */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000122 /*
Alexandre Julliard889f7421997-04-15 17:19:52 +0000123 * only for multi line controls
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000124 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000125 INT lock_count; /* amount of re-entries in the EditWndProc */
126 INT tabs_count;
127 LPINT tabs;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000128 LINEDEF *first_line_def; /* linked list of (soft) linebreaks */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000129 HLOCAL hloc32W; /* our unicode local memory block */
130 HLOCAL16 hloc16; /* alias for 16-bit control receiving EM_GETHANDLE16
131 or EM_SETHANDLE16 */
132 HLOCAL hloc32A; /* alias for ANSI control receiving EM_GETHANDLE
133 or EM_SETHANDLE */
Alexandre Julliard58199531994-04-21 01:20:00 +0000134} EDITSTATE;
135
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000136
Alexandre Julliarda3960291999-02-26 11:11:13 +0000137#define SWAP_INT32(x,y) do { INT temp = (INT)(x); (x) = (INT)(y); (y) = temp; } while(0)
138#define ORDER_INT(x,y) do { if ((INT)(y) < (INT)(x)) SWAP_INT32((x),(y)); } while(0)
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000139
Alexandre Julliarda3960291999-02-26 11:11:13 +0000140#define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
141#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
Alexandre Julliard58199531994-04-21 01:20:00 +0000142
Alexandre Julliard889f7421997-04-15 17:19:52 +0000143#define DPRINTF_EDIT_NOTIFY(hwnd, str) \
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000144 do {TRACE("notification " str " sent to hwnd=%08x\n", \
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000145 (UINT)(hwnd));} while(0)
146
Luc Tourangeaudf5fbc71999-04-03 11:14:30 +0000147/* used for disabled or read-only edit control */
Alexandre Julliardde424282001-08-10 22:51:42 +0000148#define EDIT_SEND_CTLCOLORSTATIC(hwnd,hdc) \
149 (SendMessageW(GetParent(hwnd), WM_CTLCOLORSTATIC, \
150 (WPARAM)(hdc), (LPARAM)(hwnd)))
151#define EDIT_SEND_CTLCOLOR(hwnd,hdc) \
152 (SendMessageW(GetParent(hwnd), WM_CTLCOLOREDIT, \
153 (WPARAM)(hdc), (LPARAM)(hwnd)))
154#define EDIT_NOTIFY_PARENT(hwnd, es, wNotifyCode, str) \
Dmitry Timoshkov87880c52001-03-10 19:16:46 +0000155 do \
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +0000156 { /* Notify parent which has created this edit control */ \
157 DPRINTF_EDIT_NOTIFY((es)->hwndParent, str); \
158 SendMessageW((es)->hwndParent, WM_COMMAND, \
Alexandre Julliardde424282001-08-10 22:51:42 +0000159 MAKEWPARAM(GetWindowLongA((hwnd),GWL_ID), wNotifyCode), \
160 (LPARAM)(hwnd)); \
Dmitry Timoshkov87880c52001-03-10 19:16:46 +0000161 } while(0)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000162#define DPRINTF_EDIT_MSG16(str) \
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000163 TRACE(\
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000164 "16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
Alexandre Julliardde424282001-08-10 22:51:42 +0000165 hwnd, (UINT)wParam, (UINT)lParam)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000166#define DPRINTF_EDIT_MSG32(str) \
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000167 TRACE(\
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000168 "32 bit %c : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
169 unicode ? 'W' : 'A', \
Alexandre Julliardde424282001-08-10 22:51:42 +0000170 hwnd, (UINT)wParam, (UINT)lParam)
Alexandre Julliardca22b331996-07-12 19:02:39 +0000171
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000172/*********************************************************************
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000173 *
Alexandre Julliard329f0681996-04-14 13:21:20 +0000174 * Declarations
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000175 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000176 */
177
178/*
179 * These functions have trivial implementations
180 * We still like to call them internally
Patrik Stridvall1bb94031999-05-08 15:47:44 +0000181 * "static inline" makes them more like macro's
Alexandre Julliard889f7421997-04-15 17:19:52 +0000182 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000183static inline BOOL EDIT_EM_CanUndo(EDITSTATE *es);
184static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es);
Alexandre Julliardde424282001-08-10 22:51:42 +0000185static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es);
186static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es);
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000187
Alexandre Julliard889f7421997-04-15 17:19:52 +0000188/*
189 * Helper functions only valid for one type of control
190 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000191static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es, INT iStart, INT iEnd, INT delta, HRGN hrgn);
192static void EDIT_CalcLineWidth_SL(HWND hwnd, EDITSTATE *es);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000193static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es);
Alexandre Julliardde424282001-08-10 22:51:42 +0000194static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
195static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
196static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
197static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000198/*
199 * Helper functions valid for both single line _and_ multi line controls
200 */
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +0000201static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action);
Alexandre Julliardde424282001-08-10 22:51:42 +0000202static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000203static void EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y);
Alexandre Julliardde424282001-08-10 22:51:42 +0000204static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc);
205static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end);
206static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es);
207static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, UINT size);
Dmitry Timoshkov366c0a12000-12-22 20:28:05 +0000208static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size);
Alexandre Julliardde424282001-08-10 22:51:42 +0000209static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
210static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend);
211static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend);
212static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend);
213static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend);
214static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend);
215static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000216static INT EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
Vincent Béron9a624912002-05-31 23:06:46 +0000217static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos, BOOL after_wrap);
Alexandre Julliardde424282001-08-10 22:51:42 +0000218static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT lprc);
219static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force);
220static void EDIT_UpdateScrollInfo(HWND hwnd, EDITSTATE *es);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000221static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000222/*
223 * EM_XXX message handlers
224 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000225static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000226static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol);
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +0000227static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es);
Alexandre Julliardde424282001-08-10 22:51:42 +0000228static HLOCAL16 EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es);
Dmitry Timoshkovbf604532001-02-12 19:15:33 +0000229static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000230static LRESULT EDIT_EM_GetSel(EDITSTATE *es, LPUINT start, LPUINT end);
Alexandre Julliardde424282001-08-10 22:51:42 +0000231static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000232static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index);
233static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line);
234static INT EDIT_EM_LineLength(EDITSTATE *es, INT index);
Alexandre Julliardde424282001-08-10 22:51:42 +0000235static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy);
236static BOOL EDIT_EM_LineScroll_internal(HWND hwnd, EDITSTATE *es, INT dx, INT dy);
237static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap);
238static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update);
239static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action);
240static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es);
241static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc);
242static void EDIT_EM_SetHandle16(HWND hwnd, EDITSTATE *es, HLOCAL16 hloc);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000243static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
244static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right);
Alexandre Julliardde424282001-08-10 22:51:42 +0000245static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, WCHAR c);
246static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000247static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
248static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs);
Alexandre Julliardde424282001-08-10 22:51:42 +0000249static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, LPARAM lParam);
250static void EDIT_EM_SetWordBreakProc16(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROC16 wbp);
251static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000252/*
253 * WM_XXX message handlers
254 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000255static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, WCHAR c);
256static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND conrtol);
257static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, INT x, INT y);
258static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es);
259static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCWSTR name);
260static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es);
261static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000262static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode);
Alexandre Julliardde424282001-08-10 22:51:42 +0000263static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos);
264static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key);
265static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es);
266static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es);
267static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000268static LRESULT EDIT_WM_LButtonUp(HWND hwndSelf, EDITSTATE *es);
Alexandre Julliardde424282001-08-10 22:51:42 +0000269static LRESULT EDIT_WM_MButtonDown(HWND hwnd);
270static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, INT x, INT y);
271static LRESULT EDIT_WM_NCCreate(HWND hwnd, DWORD style, HWND hwndParent, BOOL unicode);
272static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es, WPARAM wParam);
273static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es);
274static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es);
275static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw);
276static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPARAM lParam, BOOL unicode);
277static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height);
278static LRESULT EDIT_WM_StyleChanged (HWND hwnd, EDITSTATE *es, WPARAM which, const STYLESTRUCT *style);
279static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data);
280static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es);
281static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos);
282static void EDIT_UpdateText(HWND hwnd, EDITSTATE *es, LPRECT rc, BOOL bErase);
283static void EDIT_UpdateTextRegion(HWND hwnd, EDITSTATE *es, HRGN hrgn, BOOL bErase);
Alexandre Julliard58199531994-04-21 01:20:00 +0000284
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000285LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
286LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Alexandre Julliard91222da2000-12-10 23:01:33 +0000287
288/*********************************************************************
289 * edit class descriptor
290 */
291const struct builtin_class_descr EDIT_builtin_class =
292{
293 "Edit", /* name */
Dmitry Timoshkov51cf0e32002-04-08 23:46:32 +0000294 CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC, /* style */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000295 EditWndProcA, /* procA */
296 EditWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000297 sizeof(EDITSTATE *), /* extra */
298 IDC_IBEAMA, /* cursor */
299 0 /* brush */
300};
301
Alexandre Julliard58199531994-04-21 01:20:00 +0000302
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000303/*********************************************************************
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000304 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000305 * EM_CANUNDO
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000306 *
307 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000308static inline BOOL EDIT_EM_CanUndo(EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +0000309{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000310 return (es->undo_insert_count || strlenW(es->undo_text));
Alexandre Julliard889f7421997-04-15 17:19:52 +0000311}
312
313
314/*********************************************************************
315 *
316 * EM_EMPTYUNDOBUFFER
317 *
318 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000319static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +0000320{
321 es->undo_insert_count = 0;
322 *es->undo_text = '\0';
323}
324
325
326/*********************************************************************
327 *
328 * WM_CLEAR
329 *
330 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000331static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +0000332{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000333 static const WCHAR empty_stringW[] = {0};
334
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +0000335 /* Protect read-only edit control from modification */
336 if(es->style & ES_READONLY)
337 return;
338
Alexandre Julliardde424282001-08-10 22:51:42 +0000339 EDIT_EM_ReplaceSel(hwnd, es, TRUE, empty_stringW, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000340}
341
342
343/*********************************************************************
344 *
345 * WM_CUT
346 *
347 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000348static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +0000349{
Alexandre Julliardde424282001-08-10 22:51:42 +0000350 EDIT_WM_Copy(hwnd, es);
351 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000352}
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000353
354
Alexandre Julliard198746d2000-08-14 14:29:22 +0000355/**********************************************************************
356 * get_app_version
357 *
358 * Returns the window version in case Wine emulates a later version
359 * of windows then the application expects.
Vincent Béron9a624912002-05-31 23:06:46 +0000360 *
Alexandre Julliard198746d2000-08-14 14:29:22 +0000361 * In a number of cases when windows runs an application that was
362 * designed for an earlier windows version, windows reverts
363 * to "old" behaviour of that earlier version.
Vincent Béron9a624912002-05-31 23:06:46 +0000364 *
365 * An example is a disabled edit control that needs to be painted.
366 * Old style behaviour is to send a WM_CTLCOLOREDIT message. This was
367 * changed in Win95, NT4.0 by a WM_CTLCOLORSTATIC message _only_ for
Alexandre Julliard198746d2000-08-14 14:29:22 +0000368 * applications with an expected version 0f 4.0 or higher.
Vincent Béron9a624912002-05-31 23:06:46 +0000369 *
Alexandre Julliard198746d2000-08-14 14:29:22 +0000370 */
371static DWORD get_app_version(void)
372{
373 static DWORD version;
374 if (!version)
375 {
376 DWORD dwEmulatedVersion;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000377 OSVERSIONINFOW info;
Alexandre Julliard198746d2000-08-14 14:29:22 +0000378 DWORD dwProcVersion = GetProcessVersion(0);
379
James Juran75c525c2001-05-18 20:56:37 +0000380 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000381 GetVersionExW( &info );
Alexandre Julliard198746d2000-08-14 14:29:22 +0000382 dwEmulatedVersion = MAKELONG( info.dwMinorVersion, info.dwMajorVersion );
Dimitrie O. Paun693cca52002-01-29 03:12:19 +0000383 /* FIXME: this may not be 100% correct; see discussion on the
Alexandre Julliard198746d2000-08-14 14:29:22 +0000384 * wine developer list in Nov 1999 */
Vincent Béron9a624912002-05-31 23:06:46 +0000385 version = dwProcVersion < dwEmulatedVersion ? dwProcVersion : dwEmulatedVersion;
Alexandre Julliard198746d2000-08-14 14:29:22 +0000386 }
387 return version;
388}
389
390
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000391/*********************************************************************
392 *
Alexandre Julliardde424282001-08-10 22:51:42 +0000393 * EditWndProc_common
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000394 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000395 * The messages are in the order of the actual integer values
396 * (which can be found in include/windows.h)
Bill Medland86bfa4c2001-06-28 18:01:00 +0000397 * Wherever possible the 16 bit versions are converted to
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000398 * the 32 bit ones, so that we can 'fall through' to the
399 * helper functions. These are mostly 32 bit (with a few
400 * exceptions, clearly indicated by a '16' extension to their
401 * names).
402 *
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000403 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000404static LRESULT WINAPI EditWndProc_common( HWND hwnd, UINT msg,
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000405 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000406{
Alexandre Julliardde424282001-08-10 22:51:42 +0000407 EDITSTATE *es = (EDITSTATE *)GetWindowLongA( hwnd, 0 );
Alexandre Julliard889f7421997-04-15 17:19:52 +0000408 LRESULT result = 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000409
Alexandre Julliard889f7421997-04-15 17:19:52 +0000410 switch (msg) {
Alexandre Julliard889f7421997-04-15 17:19:52 +0000411 case WM_DESTROY:
412 DPRINTF_EDIT_MSG32("WM_DESTROY");
Alexandre Julliardde424282001-08-10 22:51:42 +0000413 if (es) EDIT_WM_Destroy(hwnd, es);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +0000414 result = 0;
415 goto END;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000416
417 case WM_NCCREATE:
418 DPRINTF_EDIT_MSG32("WM_NCCREATE");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000419 if(unicode)
420 {
421 LPCREATESTRUCTW cs = (LPCREATESTRUCTW)lParam;
Alexandre Julliardde424282001-08-10 22:51:42 +0000422 result = EDIT_WM_NCCreate(hwnd, cs->style, cs->hwndParent, TRUE);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000423 }
424 else
425 {
426 LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
Alexandre Julliardde424282001-08-10 22:51:42 +0000427 result = EDIT_WM_NCCreate(hwnd, cs->style, cs->hwndParent, FALSE);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000428 }
Francois Boisvert6b1b41c1999-03-14 17:25:32 +0000429 goto END;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000430 }
431
432 if (!es)
Francois Boisvert6b1b41c1999-03-14 17:25:32 +0000433 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000434 if(unicode)
Alexandre Julliardde424282001-08-10 22:51:42 +0000435 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000436 else
Alexandre Julliardde424282001-08-10 22:51:42 +0000437 result = DefWindowProcA(hwnd, msg, wParam, lParam);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +0000438 goto END;
439 }
440
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000441
Alexandre Julliardde424282001-08-10 22:51:42 +0000442 EDIT_LockBuffer(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000443 switch (msg) {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000444 case EM_GETSEL16:
445 DPRINTF_EDIT_MSG16("EM_GETSEL");
446 wParam = 0;
447 lParam = 0;
448 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000449 case EM_GETSEL:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000450 DPRINTF_EDIT_MSG32("EM_GETSEL");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000451 result = EDIT_EM_GetSel(es, (LPUINT)wParam, (LPUINT)lParam);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000452 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000453
454 case EM_SETSEL16:
455 DPRINTF_EDIT_MSG16("EM_SETSEL");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000456 if (SLOWORD(lParam) == -1)
Alexandre Julliardde424282001-08-10 22:51:42 +0000457 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000458 else
Alexandre Julliardde424282001-08-10 22:51:42 +0000459 EDIT_EM_SetSel(hwnd, es, LOWORD(lParam), HIWORD(lParam), FALSE);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000460 if (!wParam)
Alexandre Julliardde424282001-08-10 22:51:42 +0000461 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000462 result = 1;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000463 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000464 case EM_SETSEL:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000465 DPRINTF_EDIT_MSG32("EM_SETSEL");
Alexandre Julliardde424282001-08-10 22:51:42 +0000466 EDIT_EM_SetSel(hwnd, es, wParam, lParam, FALSE);
467 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000468 result = 1;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000469 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000470
471 case EM_GETRECT16:
472 DPRINTF_EDIT_MSG16("EM_GETRECT");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000473 if (lParam)
Alexandre Julliard982a2232000-12-13 20:20:09 +0000474 CONV_RECT32TO16(&es->format_rect, MapSL(lParam));
Alexandre Julliard329f0681996-04-14 13:21:20 +0000475 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000476 case EM_GETRECT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000477 DPRINTF_EDIT_MSG32("EM_GETRECT");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000478 if (lParam)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000479 CopyRect((LPRECT)lParam, &es->format_rect);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000480 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000481
482 case EM_SETRECT16:
483 DPRINTF_EDIT_MSG16("EM_SETRECT");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000484 if ((es->style & ES_MULTILINE) && lParam) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000485 RECT rc;
Alexandre Julliard982a2232000-12-13 20:20:09 +0000486 CONV_RECT16TO32(MapSL(lParam), &rc);
Alexandre Julliardde424282001-08-10 22:51:42 +0000487 EDIT_SetRectNP(hwnd, es, &rc);
488 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000489 }
490 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000491 case EM_SETRECT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000492 DPRINTF_EDIT_MSG32("EM_SETRECT");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000493 if ((es->style & ES_MULTILINE) && lParam) {
Alexandre Julliardde424282001-08-10 22:51:42 +0000494 EDIT_SetRectNP(hwnd, es, (LPRECT)lParam);
495 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000496 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000497 break;
498
499 case EM_SETRECTNP16:
500 DPRINTF_EDIT_MSG16("EM_SETRECTNP");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000501 if ((es->style & ES_MULTILINE) && lParam) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000502 RECT rc;
Alexandre Julliard982a2232000-12-13 20:20:09 +0000503 CONV_RECT16TO32(MapSL(lParam), &rc);
Alexandre Julliardde424282001-08-10 22:51:42 +0000504 EDIT_SetRectNP(hwnd, es, &rc);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000505 }
506 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000507 case EM_SETRECTNP:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000508 DPRINTF_EDIT_MSG32("EM_SETRECTNP");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000509 if ((es->style & ES_MULTILINE) && lParam)
Alexandre Julliardde424282001-08-10 22:51:42 +0000510 EDIT_SetRectNP(hwnd, es, (LPRECT)lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000511 break;
512
513 case EM_SCROLL16:
514 DPRINTF_EDIT_MSG16("EM_SCROLL");
515 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000516 case EM_SCROLL:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000517 DPRINTF_EDIT_MSG32("EM_SCROLL");
Alexandre Julliardde424282001-08-10 22:51:42 +0000518 result = EDIT_EM_Scroll(hwnd, es, (INT)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000519 break;
520
521 case EM_LINESCROLL16:
522 DPRINTF_EDIT_MSG16("EM_LINESCROLL");
Alexandre Julliarda3960291999-02-26 11:11:13 +0000523 wParam = (WPARAM)(INT)SHIWORD(lParam);
524 lParam = (LPARAM)(INT)SLOWORD(lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000525 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000526 case EM_LINESCROLL:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000527 DPRINTF_EDIT_MSG32("EM_LINESCROLL");
Alexandre Julliardde424282001-08-10 22:51:42 +0000528 result = (LRESULT)EDIT_EM_LineScroll(hwnd, es, (INT)wParam, (INT)lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000529 break;
530
531 case EM_SCROLLCARET16:
532 DPRINTF_EDIT_MSG16("EM_SCROLLCARET");
533 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000534 case EM_SCROLLCARET:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000535 DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
Alexandre Julliardde424282001-08-10 22:51:42 +0000536 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000537 result = 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000538 break;
539
540 case EM_GETMODIFY16:
541 DPRINTF_EDIT_MSG16("EM_GETMODIFY");
542 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000543 case EM_GETMODIFY:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000544 DPRINTF_EDIT_MSG32("EM_GETMODIFY");
Eric Pouech8dde5a41999-04-25 10:58:04 +0000545 result = ((es->flags & EF_MODIFIED) != 0);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000546 break;
547
548 case EM_SETMODIFY16:
549 DPRINTF_EDIT_MSG16("EM_SETMODIFY");
550 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000551 case EM_SETMODIFY:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000552 DPRINTF_EDIT_MSG32("EM_SETMODIFY");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000553 if (wParam)
554 es->flags |= EF_MODIFIED;
555 else
Gerard Patel40ed5111999-07-03 15:47:50 +0000556 es->flags &= ~(EF_MODIFIED | EF_UPDATE); /* reset pending updates */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000557 break;
558
559 case EM_GETLINECOUNT16:
560 DPRINTF_EDIT_MSG16("EM_GETLINECOUNT");
561 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000562 case EM_GETLINECOUNT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000563 DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000564 result = (es->style & ES_MULTILINE) ? es->line_count : 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000565 break;
566
567 case EM_LINEINDEX16:
568 DPRINTF_EDIT_MSG16("EM_LINEINDEX");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000569 if ((INT16)wParam == -1)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000570 wParam = (WPARAM)-1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000571 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000572 case EM_LINEINDEX:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000573 DPRINTF_EDIT_MSG32("EM_LINEINDEX");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000574 result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000575 break;
576
577 case EM_SETHANDLE16:
578 DPRINTF_EDIT_MSG16("EM_SETHANDLE");
Alexandre Julliardde424282001-08-10 22:51:42 +0000579 EDIT_EM_SetHandle16(hwnd, es, (HLOCAL16)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000580 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000581 case EM_SETHANDLE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000582 DPRINTF_EDIT_MSG32("EM_SETHANDLE");
Alexandre Julliardde424282001-08-10 22:51:42 +0000583 EDIT_EM_SetHandle(hwnd, es, (HLOCAL)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000584 break;
585
586 case EM_GETHANDLE16:
587 DPRINTF_EDIT_MSG16("EM_GETHANDLE");
Alexandre Julliardde424282001-08-10 22:51:42 +0000588 result = (LRESULT)EDIT_EM_GetHandle16(hwnd, es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000589 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000590 case EM_GETHANDLE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000591 DPRINTF_EDIT_MSG32("EM_GETHANDLE");
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +0000592 result = (LRESULT)EDIT_EM_GetHandle(es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000593 break;
594
595 case EM_GETTHUMB16:
596 DPRINTF_EDIT_MSG16("EM_GETTHUMB");
597 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000598 case EM_GETTHUMB:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000599 DPRINTF_EDIT_MSG32("EM_GETTHUMB");
Alexandre Julliardde424282001-08-10 22:51:42 +0000600 result = EDIT_EM_GetThumb(hwnd, es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000601 break;
602
603 /* messages 0x00bf and 0x00c0 missing from specs */
604
605 case WM_USER+15:
606 DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
607 /* fall through */
608 case 0x00bf:
609 DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
Alexandre Julliardde424282001-08-10 22:51:42 +0000610 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000611 break;
612
613 case WM_USER+16:
614 DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
615 /* fall through */
616 case 0x00c0:
617 DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
Alexandre Julliardde424282001-08-10 22:51:42 +0000618 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000619 break;
620
621 case EM_LINELENGTH16:
622 DPRINTF_EDIT_MSG16("EM_LINELENGTH");
623 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000624 case EM_LINELENGTH:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000625 DPRINTF_EDIT_MSG32("EM_LINELENGTH");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000626 result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000627 break;
628
629 case EM_REPLACESEL16:
630 DPRINTF_EDIT_MSG16("EM_REPLACESEL");
Alexandre Julliard982a2232000-12-13 20:20:09 +0000631 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardc9e11392001-04-10 21:46:27 +0000632 unicode = FALSE; /* 16-bit message is always ascii */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000633 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000634 case EM_REPLACESEL:
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000635 {
636 LPWSTR textW;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000637 DPRINTF_EDIT_MSG32("EM_REPLACESEL");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000638
639 if(unicode)
640 textW = (LPWSTR)lParam;
641 else
642 {
643 LPSTR textA = (LPSTR)lParam;
644 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
645 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
646 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
647 }
648
Alexandre Julliardde424282001-08-10 22:51:42 +0000649 EDIT_EM_ReplaceSel(hwnd, es, (BOOL)wParam, textW, TRUE);
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000650 result = 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000651
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000652 if(!unicode)
653 HeapFree(GetProcessHeap(), 0, textW);
654 break;
655 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000656 /* message 0x00c3 missing from specs */
657
658 case WM_USER+19:
659 DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
660 /* fall through */
661 case 0x00c3:
662 DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
Alexandre Julliardde424282001-08-10 22:51:42 +0000663 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000664 break;
665
666 case EM_GETLINE16:
667 DPRINTF_EDIT_MSG16("EM_GETLINE");
Alexandre Julliard982a2232000-12-13 20:20:09 +0000668 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardc9e11392001-04-10 21:46:27 +0000669 unicode = FALSE; /* 16-bit message is always ascii */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000670 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000671 case EM_GETLINE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000672 DPRINTF_EDIT_MSG32("EM_GETLINE");
Dmitry Timoshkovbf604532001-02-12 19:15:33 +0000673 result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, lParam, unicode);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000674 break;
675
676 case EM_LIMITTEXT16:
677 DPRINTF_EDIT_MSG16("EM_LIMITTEXT");
678 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000679 case EM_SETLIMITTEXT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000680 DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000681 EDIT_EM_SetLimitText(es, (INT)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000682 break;
683
684 case EM_CANUNDO16:
685 DPRINTF_EDIT_MSG16("EM_CANUNDO");
686 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000687 case EM_CANUNDO:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000688 DPRINTF_EDIT_MSG32("EM_CANUNDO");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000689 result = (LRESULT)EDIT_EM_CanUndo(es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000690 break;
691
692 case EM_UNDO16:
693 DPRINTF_EDIT_MSG16("EM_UNDO");
694 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000695 case EM_UNDO:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000696 /* fall through */
Alexandre Julliard329f0681996-04-14 13:21:20 +0000697 case WM_UNDO:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000698 DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
Alexandre Julliardde424282001-08-10 22:51:42 +0000699 result = (LRESULT)EDIT_EM_Undo(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000700 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000701
702 case EM_FMTLINES16:
703 DPRINTF_EDIT_MSG16("EM_FMTLINES");
704 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000705 case EM_FMTLINES:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000706 DPRINTF_EDIT_MSG32("EM_FMTLINES");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000707 result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000708 break;
709
710 case EM_LINEFROMCHAR16:
711 DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR");
712 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000713 case EM_LINEFROMCHAR:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000714 DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000715 result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000716 break;
717
718 /* message 0x00ca missing from specs */
719
720 case WM_USER+26:
721 DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
722 /* fall through */
723 case 0x00ca:
724 DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
Alexandre Julliardde424282001-08-10 22:51:42 +0000725 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000726 break;
727
728 case EM_SETTABSTOPS16:
729 DPRINTF_EDIT_MSG16("EM_SETTABSTOPS");
Alexandre Julliard982a2232000-12-13 20:20:09 +0000730 result = (LRESULT)EDIT_EM_SetTabStops16(es, (INT)wParam, MapSL(lParam));
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000731 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000732 case EM_SETTABSTOPS:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000733 DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000734 result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000735 break;
736
737 case EM_SETPASSWORDCHAR16:
738 DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR");
Alexandre Julliardc9e11392001-04-10 21:46:27 +0000739 unicode = FALSE; /* 16-bit message is always ascii */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000740 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000741 case EM_SETPASSWORDCHAR:
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000742 {
743 WCHAR charW = 0;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000744 DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000745
746 if(unicode)
747 charW = (WCHAR)wParam;
748 else
749 {
750 CHAR charA = wParam;
751 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
752 }
753
Alexandre Julliardde424282001-08-10 22:51:42 +0000754 EDIT_EM_SetPasswordChar(hwnd, es, charW);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000755 break;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000756 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000757
758 case EM_EMPTYUNDOBUFFER16:
759 DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER");
760 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000761 case EM_EMPTYUNDOBUFFER:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000762 DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000763 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000764 break;
765
766 case EM_GETFIRSTVISIBLELINE16:
767 DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000768 result = es->y_offset;
769 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000770 case EM_GETFIRSTVISIBLELINE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000771 DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000772 result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000773 break;
774
775 case EM_SETREADONLY16:
776 DPRINTF_EDIT_MSG16("EM_SETREADONLY");
777 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000778 case EM_SETREADONLY:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000779 DPRINTF_EDIT_MSG32("EM_SETREADONLY");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000780 if (wParam) {
Alexandre Julliardde424282001-08-10 22:51:42 +0000781 SetWindowLongA( hwnd, GWL_STYLE,
782 GetWindowLongA( hwnd, GWL_STYLE ) | ES_READONLY );
783 es->style |= ES_READONLY;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000784 } else {
Alexandre Julliardde424282001-08-10 22:51:42 +0000785 SetWindowLongA( hwnd, GWL_STYLE,
786 GetWindowLongA( hwnd, GWL_STYLE ) & ~ES_READONLY );
787 es->style &= ~ES_READONLY;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000788 }
Francois Boisvert6b1b41c1999-03-14 17:25:32 +0000789 result = 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000790 break;
791
792 case EM_SETWORDBREAKPROC16:
793 DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC");
Alexandre Julliardde424282001-08-10 22:51:42 +0000794 EDIT_EM_SetWordBreakProc16(hwnd, es, (EDITWORDBREAKPROC16)lParam);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000795 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000796 case EM_SETWORDBREAKPROC:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000797 DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
Alexandre Julliardde424282001-08-10 22:51:42 +0000798 EDIT_EM_SetWordBreakProc(hwnd, es, lParam);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000799 break;
800
801 case EM_GETWORDBREAKPROC16:
802 DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000803 result = (LRESULT)es->word_break_proc16;
804 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000805 case EM_GETWORDBREAKPROC:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000806 DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000807 result = (LRESULT)es->word_break_proc;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000808 break;
809
810 case EM_GETPASSWORDCHAR16:
811 DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR");
Alexandre Julliardc9e11392001-04-10 21:46:27 +0000812 unicode = FALSE; /* 16-bit message is always ascii */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000813 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000814 case EM_GETPASSWORDCHAR:
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000815 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000816 DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000817
818 if(unicode)
819 result = es->password_char;
820 else
821 {
822 WCHAR charW = es->password_char;
823 CHAR charA = 0;
824 WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
825 result = charA;
826 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000827 break;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000828 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000829
830 /* The following EM_xxx are new to win95 and don't exist for 16 bit */
831
Alexandre Julliarda3960291999-02-26 11:11:13 +0000832 case EM_SETMARGINS:
Alexandre Julliard889f7421997-04-15 17:19:52 +0000833 DPRINTF_EDIT_MSG32("EM_SETMARGINS");
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000834 EDIT_EM_SetMargins(es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam));
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000835 break;
836
Alexandre Julliarda3960291999-02-26 11:11:13 +0000837 case EM_GETMARGINS:
Alexandre Julliard889f7421997-04-15 17:19:52 +0000838 DPRINTF_EDIT_MSG32("EM_GETMARGINS");
839 result = MAKELONG(es->left_margin, es->right_margin);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000840 break;
841
Alexandre Julliarda3960291999-02-26 11:11:13 +0000842 case EM_GETLIMITTEXT:
Alexandre Julliard889f7421997-04-15 17:19:52 +0000843 DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT");
844 result = es->buffer_limit;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000845 break;
846
Alexandre Julliarda3960291999-02-26 11:11:13 +0000847 case EM_POSFROMCHAR:
Alexandre Julliard889f7421997-04-15 17:19:52 +0000848 DPRINTF_EDIT_MSG32("EM_POSFROMCHAR");
Alexandre Julliardde424282001-08-10 22:51:42 +0000849 result = EDIT_EM_PosFromChar(hwnd, es, (INT)wParam, FALSE);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000850 break;
851
Alexandre Julliarda3960291999-02-26 11:11:13 +0000852 case EM_CHARFROMPOS:
Alexandre Julliard889f7421997-04-15 17:19:52 +0000853 DPRINTF_EDIT_MSG32("EM_CHARFROMPOS");
Alexandre Julliardde424282001-08-10 22:51:42 +0000854 result = EDIT_EM_CharFromPos(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000855 break;
856
Bill Medland86bfa4c2001-06-28 18:01:00 +0000857 /* End of the EM_ messages which were in numerical order; what order
858 * are these in? vaguely alphabetical?
859 */
860
Alexandre Julliard329f0681996-04-14 13:21:20 +0000861 case WM_GETDLGCODE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000862 DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
Alexandre Julliardd566a0e2000-05-30 20:50:09 +0000863 result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000864
865 if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
Alexandre Julliardd566a0e2000-05-30 20:50:09 +0000866 {
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000867 int vk = (int)((LPMSG)lParam)->wParam;
868
Alexandre Julliardde424282001-08-10 22:51:42 +0000869 if (vk == VK_RETURN && (GetWindowLongA( hwnd, GWL_STYLE ) & ES_WANTRETURN))
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000870 {
Alexandre Julliardd566a0e2000-05-30 20:50:09 +0000871 result |= DLGC_WANTMESSAGE;
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000872 }
873 else if (es->hwndListBox && (vk == VK_RETURN || vk == VK_ESCAPE))
874 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000875 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000876 result |= DLGC_WANTMESSAGE;
877 }
Alexandre Julliardd566a0e2000-05-30 20:50:09 +0000878 }
Alexandre Julliard329f0681996-04-14 13:21:20 +0000879 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000880
Alexandre Julliard329f0681996-04-14 13:21:20 +0000881 case WM_CHAR:
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000882 {
883 WCHAR charW;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000884 DPRINTF_EDIT_MSG32("WM_CHAR");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000885
886 if(unicode)
887 charW = wParam;
888 else
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000889 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000890 CHAR charA = wParam;
891 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
892 }
893
894 if ((charW == VK_RETURN || charW == VK_ESCAPE) && es->hwndListBox)
895 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000896 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
897 SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +0000898 break;
899 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000900 EDIT_WM_Char(hwnd, es, charW);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000901 break;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000902 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000903
Alexandre Julliard329f0681996-04-14 13:21:20 +0000904 case WM_CLEAR:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000905 DPRINTF_EDIT_MSG32("WM_CLEAR");
Alexandre Julliardde424282001-08-10 22:51:42 +0000906 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000907 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000908
Alexandre Julliard01d63461997-01-20 19:43:45 +0000909 case WM_COMMAND:
910 DPRINTF_EDIT_MSG32("WM_COMMAND");
Alexandre Julliardde424282001-08-10 22:51:42 +0000911 EDIT_WM_Command(hwnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
Alexandre Julliard01d63461997-01-20 19:43:45 +0000912 break;
913
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000914 case WM_CONTEXTMENU:
915 DPRINTF_EDIT_MSG32("WM_CONTEXTMENU");
Alexandre Julliardde424282001-08-10 22:51:42 +0000916 EDIT_WM_ContextMenu(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
Alexandre Julliard01d63461997-01-20 19:43:45 +0000917 break;
918
Alexandre Julliard329f0681996-04-14 13:21:20 +0000919 case WM_COPY:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000920 DPRINTF_EDIT_MSG32("WM_COPY");
Alexandre Julliardde424282001-08-10 22:51:42 +0000921 EDIT_WM_Copy(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000922 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000923
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000924 case WM_CREATE:
925 DPRINTF_EDIT_MSG32("WM_CREATE");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000926 if(unicode)
Alexandre Julliardde424282001-08-10 22:51:42 +0000927 result = EDIT_WM_Create(hwnd, es, ((LPCREATESTRUCTW)lParam)->lpszName);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000928 else
929 {
930 LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
931 LPWSTR nameW = NULL;
932 if(nameA)
933 {
934 INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
935 if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
936 MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
937 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000938 result = EDIT_WM_Create(hwnd, es, nameW);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000939 if(nameW)
940 HeapFree(GetProcessHeap(), 0, nameW);
941 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000942 break;
943
Alexandre Julliard329f0681996-04-14 13:21:20 +0000944 case WM_CUT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000945 DPRINTF_EDIT_MSG32("WM_CUT");
Alexandre Julliardde424282001-08-10 22:51:42 +0000946 EDIT_WM_Cut(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000947 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000948
Alexandre Julliard329f0681996-04-14 13:21:20 +0000949 case WM_ENABLE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000950 DPRINTF_EDIT_MSG32("WM_ENABLE");
Stephane Lussier93805341999-09-03 16:37:00 +0000951 es->bEnableState = (BOOL) wParam;
Alexandre Julliardde424282001-08-10 22:51:42 +0000952 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000953 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000954
Alexandre Julliard329f0681996-04-14 13:21:20 +0000955 case WM_ERASEBKGND:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000956 DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
Alexandre Julliardde424282001-08-10 22:51:42 +0000957 result = EDIT_WM_EraseBkGnd(hwnd, es, (HDC)wParam);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000958 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000959
Alexandre Julliard329f0681996-04-14 13:21:20 +0000960 case WM_GETFONT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000961 DPRINTF_EDIT_MSG32("WM_GETFONT");
Alexandre Julliard889f7421997-04-15 17:19:52 +0000962 result = (LRESULT)es->font;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000963 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000964
Alexandre Julliard329f0681996-04-14 13:21:20 +0000965 case WM_GETTEXT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000966 DPRINTF_EDIT_MSG32("WM_GETTEXT");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000967 result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, lParam, unicode);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000968 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000969
Alexandre Julliard329f0681996-04-14 13:21:20 +0000970 case WM_GETTEXTLENGTH:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000971 DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
Alexandre Julliard741325b2002-06-13 19:20:43 +0000972 if (unicode) result = strlenW(es->text);
973 else result = WideCharToMultiByte( CP_ACP, 0, es->text, strlenW(es->text),
974 NULL, 0, NULL, NULL );
Alexandre Julliard329f0681996-04-14 13:21:20 +0000975 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000976
Alexandre Julliard329f0681996-04-14 13:21:20 +0000977 case WM_HSCROLL:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000978 DPRINTF_EDIT_MSG32("WM_HSCROLL");
Alexandre Julliardde424282001-08-10 22:51:42 +0000979 result = EDIT_WM_HScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam));
Alexandre Julliard01d63461997-01-20 19:43:45 +0000980 break;
981
Alexandre Julliard329f0681996-04-14 13:21:20 +0000982 case WM_KEYDOWN:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000983 DPRINTF_EDIT_MSG32("WM_KEYDOWN");
Alexandre Julliardde424282001-08-10 22:51:42 +0000984 result = EDIT_WM_KeyDown(hwnd, es, (INT)wParam);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000985 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000986
Alexandre Julliard329f0681996-04-14 13:21:20 +0000987 case WM_KILLFOCUS:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000988 DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
Alexandre Julliardde424282001-08-10 22:51:42 +0000989 result = EDIT_WM_KillFocus(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000990 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000991
Alexandre Julliard329f0681996-04-14 13:21:20 +0000992 case WM_LBUTTONDBLCLK:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000993 DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
Alexandre Julliardde424282001-08-10 22:51:42 +0000994 result = EDIT_WM_LButtonDblClk(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000995 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000996
Alexandre Julliard329f0681996-04-14 13:21:20 +0000997 case WM_LBUTTONDOWN:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000998 DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
Alexandre Julliardde424282001-08-10 22:51:42 +0000999 result = EDIT_WM_LButtonDown(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam));
Alexandre Julliard329f0681996-04-14 13:21:20 +00001000 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001001
Alexandre Julliard329f0681996-04-14 13:21:20 +00001002 case WM_LBUTTONUP:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001003 DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
Alexandre Julliardde424282001-08-10 22:51:42 +00001004 result = EDIT_WM_LButtonUp(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001005 break;
1006
Vincent Béron9a624912002-05-31 23:06:46 +00001007 case WM_MBUTTONDOWN:
1008 DPRINTF_EDIT_MSG32("WM_MBUTTONDOWN");
Alexandre Julliardde424282001-08-10 22:51:42 +00001009 result = EDIT_WM_MButtonDown(hwnd);
Alexandre Julliardc6166252000-05-25 23:01:39 +00001010 break;
1011
Alexandre Julliard889f7421997-04-15 17:19:52 +00001012 case WM_MOUSEACTIVATE:
1013 /*
1014 * FIXME: maybe DefWindowProc() screws up, but it seems that
Andreas Mohra8edb3e2000-05-23 04:05:05 +00001015 * modeless dialog boxes need this. If we don't do this, the focus
Alexandre Julliard889f7421997-04-15 17:19:52 +00001016 * will _not_ be set by DefWindowProc() for edit controls in a
Andreas Mohra8edb3e2000-05-23 04:05:05 +00001017 * modeless dialog box ???
Alexandre Julliard889f7421997-04-15 17:19:52 +00001018 */
1019 DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE");
Alexandre Julliardde424282001-08-10 22:51:42 +00001020 SetFocus(hwnd);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001021 result = MA_ACTIVATE;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001022 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001023
Alexandre Julliard329f0681996-04-14 13:21:20 +00001024 case WM_MOUSEMOVE:
1025 /*
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001026 * DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
Alexandre Julliard329f0681996-04-14 13:21:20 +00001027 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001028 result = EDIT_WM_MouseMove(hwnd, es, SLOWORD(lParam), SHIWORD(lParam));
Alexandre Julliard329f0681996-04-14 13:21:20 +00001029 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001030
Alexandre Julliard329f0681996-04-14 13:21:20 +00001031 case WM_PAINT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001032 DPRINTF_EDIT_MSG32("WM_PAINT");
Alexandre Julliardde424282001-08-10 22:51:42 +00001033 EDIT_WM_Paint(hwnd, es, wParam);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001034 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001035
Alexandre Julliard329f0681996-04-14 13:21:20 +00001036 case WM_PASTE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001037 DPRINTF_EDIT_MSG32("WM_PASTE");
Alexandre Julliardde424282001-08-10 22:51:42 +00001038 EDIT_WM_Paste(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001039 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001040
Alexandre Julliard329f0681996-04-14 13:21:20 +00001041 case WM_SETFOCUS:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001042 DPRINTF_EDIT_MSG32("WM_SETFOCUS");
Alexandre Julliardde424282001-08-10 22:51:42 +00001043 EDIT_WM_SetFocus(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001044 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001045
Alexandre Julliard329f0681996-04-14 13:21:20 +00001046 case WM_SETFONT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001047 DPRINTF_EDIT_MSG32("WM_SETFONT");
Alexandre Julliardde424282001-08-10 22:51:42 +00001048 EDIT_WM_SetFont(hwnd, es, (HFONT)wParam, LOWORD(lParam) != 0);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001049 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001050
Dmitry Timoshkova234db82001-01-19 20:49:54 +00001051 case WM_SETREDRAW:
1052 /* FIXME: actually set an internal flag and behave accordingly */
1053 break;
1054
Alexandre Julliard329f0681996-04-14 13:21:20 +00001055 case WM_SETTEXT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001056 DPRINTF_EDIT_MSG32("WM_SETTEXT");
Alexandre Julliardde424282001-08-10 22:51:42 +00001057 EDIT_WM_SetText(hwnd, es, lParam, unicode);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001058 result = TRUE;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001059 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001060
Alexandre Julliard329f0681996-04-14 13:21:20 +00001061 case WM_SIZE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001062 DPRINTF_EDIT_MSG32("WM_SIZE");
Alexandre Julliardde424282001-08-10 22:51:42 +00001063 EDIT_WM_Size(hwnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
Alexandre Julliard329f0681996-04-14 13:21:20 +00001064 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001065
Bill Medland86bfa4c2001-06-28 18:01:00 +00001066 case WM_STYLECHANGED:
1067 DPRINTF_EDIT_MSG32("WM_STYLECHANGED");
Alexandre Julliardde424282001-08-10 22:51:42 +00001068 result = EDIT_WM_StyleChanged (hwnd, es, wParam, (const STYLESTRUCT *)lParam);
Bill Medland86bfa4c2001-06-28 18:01:00 +00001069 break;
Vincent Béron9a624912002-05-31 23:06:46 +00001070
Bill Medland86bfa4c2001-06-28 18:01:00 +00001071 case WM_STYLECHANGING:
1072 DPRINTF_EDIT_MSG32("WM_STYLECHANGING");
1073 result = 0; /* See EDIT_WM_StyleChanged */
1074 break;
1075
Alexandre Julliard01d63461997-01-20 19:43:45 +00001076 case WM_SYSKEYDOWN:
1077 DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
Alexandre Julliardde424282001-08-10 22:51:42 +00001078 result = EDIT_WM_SysKeyDown(hwnd, es, (INT)wParam, (DWORD)lParam);
Alexandre Julliard01d63461997-01-20 19:43:45 +00001079 break;
1080
1081 case WM_TIMER:
1082 DPRINTF_EDIT_MSG32("WM_TIMER");
Alexandre Julliardde424282001-08-10 22:51:42 +00001083 EDIT_WM_Timer(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00001084 break;
1085
Alexandre Julliard329f0681996-04-14 13:21:20 +00001086 case WM_VSCROLL:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001087 DPRINTF_EDIT_MSG32("WM_VSCROLL");
Alexandre Julliardde424282001-08-10 22:51:42 +00001088 result = EDIT_WM_VScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam));
Alexandre Julliard329f0681996-04-14 13:21:20 +00001089 break;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001090
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001091 case WM_MOUSEWHEEL:
1092 {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001093 int gcWheelDelta = 0;
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001094 UINT pulScrollLines = 3;
1095 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1096
1097 if (wParam & (MK_SHIFT | MK_CONTROL)) {
Alexandre Julliardde424282001-08-10 22:51:42 +00001098 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001099 break;
1100 }
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001101 gcWheelDelta -= SHIWORD(wParam);
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001102 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1103 {
1104 int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
1105 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
Alexandre Julliardde424282001-08-10 22:51:42 +00001106 result = EDIT_EM_LineScroll(hwnd, es, 0, cLineScroll);
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001107 }
1108 }
1109 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001110 default:
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001111 if(unicode)
Alexandre Julliardde424282001-08-10 22:51:42 +00001112 result = DefWindowProcW(hwnd, msg, wParam, lParam);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001113 else
Alexandre Julliardde424282001-08-10 22:51:42 +00001114 result = DefWindowProcA(hwnd, msg, wParam, lParam);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001115 break;
1116 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001117 EDIT_UnlockBuffer(hwnd, es, FALSE);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00001118 END:
Alexandre Julliard889f7421997-04-15 17:19:52 +00001119 return result;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00001120}
1121
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001122/*********************************************************************
1123 *
1124 * EditWndProcW (USER32.@)
1125 */
1126LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1127{
Alexandre Julliardde424282001-08-10 22:51:42 +00001128 if (!IsWindow( hWnd )) return 0;
1129 return EditWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001130}
1131
1132/*********************************************************************
1133 *
Patrik Stridvall15a3b742001-04-27 18:03:51 +00001134 * EditWndProc (USER32.@)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001135 */
1136LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1137{
Alexandre Julliardde424282001-08-10 22:51:42 +00001138 if (!IsWindow( hWnd )) return 0;
1139 return EditWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001140}
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00001141
1142/*********************************************************************
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001143 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001144 * EDIT_BuildLineDefs_ML
Alexandre Julliard329f0681996-04-14 13:21:20 +00001145 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001146 * Build linked list of text lines.
1147 * Lines can end with '\0' (last line), a character (if it is wrapped),
1148 * a soft return '\r\r\n' or a hard return '\r\n'
Alexandre Julliard329f0681996-04-14 13:21:20 +00001149 *
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001150 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001151static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn)
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001152{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001153 HDC dc;
1154 HFONT old_font = 0;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001155 LPWSTR current_position, cp;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001156 INT fw;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001157 LINEDEF *current_line;
1158 LINEDEF *previous_line;
1159 LINEDEF *start_line;
1160 INT line_index = 0, nstart_line = 0, nstart_index = 0;
1161 INT line_count = es->line_count;
1162 INT orig_net_length;
1163 RECT rc;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001164
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001165 if (istart == iend && delta == 0)
1166 return;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001167
Alexandre Julliardde424282001-08-10 22:51:42 +00001168 dc = GetDC(hwnd);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001169 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001170 old_font = SelectObject(dc, es->font);
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001171
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001172 previous_line = NULL;
1173 current_line = es->first_line_def;
1174
1175 /* Find starting line. istart must lie inside an existing line or
1176 * at the end of buffer */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001177 do {
Vincent Béron9a624912002-05-31 23:06:46 +00001178 if (istart < current_line->index + current_line->length ||
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001179 current_line->ending == END_0)
1180 break;
Vincent Béron9a624912002-05-31 23:06:46 +00001181
1182 previous_line = current_line;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001183 current_line = current_line->next;
1184 line_index++;
1185 } while (current_line);
1186
1187 if (!current_line) /* Error occurred start is not inside previous buffer */
1188 {
1189 FIXME(" modification occurred outside buffer\n");
1190 return;
1191 }
1192
1193 /* Remember start of modifications in order to calculate update region */
1194 nstart_line = line_index;
1195 nstart_index = current_line->index;
1196
1197 /* We must start to reformat from the previous line since the modifications
1198 * may have caused the line to wrap upwards. */
1199 if (!(es->style & ES_AUTOHSCROLL) && line_index > 0)
1200 {
1201 line_index--;
1202 current_line = previous_line;
1203 }
1204 start_line = current_line;
1205
1206 fw = es->format_rect.right - es->format_rect.left;
1207 current_position = es->text + current_line->index;
1208 do {
1209 if (current_line != start_line)
1210 {
1211 if (!current_line || current_line->index + delta > current_position - es->text)
1212 {
Vincent Béron9a624912002-05-31 23:06:46 +00001213 /* The buffer has been expanded, create a new line and
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001214 insert it into the link list */
1215 LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF));
1216 new_line->next = previous_line->next;
1217 previous_line->next = new_line;
1218 current_line = new_line;
1219 es->line_count++;
1220 }
1221 else if (current_line->index + delta < current_position - es->text)
1222 {
1223 /* The previous line merged with this line so we delete this extra entry */
1224 previous_line->next = current_line->next;
1225 HeapFree(GetProcessHeap(), 0, current_line);
1226 current_line = previous_line->next;
1227 es->line_count--;
1228 continue;
1229 }
1230 else /* current_line->index + delta == current_position */
1231 {
1232 if (current_position - es->text > iend)
1233 break; /* We reached end of line modifications */
1234 /* else recalulate this line */
1235 }
1236 }
1237
1238 current_line->index = current_position - es->text;
1239 orig_net_length = current_line->net_length;
1240
1241 /* Find end of line */
1242 cp = current_position;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001243 while (*cp) {
Chuck Craynece2024c2002-04-22 23:08:19 +00001244 if (*cp == '\n') break;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001245 if ((*cp == '\r') && (*(cp + 1) == '\n'))
1246 break;
1247 cp++;
1248 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001249
1250 /* Mark type of line termination */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001251 if (!(*cp)) {
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001252 current_line->ending = END_0;
1253 current_line->net_length = strlenW(current_position);
1254 } else if ((cp > current_position) && (*(cp - 1) == '\r')) {
1255 current_line->ending = END_SOFT;
1256 current_line->net_length = cp - current_position - 1;
Chuck Craynece2024c2002-04-22 23:08:19 +00001257 } else if (*cp == '\n') {
1258 current_line->ending = END_RICH;
1259 current_line->net_length = cp - current_position;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001260 } else {
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001261 current_line->ending = END_HARD;
1262 current_line->net_length = cp - current_position;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001263 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001264
1265 /* Calculate line width */
1266 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
1267 current_position, current_line->net_length,
Alexandre Julliard889f7421997-04-15 17:19:52 +00001268 es->tabs_count, es->tabs));
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001269
Alexandre Julliard889f7421997-04-15 17:19:52 +00001270 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001271 if ((!(es->style & ES_AUTOHSCROLL)) && (current_line->width > fw)) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001272 INT next = 0;
1273 INT prev;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001274 do {
1275 prev = next;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001276 next = EDIT_CallWordBreakProc(es, current_position - es->text,
1277 prev + 1, current_line->net_length, WB_RIGHT);
1278 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
1279 current_position, next, es->tabs_count, es->tabs));
1280 } while (current_line->width <= fw);
1281 if (!prev) { /* Didn't find a line break so force a break */
Alexandre Julliard329f0681996-04-14 13:21:20 +00001282 next = 0;
1283 do {
1284 prev = next;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001285 next++;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001286 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
1287 current_position, next, es->tabs_count, es->tabs));
1288 } while (current_line->width <= fw);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001289 if (!prev)
1290 prev = 1;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001291 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001292
Vincent Béron9a624912002-05-31 23:06:46 +00001293 /* If the first line we are calculating, wrapped before istart, we must
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001294 * adjust istart in order for this to be reflected in the update region. */
1295 if (current_line->index == nstart_index && istart > current_line->index + prev)
1296 istart = current_line->index + prev;
1297 /* else if we are updating the previous line before the first line we
Andreas Mohr07216db2001-11-13 21:29:38 +00001298 * are re-calculating and it expanded */
Vincent Béron9a624912002-05-31 23:06:46 +00001299 else if (current_line == start_line &&
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001300 current_line->index != nstart_index && orig_net_length < prev)
Vincent Béron9a624912002-05-31 23:06:46 +00001301 {
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001302 /* Line expanded due to an upwards line wrap so we must partially include
1303 * previous line in update region */
1304 nstart_line = line_index;
1305 nstart_index = current_line->index;
1306 istart = current_line->index + orig_net_length;
1307 }
1308
1309 current_line->net_length = prev;
1310 current_line->ending = END_WRAP;
1311 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position,
1312 current_line->net_length, es->tabs_count, es->tabs));
Alexandre Julliard889f7421997-04-15 17:19:52 +00001313 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001314
1315
1316 /* Adjust length to include line termination */
1317 switch (current_line->ending) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00001318 case END_SOFT:
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001319 current_line->length = current_line->net_length + 3;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001320 break;
Chuck Craynece2024c2002-04-22 23:08:19 +00001321 case END_RICH:
1322 current_line->length = current_line->net_length + 1;
1323 break;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001324 case END_HARD:
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001325 current_line->length = current_line->net_length + 2;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001326 break;
1327 case END_WRAP:
1328 case END_0:
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001329 current_line->length = current_line->net_length;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001330 break;
1331 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001332 es->text_width = max(es->text_width, current_line->width);
1333 current_position += current_line->length;
1334 previous_line = current_line;
1335 current_line = current_line->next;
1336 line_index++;
1337 } while (previous_line->ending != END_0);
1338
Andreas Mohr07216db2001-11-13 21:29:38 +00001339 /* Finish adjusting line indexes by delta or remove hanging lines */
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001340 if (previous_line->ending == END_0)
1341 {
1342 LINEDEF *pnext = NULL;
1343
1344 previous_line->next = NULL;
1345 while (current_line)
1346 {
1347 pnext = current_line->next;
1348 HeapFree(GetProcessHeap(), 0, current_line);
1349 current_line = pnext;
1350 es->line_count--;
1351 }
1352 }
1353 else
1354 {
1355 while (current_line)
1356 {
1357 current_line->index += delta;
1358 current_line = current_line->next;
1359 }
1360 }
1361
1362 /* Calculate rest of modification rectangle */
1363 if (hrgn)
1364 {
1365 HRGN tmphrgn;
Vincent Béron9a624912002-05-31 23:06:46 +00001366 /*
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001367 * We calculate two rectangles. One for the first line which may have
1368 * an indent with respect to the format rect. The other is a format-width
1369 * rectangle that spans the rest of the lines that changed or moved.
1370 */
Vincent Béron9a624912002-05-31 23:06:46 +00001371 rc.top = es->format_rect.top + nstart_line * es->line_height -
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001372 (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
1373 rc.bottom = rc.top + es->line_height;
Vincent Béron9a624912002-05-31 23:06:46 +00001374 rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
1375 es->text + nstart_index, istart - nstart_index,
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001376 es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
1377 rc.right = es->format_rect.right;
1378 SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom);
1379
1380 rc.top = rc.bottom;
1381 rc.left = es->format_rect.left;
1382 rc.right = es->format_rect.right;
Vincent Béron9a624912002-05-31 23:06:46 +00001383 /*
1384 * If lines were added or removed we must re-paint the remainder of the
1385 * lines since the remaining lines were either shifted up or down.
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001386 */
1387 if (line_count < es->line_count) /* We added lines */
1388 rc.bottom = es->line_count * es->line_height;
1389 else if (line_count > es->line_count) /* We removed lines */
1390 rc.bottom = line_count * es->line_height;
1391 else
1392 rc.bottom = line_index * es->line_height;
1393 rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
1394 tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
1395 CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
1396 DeleteObject(tmphrgn);
1397 }
1398
Alexandre Julliard889f7421997-04-15 17:19:52 +00001399 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001400 SelectObject(dc, old_font);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00001401
Alexandre Julliardde424282001-08-10 22:51:42 +00001402 ReleaseDC(hwnd, dc);
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001403}
1404
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00001405/*********************************************************************
1406 *
1407 * EDIT_CalcLineWidth_SL
1408 *
1409 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001410static void EDIT_CalcLineWidth_SL(HWND hwnd, EDITSTATE *es)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00001411{
Alexandre Julliardde424282001-08-10 22:51:42 +00001412 es->text_width = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, strlenW(es->text), FALSE));
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00001413}
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001414
Alexandre Julliard329f0681996-04-14 13:21:20 +00001415/*********************************************************************
1416 *
1417 * EDIT_CallWordBreakProc
1418 *
1419 * Call appropriate WordBreakProc (internal or external).
1420 *
Andreas Mohr07216db2001-11-13 21:29:38 +00001421 * Note: The "start" argument should always be an index referring
Alexandre Julliard889f7421997-04-15 17:19:52 +00001422 * to es->text. The actual wordbreak proc might be
1423 * 16 bit, so we can't always pass any 32 bit LPSTR.
1424 * Hence we assume that es->text is the buffer that holds
1425 * the string under examination (we can decide this for ourselves).
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001426 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00001427 */
Alexandre Julliard198746d2000-08-14 14:29:22 +00001428/* ### start build ### */
1429extern WORD CALLBACK EDIT_CallTo16_word_lwww(EDITWORDBREAKPROC16,SEGPTR,WORD,WORD,WORD);
1430/* ### stop build ### */
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00001431static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001432{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001433 INT ret, iWndsLocks;
1434
Andreas Mohr07216db2001-11-13 21:29:38 +00001435 /* To avoid any deadlocks, all the locks on the window structures
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001436 must be suspended before the control is passed to the application */
1437 iWndsLocks = WIN_SuspendWndsLock();
1438
Alexandre Julliard889f7421997-04-15 17:19:52 +00001439 if (es->word_break_proc16) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001440 HGLOBAL16 hglob16;
1441 SEGPTR segptr;
1442 INT countA;
1443
1444 countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
1445 hglob16 = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, countA);
Alexandre Julliard58017232000-12-22 01:09:26 +00001446 segptr = K32WOWGlobalLock16(hglob16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001447 WideCharToMultiByte(CP_ACP, 0, es->text + start, count, MapSL(segptr), countA, NULL, NULL);
1448 ret = (INT)EDIT_CallTo16_word_lwww(es->word_break_proc16,
1449 segptr, index, countA, action);
1450 GlobalUnlock16(hglob16);
1451 GlobalFree16(hglob16);
Alexandre Julliard77b99181997-09-14 17:17:23 +00001452 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001453 else if (es->word_break_proc)
Alexandre Julliard77b99181997-09-14 17:17:23 +00001454 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001455 if(es->is_unicode)
1456 {
1457 EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc;
1458
1459 TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
1460 es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action);
1461 ret = wbpW(es->text + start, index, count, action);
1462 }
1463 else
1464 {
1465 EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc;
1466 INT countA;
1467 CHAR *textA;
1468
1469 countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
1470 textA = HeapAlloc(GetProcessHeap(), 0, countA);
1471 WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL);
1472 TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
1473 es->word_break_proc, debugstr_an(textA, countA), index, countA, action);
1474 ret = wbpA(textA, index, countA, action);
1475 HeapFree(GetProcessHeap(), 0, textA);
1476 }
Alexandre Julliard77b99181997-09-14 17:17:23 +00001477 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00001478 else
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001479 ret = EDIT_WordBreakProc(es->text + start, index, count, action);
1480
1481 WIN_RestoreWndsLock(iWndsLocks);
1482 return ret;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001483}
1484
Alexandre Julliard329f0681996-04-14 13:21:20 +00001485
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001486/*********************************************************************
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001487 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001488 * EDIT_CharFromPos
Alexandre Julliard329f0681996-04-14 13:21:20 +00001489 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001490 * Beware: This is not the function called on EM_CHARFROMPOS
1491 * The position _can_ be outside the formatting / client
1492 * rectangle
1493 * The return value is only the character index
Alexandre Julliard329f0681996-04-14 13:21:20 +00001494 *
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001495 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001496static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001497{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001498 INT index;
1499 HDC dc;
1500 HFONT old_font = 0;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001501
Alexandre Julliard889f7421997-04-15 17:19:52 +00001502 if (es->style & ES_MULTILINE) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001503 INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
1504 INT line_index = 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001505 LINEDEF *line_def = es->first_line_def;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001506 INT low, high;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001507 while ((line > 0) && line_def->next) {
1508 line_index += line_def->length;
1509 line_def = line_def->next;
1510 line--;
1511 }
1512 x += es->x_offset - es->format_rect.left;
1513 if (x >= line_def->width) {
1514 if (after_wrap)
1515 *after_wrap = (line_def->ending == END_WRAP);
1516 return line_index + line_def->net_length;
1517 }
1518 if (x <= 0) {
1519 if (after_wrap)
1520 *after_wrap = FALSE;
1521 return line_index;
1522 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001523 dc = GetDC(hwnd);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001524 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001525 old_font = SelectObject(dc, es->font);
Alexandre Julliarde658d821997-11-30 17:45:40 +00001526 low = line_index + 1;
1527 high = line_index + line_def->net_length + 1;
1528 while (low < high - 1)
1529 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001530 INT mid = (low + high) / 2;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001531 if (LOWORD(GetTabbedTextExtentW(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid;
Alexandre Julliarde658d821997-11-30 17:45:40 +00001532 else low = mid;
1533 }
1534 index = low;
1535
Alexandre Julliard889f7421997-04-15 17:19:52 +00001536 if (after_wrap)
1537 *after_wrap = ((index == line_index + line_def->net_length) &&
1538 (line_def->ending == END_WRAP));
1539 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001540 LPWSTR text;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001541 SIZE size;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001542 if (after_wrap)
1543 *after_wrap = FALSE;
1544 x -= es->format_rect.left;
1545 if (!x)
1546 return es->x_offset;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001547 text = EDIT_GetPasswordPointer_SL(es);
Alexandre Julliardde424282001-08-10 22:51:42 +00001548 dc = GetDC(hwnd);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001549 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001550 old_font = SelectObject(dc, es->font);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001551 if (x < 0)
1552 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001553 INT low = 0;
1554 INT high = es->x_offset;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001555 while (low < high - 1)
1556 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001557 INT mid = (low + high) / 2;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001558 GetTextExtentPoint32W( dc, text + mid,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001559 es->x_offset - mid, &size );
1560 if (size.cx > -x) low = mid;
1561 else high = mid;
1562 }
1563 index = low;
1564 }
1565 else
1566 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001567 INT low = es->x_offset;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001568 INT high = strlenW(es->text) + 1;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001569 while (low < high - 1)
1570 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001571 INT mid = (low + high) / 2;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001572 GetTextExtentPoint32W( dc, text + es->x_offset,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001573 mid - es->x_offset, &size );
1574 if (size.cx > x) high = mid;
1575 else low = mid;
1576 }
1577 index = low;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001578 }
1579 if (es->style & ES_PASSWORD)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001580 HeapFree(GetProcessHeap(), 0, text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001581 }
1582 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001583 SelectObject(dc, old_font);
Alexandre Julliardde424282001-08-10 22:51:42 +00001584 ReleaseDC(hwnd, dc);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001585 return index;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001586}
1587
Alexandre Julliard329f0681996-04-14 13:21:20 +00001588
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001589/*********************************************************************
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00001590 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001591 * EDIT_ConfinePoint
Alexandre Julliard329f0681996-04-14 13:21:20 +00001592 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001593 * adjusts the point to be within the formatting rectangle
1594 * (so CharFromPos returns the nearest _visible_ character)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001595 *
1596 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001597static void EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001598{
Francois Gouget6d77d3a2000-03-25 21:44:35 +00001599 *x = min(max(*x, es->format_rect.left), es->format_rect.right - 1);
1600 *y = min(max(*y, es->format_rect.top), es->format_rect.bottom - 1);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001601}
1602
1603
1604/*********************************************************************
1605 *
1606 * EDIT_GetLineRect
1607 *
1608 * Calculates the bounding rectangle for a line from a starting
1609 * column to an ending column.
1610 *
1611 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001612static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001613{
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001614 INT line_index = EDIT_EM_LineIndex(es, line);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001615
1616 if (es->style & ES_MULTILINE)
1617 rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
1618 else
1619 rc->top = es->format_rect.top;
1620 rc->bottom = rc->top + es->line_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001621 rc->left = (scol == 0) ? es->format_rect.left : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + scol, TRUE));
1622 rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + ecol, TRUE));
Alexandre Julliard329f0681996-04-14 13:21:20 +00001623}
1624
1625
1626/*********************************************************************
1627 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001628 * EDIT_GetPasswordPointer_SL
1629 *
1630 * note: caller should free the (optionally) allocated buffer
1631 *
1632 */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001633static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +00001634{
1635 if (es->style & ES_PASSWORD) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001636 INT len = strlenW(es->text);
1637 LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
Alexandre Julliard889f7421997-04-15 17:19:52 +00001638 text[len] = '\0';
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00001639 while(len) text[--len] = es->password_char;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001640 return text;
1641 } else
1642 return es->text;
1643}
1644
1645
1646/*********************************************************************
1647 *
1648 * EDIT_LockBuffer
Alexandre Julliard329f0681996-04-14 13:21:20 +00001649 *
1650 * This acts as a LOCAL_Lock(), but it locks only once. This way
1651 * you can call it whenever you like, without unlocking.
1652 *
1653 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001654static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001655{
Alexandre Julliardde424282001-08-10 22:51:42 +00001656 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
Alexandre Julliard889f7421997-04-15 17:19:52 +00001657 if (!es) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001658 ERR("no EDITSTATE ... please report\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00001659 return;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001660 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00001661 if (!es->text) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001662 CHAR *textA = NULL;
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001663 UINT countA = 0;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001664 BOOL _16bit = FALSE;
1665
1666 if(es->hloc32W)
1667 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001668 if(es->hloc32A)
1669 {
1670 TRACE("Synchronizing with 32-bit ANSI buffer\n");
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001671 textA = LocalLock(es->hloc32A);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001672 countA = strlen(textA) + 1;
Alexandre Julliard3051b641996-07-05 17:14:13 +00001673 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001674 else if(es->hloc16)
1675 {
1676 TRACE("Synchronizing with 16-bit ANSI buffer\n");
Alexandre Julliardde424282001-08-10 22:51:42 +00001677 textA = LOCAL_Lock(hInstance, es->hloc16);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001678 countA = strlen(textA) + 1;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001679 _16bit = TRUE;
1680 }
1681 }
1682 else {
1683 ERR("no buffer ... please report\n");
1684 return;
1685 }
1686
1687 if(textA)
1688 {
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001689 HLOCAL hloc32W_new;
1690 UINT countW_new = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
1691 TRACE("%d bytes translated to %d WCHARs\n", countA, countW_new);
1692 if(countW_new > es->buffer_size + 1)
1693 {
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00001694 UINT alloc_size = ROUND_TO_GROW(countW_new * sizeof(WCHAR));
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001695 TRACE("Resizing 32-bit UNICODE buffer from %d+1 to %d WCHARs\n", es->buffer_size, countW_new);
1696 hloc32W_new = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
1697 if(hloc32W_new)
1698 {
1699 es->hloc32W = hloc32W_new;
1700 es->buffer_size = LocalSize(hloc32W_new)/sizeof(WCHAR) - 1;
1701 TRACE("Real new size %d+1 WCHARs\n", es->buffer_size);
1702 }
1703 else
1704 WARN("FAILED! Will synchronize partially\n");
1705 }
1706 }
1707
1708 /*TRACE("Locking 32-bit UNICODE buffer\n");*/
1709 es->text = LocalLock(es->hloc32W);
1710
1711 if(textA)
1712 {
1713 MultiByteToWideChar(CP_ACP, 0, textA, countA, es->text, es->buffer_size + 1);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001714 if(_16bit)
Alexandre Julliardde424282001-08-10 22:51:42 +00001715 LOCAL_Unlock(hInstance, es->hloc16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001716 else
1717 LocalUnlock(es->hloc32A);
1718 }
Alexandre Julliard3051b641996-07-05 17:14:13 +00001719 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00001720 es->lock_count++;
Alexandre Julliard3051b641996-07-05 17:14:13 +00001721}
1722
1723
1724/*********************************************************************
1725 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001726 * EDIT_SL_InvalidateText
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001727 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001728 * Called from EDIT_InvalidateText().
1729 * Does the job for single-line controls only.
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001730 *
1731 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001732static void EDIT_SL_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001733{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001734 RECT line_rect;
1735 RECT rc;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001736
Alexandre Julliardde424282001-08-10 22:51:42 +00001737 EDIT_GetLineRect(hwnd, es, 0, start, end, &line_rect);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001738 if (IntersectRect(&rc, &line_rect, &es->format_rect))
Alexandre Julliardd376e642002-08-16 23:21:51 +00001739 EDIT_UpdateText(hwnd, es, &rc, TRUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001740}
1741
1742
1743/*********************************************************************
1744 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001745 * EDIT_ML_InvalidateText
1746 *
1747 * Called from EDIT_InvalidateText().
1748 * Does the job for multi-line controls only.
Alexandre Julliard329f0681996-04-14 13:21:20 +00001749 *
1750 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001751static void EDIT_ML_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001752{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001753 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001754 INT sl = EDIT_EM_LineFromChar(es, start);
1755 INT el = EDIT_EM_LineFromChar(es, end);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001756 INT sc;
1757 INT ec;
1758 RECT rc1;
1759 RECT rcWnd;
1760 RECT rcLine;
1761 RECT rcUpdate;
1762 INT l;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001763
Alexandre Julliard889f7421997-04-15 17:19:52 +00001764 if ((el < es->y_offset) || (sl > es->y_offset + vlc))
1765 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001766
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001767 sc = start - EDIT_EM_LineIndex(es, sl);
1768 ec = end - EDIT_EM_LineIndex(es, el);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001769 if (sl < es->y_offset) {
1770 sl = es->y_offset;
1771 sc = 0;
1772 }
1773 if (el > es->y_offset + vlc) {
1774 el = es->y_offset + vlc;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001775 ec = EDIT_EM_LineLength(es, EDIT_EM_LineIndex(es, el));
Alexandre Julliard889f7421997-04-15 17:19:52 +00001776 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001777 GetClientRect(hwnd, &rc1);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001778 IntersectRect(&rcWnd, &rc1, &es->format_rect);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001779 if (sl == el) {
Alexandre Julliardde424282001-08-10 22:51:42 +00001780 EDIT_GetLineRect(hwnd, es, sl, sc, ec, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001781 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Alexandre Julliardd376e642002-08-16 23:21:51 +00001782 EDIT_UpdateText(hwnd, es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001783 } else {
Alexandre Julliardde424282001-08-10 22:51:42 +00001784 EDIT_GetLineRect(hwnd, es, sl, sc,
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001785 EDIT_EM_LineLength(es,
1786 EDIT_EM_LineIndex(es, sl)),
Alexandre Julliard889f7421997-04-15 17:19:52 +00001787 &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001788 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Alexandre Julliardd376e642002-08-16 23:21:51 +00001789 EDIT_UpdateText(hwnd, es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001790 for (l = sl + 1 ; l < el ; l++) {
Alexandre Julliardde424282001-08-10 22:51:42 +00001791 EDIT_GetLineRect(hwnd, es, l, 0,
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001792 EDIT_EM_LineLength(es,
1793 EDIT_EM_LineIndex(es, l)),
Alexandre Julliard889f7421997-04-15 17:19:52 +00001794 &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001795 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Alexandre Julliardd376e642002-08-16 23:21:51 +00001796 EDIT_UpdateText(hwnd, es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001797 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001798 EDIT_GetLineRect(hwnd, es, el, 0, ec, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001799 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Alexandre Julliardd376e642002-08-16 23:21:51 +00001800 EDIT_UpdateText(hwnd, es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001801 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00001802}
1803
1804
1805/*********************************************************************
1806 *
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001807 * EDIT_InvalidateText
1808 *
1809 * Invalidate the text from offset start upto, but not including,
1810 * offset end. Useful for (re)painting the selection.
1811 * Regions outside the linewidth are not invalidated.
1812 * end == -1 means end == TextLength.
1813 * start and end need not be ordered.
1814 *
1815 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001816static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end)
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001817{
Alexandre Julliard01d63461997-01-20 19:43:45 +00001818 if (end == start)
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001819 return;
1820
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001821 if (end == -1)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001822 end = strlenW(es->text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001823
Alexandre Julliarda3960291999-02-26 11:11:13 +00001824 ORDER_INT(start, end);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001825
Alexandre Julliard889f7421997-04-15 17:19:52 +00001826 if (es->style & ES_MULTILINE)
Alexandre Julliardde424282001-08-10 22:51:42 +00001827 EDIT_ML_InvalidateText(hwnd, es, start, end);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001828 else
Alexandre Julliardde424282001-08-10 22:51:42 +00001829 EDIT_SL_InvalidateText(hwnd, es, start, end);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001830}
1831
1832
1833/*********************************************************************
1834 *
1835 * EDIT_MakeFit
1836 *
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001837 * Try to fit size + 1 characters in the buffer. Constrain to limits.
Alexandre Julliard329f0681996-04-14 13:21:20 +00001838 *
1839 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001840static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, UINT size)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001841{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001842 HLOCAL hNew32W;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001843
Alexandre Julliard889f7421997-04-15 17:19:52 +00001844 if (size <= es->buffer_size)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001845 return TRUE;
Aric Stewart08e69392002-08-16 01:41:32 +00001846 if ((es->buffer_limit > 0) && (size > es->buffer_limit)) {
Alexandre Julliardde424282001-08-10 22:51:42 +00001847 EDIT_NOTIFY_PARENT(hwnd, es, EN_MAXTEXT, "EN_MAXTEXT");
Alexandre Julliard329f0681996-04-14 13:21:20 +00001848 return FALSE;
Alexandre Julliard01d63461997-01-20 19:43:45 +00001849 }
Aric Stewart08e69392002-08-16 01:41:32 +00001850 if ((es->buffer_limit > 0) && (size > es->buffer_limit))
Alexandre Julliard889f7421997-04-15 17:19:52 +00001851 size = es->buffer_limit;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001852
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001853 TRACE("trying to ReAlloc to %d+1 characters\n", size);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001854
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001855 /* Force edit to unlock it's buffer. es->text now NULL */
Alexandre Julliardde424282001-08-10 22:51:42 +00001856 EDIT_UnlockBuffer(hwnd, es, TRUE);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001857
1858 if (es->hloc32W) {
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00001859 UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00001860 if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001861 TRACE("Old 32 bit handle %08x, new handle %08x\n", es->hloc32W, hNew32W);
1862 es->hloc32W = hNew32W;
1863 es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1;
1864 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001865 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001866
Alexandre Julliardde424282001-08-10 22:51:42 +00001867 EDIT_LockBuffer(hwnd, es);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001868
Alexandre Julliard889f7421997-04-15 17:19:52 +00001869 if (es->buffer_size < size) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001870 WARN("FAILED ! We now have %d+1\n", es->buffer_size);
Alexandre Julliardde424282001-08-10 22:51:42 +00001871 EDIT_NOTIFY_PARENT(hwnd, es, EN_ERRSPACE, "EN_ERRSPACE");
Alexandre Julliard889f7421997-04-15 17:19:52 +00001872 return FALSE;
1873 } else {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001874 TRACE("We now have %d+1\n", es->buffer_size);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001875 return TRUE;
1876 }
Alexandre Julliard01d63461997-01-20 19:43:45 +00001877}
1878
1879
1880/*********************************************************************
1881 *
1882 * EDIT_MakeUndoFit
1883 *
1884 * Try to fit size + 1 bytes in the undo buffer.
1885 *
1886 */
Dmitry Timoshkov366c0a12000-12-22 20:28:05 +00001887static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size)
Alexandre Julliard01d63461997-01-20 19:43:45 +00001888{
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00001889 UINT alloc_size;
1890
Alexandre Julliard889f7421997-04-15 17:19:52 +00001891 if (size <= es->undo_buffer_size)
Alexandre Julliard01d63461997-01-20 19:43:45 +00001892 return TRUE;
Alexandre Julliard01d63461997-01-20 19:43:45 +00001893
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001894 TRACE("trying to ReAlloc to %d+1\n", size);
Alexandre Julliard01d63461997-01-20 19:43:45 +00001895
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00001896 alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00001897 if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) {
1898 es->undo_buffer_size = alloc_size/sizeof(WCHAR);
Alexandre Julliard01d63461997-01-20 19:43:45 +00001899 return TRUE;
1900 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001901 else
1902 {
1903 WARN("FAILED ! We now have %d+1\n", es->undo_buffer_size);
1904 return FALSE;
1905 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00001906}
1907
1908
1909/*********************************************************************
1910 *
1911 * EDIT_MoveBackward
1912 *
1913 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001914static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001915{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001916 INT e = es->selection_end;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001917
Alexandre Julliard889f7421997-04-15 17:19:52 +00001918 if (e) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00001919 e--;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001920 if ((es->style & ES_MULTILINE) && e &&
1921 (es->text[e - 1] == '\r') && (es->text[e] == '\n')) {
1922 e--;
1923 if (e && (es->text[e - 1] == '\r'))
1924 e--;
1925 }
1926 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001927 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
1928 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001929}
1930
1931
1932/*********************************************************************
1933 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001934 * EDIT_MoveDown_ML
1935 *
1936 * Only for multi line controls
1937 * Move the caret one line down, on a column with the nearest
1938 * x coordinate on the screen (might be a different column).
Alexandre Julliard329f0681996-04-14 13:21:20 +00001939 *
1940 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001941static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001942{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001943 INT s = es->selection_start;
1944 INT e = es->selection_end;
1945 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Alexandre Julliardde424282001-08-10 22:51:42 +00001946 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001947 INT x = SLOWORD(pos);
1948 INT y = SHIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001949
Alexandre Julliardde424282001-08-10 22:51:42 +00001950 e = EDIT_CharFromPos(hwnd, es, x, y + es->line_height, &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001951 if (!extend)
1952 s = e;
Alexandre Julliardde424282001-08-10 22:51:42 +00001953 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
1954 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001955}
1956
1957
1958/*********************************************************************
1959 *
1960 * EDIT_MoveEnd
1961 *
1962 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001963static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001964{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001965 BOOL after_wrap = FALSE;
1966 INT e;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001967
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001968 /* Pass a high value in x to make sure of receiving the end of the line */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001969 if (es->style & ES_MULTILINE)
Alexandre Julliardde424282001-08-10 22:51:42 +00001970 e = EDIT_CharFromPos(hwnd, es, 0x3fffffff,
1971 HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001972 else
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001973 e = strlenW(es->text);
Alexandre Julliardde424282001-08-10 22:51:42 +00001974 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, after_wrap);
1975 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001976}
1977
1978
1979/*********************************************************************
1980 *
1981 * EDIT_MoveForward
1982 *
1983 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001984static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001985{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001986 INT e = es->selection_end;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001987
Alexandre Julliard889f7421997-04-15 17:19:52 +00001988 if (es->text[e]) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00001989 e++;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001990 if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) {
1991 if (es->text[e] == '\n')
1992 e++;
1993 else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n'))
1994 e += 2;
1995 }
1996 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001997 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
1998 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001999}
2000
2001
2002/*********************************************************************
2003 *
2004 * EDIT_MoveHome
2005 *
2006 * Home key: move to beginning of line.
2007 *
2008 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002009static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002010{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002011 INT e;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002012
Pascal Lessard3405f5c1999-09-04 10:59:07 +00002013 /* Pass the x_offset in x to make sure of receiving the first position of the line */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002014 if (es->style & ES_MULTILINE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002015 e = EDIT_CharFromPos(hwnd, es, -es->x_offset,
2016 HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002017 else
Alexandre Julliardd37eb361997-07-20 16:23:21 +00002018 e = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00002019 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE);
2020 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002021}
2022
2023
2024/*********************************************************************
2025 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002026 * EDIT_MovePageDown_ML
2027 *
2028 * Only for multi line controls
2029 * Move the caret one page down, on a column with the nearest
2030 * x coordinate on the screen (might be a different column).
Alexandre Julliard329f0681996-04-14 13:21:20 +00002031 *
2032 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002033static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002034{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002035 INT s = es->selection_start;
2036 INT e = es->selection_end;
2037 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Alexandre Julliardde424282001-08-10 22:51:42 +00002038 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002039 INT x = SLOWORD(pos);
2040 INT y = SHIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002041
Alexandre Julliardde424282001-08-10 22:51:42 +00002042 e = EDIT_CharFromPos(hwnd, es, x,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002043 y + (es->format_rect.bottom - es->format_rect.top),
2044 &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002045 if (!extend)
2046 s = e;
Alexandre Julliardde424282001-08-10 22:51:42 +00002047 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
2048 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002049}
2050
2051
2052/*********************************************************************
2053 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002054 * EDIT_MovePageUp_ML
2055 *
2056 * Only for multi line controls
2057 * Move the caret one page up, on a column with the nearest
2058 * x coordinate on the screen (might be a different column).
Alexandre Julliard329f0681996-04-14 13:21:20 +00002059 *
2060 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002061static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002062{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002063 INT s = es->selection_start;
2064 INT e = es->selection_end;
2065 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Alexandre Julliardde424282001-08-10 22:51:42 +00002066 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002067 INT x = SLOWORD(pos);
2068 INT y = SHIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002069
Alexandre Julliardde424282001-08-10 22:51:42 +00002070 e = EDIT_CharFromPos(hwnd, es, x,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002071 y - (es->format_rect.bottom - es->format_rect.top),
2072 &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002073 if (!extend)
2074 s = e;
Alexandre Julliardde424282001-08-10 22:51:42 +00002075 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
2076 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002077}
2078
2079
2080/*********************************************************************
2081 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002082 * EDIT_MoveUp_ML
Alexandre Julliard329f0681996-04-14 13:21:20 +00002083 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002084 * Only for multi line controls
2085 * Move the caret one line up, on a column with the nearest
2086 * x coordinate on the screen (might be a different column).
2087 *
Vincent Béron9a624912002-05-31 23:06:46 +00002088 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002089static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002090{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002091 INT s = es->selection_start;
2092 INT e = es->selection_end;
2093 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Alexandre Julliardde424282001-08-10 22:51:42 +00002094 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002095 INT x = SLOWORD(pos);
2096 INT y = SHIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002097
Alexandre Julliardde424282001-08-10 22:51:42 +00002098 e = EDIT_CharFromPos(hwnd, es, x, y - es->line_height, &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002099 if (!extend)
2100 s = e;
Alexandre Julliardde424282001-08-10 22:51:42 +00002101 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap);
2102 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002103}
2104
2105
2106/*********************************************************************
2107 *
2108 * EDIT_MoveWordBackward
2109 *
2110 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002111static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002112{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002113 INT s = es->selection_start;
2114 INT e = es->selection_end;
2115 INT l;
2116 INT ll;
2117 INT li;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002118
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002119 l = EDIT_EM_LineFromChar(es, e);
2120 ll = EDIT_EM_LineLength(es, e);
2121 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00002122 if (e - li == 0) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00002123 if (l) {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002124 li = EDIT_EM_LineIndex(es, l - 1);
2125 e = li + EDIT_EM_LineLength(es, li);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002126 }
2127 } else {
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00002128 e = li + (INT)EDIT_CallWordBreakProc(es,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002129 li, e - li, ll, WB_LEFT);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002130 }
2131 if (!extend)
2132 s = e;
Alexandre Julliardde424282001-08-10 22:51:42 +00002133 EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
2134 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002135}
2136
2137
2138/*********************************************************************
2139 *
2140 * EDIT_MoveWordForward
2141 *
2142 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002143static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002144{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002145 INT s = es->selection_start;
2146 INT e = es->selection_end;
2147 INT l;
2148 INT ll;
2149 INT li;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002150
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002151 l = EDIT_EM_LineFromChar(es, e);
2152 ll = EDIT_EM_LineLength(es, e);
2153 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00002154 if (e - li == ll) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00002155 if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002156 e = EDIT_EM_LineIndex(es, l + 1);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002157 } else {
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00002158 e = li + EDIT_CallWordBreakProc(es,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002159 li, e - li + 1, ll, WB_RIGHT);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002160 }
2161 if (!extend)
2162 s = e;
Alexandre Julliardde424282001-08-10 22:51:42 +00002163 EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
2164 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002165}
2166
2167
2168/*********************************************************************
2169 *
2170 * EDIT_PaintLine
2171 *
2172 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002173static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC dc, INT line, BOOL rev)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002174{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002175 INT s = es->selection_start;
2176 INT e = es->selection_end;
2177 INT li;
2178 INT ll;
2179 INT x;
2180 INT y;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002181 LRESULT pos;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002182
Alexandre Julliard889f7421997-04-15 17:19:52 +00002183 if (es->style & ES_MULTILINE) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002184 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002185 if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
2186 return;
2187 } else if (line)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002188 return;
2189
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002190 TRACE("line=%d\n", line);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002191
Alexandre Julliardde424282001-08-10 22:51:42 +00002192 pos = EDIT_EM_PosFromChar(hwnd, es, EDIT_EM_LineIndex(es, line), FALSE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002193 x = SLOWORD(pos);
2194 y = SHIWORD(pos);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002195 li = EDIT_EM_LineIndex(es, line);
2196 ll = EDIT_EM_LineLength(es, li);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002197 s = es->selection_start;
2198 e = es->selection_end;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002199 ORDER_INT(s, e);
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002200 s = min(li + ll, max(li, s));
2201 e = min(li + ll, max(li, e));
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00002202 if (rev && (s != e) &&
Alexandre Julliard889f7421997-04-15 17:19:52 +00002203 ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002204 x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
2205 x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
2206 x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002207 } else
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002208 x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002209}
2210
2211
2212/*********************************************************************
2213 *
2214 * EDIT_PaintText
2215 *
2216 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002217static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002218{
Alexandre Julliard329f0681996-04-14 13:21:20 +00002219 COLORREF BkColor;
2220 COLORREF TextColor;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002221 INT ret;
2222 INT li;
Dan Engel7c7a3572001-04-16 19:32:05 +00002223 INT BkMode;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002224 SIZE size;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002225
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00002226 if (!count)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002227 return 0;
Dan Engel7c7a3572001-04-16 19:32:05 +00002228 BkMode = GetBkMode(dc);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002229 BkColor = GetBkColor(dc);
2230 TextColor = GetTextColor(dc);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002231 if (rev) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002232 SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
2233 SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Dan Engel7c7a3572001-04-16 19:32:05 +00002234 SetBkMode( dc, OPAQUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002235 }
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002236 li = EDIT_EM_LineIndex(es, line);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002237 if (es->style & ES_MULTILINE) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002238 ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002239 es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
2240 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002241 LPWSTR text = EDIT_GetPasswordPointer_SL(es);
2242 TextOutW(dc, x, y, text + li + col, count);
2243 GetTextExtentPoint32W(dc, text + li + col, count, &size);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002244 ret = size.cx;
2245 if (es->style & ES_PASSWORD)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002246 HeapFree(GetProcessHeap(), 0, text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002247 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002248 if (rev) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002249 SetBkColor(dc, BkColor);
2250 SetTextColor(dc, TextColor);
Dan Engel7c7a3572001-04-16 19:32:05 +00002251 SetBkMode( dc, BkMode);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002252 }
2253 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002254}
Alexandre Julliard329f0681996-04-14 13:21:20 +00002255
2256
2257/*********************************************************************
2258 *
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002259 * EDIT_SetCaretPos
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002260 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002261 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002262static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002263 BOOL after_wrap)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002264{
Alexandre Julliardde424282001-08-10 22:51:42 +00002265 LRESULT res = EDIT_EM_PosFromChar(hwnd, es, pos, after_wrap);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002266 SetCaretPos(SLOWORD(res), SHIWORD(res));
Alexandre Julliard01d63461997-01-20 19:43:45 +00002267}
2268
2269
2270/*********************************************************************
2271 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002272 * EDIT_SetRectNP
Alexandre Julliard329f0681996-04-14 13:21:20 +00002273 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002274 * note: this is not (exactly) the handler called on EM_SETRECTNP
2275 * it is also used to set the rect of a single line control
Alexandre Julliard329f0681996-04-14 13:21:20 +00002276 *
2277 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002278static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT rc)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002279{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002280 CopyRect(&es->format_rect, rc);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002281 if (es->style & WS_BORDER) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002282 INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002283 if(TWEAK_WineLook == WIN31_LOOK)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002284 bw += 2;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002285 es->format_rect.left += bw;
2286 es->format_rect.top += bw;
2287 es->format_rect.right -= bw;
2288 es->format_rect.bottom -= bw;
2289 }
2290 es->format_rect.left += es->left_margin;
2291 es->format_rect.right -= es->right_margin;
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002292 es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002293 if (es->style & ES_MULTILINE)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002294 {
2295 INT fw, vlc, max_x_offset, max_y_offset;
2296
2297 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2298 es->format_rect.bottom = es->format_rect.top + max(1, vlc) * es->line_height;
2299
2300 /* correct es->x_offset */
2301 fw = es->format_rect.right - es->format_rect.left;
2302 max_x_offset = es->text_width - fw;
2303 if(max_x_offset < 0) max_x_offset = 0;
2304 if(es->x_offset > max_x_offset)
2305 es->x_offset = max_x_offset;
2306
2307 /* correct es->y_offset */
2308 max_y_offset = es->line_count - vlc;
2309 if(max_y_offset < 0) max_y_offset = 0;
2310 if(es->y_offset > max_y_offset)
2311 es->y_offset = max_y_offset;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00002312
2313 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00002314 EDIT_UpdateScrollInfo(hwnd, es);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002315 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002316 else
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002317 /* Windows doesn't care to fix text placement for SL controls */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002318 es->format_rect.bottom = es->format_rect.top + es->line_height;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002319
Alexandre Julliard889f7421997-04-15 17:19:52 +00002320 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
Alexandre Julliardde424282001-08-10 22:51:42 +00002321 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002322}
2323
2324
2325/*********************************************************************
2326 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002327 * EDIT_UnlockBuffer
Alexandre Julliard329f0681996-04-14 13:21:20 +00002328 *
2329 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002330static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002331{
Alexandre Julliardde424282001-08-10 22:51:42 +00002332 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
2333
Dmitry Timoshkovfbc36192001-03-05 19:29:47 +00002334 /* Edit window might be already destroyed */
Alexandre Julliardde424282001-08-10 22:51:42 +00002335 if(!IsWindow(hwnd))
Dmitry Timoshkovfbc36192001-03-05 19:29:47 +00002336 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002337 WARN("edit hwnd %04x already destroyed\n", hwnd);
Dmitry Timoshkovfbc36192001-03-05 19:29:47 +00002338 return;
2339 }
2340
Alexandre Julliard889f7421997-04-15 17:19:52 +00002341 if (!es) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002342 ERR("no EDITSTATE ... please report\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00002343 return;
2344 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002345 if (!es->lock_count) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002346 ERR("lock_count == 0 ... please report\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00002347 return;
2348 }
2349 if (!es->text) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002350 ERR("es->text == 0 ... please report\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00002351 return;
2352 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002353
Alexandre Julliard889f7421997-04-15 17:19:52 +00002354 if (force || (es->lock_count == 1)) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002355 if (es->hloc32W) {
2356 CHAR *textA = NULL;
2357 BOOL _16bit = FALSE;
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002358 UINT countA = 0;
2359 UINT countW = strlenW(es->text) + 1;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002360
2361 if(es->hloc32A)
2362 {
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002363 UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002364 TRACE("Synchronizing with 32-bit ANSI buffer\n");
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002365 TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002366 countA = LocalSize(es->hloc32A);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002367 if(countA_new > countA)
2368 {
2369 HLOCAL hloc32A_new;
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002370 UINT alloc_size = ROUND_TO_GROW(countA_new);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002371 TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
2372 hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
2373 if(hloc32A_new)
2374 {
2375 es->hloc32A = hloc32A_new;
2376 countA = LocalSize(hloc32A_new);
2377 TRACE("Real new size %d bytes\n", countA);
2378 }
2379 else
2380 WARN("FAILED! Will synchronize partially\n");
2381 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002382 textA = LocalLock(es->hloc32A);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002383 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002384 else if(es->hloc16)
2385 {
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002386 UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002387 TRACE("Synchronizing with 16-bit ANSI buffer\n");
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002388 TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
Alexandre Julliardde424282001-08-10 22:51:42 +00002389 countA = LOCAL_Size(hInstance, es->hloc16);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002390 if(countA_new > countA)
2391 {
2392 HLOCAL16 hloc16_new;
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002393 UINT alloc_size = ROUND_TO_GROW(countA_new);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002394 TRACE("Resizing 16-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
Alexandre Julliardde424282001-08-10 22:51:42 +00002395 hloc16_new = LOCAL_ReAlloc(hInstance, es->hloc16, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002396 if(hloc16_new)
2397 {
2398 es->hloc16 = hloc16_new;
Alexandre Julliardde424282001-08-10 22:51:42 +00002399 countA = LOCAL_Size(hInstance, hloc16_new);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002400 TRACE("Real new size %d bytes\n", countA);
2401 }
2402 else
2403 WARN("FAILED! Will synchronize partially\n");
2404 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002405 textA = LOCAL_Lock(hInstance, es->hloc16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002406 _16bit = TRUE;
2407 }
2408
2409 if(textA)
2410 {
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00002411 WideCharToMultiByte(CP_ACP, 0, es->text, countW, textA, countA, NULL, NULL);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002412 if(_16bit)
Alexandre Julliardde424282001-08-10 22:51:42 +00002413 LOCAL_Unlock(hInstance, es->hloc16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002414 else
2415 LocalUnlock(es->hloc32A);
2416 }
2417
2418 LocalUnlock(es->hloc32W);
2419 es->text = NULL;
2420 }
2421 else {
2422 ERR("no buffer ... please report\n");
2423 return;
2424 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002425 }
2426 es->lock_count--;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002427}
2428
2429
2430/*********************************************************************
2431 *
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002432 * EDIT_UpdateScrollInfo
2433 *
2434 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002435static void EDIT_UpdateScrollInfo(HWND hwnd, EDITSTATE *es)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002436{
2437 if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
2438 {
2439 SCROLLINFO si;
2440 si.cbSize = sizeof(SCROLLINFO);
2441 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
2442 si.nMin = 0;
2443 si.nMax = es->line_count - 1;
2444 si.nPage = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
2445 si.nPos = es->y_offset;
2446 TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
2447 si.nMin, si.nMax, si.nPage, si.nPos);
Alexandre Julliardde424282001-08-10 22:51:42 +00002448 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002449 }
2450
2451 if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
2452 {
2453 SCROLLINFO si;
2454 si.cbSize = sizeof(SCROLLINFO);
2455 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
2456 si.nMin = 0;
2457 si.nMax = es->text_width - 1;
2458 si.nPage = es->format_rect.right - es->format_rect.left;
2459 si.nPos = es->x_offset;
2460 TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
2461 si.nMin, si.nMax, si.nPage, si.nPos);
Alexandre Julliardde424282001-08-10 22:51:42 +00002462 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002463 }
2464}
2465
2466/*********************************************************************
2467 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002468 * EDIT_WordBreakProc
2469 *
2470 * Find the beginning of words.
2471 * Note: unlike the specs for a WordBreakProc, this function only
2472 * allows to be called without linebreaks between s[0] upto
2473 * s[count - 1]. Remember it is only called
2474 * internally, so we can decide this for ourselves.
2475 *
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00002476 */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002477static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action)
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00002478{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002479 INT ret = 0;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +00002480
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002481 TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action);
2482
2483 if(!s) return 0;
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00002484
Alexandre Julliard329f0681996-04-14 13:21:20 +00002485 switch (action) {
2486 case WB_LEFT:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002487 if (!count)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002488 break;
2489 if (index)
2490 index--;
2491 if (s[index] == ' ') {
2492 while (index && (s[index] == ' '))
2493 index--;
2494 if (index) {
2495 while (index && (s[index] != ' '))
2496 index--;
2497 if (s[index] == ' ')
2498 index++;
2499 }
2500 } else {
2501 while (index && (s[index] != ' '))
2502 index--;
2503 if (s[index] == ' ')
2504 index++;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002505 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002506 ret = index;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002507 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002508 case WB_RIGHT:
2509 if (!count)
2510 break;
2511 if (index)
2512 index--;
2513 if (s[index] == ' ')
2514 while ((index < count) && (s[index] == ' ')) index++;
2515 else {
2516 while (s[index] && (s[index] != ' ') && (index < count))
2517 index++;
2518 while ((s[index] == ' ') && (index < count)) index++;
2519 }
2520 ret = index;
2521 break;
2522 case WB_ISDELIMITER:
2523 ret = (s[index] == ' ');
2524 break;
2525 default:
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002526 ERR("unknown action code, please report !\n");
Alexandre Julliard329f0681996-04-14 13:21:20 +00002527 break;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002528 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002529 return ret;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002530}
2531
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002532
Alexandre Julliard329f0681996-04-14 13:21:20 +00002533/*********************************************************************
2534 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002535 * EM_CHARFROMPOS
2536 *
Gerard Patelc9b65341999-01-24 18:57:23 +00002537 * returns line number (not index) in high-order word of result.
Vincent Béron9a624912002-05-31 23:06:46 +00002538 * NB : Q137805 is unclear about this. POINT * pointer in lParam apply
Gerard Patelc9b65341999-01-24 18:57:23 +00002539 * to Richedit, not to the edit control. Original documentation is valid.
Alexandre Julliard889f7421997-04-15 17:19:52 +00002540 * FIXME: do the specs mean to return -1 if outside client area or
2541 * if outside formatting rectangle ???
2542 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002543 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002544static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002545{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002546 POINT pt;
2547 RECT rc;
2548 INT index;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002549
Alexandre Julliard889f7421997-04-15 17:19:52 +00002550 pt.x = x;
2551 pt.y = y;
Alexandre Julliardde424282001-08-10 22:51:42 +00002552 GetClientRect(hwnd, &rc);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002553 if (!PtInRect(&rc, pt))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002554 return -1;
2555
Alexandre Julliardde424282001-08-10 22:51:42 +00002556 index = EDIT_CharFromPos(hwnd, es, x, y, NULL);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002557 return MAKELONG(index, EDIT_EM_LineFromChar(es, index));
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00002558}
2559
Alexandre Julliard329f0681996-04-14 13:21:20 +00002560
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00002561/*********************************************************************
Alexandre Julliard329f0681996-04-14 13:21:20 +00002562 *
2563 * EM_FMTLINES
2564 *
Alexandre Julliarda845b881998-06-01 10:44:35 +00002565 * Enable or disable soft breaks.
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002566 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002567static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol)
Alexandre Julliard58199531994-04-21 01:20:00 +00002568{
Alexandre Julliarda845b881998-06-01 10:44:35 +00002569 es->flags &= ~EF_USE_SOFTBRK;
2570 if (add_eol) {
2571 es->flags |= EF_USE_SOFTBRK;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002572 FIXME("soft break enabled, not implemented\n");
Alexandre Julliarda845b881998-06-01 10:44:35 +00002573 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002574 return add_eol;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002575}
Alexandre Julliard988ca971994-06-21 16:15:21 +00002576
Alexandre Julliard58199531994-04-21 01:20:00 +00002577
Alexandre Julliard329f0681996-04-14 13:21:20 +00002578/*********************************************************************
2579 *
2580 * EM_GETHANDLE
2581 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002582 * Hopefully this won't fire back at us.
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002583 * We always start with a fixed buffer in the local heap.
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002584 * Despite of the documentation says that the local heap is used
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002585 * only if DS_LOCALEDIT flag is set, NT and 2000 always allocate
2586 * buffer on the local heap.
Alexandre Julliard889f7421997-04-15 17:19:52 +00002587 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002588 */
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00002589static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002590{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002591 HLOCAL hLocal;
Alexandre Julliard58199531994-04-21 01:20:00 +00002592
Alexandre Julliard889f7421997-04-15 17:19:52 +00002593 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002594 return 0;
2595
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002596 if(es->is_unicode)
2597 hLocal = es->hloc32W;
2598 else
2599 {
2600 if(!es->hloc32A)
2601 {
2602 CHAR *textA;
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002603 UINT countA, alloc_size;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002604 TRACE("Allocating 32-bit ANSI alias buffer\n");
James Hathewayba9b9642001-01-10 22:54:33 +00002605 countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002606 alloc_size = ROUND_TO_GROW(countA);
2607 if(!(es->hloc32A = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002608 {
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002609 ERR("Could not allocate %d bytes for 32-bit ANSI alias buffer\n", alloc_size);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002610 return 0;
2611 }
2612 textA = LocalLock(es->hloc32A);
James Hathewayba9b9642001-01-10 22:54:33 +00002613 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002614 LocalUnlock(es->hloc32A);
2615 }
2616 hLocal = es->hloc32A;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002617 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002618
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002619 TRACE("Returning %04X, LocalSize() = %d\n", hLocal, LocalSize(hLocal));
2620 return hLocal;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002621}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002622
2623
2624/*********************************************************************
2625 *
2626 * EM_GETHANDLE16
2627 *
2628 * Hopefully this won't fire back at us.
2629 * We always start with a buffer in 32 bit linear memory.
2630 * However, with this message a 16 bit application requests
2631 * a handle of 16 bit local heap memory, where it expects to find
2632 * the text.
2633 * It's a pitty that from this moment on we have to use this
2634 * local heap, because applications may rely on the handle
2635 * in the future.
2636 *
2637 * In this function we'll try to switch to local heap.
2638 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002639static HLOCAL16 EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002640{
Alexandre Julliardde424282001-08-10 22:51:42 +00002641 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002642 CHAR *textA;
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002643 UINT countA, alloc_size;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002644
Alexandre Julliard889f7421997-04-15 17:19:52 +00002645 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002646 return 0;
2647
Alexandre Julliard889f7421997-04-15 17:19:52 +00002648 if (es->hloc16)
2649 return es->hloc16;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002650
Alexandre Julliardde424282001-08-10 22:51:42 +00002651 if (!LOCAL_HeapSize(hInstance)) {
2652 if (!LocalInit16(hInstance, 0,
2653 GlobalSize16(hInstance))) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002654 ERR("could not initialize local heap\n");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002655 return 0;
2656 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002657 TRACE("local heap initialized\n");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002658 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002659
James Hathewayba9b9642001-01-10 22:54:33 +00002660 countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002661 alloc_size = ROUND_TO_GROW(countA);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002662
2663 TRACE("Allocating 16-bit ANSI alias buffer\n");
Alexandre Julliardde424282001-08-10 22:51:42 +00002664 if (!(es->hloc16 = LOCAL_Alloc(hInstance, LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002665 ERR("could not allocate new 16 bit buffer\n");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002666 return 0;
2667 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002668
Alexandre Julliardde424282001-08-10 22:51:42 +00002669 if (!(textA = (LPSTR)LOCAL_Lock(hInstance, es->hloc16))) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002670 ERR("could not lock new 16 bit buffer\n");
Alexandre Julliardde424282001-08-10 22:51:42 +00002671 LOCAL_Free(hInstance, es->hloc16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002672 es->hloc16 = 0;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002673 return 0;
2674 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002675
James Hathewayba9b9642001-01-10 22:54:33 +00002676 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
Alexandre Julliardde424282001-08-10 22:51:42 +00002677 LOCAL_Unlock(hInstance, es->hloc16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002678
Alexandre Julliardde424282001-08-10 22:51:42 +00002679 TRACE("Returning %04X, LocalSize() = %d\n", es->hloc16, LOCAL_Size(hInstance, es->hloc16));
Alexandre Julliard889f7421997-04-15 17:19:52 +00002680 return es->hloc16;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002681}
2682
Alexandre Julliard58199531994-04-21 01:20:00 +00002683
Alexandre Julliard329f0681996-04-14 13:21:20 +00002684/*********************************************************************
2685 *
2686 * EM_GETLINE
2687 *
2688 */
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002689static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002690{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002691 LPWSTR src;
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002692 INT line_len, dst_len;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002693 INT i;
Alexandre Julliard58199531994-04-21 01:20:00 +00002694
Alexandre Julliard889f7421997-04-15 17:19:52 +00002695 if (es->style & ES_MULTILINE) {
2696 if (line >= es->line_count)
2697 return 0;
2698 } else
2699 line = 0;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002700 i = EDIT_EM_LineIndex(es, line);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002701 src = es->text + i;
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002702 line_len = EDIT_EM_LineLength(es, i);
2703 dst_len = *(WORD *)lParam;
2704 if(unicode)
2705 {
2706 LPWSTR dst = (LPWSTR)lParam;
2707 if(dst_len <= line_len)
2708 {
2709 memcpy(dst, src, dst_len * sizeof(WCHAR));
2710 return dst_len;
2711 }
2712 else /* Append 0 if enough space */
2713 {
2714 memcpy(dst, src, line_len * sizeof(WCHAR));
2715 dst[line_len] = 0;
2716 return line_len;
2717 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002718 }
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002719 else
2720 {
2721 LPSTR dst = (LPSTR)lParam;
2722 INT ret;
2723 ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, dst, dst_len, NULL, NULL);
2724 if(!ret) /* Insufficient buffer size */
2725 return dst_len;
2726 if(ret < dst_len) /* Append 0 if enough space */
2727 dst[ret] = 0;
2728 return ret;
2729 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002730}
Alexandre Julliard58199531994-04-21 01:20:00 +00002731
Alexandre Julliard58199531994-04-21 01:20:00 +00002732
Alexandre Julliard329f0681996-04-14 13:21:20 +00002733/*********************************************************************
2734 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002735 * EM_GETSEL
2736 *
2737 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002738static LRESULT EDIT_EM_GetSel(EDITSTATE *es, LPUINT start, LPUINT end)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002739{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002740 UINT s = es->selection_start;
2741 UINT e = es->selection_end;
Alexandre Julliard58199531994-04-21 01:20:00 +00002742
Alexandre Julliarda3960291999-02-26 11:11:13 +00002743 ORDER_UINT(s, e);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002744 if (start)
2745 *start = s;
2746 if (end)
2747 *end = e;
2748 return MAKELONG(s, e);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002749}
2750
2751
2752/*********************************************************************
2753 *
2754 * EM_GETTHUMB
2755 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002756 * FIXME: is this right ? (or should it be only VSCROLL)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002757 * (and maybe only for edit controls that really have their
2758 * own scrollbars) (and maybe only for multiline controls ?)
2759 * All in all: very poorly documented
Alexandre Julliard329f0681996-04-14 13:21:20 +00002760 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002761 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002762static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002763{
Alexandre Julliardde424282001-08-10 22:51:42 +00002764 return MAKELONG(EDIT_WM_VScroll(hwnd, es, EM_GETTHUMB16, 0),
2765 EDIT_WM_HScroll(hwnd, es, EM_GETTHUMB16, 0));
Alexandre Julliard329f0681996-04-14 13:21:20 +00002766}
2767
2768
2769/*********************************************************************
2770 *
2771 * EM_LINEFROMCHAR
2772 *
2773 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002774static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002775{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002776 INT line;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002777 LINEDEF *line_def;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002778
Alexandre Julliard889f7421997-04-15 17:19:52 +00002779 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002780 return 0;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002781 if (index > (INT)strlenW(es->text))
Alexandre Julliard889f7421997-04-15 17:19:52 +00002782 return es->line_count - 1;
2783 if (index == -1)
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002784 index = min(es->selection_start, es->selection_end);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002785
2786 line = 0;
2787 line_def = es->first_line_def;
2788 index -= line_def->length;
2789 while ((index >= 0) && line_def->next) {
2790 line++;
2791 line_def = line_def->next;
2792 index -= line_def->length;
2793 }
2794 return line;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002795}
2796
2797
2798/*********************************************************************
2799 *
2800 * EM_LINEINDEX
2801 *
2802 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002803static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002804{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002805 INT line_index;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002806 LINEDEF *line_def;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002807
Alexandre Julliard889f7421997-04-15 17:19:52 +00002808 if (!(es->style & ES_MULTILINE))
2809 return 0;
2810 if (line >= es->line_count)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002811 return -1;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002812
2813 line_index = 0;
2814 line_def = es->first_line_def;
2815 if (line == -1) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002816 INT index = es->selection_end - line_def->length;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002817 while ((index >= 0) && line_def->next) {
2818 line_index += line_def->length;
2819 line_def = line_def->next;
2820 index -= line_def->length;
2821 }
2822 } else {
2823 while (line > 0) {
2824 line_index += line_def->length;
2825 line_def = line_def->next;
2826 line--;
2827 }
2828 }
2829 return line_index;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002830}
2831
2832
2833/*********************************************************************
2834 *
2835 * EM_LINELENGTH
2836 *
2837 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002838static INT EDIT_EM_LineLength(EDITSTATE *es, INT index)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002839{
Alexandre Julliard889f7421997-04-15 17:19:52 +00002840 LINEDEF *line_def;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002841
Alexandre Julliard889f7421997-04-15 17:19:52 +00002842 if (!(es->style & ES_MULTILINE))
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002843 return strlenW(es->text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002844
2845 if (index == -1) {
Andreas Mohra8edb3e2000-05-23 04:05:05 +00002846 /* get the number of remaining non-selected chars of selected lines */
Andreas Mohr07216db2001-11-13 21:29:38 +00002847 INT32 l; /* line number */
2848 INT32 li; /* index of first char in line */
Andreas Mohra8edb3e2000-05-23 04:05:05 +00002849 INT32 count;
Andreas Mohr07216db2001-11-13 21:29:38 +00002850 l = EDIT_EM_LineFromChar(es, es->selection_start);
Andreas Mohra8edb3e2000-05-23 04:05:05 +00002851 /* # chars before start of selection area */
Andreas Mohr07216db2001-11-13 21:29:38 +00002852 count = es->selection_start - EDIT_EM_LineIndex(es, l);
2853 l = EDIT_EM_LineFromChar(es, es->selection_end);
Andreas Mohra8edb3e2000-05-23 04:05:05 +00002854 /* # chars after end of selection */
Andreas Mohr07216db2001-11-13 21:29:38 +00002855 li = EDIT_EM_LineIndex(es, l);
2856 count += li + EDIT_EM_LineLength(es, li) - es->selection_end;
Andreas Mohra8edb3e2000-05-23 04:05:05 +00002857 return count;
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00002858 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002859 line_def = es->first_line_def;
2860 index -= line_def->length;
2861 while ((index >= 0) && line_def->next) {
2862 line_def = line_def->next;
2863 index -= line_def->length;
2864 }
2865 return line_def->net_length;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002866}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002867
Alexandre Julliard329f0681996-04-14 13:21:20 +00002868
2869/*********************************************************************
2870 *
2871 * EM_LINESCROLL
2872 *
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002873 * NOTE: dx is in average character widths, dy - in lines;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002874 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002875 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002876static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002877{
Alexandre Julliard889f7421997-04-15 17:19:52 +00002878 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002879 return FALSE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002880
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002881 dx *= es->char_width;
Alexandre Julliardde424282001-08-10 22:51:42 +00002882 return EDIT_EM_LineScroll_internal(hwnd, es, dx, dy);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002883}
2884
2885/*********************************************************************
2886 *
2887 * EDIT_EM_LineScroll_internal
2888 *
2889 * Version of EDIT_EM_LineScroll for internal use.
2890 * It doesn't refuse if ES_MULTILINE is set and assumes that
2891 * dx is in pixels, dy - in lines.
2892 *
2893 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002894static BOOL EDIT_EM_LineScroll_internal(HWND hwnd, EDITSTATE *es, INT dx, INT dy)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002895{
2896 INT nyoff;
2897 INT x_offset_in_pixels;
2898
2899 if (es->style & ES_MULTILINE)
2900 {
2901 x_offset_in_pixels = es->x_offset;
2902 }
2903 else
2904 {
2905 dy = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00002906 x_offset_in_pixels = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->x_offset, FALSE));
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002907 }
2908
2909 if (-dx > x_offset_in_pixels)
2910 dx = -x_offset_in_pixels;
2911 if (dx > es->text_width - x_offset_in_pixels)
2912 dx = es->text_width - x_offset_in_pixels;
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002913 nyoff = max(0, es->y_offset + dy);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002914 if (nyoff >= es->line_count)
2915 nyoff = es->line_count - 1;
2916 dy = (es->y_offset - nyoff) * es->line_height;
2917 if (dx || dy) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002918 RECT rc1;
2919 RECT rc;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002920
2921 es->y_offset = nyoff;
2922 if(es->style & ES_MULTILINE)
2923 es->x_offset += dx;
2924 else
2925 es->x_offset += dx / es->char_width;
2926
Alexandre Julliardde424282001-08-10 22:51:42 +00002927 GetClientRect(hwnd, &rc1);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002928 IntersectRect(&rc, &rc1, &es->format_rect);
Alexandre Julliardde424282001-08-10 22:51:42 +00002929 ScrollWindowEx(hwnd, -dx, dy,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002930 NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00002931 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00002932 EDIT_UpdateScrollInfo(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002933 }
2934 if (dx && !(es->flags & EF_HSCROLL_TRACK))
Alexandre Julliardde424282001-08-10 22:51:42 +00002935 EDIT_NOTIFY_PARENT(hwnd, es, EN_HSCROLL, "EN_HSCROLL");
Alexandre Julliard889f7421997-04-15 17:19:52 +00002936 if (dy && !(es->flags & EF_VSCROLL_TRACK))
Alexandre Julliardde424282001-08-10 22:51:42 +00002937 EDIT_NOTIFY_PARENT(hwnd, es, EN_VSCROLL, "EN_VSCROLL");
Alexandre Julliard889f7421997-04-15 17:19:52 +00002938 return TRUE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002939}
2940
2941
2942/*********************************************************************
2943 *
2944 * EM_POSFROMCHAR
2945 *
2946 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002947static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002948{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002949 INT len = strlenW(es->text);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002950 INT l;
2951 INT li;
2952 INT x;
2953 INT y = 0;
2954 HDC dc;
2955 HFONT old_font = 0;
2956 SIZE size;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002957
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002958 index = min(index, len);
Alexandre Julliardde424282001-08-10 22:51:42 +00002959 dc = GetDC(hwnd);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002960 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002961 old_font = SelectObject(dc, es->font);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002962 if (es->style & ES_MULTILINE) {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002963 l = EDIT_EM_LineFromChar(es, index);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002964 y = (l - es->y_offset) * es->line_height;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002965 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002966 if (after_wrap && (li == index) && l) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002967 INT l2 = l - 1;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002968 LINEDEF *line_def = es->first_line_def;
2969 while (l2) {
2970 line_def = line_def->next;
2971 l2--;
2972 }
2973 if (line_def->ending == END_WRAP) {
2974 l--;
2975 y -= es->line_height;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002976 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002977 }
2978 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002979 x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002980 es->tabs_count, es->tabs)) - es->x_offset;
2981 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002982 LPWSTR text = EDIT_GetPasswordPointer_SL(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002983 if (index < es->x_offset) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002984 GetTextExtentPoint32W(dc, text + index,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002985 es->x_offset - index, &size);
2986 x = -size.cx;
2987 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002988 GetTextExtentPoint32W(dc, text + es->x_offset,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002989 index - es->x_offset, &size);
2990 x = size.cx;
2991 }
2992 y = 0;
2993 if (es->style & ES_PASSWORD)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002994 HeapFree(GetProcessHeap(), 0, text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002995 }
2996 x += es->format_rect.left;
2997 y += es->format_rect.top;
2998 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002999 SelectObject(dc, old_font);
Alexandre Julliardde424282001-08-10 22:51:42 +00003000 ReleaseDC(hwnd, dc);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003001 return MAKELONG((INT16)x, (INT16)y);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003002}
3003
3004
3005/*********************************************************************
3006 *
3007 * EM_REPLACESEL
3008 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003009 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here
3010 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003011 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003012static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003013{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003014 UINT strl = strlenW(lpsz_replace);
3015 UINT tl = strlenW(es->text);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003016 UINT utl;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003017 UINT s;
3018 UINT e;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003019 UINT i;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003020 LPWSTR p;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003021 HRGN hrgn = 0;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003022
3023 TRACE("%s, can_undo %d, send_update %d\n",
3024 debugstr_w(lpsz_replace), can_undo, send_update);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003025
Alexandre Julliard889f7421997-04-15 17:19:52 +00003026 s = es->selection_start;
3027 e = es->selection_end;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003028
3029 if ((s == e) && !strl)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003030 return;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003031
Alexandre Julliarda3960291999-02-26 11:11:13 +00003032 ORDER_UINT(s, e);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003033
Alexandre Julliardde424282001-08-10 22:51:42 +00003034 if (!EDIT_MakeFit(hwnd, es, tl - (e - s) + strl))
Alexandre Julliard889f7421997-04-15 17:19:52 +00003035 return;
3036
Alexandre Julliard01d63461997-01-20 19:43:45 +00003037 if (e != s) {
3038 /* there is something to be deleted */
Andreas Mohr07216db2001-11-13 21:29:38 +00003039 TRACE("deleting stuff.\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00003040 if (can_undo) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003041 utl = strlenW(es->undo_text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003042 if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
Alexandre Julliard01d63461997-01-20 19:43:45 +00003043 /* undo-buffer is extended to the right */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003044 EDIT_MakeUndoFit(es, utl + e - s);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003045 strncpyW(es->undo_text + utl, es->text + s, e - s + 1);
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00003046 (es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003047 } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
Alexandre Julliard01d63461997-01-20 19:43:45 +00003048 /* undo-buffer is extended to the left */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003049 EDIT_MakeUndoFit(es, utl + e - s);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003050 for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003051 p[e - s] = p[0];
Alexandre Julliard889f7421997-04-15 17:19:52 +00003052 for (i = 0 , p = es->undo_text ; i < e - s ; i++)
3053 p[i] = (es->text + s)[i];
3054 es->undo_position = s;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003055 } else {
3056 /* new undo-buffer */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003057 EDIT_MakeUndoFit(es, e - s);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003058 strncpyW(es->undo_text, es->text + s, e - s + 1);
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00003059 es->undo_text[e - s] = 0; /* ensure 0 termination */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003060 es->undo_position = s;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003061 }
3062 /* any deletion makes the old insertion-undo invalid */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003063 es->undo_insert_count = 0;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003064 } else
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003065 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003066
3067 /* now delete */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003068 strcpyW(es->text + s, es->text + e);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003069 }
3070 if (strl) {
3071 /* there is an insertion */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003072 if (can_undo) {
3073 if ((s == es->undo_position) ||
3074 ((es->undo_insert_count) &&
3075 (s == es->undo_position + es->undo_insert_count)))
Alexandre Julliard01d63461997-01-20 19:43:45 +00003076 /*
3077 * insertion is new and at delete position or
3078 * an extension to either left or right
3079 */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003080 es->undo_insert_count += strl;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003081 else {
3082 /* new insertion undo */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003083 es->undo_position = s;
3084 es->undo_insert_count = strl;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003085 /* new insertion makes old delete-buffer invalid */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003086 *es->undo_text = '\0';
Alexandre Julliard01d63461997-01-20 19:43:45 +00003087 }
3088 } else
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003089 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003090
3091 /* now insert */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003092 tl = strlenW(es->text);
Andreas Mohr07216db2001-11-13 21:29:38 +00003093 TRACE("inserting stuff (tl %d, strl %d, selstart %d ('%s'), text '%s')\n", tl, strl, s, debugstr_w(es->text + s), debugstr_w(es->text));
Alexandre Julliard889f7421997-04-15 17:19:52 +00003094 for (p = es->text + tl ; p >= es->text + s ; p--)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003095 p[strl] = p[0];
Alexandre Julliard889f7421997-04-15 17:19:52 +00003096 for (i = 0 , p = es->text + s ; i < strl ; i++)
3097 p[i] = lpsz_replace[i];
3098 if(es->style & ES_UPPERCASE)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003099 CharUpperBuffW(p, strl);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003100 else if(es->style & ES_LOWERCASE)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003101 CharLowerBuffW(p, strl);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003102 s += strl;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003103 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003104 if (es->style & ES_MULTILINE)
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003105 {
3106 INT s = min(es->selection_start, es->selection_end);
3107
3108 hrgn = CreateRectRgn(0, 0, 0, 0);
Vincent Béron9a624912002-05-31 23:06:46 +00003109 EDIT_BuildLineDefs_ML(hwnd, es, s, s + strl,
Ulrich Czekalla2d382c62001-05-09 17:12:30 +00003110 strl - abs(es->selection_end - es->selection_start), hrgn);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003111 }
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003112 else
Alexandre Julliardde424282001-08-10 22:51:42 +00003113 EDIT_CalcLineWidth_SL(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003114
Alexandre Julliardde424282001-08-10 22:51:42 +00003115 EDIT_EM_SetSel(hwnd, es, s, s, FALSE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003116 es->flags |= EF_MODIFIED;
Ulrich Weigand6bfbc3d2000-10-23 00:38:10 +00003117 if (send_update) es->flags |= EF_UPDATE;
Alexandre Julliardde424282001-08-10 22:51:42 +00003118 EDIT_EM_ScrollCaret(hwnd, es);
Vincent Béron9a624912002-05-31 23:06:46 +00003119
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003120 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00003121 EDIT_UpdateScrollInfo(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003122
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003123 if (hrgn)
3124 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003125 EDIT_UpdateTextRegion(hwnd, es, hrgn, TRUE);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003126 DeleteObject(hrgn);
3127 }
3128 else
Alexandre Julliardde424282001-08-10 22:51:42 +00003129 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +00003130
3131 if(es->flags & EF_UPDATE)
3132 {
3133 es->flags &= ~EF_UPDATE;
Alexandre Julliardde424282001-08-10 22:51:42 +00003134 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +00003135 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003136}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003137
Alexandre Julliard329f0681996-04-14 13:21:20 +00003138
3139/*********************************************************************
3140 *
3141 * EM_SCROLL
Alexandre Julliard889f7421997-04-15 17:19:52 +00003142 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003143 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003144static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003145{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003146 INT dy;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003147
Alexandre Julliard889f7421997-04-15 17:19:52 +00003148 if (!(es->style & ES_MULTILINE))
3149 return (LRESULT)FALSE;
3150
3151 dy = 0;
3152
3153 switch (action) {
3154 case SB_LINEUP:
3155 if (es->y_offset)
3156 dy = -1;
3157 break;
3158 case SB_LINEDOWN:
3159 if (es->y_offset < es->line_count - 1)
3160 dy = 1;
3161 break;
3162 case SB_PAGEUP:
3163 if (es->y_offset)
3164 dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
3165 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003166 case SB_PAGEDOWN:
Alexandre Julliard889f7421997-04-15 17:19:52 +00003167 if (es->y_offset < es->line_count - 1)
3168 dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3169 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003170 default:
Alexandre Julliard889f7421997-04-15 17:19:52 +00003171 return (LRESULT)FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003172 }
3173 if (dy) {
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003174 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3175 /* check if we are going to move too far */
3176 if(es->y_offset + dy > es->line_count - vlc)
3177 dy = es->line_count - vlc - es->y_offset;
3178
3179 /* Notification is done in EDIT_EM_LineScroll */
3180 if(dy)
Alexandre Julliardde424282001-08-10 22:51:42 +00003181 EDIT_EM_LineScroll(hwnd, es, 0, dy);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003182 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003183 return MAKELONG((INT16)dy, (BOOL16)TRUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003184}
3185
3186
3187/*********************************************************************
3188 *
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003189 * EM_SCROLLCARET
3190 *
3191 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003192static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003193{
3194 if (es->style & ES_MULTILINE) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003195 INT l;
3196 INT li;
3197 INT vlc;
3198 INT ww;
3199 INT cw = es->char_width;
3200 INT x;
3201 INT dy = 0;
3202 INT dx = 0;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003203
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003204 l = EDIT_EM_LineFromChar(es, es->selection_end);
3205 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliardde424282001-08-10 22:51:42 +00003206 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP));
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003207 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
3208 if (l >= es->y_offset + vlc)
3209 dy = l - vlc + 1 - es->y_offset;
3210 if (l < es->y_offset)
3211 dy = l - es->y_offset;
3212 ww = es->format_rect.right - es->format_rect.left;
3213 if (x < es->format_rect.left)
3214 dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
3215 if (x > es->format_rect.right)
3216 dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
3217 if (dy || dx)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003218 {
3219 /* check if we are going to move too far */
3220 if(es->x_offset + dx + ww > es->text_width)
3221 dx = es->text_width - ww - es->x_offset;
3222 if(dx || dy)
Alexandre Julliardde424282001-08-10 22:51:42 +00003223 EDIT_EM_LineScroll_internal(hwnd, es, dx, dy);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003224 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003225 } else {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003226 INT x;
3227 INT goal;
3228 INT format_width;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003229
3230 if (!(es->style & ES_AUTOHSCROLL))
3231 return;
3232
Alexandre Julliardde424282001-08-10 22:51:42 +00003233 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003234 format_width = es->format_rect.right - es->format_rect.left;
3235 if (x < es->format_rect.left) {
3236 goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
3237 do {
3238 es->x_offset--;
Alexandre Julliardde424282001-08-10 22:51:42 +00003239 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003240 } while ((x < goal) && es->x_offset);
3241 /* FIXME: use ScrollWindow() somehow to improve performance */
Alexandre Julliardde424282001-08-10 22:51:42 +00003242 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003243 } else if (x > es->format_rect.right) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003244 INT x_last;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003245 INT len = strlenW(es->text);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003246 goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
3247 do {
3248 es->x_offset++;
Alexandre Julliardde424282001-08-10 22:51:42 +00003249 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE));
3250 x_last = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, len, FALSE));
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003251 } while ((x > goal) && (x_last > es->format_rect.right));
3252 /* FIXME: use ScrollWindow() somehow to improve performance */
Alexandre Julliardde424282001-08-10 22:51:42 +00003253 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003254 }
3255 }
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003256
3257 if(es->flags & EF_FOCUSED)
Alexandre Julliardde424282001-08-10 22:51:42 +00003258 EDIT_SetCaretPos(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003259}
3260
3261
3262/*********************************************************************
3263 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003264 * EM_SETHANDLE
3265 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003266 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
3267 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003268 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003269static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003270{
Alexandre Julliardde424282001-08-10 22:51:42 +00003271 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
3272
Alexandre Julliard889f7421997-04-15 17:19:52 +00003273 if (!(es->style & ES_MULTILINE))
3274 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003275
Alexandre Julliard889f7421997-04-15 17:19:52 +00003276 if (!hloc) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003277 WARN("called with NULL handle\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00003278 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003279 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003280
Alexandre Julliardde424282001-08-10 22:51:42 +00003281 EDIT_UnlockBuffer(hwnd, es, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003282
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003283 if(es->hloc16)
3284 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003285 LOCAL_Free(hInstance, es->hloc16);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003286 es->hloc16 = (HLOCAL16)NULL;
3287 }
3288
3289 if(es->is_unicode)
3290 {
3291 if(es->hloc32A)
3292 {
3293 LocalFree(es->hloc32A);
3294 es->hloc32A = (HLOCAL)NULL;
3295 }
3296 es->hloc32W = hloc;
3297 }
3298 else
3299 {
3300 INT countW, countA;
3301 HLOCAL hloc32W_new;
3302 WCHAR *textW;
3303 CHAR *textA;
3304
3305 countA = LocalSize(hloc);
3306 textA = LocalLock(hloc);
3307 countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
3308 if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
3309 {
3310 ERR("Could not allocate new unicode buffer\n");
3311 return;
3312 }
3313 textW = LocalLock(hloc32W_new);
3314 MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
3315 LocalUnlock(hloc32W_new);
3316 LocalUnlock(hloc);
3317
3318 if(es->hloc32W)
3319 LocalFree(es->hloc32W);
3320
3321 es->hloc32W = hloc32W_new;
3322 es->hloc32A = hloc;
3323 }
3324
3325 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
3326
Alexandre Julliardde424282001-08-10 22:51:42 +00003327 EDIT_LockBuffer(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003328
3329 es->x_offset = es->y_offset = 0;
3330 es->selection_start = es->selection_end = 0;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003331 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003332 es->flags &= ~EF_MODIFIED;
3333 es->flags &= ~EF_UPDATE;
Alexandre Julliardde424282001-08-10 22:51:42 +00003334 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
3335 EDIT_UpdateText(hwnd, es, NULL, TRUE);
3336 EDIT_EM_ScrollCaret(hwnd, es);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003337 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00003338 EDIT_UpdateScrollInfo(hwnd, es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003339}
3340
3341
3342/*********************************************************************
3343 *
3344 * EM_SETHANDLE16
3345 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003346 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
3347 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003348 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003349static void EDIT_EM_SetHandle16(HWND hwnd, EDITSTATE *es, HLOCAL16 hloc)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003350{
Alexandre Julliardde424282001-08-10 22:51:42 +00003351 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003352 INT countW, countA;
3353 HLOCAL hloc32W_new;
3354 WCHAR *textW;
3355 CHAR *textA;
3356
Alexandre Julliard889f7421997-04-15 17:19:52 +00003357 if (!(es->style & ES_MULTILINE))
3358 return;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003359
Alexandre Julliard889f7421997-04-15 17:19:52 +00003360 if (!hloc) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003361 WARN("called with NULL handle\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00003362 return;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003363 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003364
Alexandre Julliardde424282001-08-10 22:51:42 +00003365 EDIT_UnlockBuffer(hwnd, es, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003366
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003367 if(es->hloc32A)
3368 {
3369 LocalFree(es->hloc32A);
3370 es->hloc32A = (HLOCAL)NULL;
3371 }
3372
Alexandre Julliardde424282001-08-10 22:51:42 +00003373 countA = LOCAL_Size(hInstance, hloc);
3374 textA = LOCAL_Lock(hInstance, hloc);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003375 countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
3376 if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
3377 {
3378 ERR("Could not allocate new unicode buffer\n");
3379 return;
3380 }
3381 textW = LocalLock(hloc32W_new);
3382 MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
3383 LocalUnlock(hloc32W_new);
Alexandre Julliardde424282001-08-10 22:51:42 +00003384 LOCAL_Unlock(hInstance, hloc);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003385
3386 if(es->hloc32W)
3387 LocalFree(es->hloc32W);
3388
3389 es->hloc32W = hloc32W_new;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003390 es->hloc16 = hloc;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003391
3392 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
3393
Alexandre Julliardde424282001-08-10 22:51:42 +00003394 EDIT_LockBuffer(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003395
3396 es->x_offset = es->y_offset = 0;
3397 es->selection_start = es->selection_end = 0;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003398 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003399 es->flags &= ~EF_MODIFIED;
3400 es->flags &= ~EF_UPDATE;
Alexandre Julliardde424282001-08-10 22:51:42 +00003401 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
3402 EDIT_UpdateText(hwnd, es, NULL, TRUE);
3403 EDIT_EM_ScrollCaret(hwnd, es);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003404 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00003405 EDIT_UpdateScrollInfo(hwnd, es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003406}
3407
3408
3409/*********************************************************************
3410 *
3411 * EM_SETLIMITTEXT
3412 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003413 * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
3414 * However, the windows version is not complied to yet in all of edit.c
3415 *
Aric Stewart08e69392002-08-16 01:41:32 +00003416 * Additionally as the wrapper for RichEdit controls we need larger buffers
3417 * at present -1 will represent nolimit
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003418 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003419static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003420{
Aric Stewart08e69392002-08-16 01:41:32 +00003421 if (limit == 0xFFFFFFFF)
3422 es->buffer_limit = -1;
3423 else if (es->style & ES_MULTILINE) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00003424 if (limit)
Francois Gouget6d77d3a2000-03-25 21:44:35 +00003425 es->buffer_limit = min(limit, BUFLIMIT_MULTI);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003426 else
Alexandre Julliard889f7421997-04-15 17:19:52 +00003427 es->buffer_limit = BUFLIMIT_MULTI;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003428 } else {
Alexandre Julliard889f7421997-04-15 17:19:52 +00003429 if (limit)
Francois Gouget6d77d3a2000-03-25 21:44:35 +00003430 es->buffer_limit = min(limit, BUFLIMIT_SINGLE);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003431 else
Alexandre Julliard889f7421997-04-15 17:19:52 +00003432 es->buffer_limit = BUFLIMIT_SINGLE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003433 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003434}
3435
3436
3437/*********************************************************************
3438 *
3439 * EM_SETMARGINS
Vincent Béron9a624912002-05-31 23:06:46 +00003440 *
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003441 * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
Pavel Roskindc75bd41999-04-01 11:56:41 +00003442 * action wParam despite what the docs say. EC_USEFONTINFO means one third
3443 * of the char's width, according to the new docs.
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003444 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003445 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003446static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
Alexandre Julliarda3960291999-02-26 11:11:13 +00003447 INT left, INT right)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003448{
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003449 if (action & EC_LEFTMARGIN) {
3450 if (left != EC_USEFONTINFO)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003451 es->left_margin = left;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003452 else
Pavel Roskindc75bd41999-04-01 11:56:41 +00003453 es->left_margin = es->char_width / 3;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003454 }
3455
3456 if (action & EC_RIGHTMARGIN) {
3457 if (right != EC_USEFONTINFO)
3458 es->right_margin = right;
3459 else
Pavel Roskindc75bd41999-04-01 11:56:41 +00003460 es->right_margin = es->char_width / 3;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003461 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003462 TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
Alexandre Julliard58199531994-04-21 01:20:00 +00003463}
3464
Alexandre Julliard329f0681996-04-14 13:21:20 +00003465
3466/*********************************************************************
3467 *
3468 * EM_SETPASSWORDCHAR
3469 *
3470 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003471static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, WCHAR c)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003472{
Alexandre Julliardde424282001-08-10 22:51:42 +00003473 LONG style;
3474
Alexandre Julliard889f7421997-04-15 17:19:52 +00003475 if (es->style & ES_MULTILINE)
3476 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003477
Alexandre Julliard889f7421997-04-15 17:19:52 +00003478 if (es->password_char == c)
3479 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003480
Alexandre Julliardde424282001-08-10 22:51:42 +00003481 style = GetWindowLongA( hwnd, GWL_STYLE );
Alexandre Julliard889f7421997-04-15 17:19:52 +00003482 es->password_char = c;
3483 if (c) {
Alexandre Julliardde424282001-08-10 22:51:42 +00003484 SetWindowLongA( hwnd, GWL_STYLE, style | ES_PASSWORD );
3485 es->style |= ES_PASSWORD;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003486 } else {
Alexandre Julliardde424282001-08-10 22:51:42 +00003487 SetWindowLongA( hwnd, GWL_STYLE, style & ~ES_PASSWORD );
3488 es->style &= ~ES_PASSWORD;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003489 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003490 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003491}
3492
3493
3494/*********************************************************************
3495 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003496 * EDIT_EM_SetSel
3497 *
3498 * note: unlike the specs say: the order of start and end
3499 * _is_ preserved in Windows. (i.e. start can be > end)
3500 * In other words: this handler is OK
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003501 *
3502 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003503static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003504{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003505 UINT old_start = es->selection_start;
3506 UINT old_end = es->selection_end;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003507 UINT len = strlenW(es->text);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003508
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003509 if (start == (UINT)-1) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00003510 start = es->selection_end;
3511 end = es->selection_end;
3512 } else {
Francois Gouget6d77d3a2000-03-25 21:44:35 +00003513 start = min(start, len);
3514 end = min(end, len);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003515 }
3516 es->selection_start = start;
3517 es->selection_end = end;
3518 if (after_wrap)
3519 es->flags |= EF_AFTER_WRAP;
3520 else
3521 es->flags &= ~EF_AFTER_WRAP;
Andreas Mohra8edb3e2000-05-23 04:05:05 +00003522/* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003523 ORDER_UINT(start, end);
3524 ORDER_UINT(end, old_end);
3525 ORDER_UINT(start, old_start);
3526 ORDER_UINT(old_start, old_end);
Alexandre Julliarde658d821997-11-30 17:45:40 +00003527 if (end != old_start)
3528 {
3529/*
Vincent Béron9a624912002-05-31 23:06:46 +00003530 * One can also do
Alexandre Julliarde658d821997-11-30 17:45:40 +00003531 * ORDER_UINT32(end, old_start);
Alexandre Julliardde424282001-08-10 22:51:42 +00003532 * EDIT_InvalidateText(hwnd, es, start, end);
3533 * EDIT_InvalidateText(hwnd, es, old_start, old_end);
Vincent Béron9a624912002-05-31 23:06:46 +00003534 * in place of the following if statement.
Alexandre Julliarde658d821997-11-30 17:45:40 +00003535 */
3536 if (old_start > end )
3537 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003538 EDIT_InvalidateText(hwnd, es, start, end);
3539 EDIT_InvalidateText(hwnd, es, old_start, old_end);
Alexandre Julliarde658d821997-11-30 17:45:40 +00003540 }
3541 else
3542 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003543 EDIT_InvalidateText(hwnd, es, start, old_start);
3544 EDIT_InvalidateText(hwnd, es, end, old_end);
Alexandre Julliarde658d821997-11-30 17:45:40 +00003545 }
3546 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003547 else EDIT_InvalidateText(hwnd, es, start, old_end);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003548}
3549
3550
3551/*********************************************************************
3552 *
3553 * EM_SETTABSTOPS
3554 *
3555 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003556static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003557{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003558 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003559 return FALSE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003560 if (es->tabs)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003561 HeapFree(GetProcessHeap(), 0, es->tabs);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003562 es->tabs_count = count;
3563 if (!count)
3564 es->tabs = NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003565 else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003566 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
Alexandre Julliarda3960291999-02-26 11:11:13 +00003567 memcpy(es->tabs, tabs, count * sizeof(INT));
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003568 }
3569 return TRUE;
3570}
3571
3572
3573/*********************************************************************
3574 *
3575 * EM_SETTABSTOPS16
3576 *
3577 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003578static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003579{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003580 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003581 return FALSE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003582 if (es->tabs)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003583 HeapFree(GetProcessHeap(), 0, es->tabs);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003584 es->tabs_count = count;
3585 if (!count)
3586 es->tabs = NULL;
3587 else {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003588 INT i;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003589 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
Alexandre Julliard889f7421997-04-15 17:19:52 +00003590 for (i = 0 ; i < count ; i++)
3591 es->tabs[i] = *tabs++;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003592 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003593 return TRUE;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003594}
3595
3596
3597/*********************************************************************
3598 *
3599 * EM_SETWORDBREAKPROC
3600 *
3601 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003602static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, LPARAM lParam)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003603{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003604 if (es->word_break_proc == (void *)lParam)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003605 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003606
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003607 es->word_break_proc = (void *)lParam;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003608 es->word_break_proc16 = NULL;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003609
Alexandre Julliard889f7421997-04-15 17:19:52 +00003610 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
Alexandre Julliardde424282001-08-10 22:51:42 +00003611 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
3612 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003613 }
3614}
3615
3616
3617/*********************************************************************
3618 *
3619 * EM_SETWORDBREAKPROC16
3620 *
3621 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003622static void EDIT_EM_SetWordBreakProc16(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROC16 wbp)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003623{
3624 if (es->word_break_proc16 == wbp)
3625 return;
3626
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003627 es->word_break_proc = NULL;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003628 es->word_break_proc16 = wbp;
3629 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
Alexandre Julliardde424282001-08-10 22:51:42 +00003630 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
3631 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003632 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003633}
3634
3635
3636/*********************************************************************
3637 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003638 * EM_UNDO / WM_UNDO
Alexandre Julliard329f0681996-04-14 13:21:20 +00003639 *
3640 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003641static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003642{
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003643 INT ulength;
3644 LPWSTR utext;
3645
3646 /* Protect read-only edit control from modification */
3647 if(es->style & ES_READONLY)
3648 return FALSE;
3649
3650 ulength = strlenW(es->undo_text);
3651 utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR));
Alexandre Julliard889f7421997-04-15 17:19:52 +00003652
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003653 strcpyW(utext, es->undo_text);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003654
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003655 TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003656 es->undo_insert_count, debugstr_w(utext));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003657
Alexandre Julliardde424282001-08-10 22:51:42 +00003658 EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003659 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliardde424282001-08-10 22:51:42 +00003660 EDIT_EM_ReplaceSel(hwnd, es, TRUE, utext, FALSE);
3661 EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
Rein Klazes9d4ae0e2001-04-02 19:13:24 +00003662 /* send the notification after the selection start and end are set */
Alexandre Julliardde424282001-08-10 22:51:42 +00003663 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
3664 EDIT_EM_ScrollCaret(hwnd, es);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003665 HeapFree(GetProcessHeap(), 0, utext);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003666
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003667 TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003668 es->undo_insert_count, debugstr_w(es->undo_text));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003669 return TRUE;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003670}
3671
3672
3673/*********************************************************************
3674 *
3675 * WM_CHAR
3676 *
3677 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003678static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, WCHAR c)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003679{
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003680 BOOL control;
3681
3682 /* Protect read-only edit control from modification */
3683 if(es->style & ES_READONLY)
3684 return;
3685
3686 control = GetKeyState(VK_CONTROL) & 0x8000;
3687
Alexandre Julliard329f0681996-04-14 13:21:20 +00003688 switch (c) {
3689 case '\r':
Stephane Lussier5ca2ec41999-09-27 11:45:07 +00003690 /* If the edit doesn't want the return and it's not a multiline edit, do nothing */
3691 if(!(es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN))
Pascal Lessardaed79e51999-09-10 13:58:34 +00003692 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003693 case '\n':
Alexandre Julliard889f7421997-04-15 17:19:52 +00003694 if (es->style & ES_MULTILINE) {
3695 if (es->style & ES_READONLY) {
Alexandre Julliardde424282001-08-10 22:51:42 +00003696 EDIT_MoveHome(hwnd, es, FALSE);
3697 EDIT_MoveDown_ML(hwnd, es, FALSE);
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00003698 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003699 static const WCHAR cr_lfW[] = {'\r','\n',0};
Alexandre Julliardde424282001-08-10 22:51:42 +00003700 EDIT_EM_ReplaceSel(hwnd, es, TRUE, cr_lfW, TRUE);
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00003701 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003702 }
3703 break;
3704 case '\t':
Alexandre Julliard889f7421997-04-15 17:19:52 +00003705 if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00003706 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003707 static const WCHAR tabW[] = {'\t',0};
Alexandre Julliardde424282001-08-10 22:51:42 +00003708 EDIT_EM_ReplaceSel(hwnd, es, TRUE, tabW, TRUE);
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00003709 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003710 break;
Pascal Lessard6fe38e51999-09-03 15:02:48 +00003711 case VK_BACK:
3712 if (!(es->style & ES_READONLY) && !control) {
3713 if (es->selection_start != es->selection_end)
Alexandre Julliardde424282001-08-10 22:51:42 +00003714 EDIT_WM_Clear(hwnd, es);
Pascal Lessard6fe38e51999-09-03 15:02:48 +00003715 else {
3716 /* delete character left of caret */
Alexandre Julliardde424282001-08-10 22:51:42 +00003717 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
3718 EDIT_MoveBackward(hwnd, es, TRUE);
3719 EDIT_WM_Clear(hwnd, es);
Pascal Lessard6fe38e51999-09-03 15:02:48 +00003720 }
3721 }
3722 break;
Ulrich Czekallac804e3e2000-05-23 21:16:07 +00003723 case 0x03: /* ^C */
Alexandre Julliardde424282001-08-10 22:51:42 +00003724 SendMessageW(hwnd, WM_COPY, 0, 0);
Susan Farley86d0b032000-05-05 18:21:02 +00003725 break;
Ulrich Czekallac804e3e2000-05-23 21:16:07 +00003726 case 0x16: /* ^V */
Alexandre Julliardde424282001-08-10 22:51:42 +00003727 SendMessageW(hwnd, WM_PASTE, 0, 0);
Susan Farley86d0b032000-05-05 18:21:02 +00003728 break;
Ulrich Czekallac804e3e2000-05-23 21:16:07 +00003729 case 0x18: /* ^X */
Alexandre Julliardde424282001-08-10 22:51:42 +00003730 SendMessageW(hwnd, WM_CUT, 0, 0);
Susan Farley86d0b032000-05-05 18:21:02 +00003731 break;
Vincent Béron9a624912002-05-31 23:06:46 +00003732
Alexandre Julliard329f0681996-04-14 13:21:20 +00003733 default:
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003734 if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) {
3735 WCHAR str[2];
Alexandre Julliard329f0681996-04-14 13:21:20 +00003736 str[0] = c;
3737 str[1] = '\0';
Alexandre Julliardde424282001-08-10 22:51:42 +00003738 EDIT_EM_ReplaceSel(hwnd, es, TRUE, str, TRUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003739 }
3740 break;
3741 }
Alexandre Julliard01d63461997-01-20 19:43:45 +00003742}
3743
3744
3745/*********************************************************************
3746 *
3747 * WM_COMMAND
3748 *
3749 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003750static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND control)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003751{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003752 if (code || control)
3753 return;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003754
Alexandre Julliard889f7421997-04-15 17:19:52 +00003755 switch (id) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003756 case EM_UNDO:
Alexandre Julliardde424282001-08-10 22:51:42 +00003757 EDIT_EM_Undo(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003758 break;
3759 case WM_CUT:
Alexandre Julliardde424282001-08-10 22:51:42 +00003760 EDIT_WM_Cut(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003761 break;
3762 case WM_COPY:
Alexandre Julliardde424282001-08-10 22:51:42 +00003763 EDIT_WM_Copy(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003764 break;
3765 case WM_PASTE:
Alexandre Julliardde424282001-08-10 22:51:42 +00003766 EDIT_WM_Paste(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003767 break;
3768 case WM_CLEAR:
Alexandre Julliardde424282001-08-10 22:51:42 +00003769 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003770 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003771 case EM_SETSEL:
Alexandre Julliardde424282001-08-10 22:51:42 +00003772 EDIT_EM_SetSel(hwnd, es, 0, (UINT)-1, FALSE);
3773 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003774 break;
3775 default:
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003776 ERR("unknown menu item, please report\n");
Alexandre Julliard01d63461997-01-20 19:43:45 +00003777 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003778 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003779}
3780
3781
3782/*********************************************************************
3783 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003784 * WM_CONTEXTMENU
3785 *
3786 * Note: the resource files resource/sysres_??.rc cannot define a
3787 * single popup menu. Hence we use a (dummy) menubar
3788 * containing the single popup menu as its first item.
3789 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003790 * FIXME: the message identifiers have been chosen arbitrarily,
3791 * hence we use MF_BYPOSITION.
3792 * We might as well use the "real" values (anybody knows ?)
3793 * The menu definition is in resources/sysres_??.rc.
3794 * Once these are OK, we better use MF_BYCOMMAND here
3795 * (as we do in EDIT_WM_Command()).
3796 *
3797 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003798static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, INT x, INT y)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003799{
Bertho Stultiensd1895a71999-04-25 18:31:35 +00003800 HMENU menu = LoadMenuA(GetModuleHandleA("USER32"), "EDITMENU");
Alexandre Julliarda3960291999-02-26 11:11:13 +00003801 HMENU popup = GetSubMenu(menu, 0);
3802 UINT start = es->selection_start;
3803 UINT end = es->selection_end;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003804
Alexandre Julliarda3960291999-02-26 11:11:13 +00003805 ORDER_UINT(start, end);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003806
3807 /* undo */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003808 EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003809 /* cut */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003810 EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003811 /* copy */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003812 EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003813 /* paste */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003814 EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003815 /* delete */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003816 EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003817 /* select all */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003818 EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != strlenW(es->text)) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003819
Alexandre Julliardde424282001-08-10 22:51:42 +00003820 TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, hwnd, NULL);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003821 DestroyMenu(menu);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003822}
3823
Alexandre Julliard889f7421997-04-15 17:19:52 +00003824
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003825/*********************************************************************
3826 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003827 * WM_COPY
3828 *
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003829 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003830static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003831{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003832 INT s = es->selection_start;
3833 INT e = es->selection_end;
3834 HGLOBAL hdst;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003835 LPWSTR dst;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003836
Alexandre Julliard889f7421997-04-15 17:19:52 +00003837 if (e == s)
3838 return;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003839 ORDER_INT(s, e);
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00003840 hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)(e - s + 1) * sizeof(WCHAR));
Alexandre Julliarda3960291999-02-26 11:11:13 +00003841 dst = GlobalLock(hdst);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003842 strncpyW(dst, es->text + s, e - s);
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00003843 dst[e - s] = 0; /* ensure 0 termination */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003844 TRACE("%s\n", debugstr_w(dst));
Alexandre Julliarda3960291999-02-26 11:11:13 +00003845 GlobalUnlock(hdst);
Alexandre Julliardde424282001-08-10 22:51:42 +00003846 OpenClipboard(hwnd);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003847 EmptyClipboard();
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003848 SetClipboardData(CF_UNICODETEXT, hdst);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003849 CloseClipboard();
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003850}
Alexandre Julliard01d63461997-01-20 19:43:45 +00003851
Alexandre Julliard889f7421997-04-15 17:19:52 +00003852
3853/*********************************************************************
3854 *
3855 * WM_CREATE
3856 *
3857 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003858static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCWSTR name)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003859{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003860 TRACE("%s\n", debugstr_w(name));
Pascal Lessarddde4d611999-08-15 16:30:11 +00003861 /*
3862 * To initialize some final structure members, we call some helper
3863 * functions. However, since the EDITSTATE is not consistent (i.e.
3864 * not fully initialized), we should be very careful which
3865 * functions can be called, and in what order.
3866 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003867 EDIT_WM_SetFont(hwnd, es, 0, FALSE);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003868 EDIT_EM_EmptyUndoBuffer(es);
Andreas Mohr5f5213a1999-02-13 09:04:22 +00003869
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003870 if (name && *name) {
Alexandre Julliardde424282001-08-10 22:51:42 +00003871 EDIT_EM_ReplaceSel(hwnd, es, FALSE, name, FALSE);
Pascal Lessarddde4d611999-08-15 16:30:11 +00003872 /* if we insert text to the editline, the text scrolls out
3873 * of the window, as the caret is placed after the insert
3874 * pos normally; thus we reset es->selection... to 0 and
3875 * update caret
3876 */
3877 es->selection_start = es->selection_end = 0;
Aric Stewart2e0d8cf2002-08-20 00:24:17 +00003878 /* Adobe Photoshop does NOT like this. and MSDN says that EN_CHANGE
3879 * Messages are only to be sent when the USER does something to
3880 * change the contents. So I am removing this EN_CHANGE
3881 *
3882 * EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
3883 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003884 EDIT_EM_ScrollCaret(hwnd, es);
Pascal Lessarddde4d611999-08-15 16:30:11 +00003885 }
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003886 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00003887 EDIT_UpdateScrollInfo(hwnd, es);
Pascal Lessarddde4d611999-08-15 16:30:11 +00003888 return 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003889}
3890
3891
3892/*********************************************************************
3893 *
3894 * WM_DESTROY
3895 *
3896 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003897static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003898{
Alexandre Julliardde424282001-08-10 22:51:42 +00003899 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE );
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003900 LINEDEF *pc, *pp;
3901
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003902 if (es->hloc32W) {
3903 while (LocalUnlock(es->hloc32W)) ;
3904 LocalFree(es->hloc32W);
3905 }
3906 if (es->hloc32A) {
3907 while (LocalUnlock(es->hloc32A)) ;
3908 LocalFree(es->hloc32A);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003909 }
3910 if (es->hloc16) {
Alexandre Julliardde424282001-08-10 22:51:42 +00003911 while (LOCAL_Unlock(hInstance, es->hloc16)) ;
3912 LOCAL_Free(hInstance, es->hloc16);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003913 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00003914
3915 pc = es->first_line_def;
3916 while (pc)
3917 {
3918 pp = pc->next;
3919 HeapFree(GetProcessHeap(), 0, pc);
3920 pc = pp;
3921 }
3922
Alexandre Julliardde424282001-08-10 22:51:42 +00003923 SetWindowLongA( hwnd, 0, 0 );
Alexandre Julliard889f7421997-04-15 17:19:52 +00003924 HeapFree(GetProcessHeap(), 0, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003925}
3926
3927
3928/*********************************************************************
3929 *
3930 * WM_ERASEBKGND
3931 *
3932 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003933static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003934{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003935 HBRUSH brush;
3936 RECT rc;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003937
Alexandre Julliard198746d2000-08-14 14:29:22 +00003938 if ( get_app_version() >= 0x40000 &&(
Rein Klazes077ec0c1999-11-10 19:55:29 +00003939 !es->bEnableState || (es->style & ES_READONLY)))
Alexandre Julliardde424282001-08-10 22:51:42 +00003940 brush = (HBRUSH)EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
Luc Tourangeaudf5fbc71999-04-03 11:14:30 +00003941 else
Alexandre Julliardde424282001-08-10 22:51:42 +00003942 brush = (HBRUSH)EDIT_SEND_CTLCOLOR(hwnd, dc);
Luc Tourangeaudf5fbc71999-04-03 11:14:30 +00003943
3944 if (!brush)
3945 brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003946
Alexandre Julliardde424282001-08-10 22:51:42 +00003947 GetClientRect(hwnd, &rc);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003948 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
3949 GetClipBox(dc, &rc);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003950 /*
3951 * FIXME: specs say that we should UnrealizeObject() the brush,
3952 * but the specs of UnrealizeObject() say that we shouldn't
3953 * unrealize a stock object. The default brush that
3954 * DefWndProc() returns is ... a stock object.
3955 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003956 FillRect(dc, &rc, brush);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003957 return -1;
3958}
3959
3960
3961/*********************************************************************
3962 *
3963 * WM_GETTEXT
3964 *
3965 */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003966static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003967{
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00003968 if(!count) return 0;
3969
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003970 if(unicode)
3971 {
3972 LPWSTR textW = (LPWSTR)lParam;
Alexandre Julliard331bf3d2002-08-15 23:28:45 +00003973 lstrcpynW(textW, es->text, count);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003974 return strlenW(textW);
3975 }
3976 else
3977 {
3978 LPSTR textA = (LPSTR)lParam;
Alexandre Julliard331bf3d2002-08-15 23:28:45 +00003979 if (!WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL))
3980 textA[count - 1] = 0; /* ensure 0 termination */
Dmitry Timoshkov785203c2001-01-11 20:17:21 +00003981 return strlen(textA);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003982 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003983}
3984
Alexandre Julliard889f7421997-04-15 17:19:52 +00003985/*********************************************************************
3986 *
3987 * WM_HSCROLL
3988 *
3989 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003990static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003991{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003992 INT dx;
3993 INT fw;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003994
3995 if (!(es->style & ES_MULTILINE))
3996 return 0;
3997
3998 if (!(es->style & ES_AUTOHSCROLL))
3999 return 0;
4000
Alexandre Julliard889f7421997-04-15 17:19:52 +00004001 dx = 0;
4002 fw = es->format_rect.right - es->format_rect.left;
4003 switch (action) {
4004 case SB_LINELEFT:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004005 TRACE("SB_LINELEFT\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004006 if (es->x_offset)
4007 dx = -es->char_width;
4008 break;
4009 case SB_LINERIGHT:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004010 TRACE("SB_LINERIGHT\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004011 if (es->x_offset < es->text_width)
4012 dx = es->char_width;
4013 break;
4014 case SB_PAGELEFT:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004015 TRACE("SB_PAGELEFT\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004016 if (es->x_offset)
4017 dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
4018 break;
4019 case SB_PAGERIGHT:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004020 TRACE("SB_PAGERIGHT\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004021 if (es->x_offset < es->text_width)
4022 dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
4023 break;
4024 case SB_LEFT:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004025 TRACE("SB_LEFT\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004026 if (es->x_offset)
4027 dx = -es->x_offset;
4028 break;
4029 case SB_RIGHT:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004030 TRACE("SB_RIGHT\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004031 if (es->x_offset < es->text_width)
4032 dx = es->text_width - es->x_offset;
4033 break;
4034 case SB_THUMBTRACK:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004035 TRACE("SB_THUMBTRACK %d\n", pos);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004036 es->flags |= EF_HSCROLL_TRACK;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004037 if(es->style & WS_HSCROLL)
4038 dx = pos - es->x_offset;
4039 else
4040 {
4041 INT fw, new_x;
4042 /* Sanity check */
4043 if(pos < 0 || pos > 100) return 0;
4044 /* Assume default scroll range 0-100 */
4045 fw = es->format_rect.right - es->format_rect.left;
4046 new_x = pos * (es->text_width - fw) / 100;
4047 dx = es->text_width ? (new_x - es->x_offset) : 0;
4048 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00004049 break;
4050 case SB_THUMBPOSITION:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004051 TRACE("SB_THUMBPOSITION %d\n", pos);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004052 es->flags &= ~EF_HSCROLL_TRACK;
Alexandre Julliardde424282001-08-10 22:51:42 +00004053 if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_HSCROLL)
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004054 dx = pos - es->x_offset;
4055 else
4056 {
4057 INT fw, new_x;
4058 /* Sanity check */
4059 if(pos < 0 || pos > 100) return 0;
4060 /* Assume default scroll range 0-100 */
4061 fw = es->format_rect.right - es->format_rect.left;
4062 new_x = pos * (es->text_width - fw) / 100;
4063 dx = es->text_width ? (new_x - es->x_offset) : 0;
4064 }
4065 if (!dx) {
4066 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00004067 EDIT_UpdateScrollInfo(hwnd, es);
4068 EDIT_NOTIFY_PARENT(hwnd, es, EN_HSCROLL, "EN_HSCROLL");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004069 }
4070 break;
4071 case SB_ENDSCROLL:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004072 TRACE("SB_ENDSCROLL\n");
4073 break;
4074 /*
4075 * FIXME : the next two are undocumented !
4076 * Are we doing the right thing ?
4077 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
4078 * although it's also a regular control message.
4079 */
4080 case EM_GETTHUMB: /* this one is used by NT notepad */
4081 case EM_GETTHUMB16:
4082 {
4083 LRESULT ret;
Alexandre Julliardde424282001-08-10 22:51:42 +00004084 if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_HSCROLL)
4085 ret = GetScrollPos(hwnd, SB_HORZ);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004086 else
4087 {
4088 /* Assume default scroll range 0-100 */
4089 INT fw = es->format_rect.right - es->format_rect.left;
4090 ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
4091 }
4092 TRACE("EM_GETTHUMB: returning %ld\n", ret);
4093 return ret;
4094 }
4095 case EM_LINESCROLL16:
4096 TRACE("EM_LINESCROLL16\n");
4097 dx = pos;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004098 break;
4099
4100 default:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004101 ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
4102 action, action);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004103 return 0;
4104 }
4105 if (dx)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00004106 {
4107 INT fw = es->format_rect.right - es->format_rect.left;
4108 /* check if we are going to move too far */
4109 if(es->x_offset + dx + fw > es->text_width)
4110 dx = es->text_width - fw - es->x_offset;
4111 if(dx)
Alexandre Julliardde424282001-08-10 22:51:42 +00004112 EDIT_EM_LineScroll_internal(hwnd, es, dx, 0);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00004113 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00004114 return 0;
4115}
4116
4117
4118/*********************************************************************
4119 *
4120 * EDIT_CheckCombo
4121 *
4122 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004123static BOOL EDIT_CheckCombo(HWND hwnd, EDITSTATE *es, UINT msg, INT key)
Alexandre Julliard889f7421997-04-15 17:19:52 +00004124{
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004125 HWND hLBox = es->hwndListBox;
4126 HWND hCombo;
4127 BOOL bDropped;
4128 int nEUI;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004129
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004130 if (!hLBox)
4131 return FALSE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004132
Alexandre Julliardde424282001-08-10 22:51:42 +00004133 hCombo = GetParent(hwnd);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004134 bDropped = TRUE;
4135 nEUI = 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004136
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004137 TRACE_(combo)("[%04x]: handling msg %04x (%04x)\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00004138 hwnd, (UINT16)msg, (UINT16)key);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004139
4140 if (key == VK_UP || key == VK_DOWN)
4141 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004142 if (SendMessageW(hCombo, CB_GETEXTENDEDUI, 0, 0))
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004143 nEUI = 1;
4144
4145 if (msg == WM_KEYDOWN || nEUI)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004146 bDropped = (BOOL)SendMessageW(hCombo, CB_GETDROPPEDSTATE, 0, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004147 }
4148
4149 switch (msg)
4150 {
4151 case WM_KEYDOWN:
4152 if (!bDropped && nEUI && (key == VK_UP || key == VK_DOWN))
4153 {
4154 /* make sure ComboLBox pops up */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004155 SendMessageW(hCombo, CB_SETEXTENDEDUI, FALSE, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004156 key = VK_F4;
4157 nEUI = 2;
4158 }
4159
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004160 SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)key, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004161 break;
4162
4163 case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
4164 if (nEUI)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004165 SendMessageW(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004166 else
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004167 SendMessageW(hLBox, WM_KEYDOWN, (WPARAM)VK_F4, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004168 break;
4169 }
4170
4171 if(nEUI == 2)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004172 SendMessageW(hCombo, CB_SETEXTENDEDUI, TRUE, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004173
4174 return TRUE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004175}
4176
4177
Alexandre Julliard01d63461997-01-20 19:43:45 +00004178/*********************************************************************
4179 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004180 * WM_KEYDOWN
4181 *
4182 * Handling of special keys that don't produce a WM_CHAR
4183 * (i.e. non-printable keys) & Backspace & Delete
4184 *
4185 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004186static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004187{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004188 BOOL shift;
4189 BOOL control;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004190
Alexandre Julliarda3960291999-02-26 11:11:13 +00004191 if (GetKeyState(VK_MENU) & 0x8000)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004192 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004193
Alexandre Julliarda3960291999-02-26 11:11:13 +00004194 shift = GetKeyState(VK_SHIFT) & 0x8000;
4195 control = GetKeyState(VK_CONTROL) & 0x8000;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004196
Alexandre Julliard889f7421997-04-15 17:19:52 +00004197 switch (key) {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00004198 case VK_F4:
Alexandre Julliard329f0681996-04-14 13:21:20 +00004199 case VK_UP:
Alexandre Julliardde424282001-08-10 22:51:42 +00004200 if (EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key) || key == VK_F4)
Alexandre Julliard889f7421997-04-15 17:19:52 +00004201 break;
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004202
Alexandre Julliard889f7421997-04-15 17:19:52 +00004203 /* fall through */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00004204 case VK_LEFT:
Alexandre Julliard889f7421997-04-15 17:19:52 +00004205 if ((es->style & ES_MULTILINE) && (key == VK_UP))
Alexandre Julliardde424282001-08-10 22:51:42 +00004206 EDIT_MoveUp_ML(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004207 else
4208 if (control)
Alexandre Julliardde424282001-08-10 22:51:42 +00004209 EDIT_MoveWordBackward(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004210 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004211 EDIT_MoveBackward(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004212 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004213 case VK_DOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00004214 if (EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key))
Alexandre Julliard889f7421997-04-15 17:19:52 +00004215 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00004216 /* fall through */
4217 case VK_RIGHT:
Alexandre Julliard889f7421997-04-15 17:19:52 +00004218 if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
Alexandre Julliardde424282001-08-10 22:51:42 +00004219 EDIT_MoveDown_ML(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004220 else if (control)
Alexandre Julliardde424282001-08-10 22:51:42 +00004221 EDIT_MoveWordForward(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004222 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004223 EDIT_MoveForward(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004224 break;
4225 case VK_HOME:
Alexandre Julliardde424282001-08-10 22:51:42 +00004226 EDIT_MoveHome(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004227 break;
4228 case VK_END:
Alexandre Julliardde424282001-08-10 22:51:42 +00004229 EDIT_MoveEnd(hwnd, es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004230 break;
4231 case VK_PRIOR:
Alexandre Julliard889f7421997-04-15 17:19:52 +00004232 if (es->style & ES_MULTILINE)
Alexandre Julliardde424282001-08-10 22:51:42 +00004233 EDIT_MovePageUp_ML(hwnd, es, shift);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004234 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004235 EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004236 break;
4237 case VK_NEXT:
Alexandre Julliard889f7421997-04-15 17:19:52 +00004238 if (es->style & ES_MULTILINE)
Alexandre Julliardde424282001-08-10 22:51:42 +00004239 EDIT_MovePageDown_ML(hwnd, es, shift);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004240 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004241 EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004242 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004243 case VK_DELETE:
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00004244 if (!(es->style & ES_READONLY) && !(shift && control)) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00004245 if (es->selection_start != es->selection_end) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00004246 if (shift)
Alexandre Julliardde424282001-08-10 22:51:42 +00004247 EDIT_WM_Cut(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004248 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004249 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004250 } else {
Alexandre Julliard889f7421997-04-15 17:19:52 +00004251 if (shift) {
4252 /* delete character left of caret */
Alexandre Julliardde424282001-08-10 22:51:42 +00004253 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
4254 EDIT_MoveBackward(hwnd, es, TRUE);
4255 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004256 } else if (control) {
4257 /* delete to end of line */
Alexandre Julliardde424282001-08-10 22:51:42 +00004258 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
4259 EDIT_MoveEnd(hwnd, es, TRUE);
4260 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004261 } else {
4262 /* delete character right of caret */
Alexandre Julliardde424282001-08-10 22:51:42 +00004263 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE);
4264 EDIT_MoveForward(hwnd, es, TRUE);
4265 EDIT_WM_Clear(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004266 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00004267 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00004268 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00004269 break;
4270 case VK_INSERT:
4271 if (shift) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00004272 if (!(es->style & ES_READONLY))
Alexandre Julliardde424282001-08-10 22:51:42 +00004273 EDIT_WM_Paste(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004274 } else if (control)
Alexandre Julliardde424282001-08-10 22:51:42 +00004275 EDIT_WM_Copy(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004276 break;
Pascal Lessardaed79e51999-09-10 13:58:34 +00004277 case VK_RETURN:
4278 /* If the edit doesn't want the return send a message to the default object */
4279 if(!(es->style & ES_WANTRETURN))
4280 {
Alexandre Julliardde424282001-08-10 22:51:42 +00004281 HWND hwndParent = GetParent(hwnd);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004282 DWORD dw = SendMessageW( hwndParent, DM_GETDEFID, 0, 0 );
Pascal Lessardaed79e51999-09-10 13:58:34 +00004283 if (HIWORD(dw) == DC_HASDEFID)
4284 {
Vincent Béron9a624912002-05-31 23:06:46 +00004285 SendMessageW( hwndParent, WM_COMMAND,
Pascal Lessardaed79e51999-09-10 13:58:34 +00004286 MAKEWPARAM( LOWORD(dw), BN_CLICKED ),
4287 (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) );
4288 }
4289 }
4290 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004291 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004292 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004293}
4294
4295
4296/*********************************************************************
4297 *
4298 * WM_KILLFOCUS
4299 *
4300 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004301static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004302{
Alexandre Julliard889f7421997-04-15 17:19:52 +00004303 es->flags &= ~EF_FOCUSED;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004304 DestroyCaret();
Alexandre Julliard889f7421997-04-15 17:19:52 +00004305 if(!(es->style & ES_NOHIDESEL))
Alexandre Julliardde424282001-08-10 22:51:42 +00004306 EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
4307 EDIT_NOTIFY_PARENT(hwnd, es, EN_KILLFOCUS, "EN_KILLFOCUS");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004308 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004309}
4310
4311
4312/*********************************************************************
4313 *
4314 * WM_LBUTTONDBLCLK
4315 *
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00004316 * The caret position has been set on the WM_LBUTTONDOWN message
4317 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004318 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004319static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004320{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004321 INT s;
4322 INT e = es->selection_end;
4323 INT l;
4324 INT li;
4325 INT ll;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004326
Alexandre Julliard889f7421997-04-15 17:19:52 +00004327 if (!(es->flags & EF_FOCUSED))
4328 return 0;
4329
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004330 l = EDIT_EM_LineFromChar(es, e);
4331 li = EDIT_EM_LineIndex(es, l);
4332 ll = EDIT_EM_LineLength(es, e);
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00004333 s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
4334 e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT);
Alexandre Julliardde424282001-08-10 22:51:42 +00004335 EDIT_EM_SetSel(hwnd, es, s, e, FALSE);
4336 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004337 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004338}
4339
4340
4341/*********************************************************************
4342 *
4343 * WM_LBUTTONDOWN
4344 *
4345 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004346static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004347{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004348 INT e;
4349 BOOL after_wrap;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004350
Alexandre Julliard889f7421997-04-15 17:19:52 +00004351 if (!(es->flags & EF_FOCUSED))
4352 return 0;
4353
Abey George6e013e51999-07-27 17:08:26 +00004354 es->bCaptureState = TRUE;
Alexandre Julliardde424282001-08-10 22:51:42 +00004355 SetCapture(hwnd);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004356 EDIT_ConfinePoint(es, &x, &y);
Alexandre Julliardde424282001-08-10 22:51:42 +00004357 e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
4358 EDIT_EM_SetSel(hwnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
4359 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00004360 es->region_posx = es->region_posy = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00004361 SetTimer(hwnd, 0, 100, NULL);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004362 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004363}
4364
4365
4366/*********************************************************************
4367 *
4368 * WM_LBUTTONUP
4369 *
4370 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004371static LRESULT EDIT_WM_LButtonUp(HWND hwndSelf, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004372{
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004373 if (es->bCaptureState && GetCapture() == hwndSelf) {
4374 KillTimer(hwndSelf, 0);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004375 ReleaseCapture();
Alexandre Julliard01d63461997-01-20 19:43:45 +00004376 }
Abey George6e013e51999-07-27 17:08:26 +00004377 es->bCaptureState = FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004378 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004379}
4380
4381
4382/*********************************************************************
4383 *
Alexandre Julliardc6166252000-05-25 23:01:39 +00004384 * WM_MBUTTONDOWN
4385 *
4386 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004387static LRESULT EDIT_WM_MButtonDown(HWND hwnd)
Vincent Béron9a624912002-05-31 23:06:46 +00004388{
4389 SendMessageW(hwnd,WM_PASTE,0,0);
Alexandre Julliardc6166252000-05-25 23:01:39 +00004390 return 0;
4391}
4392
4393
4394/*********************************************************************
4395 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004396 * WM_MOUSEMOVE
4397 *
4398 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004399static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, INT x, INT y)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004400{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004401 INT e;
4402 BOOL after_wrap;
4403 INT prex, prey;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004404
Alexandre Julliardde424282001-08-10 22:51:42 +00004405 if (GetCapture() != hwnd)
Alexandre Julliard889f7421997-04-15 17:19:52 +00004406 return 0;
4407
Alexandre Julliard01d63461997-01-20 19:43:45 +00004408 /*
Alexandre Julliard889f7421997-04-15 17:19:52 +00004409 * FIXME: gotta do some scrolling if outside client
Alexandre Julliard01d63461997-01-20 19:43:45 +00004410 * area. Maybe reset the timer ?
4411 */
Alexandre Julliarde658d821997-11-30 17:45:40 +00004412 prex = x; prey = y;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004413 EDIT_ConfinePoint(es, &x, &y);
Alexandre Julliarde658d821997-11-30 17:45:40 +00004414 es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
4415 es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
Alexandre Julliardde424282001-08-10 22:51:42 +00004416 e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap);
4417 EDIT_EM_SetSel(hwnd, es, es->selection_start, e, after_wrap);
Zoltan Nagy5b809fd2002-08-27 18:15:26 +00004418 EDIT_SetCaretPos(hwnd,es,es->selection_end,es->flags & EF_AFTER_WRAP);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00004419 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004420}
4421
4422
4423/*********************************************************************
4424 *
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004425 * WM_NCCREATE
4426 *
Bill Medland86bfa4c2001-06-28 18:01:00 +00004427 * See also EDIT_WM_StyleChanged
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004428 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004429static LRESULT EDIT_WM_NCCreate(HWND hwnd, DWORD style, HWND hwndParent, BOOL unicode)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004430{
4431 EDITSTATE *es;
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00004432 UINT alloc_size;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004433
Alexandre Julliardde424282001-08-10 22:51:42 +00004434 TRACE("Creating %s edit control, style = %08lx\n",
4435 unicode ? "Unicode" : "ANSI", style);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004436
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004437 if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
4438 return FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00004439 SetWindowLongA( hwnd, 0, (LONG)es );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004440
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00004441 /*
4442 * Note: since the EDITSTATE has not been fully initialized yet,
4443 * we can't use any API calls that may send
4444 * WM_XXX messages before WM_NCCREATE is completed.
4445 */
4446
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004447 es->is_unicode = unicode;
4448 es->style = style;
4449
4450 es->bEnableState = !(style & WS_DISABLED);
4451
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +00004452 /* Save parent, which will be notified by EN_* messages */
4453 es->hwndParent = hwndParent;
4454
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004455 if (es->style & ES_COMBO)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004456 es->hwndListBox = GetDlgItem(hwndParent, ID_CB_LISTBOX);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004457
Bill Medland86bfa4c2001-06-28 18:01:00 +00004458 /* Number overrides lowercase overrides uppercase (at least it
4459 * does in Win95). However I'll bet that ES_NUMBER would be
4460 * invalid under Win 3.1.
4461 */
4462 if (es->style & ES_NUMBER) {
4463 ; /* do not override the ES_NUMBER */
4464 } else if (es->style & ES_LOWERCASE) {
4465 es->style &= ~ES_UPPERCASE;
4466 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004467 if (es->style & ES_MULTILINE) {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004468 es->buffer_limit = BUFLIMIT_MULTI;
4469 if (es->style & WS_VSCROLL)
4470 es->style |= ES_AUTOVSCROLL;
4471 if (es->style & WS_HSCROLL)
4472 es->style |= ES_AUTOHSCROLL;
4473 es->style &= ~ES_PASSWORD;
4474 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
Bill Medland86bfa4c2001-06-28 18:01:00 +00004475 /* Confirmed - RIGHT overrides CENTER */
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004476 if (es->style & ES_RIGHT)
4477 es->style &= ~ES_CENTER;
4478 es->style &= ~WS_HSCROLL;
4479 es->style &= ~ES_AUTOHSCROLL;
4480 }
4481
4482 /* FIXME: for now, all multi line controls are AUTOVSCROLL */
4483 es->style |= ES_AUTOVSCROLL;
4484 } else {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004485 es->buffer_limit = BUFLIMIT_SINGLE;
Bill Medland86bfa4c2001-06-28 18:01:00 +00004486 if (WIN31_LOOK == TWEAK_WineLook ||
4487 WIN95_LOOK == TWEAK_WineLook) {
4488 es->style &= ~ES_CENTER;
4489 es->style &= ~ES_RIGHT;
4490 } else {
4491 if (es->style & ES_RIGHT)
4492 es->style &= ~ES_CENTER;
4493 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004494 es->style &= ~WS_HSCROLL;
4495 es->style &= ~WS_VSCROLL;
4496 es->style &= ~ES_AUTOVSCROLL;
4497 es->style &= ~ES_WANTRETURN;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004498 if (es->style & ES_PASSWORD)
4499 es->password_char = '*';
4500
4501 /* FIXME: for now, all single line controls are AUTOHSCROLL */
4502 es->style |= ES_AUTOHSCROLL;
4503 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004504
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00004505 alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00004506 if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004507 return FALSE;
4508 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
4509
4510 if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004511 return FALSE;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004512 es->undo_buffer_size = es->buffer_size;
4513
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004514 if (es->style & ES_MULTILINE)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004515 if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004516 return FALSE;
4517 es->line_count = 1;
4518
Dmitry Timoshkovb85a6e82001-10-08 20:33:08 +00004519 /*
Vincent Béron9a624912002-05-31 23:06:46 +00004520 * In Win95 look and feel, the WS_BORDER style is replaced by the
4521 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
Dmitry Timoshkovb85a6e82001-10-08 20:33:08 +00004522 * control a non client area. Not always. This coordinates in some
Vincent Béron9a624912002-05-31 23:06:46 +00004523 * way with the window creation code in dialog.c When making
Dmitry Timoshkovb85a6e82001-10-08 20:33:08 +00004524 * modifications please ensure that the code still works for edit
4525 * controls created directly with style 0x50800000, exStyle 0 (
4526 * which should have a single pixel border)
4527 */
4528 if (TWEAK_WineLook != WIN31_LOOK)
4529 {
4530 es->style &= ~WS_BORDER;
4531 }
4532 else
4533 {
4534 if ((es->style & WS_BORDER) && !(es->style & WS_DLGFRAME))
4535 SetWindowLongA( hwnd, GWL_STYLE,
4536 GetWindowLongA( hwnd, GWL_STYLE ) & ~WS_BORDER );
4537 }
4538
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004539 return TRUE;
4540}
4541
4542/*********************************************************************
4543 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004544 * WM_PAINT
4545 *
4546 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004547static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es, WPARAM wParam)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004548{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004549 PAINTSTRUCT ps;
4550 INT i;
4551 HDC dc;
4552 HFONT old_font = 0;
4553 RECT rc;
4554 RECT rcLine;
4555 RECT rcRgn;
Stephane Lussier93805341999-09-03 16:37:00 +00004556 BOOL rev = es->bEnableState &&
Alexandre Julliard889f7421997-04-15 17:19:52 +00004557 ((es->flags & EF_FOCUSED) ||
4558 (es->style & ES_NOHIDESEL));
Gerard Patel8e5c72e1999-09-03 12:23:52 +00004559 if (!wParam)
Alexandre Julliardde424282001-08-10 22:51:42 +00004560 dc = BeginPaint(hwnd, &ps);
Gerard Patel8e5c72e1999-09-03 12:23:52 +00004561 else
4562 dc = (HDC) wParam;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004563 if(es->style & WS_BORDER) {
Alexandre Julliardde424282001-08-10 22:51:42 +00004564 GetClientRect(hwnd, &rc);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004565 if(es->style & ES_MULTILINE) {
4566 if(es->style & WS_HSCROLL) rc.bottom++;
4567 if(es->style & WS_VSCROLL) rc.right++;
4568 }
Francis Beaudet06e88861999-07-30 17:59:35 +00004569 Rectangle(dc, rc.left, rc.top, rc.right, rc.bottom);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004570 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00004571 IntersectClipRect(dc, es->format_rect.left,
Alexandre Julliard889f7421997-04-15 17:19:52 +00004572 es->format_rect.top,
4573 es->format_rect.right,
4574 es->format_rect.bottom);
4575 if (es->style & ES_MULTILINE) {
Alexandre Julliardde424282001-08-10 22:51:42 +00004576 GetClientRect(hwnd, &rc);
Alexandre Julliarda3960291999-02-26 11:11:13 +00004577 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004578 }
4579 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00004580 old_font = SelectObject(dc, es->font);
Alexandre Julliard198746d2000-08-14 14:29:22 +00004581 if ( get_app_version() >= 0x40000 &&(
Rein Klazes077ec0c1999-11-10 19:55:29 +00004582 !es->bEnableState || (es->style & ES_READONLY)))
Alexandre Julliardde424282001-08-10 22:51:42 +00004583 EDIT_SEND_CTLCOLORSTATIC(hwnd, dc);
Luc Tourangeaudf5fbc71999-04-03 11:14:30 +00004584 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004585 EDIT_SEND_CTLCOLOR(hwnd, dc);
Stephane Lussier93805341999-09-03 16:37:00 +00004586
4587 if (!es->bEnableState)
Alexandre Julliarda3960291999-02-26 11:11:13 +00004588 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
4589 GetClipBox(dc, &rcRgn);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004590 if (es->style & ES_MULTILINE) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004591 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
Francois Gouget6d77d3a2000-03-25 21:44:35 +00004592 for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
Alexandre Julliardde424282001-08-10 22:51:42 +00004593 EDIT_GetLineRect(hwnd, es, i, 0, -1, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00004594 if (IntersectRect(&rc, &rcRgn, &rcLine))
Alexandre Julliardde424282001-08-10 22:51:42 +00004595 EDIT_PaintLine(hwnd, es, dc, i, rev);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004596 }
4597 } else {
Alexandre Julliardde424282001-08-10 22:51:42 +00004598 EDIT_GetLineRect(hwnd, es, 0, 0, -1, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00004599 if (IntersectRect(&rc, &rcRgn, &rcLine))
Alexandre Julliardde424282001-08-10 22:51:42 +00004600 EDIT_PaintLine(hwnd, es, dc, 0, rev);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004601 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00004602 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00004603 SelectObject(dc, old_font);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00004604
Gerard Patel8e5c72e1999-09-03 12:23:52 +00004605 if (!wParam)
Alexandre Julliardde424282001-08-10 22:51:42 +00004606 EndPaint(hwnd, &ps);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004607}
4608
4609
4610/*********************************************************************
4611 *
4612 * WM_PASTE
4613 *
4614 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004615static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004616{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004617 HGLOBAL hsrc;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004618 LPWSTR src;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004619
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00004620 /* Protect read-only edit control from modification */
4621 if(es->style & ES_READONLY)
4622 return;
4623
Alexandre Julliardde424282001-08-10 22:51:42 +00004624 OpenClipboard(hwnd);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004625 if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
4626 src = (LPWSTR)GlobalLock(hsrc);
Alexandre Julliardde424282001-08-10 22:51:42 +00004627 EDIT_EM_ReplaceSel(hwnd, es, TRUE, src, TRUE);
Alexandre Julliarda3960291999-02-26 11:11:13 +00004628 GlobalUnlock(hsrc);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004629 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00004630 CloseClipboard();
Alexandre Julliard329f0681996-04-14 13:21:20 +00004631}
4632
4633
4634/*********************************************************************
4635 *
4636 * WM_SETFOCUS
4637 *
4638 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004639static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004640{
Alexandre Julliard889f7421997-04-15 17:19:52 +00004641 es->flags |= EF_FOCUSED;
Alexandre Julliardde424282001-08-10 22:51:42 +00004642 CreateCaret(hwnd, 0, 2, es->line_height);
4643 EDIT_SetCaretPos(hwnd, es, es->selection_end,
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004644 es->flags & EF_AFTER_WRAP);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004645 if(!(es->style & ES_NOHIDESEL))
Alexandre Julliardde424282001-08-10 22:51:42 +00004646 EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end);
4647 ShowCaret(hwnd);
4648 EDIT_NOTIFY_PARENT(hwnd, es, EN_SETFOCUS, "EN_SETFOCUS");
Alexandre Julliard329f0681996-04-14 13:21:20 +00004649}
4650
4651
4652/*********************************************************************
4653 *
4654 * WM_SETFONT
4655 *
Vincent Béron9a624912002-05-31 23:06:46 +00004656 * With Win95 look the margins are set to default font value unless
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004657 * the system font (font == 0) is being set, in which case they are left
4658 * unchanged.
4659 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004660 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004661static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004662{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004663 TEXTMETRICW tm;
Alexandre Julliarda3960291999-02-26 11:11:13 +00004664 HDC dc;
4665 HFONT old_font = 0;
Pascal Lessard3405f5c1999-09-04 10:59:07 +00004666 RECT r;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004667
Alexandre Julliard889f7421997-04-15 17:19:52 +00004668 es->font = font;
Alexandre Julliardde424282001-08-10 22:51:42 +00004669 dc = GetDC(hwnd);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004670 if (font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00004671 old_font = SelectObject(dc, font);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004672 GetTextMetricsW(dc, &tm);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004673 es->line_height = tm.tmHeight;
4674 es->char_width = tm.tmAveCharWidth;
4675 if (font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00004676 SelectObject(dc, old_font);
Alexandre Julliardde424282001-08-10 22:51:42 +00004677 ReleaseDC(hwnd, dc);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00004678 if (font && (TWEAK_WineLook > WIN31_LOOK))
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004679 EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004680 EC_USEFONTINFO, EC_USEFONTINFO);
Pascal Lessard3405f5c1999-09-04 10:59:07 +00004681
4682 /* Force the recalculation of the format rect for each font change */
Alexandre Julliardde424282001-08-10 22:51:42 +00004683 GetClientRect(hwnd, &r);
4684 EDIT_SetRectNP(hwnd, es, &r);
Pascal Lessard3405f5c1999-09-04 10:59:07 +00004685
Alexandre Julliard889f7421997-04-15 17:19:52 +00004686 if (es->style & ES_MULTILINE)
Alexandre Julliardde424282001-08-10 22:51:42 +00004687 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00004688 else
Alexandre Julliardde424282001-08-10 22:51:42 +00004689 EDIT_CalcLineWidth_SL(hwnd, es);
Pascal Lessard3405f5c1999-09-04 10:59:07 +00004690
Alexandre Julliarde658d821997-11-30 17:45:40 +00004691 if (redraw)
Alexandre Julliardde424282001-08-10 22:51:42 +00004692 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004693 if (es->flags & EF_FOCUSED) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004694 DestroyCaret();
Alexandre Julliardde424282001-08-10 22:51:42 +00004695 CreateCaret(hwnd, 0, 2, es->line_height);
4696 EDIT_SetCaretPos(hwnd, es, es->selection_end,
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004697 es->flags & EF_AFTER_WRAP);
Alexandre Julliardde424282001-08-10 22:51:42 +00004698 ShowCaret(hwnd);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004699 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00004700}
4701
4702
4703/*********************************************************************
4704 *
4705 * WM_SETTEXT
4706 *
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00004707 * NOTES
4708 * For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
4709 * The modified flag is reset. No notifications are sent.
4710 *
4711 * For single-line controls, reception of WM_SETTEXT triggers:
4712 * The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
4713 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004714 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004715static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPARAM lParam, BOOL unicode)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004716{
James Hathewayf3ea3452001-01-12 23:01:41 +00004717 LPWSTR text = NULL;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004718
4719 if(unicode)
4720 text = (LPWSTR)lParam;
James Hathewayf3ea3452001-01-12 23:01:41 +00004721 else if (lParam)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004722 {
4723 LPCSTR textA = (LPCSTR)lParam;
4724 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
4725 if((text = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
4726 MultiByteToWideChar(CP_ACP, 0, textA, -1, text, countW);
4727 }
4728
Alexandre Julliardde424282001-08-10 22:51:42 +00004729 EDIT_EM_SetSel(hwnd, es, 0, (UINT)-1, FALSE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004730 if (text) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004731 TRACE("%s\n", debugstr_w(text));
Alexandre Julliardde424282001-08-10 22:51:42 +00004732 EDIT_EM_ReplaceSel(hwnd, es, FALSE, text, FALSE);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004733 if(!unicode)
4734 HeapFree(GetProcessHeap(), 0, text);
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004735 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004736 static const WCHAR empty_stringW[] = {0};
4737 TRACE("<NULL>\n");
Alexandre Julliardde424282001-08-10 22:51:42 +00004738 EDIT_EM_ReplaceSel(hwnd, es, FALSE, empty_stringW, FALSE);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00004739 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00004740 es->x_offset = 0;
Alexandre Julliard829fe321998-07-26 14:27:39 +00004741 es->flags &= ~EF_MODIFIED;
Alexandre Julliardde424282001-08-10 22:51:42 +00004742 EDIT_EM_SetSel(hwnd, es, 0, 0, FALSE);
Rein Klazes9d4ae0e2001-04-02 19:13:24 +00004743 /* Send the notification after the selection start and end have been set
4744 * edit control doesn't send notification on WM_SETTEXT
4745 * if it is multiline, or it is part of combobox
4746 */
4747 if( !((es->style & ES_MULTILINE) || es->hwndListBox))
Rizsanyi Zsolt83d6efb2002-04-11 17:30:22 +00004748 {
Alexandre Julliardde424282001-08-10 22:51:42 +00004749 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE");
Rizsanyi Zsolt83d6efb2002-04-11 17:30:22 +00004750 EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE");
4751 }
Alexandre Julliardde424282001-08-10 22:51:42 +00004752 EDIT_EM_ScrollCaret(hwnd, es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00004753}
4754
4755
4756/*********************************************************************
4757 *
4758 * WM_SIZE
4759 *
4760 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004761static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004762{
Alexandre Julliard889f7421997-04-15 17:19:52 +00004763 if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00004764 RECT rc;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00004765 TRACE("width = %d, height = %d\n", width, height);
Alexandre Julliarda3960291999-02-26 11:11:13 +00004766 SetRect(&rc, 0, 0, width, height);
Alexandre Julliardde424282001-08-10 22:51:42 +00004767 EDIT_SetRectNP(hwnd, es, &rc);
4768 EDIT_UpdateText(hwnd, es, NULL, TRUE);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00004769 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00004770}
4771
4772
4773/*********************************************************************
4774 *
Bill Medland86bfa4c2001-06-28 18:01:00 +00004775 * WM_STYLECHANGED
4776 *
4777 * This message is sent by SetWindowLong on having changed either the Style
4778 * or the extended style.
4779 *
4780 * We ensure that the window's version of the styles and the EDITSTATE's agree.
4781 *
4782 * See also EDIT_WM_NCCreate
4783 *
4784 * It appears that the Windows version of the edit control allows the style
4785 * (as retrieved by GetWindowLong) to be any value and maintains an internal
Vincent Béron9a624912002-05-31 23:06:46 +00004786 * style variable which will generally be different. In this function we
Bill Medland86bfa4c2001-06-28 18:01:00 +00004787 * update the internal style based on what changed in the externally visible
4788 * style.
4789 *
4790 * Much of this content as based upon the MSDN, especially:
4791 * Platform SDK Documentation -> User Interface Services ->
4792 * Windows User Interface -> Edit Controls -> Edit Control Reference ->
4793 * Edit Control Styles
4794 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004795static LRESULT EDIT_WM_StyleChanged (HWND hwnd,
Bill Medland86bfa4c2001-06-28 18:01:00 +00004796 EDITSTATE *es,
4797 WPARAM which,
4798 const STYLESTRUCT *style)
4799{
4800 if (GWL_STYLE == which) {
4801 DWORD style_change_mask;
4802 DWORD new_style;
4803 /* Only a subset of changes can be applied after the control
4804 * has been created.
4805 */
4806 style_change_mask = ES_UPPERCASE | ES_LOWERCASE |
4807 ES_NUMBER;
Vincent Béron9a624912002-05-31 23:06:46 +00004808 if (es->style & ES_MULTILINE)
Bill Medland86bfa4c2001-06-28 18:01:00 +00004809 style_change_mask |= ES_WANTRETURN;
4810
4811 new_style = style->styleNew & style_change_mask;
4812
4813 /* Number overrides lowercase overrides uppercase (at least it
4814 * does in Win95). However I'll bet that ES_NUMBER would be
4815 * invalid under Win 3.1.
4816 */
4817 if (new_style & ES_NUMBER) {
4818 ; /* do not override the ES_NUMBER */
4819 } else if (new_style & ES_LOWERCASE) {
4820 new_style &= ~ES_UPPERCASE;
4821 }
Vincent Béron9a624912002-05-31 23:06:46 +00004822
Bill Medland86bfa4c2001-06-28 18:01:00 +00004823 es->style = (es->style & ~style_change_mask) | new_style;
4824 } else if (GWL_EXSTYLE == which) {
4825 ; /* FIXME - what is needed here */
4826 } else {
4827 WARN ("Invalid style change %d\n",which);
4828 }
4829
4830 return 0;
4831}
4832
4833/*********************************************************************
4834 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00004835 * WM_SYSKEYDOWN
4836 *
4837 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004838static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data)
Alexandre Julliard01d63461997-01-20 19:43:45 +00004839{
Alexandre Julliard889f7421997-04-15 17:19:52 +00004840 if ((key == VK_BACK) && (key_data & 0x2000)) {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00004841 if (EDIT_EM_CanUndo(es))
Alexandre Julliardde424282001-08-10 22:51:42 +00004842 EDIT_EM_Undo(hwnd, es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004843 return 0;
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004844 } else if (key == VK_UP || key == VK_DOWN) {
Alexandre Julliardde424282001-08-10 22:51:42 +00004845 if (EDIT_CheckCombo(hwnd, es, WM_SYSKEYDOWN, key))
Alexandre Julliard889f7421997-04-15 17:19:52 +00004846 return 0;
Serge Ivanov9eedcf52000-06-07 03:47:34 +00004847 }
Alexandre Julliardde424282001-08-10 22:51:42 +00004848 return DefWindowProcW(hwnd, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data);
Alexandre Julliard01d63461997-01-20 19:43:45 +00004849}
4850
4851
4852/*********************************************************************
4853 *
4854 * WM_TIMER
4855 *
4856 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004857static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es)
Alexandre Julliard01d63461997-01-20 19:43:45 +00004858{
Alexandre Julliarde658d821997-11-30 17:45:40 +00004859 if (es->region_posx < 0) {
Alexandre Julliardde424282001-08-10 22:51:42 +00004860 EDIT_MoveBackward(hwnd, es, TRUE);
Alexandre Julliarde658d821997-11-30 17:45:40 +00004861 } else if (es->region_posx > 0) {
Alexandre Julliardde424282001-08-10 22:51:42 +00004862 EDIT_MoveForward(hwnd, es, TRUE);
Alexandre Julliarde658d821997-11-30 17:45:40 +00004863 }
Alexandre Julliard01d63461997-01-20 19:43:45 +00004864/*
Alexandre Julliarde658d821997-11-30 17:45:40 +00004865 * FIXME: gotta do some vertical scrolling here, like
Alexandre Julliardde424282001-08-10 22:51:42 +00004866 * EDIT_EM_LineScroll(hwnd, 0, 1);
Alexandre Julliard01d63461997-01-20 19:43:45 +00004867 */
Alexandre Julliard889f7421997-04-15 17:19:52 +00004868}
4869
Alexandre Julliard01d63461997-01-20 19:43:45 +00004870/*********************************************************************
4871 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004872 * WM_VSCROLL
4873 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00004874 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004875static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos)
Alexandre Julliard329f0681996-04-14 13:21:20 +00004876{
Alexandre Julliarda3960291999-02-26 11:11:13 +00004877 INT dy;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004878
Alexandre Julliard889f7421997-04-15 17:19:52 +00004879 if (!(es->style & ES_MULTILINE))
4880 return 0;
4881
4882 if (!(es->style & ES_AUTOVSCROLL))
4883 return 0;
4884
Alexandre Julliard889f7421997-04-15 17:19:52 +00004885 dy = 0;
4886 switch (action) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00004887 case SB_LINEUP:
Alexandre Julliard329f0681996-04-14 13:21:20 +00004888 case SB_LINEDOWN:
Alexandre Julliard329f0681996-04-14 13:21:20 +00004889 case SB_PAGEUP:
Alexandre Julliard329f0681996-04-14 13:21:20 +00004890 case SB_PAGEDOWN:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004891 TRACE("action %d\n", action);
Alexandre Julliardde424282001-08-10 22:51:42 +00004892 EDIT_EM_Scroll(hwnd, es, action);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004893 return 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004894 case SB_TOP:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004895 TRACE("SB_TOP\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004896 dy = -es->y_offset;
4897 break;
4898 case SB_BOTTOM:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004899 TRACE("SB_BOTTOM\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004900 dy = es->line_count - 1 - es->y_offset;
4901 break;
4902 case SB_THUMBTRACK:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004903 TRACE("SB_THUMBTRACK %d\n", pos);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004904 es->flags |= EF_VSCROLL_TRACK;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004905 if(es->style & WS_VSCROLL)
4906 dy = pos - es->y_offset;
4907 else
4908 {
4909 /* Assume default scroll range 0-100 */
4910 INT vlc, new_y;
4911 /* Sanity check */
4912 if(pos < 0 || pos > 100) return 0;
4913 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
4914 new_y = pos * (es->line_count - vlc) / 100;
4915 dy = es->line_count ? (new_y - es->y_offset) : 0;
4916 TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
4917 es->line_count, es->y_offset, pos, dy);
4918 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00004919 break;
4920 case SB_THUMBPOSITION:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004921 TRACE("SB_THUMBPOSITION %d\n", pos);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004922 es->flags &= ~EF_VSCROLL_TRACK;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004923 if(es->style & WS_VSCROLL)
4924 dy = pos - es->y_offset;
4925 else
4926 {
4927 /* Assume default scroll range 0-100 */
4928 INT vlc, new_y;
4929 /* Sanity check */
4930 if(pos < 0 || pos > 100) return 0;
4931 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
4932 new_y = pos * (es->line_count - vlc) / 100;
4933 dy = es->line_count ? (new_y - es->y_offset) : 0;
4934 TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
4935 es->line_count, es->y_offset, pos, dy);
4936 }
4937 if (!dy)
4938 {
4939 /* force scroll info update */
Alexandre Julliardde424282001-08-10 22:51:42 +00004940 EDIT_UpdateScrollInfo(hwnd, es);
4941 EDIT_NOTIFY_PARENT(hwnd, es, EN_VSCROLL, "EN_VSCROLL");
Alexandre Julliard889f7421997-04-15 17:19:52 +00004942 }
4943 break;
4944 case SB_ENDSCROLL:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004945 TRACE("SB_ENDSCROLL\n");
4946 break;
4947 /*
4948 * FIXME : the next two are undocumented !
4949 * Are we doing the right thing ?
4950 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
4951 * although it's also a regular control message.
4952 */
4953 case EM_GETTHUMB: /* this one is used by NT notepad */
4954 case EM_GETTHUMB16:
4955 {
4956 LRESULT ret;
Alexandre Julliardde424282001-08-10 22:51:42 +00004957 if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_VSCROLL)
4958 ret = GetScrollPos(hwnd, SB_VERT);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004959 else
4960 {
4961 /* Assume default scroll range 0-100 */
4962 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
4963 ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0;
4964 }
4965 TRACE("EM_GETTHUMB: returning %ld\n", ret);
4966 return ret;
4967 }
4968 case EM_LINESCROLL16:
4969 TRACE("EM_LINESCROLL16 %d\n", pos);
4970 dy = pos;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004971 break;
4972
Alexandre Julliard329f0681996-04-14 13:21:20 +00004973 default:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004974 ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n",
4975 action, action);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004976 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004977 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00004978 if (dy)
Alexandre Julliardde424282001-08-10 22:51:42 +00004979 EDIT_EM_LineScroll(hwnd, es, 0, dy);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004980 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004981}
Ulrich Czekalla70d5a952000-05-26 01:17:34 +00004982
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004983/*********************************************************************
4984 *
4985 * EDIT_UpdateText
4986 *
4987 */
Alexandre Julliardde424282001-08-10 22:51:42 +00004988static void EDIT_UpdateTextRegion(HWND hwnd, EDITSTATE *es, HRGN hrgn, BOOL bErase)
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004989{
Alexandre Julliardde424282001-08-10 22:51:42 +00004990 if (es->flags & EF_UPDATE) EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE");
4991 InvalidateRgn(hwnd, hrgn, bErase);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004992}
4993
Ulrich Czekalla70d5a952000-05-26 01:17:34 +00004994
4995/*********************************************************************
4996 *
4997 * EDIT_UpdateText
4998 *
4999 */
Alexandre Julliardde424282001-08-10 22:51:42 +00005000static void EDIT_UpdateText(HWND hwnd, EDITSTATE *es, LPRECT rc, BOOL bErase)
Ulrich Czekalla70d5a952000-05-26 01:17:34 +00005001{
Alexandre Julliardde424282001-08-10 22:51:42 +00005002 if (es->flags & EF_UPDATE) EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE");
5003 InvalidateRect(hwnd, rc, bErase);
Ulrich Czekalla70d5a952000-05-26 01:17:34 +00005004}