blob: 05a68ead2b7d7cf18d78d1c1271ad15f3218fd1c [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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000022 *
Dimitrie O. Paun91e74372004-10-08 20:50:52 +000023 * NOTES
24 *
25 * This code was audited for completeness against the documented features
26 * of Comctl32.dll version 6.0 on Oct. 8, 2004, by Dimitrie O. Paun.
27 *
28 * Unless otherwise noted, we believe this code to be complete, as per
29 * the specification mentioned above.
30 * If you discover missing features, or bugs, please note them below.
31 *
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000032 * TODO:
Dimitrie O. Paun91e74372004-10-08 20:50:52 +000033 * - EDITBALLOONTIP structure
34 * - EM_GETCUEBANNER/Edit_GetCueBannerText
35 * - EM_HIDEBALLOONTIP/Edit_HideBalloonTip
36 * - EM_SETCUEBANNER/Edit_SetCueBannerText
37 * - EM_SHOWBALLOONTIP/Edit_ShowBalloonTip
38 * - EM_GETIMESTATUS, EM_SETIMESTATUS
39 * - EN_ALIGN_LTR_EC
40 * - EN_ALIGN_RTL_EC
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000041 * - ES_OEMCONVERT
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000042 *
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +000043 */
Alexandre Julliard58199531994-04-21 01:20:00 +000044
Patrik Stridvall1bb94031999-05-08 15:47:44 +000045#include "config.h"
46
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000047#include <stdarg.h>
Jeff Garzikc3e1f721999-02-19 15:42:11 +000048#include <string.h>
Alexandre Julliard908464d2000-11-01 03:11:12 +000049#include <stdlib.h>
Patrik Stridvall6cc47d42000-03-08 18:26:56 +000050
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000051#include "windef.h"
Patrik Stridvall6cc47d42000-03-08 18:26:56 +000052#include "winbase.h"
Alexandre Julliard889f7421997-04-15 17:19:52 +000053#include "winnt.h"
Alexandre Julliard58199531994-04-21 01:20:00 +000054#include "win.h"
Aric Stewart314f45d2005-12-19 18:17:51 +010055#include "imm.h"
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +000056#include "wine/unicode.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000057#include "controls.h"
Alexandre Julliard6a78c162004-12-08 18:06:14 +000058#include "user_private.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000059#include "wine/debug.h"
Alexandre Julliard58199531994-04-21 01:20:00 +000060
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000061WINE_DEFAULT_DEBUG_CHANNEL(edit);
62WINE_DECLARE_DEBUG_CHANNEL(combo);
63WINE_DECLARE_DEBUG_CHANNEL(relay);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000064
Alex VillacĂ­s Lasso48fd1062007-10-16 15:25:51 -050065#define BUFLIMIT_INITIAL 30000 /* initial buffer size */
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +000066#define GROWLENGTH 32 /* buffers granularity in bytes: must be power of 2 */
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +000067#define ROUND_TO_GROW(size) (((size) + (GROWLENGTH - 1)) & ~(GROWLENGTH - 1))
Alexandre Julliard329f0681996-04-14 13:21:20 +000068#define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */
Alexandre Julliard58199531994-04-21 01:20:00 +000069
Alexandre Julliard889f7421997-04-15 17:19:52 +000070/*
71 * extra flags for EDITSTATE.flags field
72 */
73#define EF_MODIFIED 0x0001 /* text has been modified */
74#define EF_FOCUSED 0x0002 /* we have input focus */
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +000075#define EF_UPDATE 0x0004 /* notify parent of changed state */
Alexandre Julliard889f7421997-04-15 17:19:52 +000076#define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */
77#define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */
Alexandre Julliard889f7421997-04-15 17:19:52 +000078#define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a
79 wrapped line, instead of in front of the next character */
Alexandre Julliarda845b881998-06-01 10:44:35 +000080#define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */
Huw Daviesc79ce3c2007-04-19 14:47:12 +010081#define EF_APP_HAS_HANDLE 0x0200 /* Set when an app sends EM_[G|S]ETHANDLE. We are in sole control of
82 the text buffer if this is clear. */
Sergey Khodych6fa48cd2009-08-24 00:10:01 +030083#define EF_DIALOGMODE 0x0400 /* Indicates that we are inside a dialog window */
84
Alexandre Julliard329f0681996-04-14 13:21:20 +000085typedef enum
86{
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000087 END_0 = 0, /* line ends with terminating '\0' character */
88 END_WRAP, /* line is wrapped */
89 END_HARD, /* line ends with a hard return '\r\n' */
90 END_SOFT, /* line ends with a soft return '\r\r\n' */
91 END_RICH /* line ends with a single '\n' */
Alexandre Julliard329f0681996-04-14 13:21:20 +000092} LINE_END;
93
Alexandre Julliard889f7421997-04-15 17:19:52 +000094typedef struct tagLINEDEF {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000095 INT length; /* bruto length of a line in bytes */
96 INT net_length; /* netto length of a line in visible characters */
Alexandre Julliard329f0681996-04-14 13:21:20 +000097 LINE_END ending;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +000098 INT width; /* width of the line in pixels */
99 INT index; /* line index into the buffer */
Alexandre Julliard889f7421997-04-15 17:19:52 +0000100 struct tagLINEDEF *next;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000101} LINEDEF;
Alexandre Julliard58199531994-04-21 01:20:00 +0000102
Alexandre Julliard58199531994-04-21 01:20:00 +0000103typedef struct
104{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000105 BOOL is_unicode; /* how the control was created */
106 LPWSTR text; /* the actual contents of the control */
Huw Davies6a945162007-04-19 15:01:13 +0100107 UINT text_length; /* cached length of text buffer (in WCHARs) - use get_text_length() to retrieve */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000108 UINT buffer_size; /* the size of the buffer in characters */
109 UINT buffer_limit; /* the maximum size to which the buffer may grow in characters */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000110 HFONT font; /* NULL means standard system font */
111 INT x_offset; /* scroll offset for multi lines this is in pixels
Alexandre Julliard889f7421997-04-15 17:19:52 +0000112 for single lines it's in characters */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000113 INT line_height; /* height of a screen line in pixels */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000114 INT char_width; /* average character width in pixels */
Alexandre Julliard889f7421997-04-15 17:19:52 +0000115 DWORD style; /* sane version of wnd->dwStyle */
116 WORD flags; /* flags that are not in es->style or wnd->flags (EF_XXX) */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000117 INT undo_insert_count; /* number of characters inserted in sequence */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000118 UINT undo_position; /* character index of the insertion and deletion */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000119 LPWSTR undo_text; /* deleted text */
Dmitry Timoshkov366c0a12000-12-22 20:28:05 +0000120 UINT undo_buffer_size; /* size of the deleted text buffer */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000121 INT selection_start; /* == selection_end if no selection */
122 INT selection_end; /* == current caret position */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000123 WCHAR password_char; /* == 0 if no password char, and for multi line controls */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000124 INT left_margin; /* in pixels */
125 INT right_margin; /* in pixels */
126 RECT format_rect;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +0000127 INT text_width; /* width of the widest line in pixels for multi line controls
128 and just line width for single line controls */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000129 INT region_posx; /* Position of cursor relative to region: */
130 INT region_posy; /* -1: to left, 0: within, 1: to right */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000131 void *word_break_proc; /* 32-bit word break proc: ANSI or Unicode */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000132 INT line_count; /* number of lines */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000133 INT y_offset; /* scroll offset in number of lines */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000134 BOOL bCaptureState; /* flag indicating whether mouse was captured */
135 BOOL bEnableState; /* flag keeping the enable state */
136 HWND hwndSelf; /* the our window handle */
137 HWND hwndParent; /* Handle of parent for sending EN_* messages.
138 Even if parent will change, EN_* messages
139 should be sent to the first parent. */
140 HWND hwndListBox; /* handle of ComboBox's listbox or NULL */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000141 /*
Alexandre Julliard889f7421997-04-15 17:19:52 +0000142 * only for multi line controls
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000143 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000144 INT lock_count; /* amount of re-entries in the EditWndProc */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000145 INT tabs_count;
146 LPINT tabs;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000147 LINEDEF *first_line_def; /* linked list of (soft) linebreaks */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000148 HLOCAL hloc32W; /* our unicode local memory block */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000149 HLOCAL hloc32A; /* alias for ANSI control receiving EM_GETHANDLE
150 or EM_SETHANDLE */
Aric Stewart314f45d2005-12-19 18:17:51 +0100151 /*
152 * IME Data
153 */
Francois Gouget8ca1f3f2006-01-03 12:10:50 +0100154 UINT composition_len; /* length of composition, 0 == no composition */
Aric Stewart314f45d2005-12-19 18:17:51 +0100155 int composition_start; /* the character position for the composition */
Alexandre Julliard58199531994-04-21 01:20:00 +0000156} EDITSTATE;
157
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000158
Alexandre Julliarda3960291999-02-26 11:11:13 +0000159#define SWAP_UINT32(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0)
160#define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT32((x),(y)); } while(0)
Alexandre Julliard58199531994-04-21 01:20:00 +0000161
Luc Tourangeaudf5fbc71999-04-03 11:14:30 +0000162/* used for disabled or read-only edit control */
Jacek Caban7371c3c2005-06-27 09:42:40 +0000163#define EDIT_NOTIFY_PARENT(es, wNotifyCode) \
Dmitry Timoshkov87880c52001-03-10 19:16:46 +0000164 do \
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +0000165 { /* Notify parent which has created this edit control */ \
Jacek Caban7371c3c2005-06-27 09:42:40 +0000166 TRACE("notification " #wNotifyCode " sent to hwnd=%p\n", es->hwndParent); \
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000167 SendMessageW(es->hwndParent, WM_COMMAND, \
Robert Shearman2e9436c2004-08-17 22:29:29 +0000168 MAKEWPARAM(GetWindowLongPtrW((es->hwndSelf),GWLP_ID), wNotifyCode), \
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000169 (LPARAM)(es->hwndSelf)); \
Dmitry Timoshkov87880c52001-03-10 19:16:46 +0000170 } while(0)
Alexandre Julliardca22b331996-07-12 19:02:39 +0000171
Kusanagi Kouichiccab1772010-02-13 11:38:21 +0900172static const WCHAR empty_stringW[] = {0};
Alexandre Julliard58199531994-04-21 01:20:00 +0000173
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000174/*********************************************************************
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000175 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000176 * EM_CANUNDO
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000177 *
178 */
Andrew Talbot49c0bd52007-11-19 15:46:20 +0000179static inline BOOL EDIT_EM_CanUndo(const EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +0000180{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000181 return (es->undo_insert_count || strlenW(es->undo_text));
Alexandre Julliard889f7421997-04-15 17:19:52 +0000182}
183
184
185/*********************************************************************
186 *
187 * EM_EMPTYUNDOBUFFER
188 *
189 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000190static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +0000191{
192 es->undo_insert_count = 0;
193 *es->undo_text = '\0';
194}
195
196
Alexandre Julliard198746d2000-08-14 14:29:22 +0000197/**********************************************************************
198 * get_app_version
199 *
200 * Returns the window version in case Wine emulates a later version
Francois Gouget61aac4e2003-06-04 20:29:05 +0000201 * of windows than the application expects.
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000202 *
Alexandre Julliard198746d2000-08-14 14:29:22 +0000203 * In a number of cases when windows runs an application that was
204 * designed for an earlier windows version, windows reverts
205 * to "old" behaviour of that earlier version.
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000206 *
207 * An example is a disabled edit control that needs to be painted.
208 * Old style behaviour is to send a WM_CTLCOLOREDIT message. This was
209 * changed in Win95, NT4.0 by a WM_CTLCOLORSTATIC message _only_ for
Alexandre Julliard198746d2000-08-14 14:29:22 +0000210 * applications with an expected version 0f 4.0 or higher.
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000211 *
Alexandre Julliard198746d2000-08-14 14:29:22 +0000212 */
213static DWORD get_app_version(void)
214{
215 static DWORD version;
216 if (!version)
217 {
218 DWORD dwEmulatedVersion;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000219 OSVERSIONINFOW info;
Alexandre Julliard198746d2000-08-14 14:29:22 +0000220 DWORD dwProcVersion = GetProcessVersion(0);
221
James Juran75c525c2001-05-18 20:56:37 +0000222 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000223 GetVersionExW( &info );
Alexandre Julliard198746d2000-08-14 14:29:22 +0000224 dwEmulatedVersion = MAKELONG( info.dwMinorVersion, info.dwMajorVersion );
Dimitrie O. Paun693cca52002-01-29 03:12:19 +0000225 /* FIXME: this may not be 100% correct; see discussion on the
Alexandre Julliard198746d2000-08-14 14:29:22 +0000226 * wine developer list in Nov 1999 */
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000227 version = dwProcVersion < dwEmulatedVersion ? dwProcVersion : dwEmulatedVersion;
Alexandre Julliard198746d2000-08-14 14:29:22 +0000228 }
229 return version;
230}
231
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000232static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
233{
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +0000234 HBRUSH hbrush;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000235 UINT msg;
236
237 if ( get_app_version() >= 0x40000 && (!es->bEnableState || (es->style & ES_READONLY)))
238 msg = WM_CTLCOLORSTATIC;
239 else
240 msg = WM_CTLCOLOREDIT;
241
242 /* why do we notify to es->hwndParent, and we send this one to GetParent()? */
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +0000243 hbrush = (HBRUSH)SendMessageW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
244 if (!hbrush)
245 hbrush = (HBRUSH)DefWindowProcW(GetParent(es->hwndSelf), msg, (WPARAM)hdc, (LPARAM)es->hwndSelf);
246 return hbrush;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000247}
248
Aric Stewart7b9e8272008-10-15 07:30:22 -0500249
Alexandre Julliardcdcdede1996-04-21 14:57:41 +0000250/*********************************************************************
251 *
Francois Gouget9e7b5562009-02-07 16:05:33 +0100252 * EDIT_WordBreakProc
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000253 *
Francois Gouget9e7b5562009-02-07 16:05:33 +0100254 * Find the beginning of words.
255 * Note: unlike the specs for a WordBreakProc, this function only
256 * allows to be called without linebreaks between s[0] up to
257 * s[count - 1]. Remember it is only called
258 * internally, so we can decide this for ourselves.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000259 *
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000260 */
Francois Gouget9e7b5562009-02-07 16:05:33 +0100261static INT EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action)
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000262{
Francois Gouget9e7b5562009-02-07 16:05:33 +0100263 INT ret = 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000264
Francois Gouget9e7b5562009-02-07 16:05:33 +0100265 TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action);
Francois Boisvert6b1b41c1999-03-14 17:25:32 +0000266
Francois Gouget9e7b5562009-02-07 16:05:33 +0100267 if(!s) return 0;
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000268
Francois Gouget9e7b5562009-02-07 16:05:33 +0100269 switch (action) {
270 case WB_LEFT:
271 if (!count)
272 break;
273 if (index)
274 index--;
275 if (s[index] == ' ') {
276 while (index && (s[index] == ' '))
277 index--;
278 if (index) {
279 while (index && (s[index] != ' '))
280 index--;
281 if (s[index] == ' ')
282 index++;
283 }
Alexandre Julliard889f7421997-04-15 17:19:52 +0000284 } else {
Francois Gouget9e7b5562009-02-07 16:05:33 +0100285 while (index && (s[index] != ' '))
286 index--;
287 if (s[index] == ' ')
288 index++;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000289 }
Francois Gouget9e7b5562009-02-07 16:05:33 +0100290 ret = index;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000291 break;
Francois Gouget9e7b5562009-02-07 16:05:33 +0100292 case WB_RIGHT:
293 if (!count)
294 break;
295 if (index)
296 index--;
297 if (s[index] == ' ')
298 while ((index < count) && (s[index] == ' ')) index++;
299 else {
300 while (s[index] && (s[index] != ' ') && (index < count))
301 index++;
302 while ((s[index] == ' ') && (index < count)) index++;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000303 }
Francois Gouget9e7b5562009-02-07 16:05:33 +0100304 ret = index;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000305 break;
Francois Gouget9e7b5562009-02-07 16:05:33 +0100306 case WB_ISDELIMITER:
307 ret = (s[index] == ' ');
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000308 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000309 default:
Francois Gouget9e7b5562009-02-07 16:05:33 +0100310 ERR("unknown action code, please report !\n");
Alexandre Julliard329f0681996-04-14 13:21:20 +0000311 break;
312 }
Francois Gouget9e7b5562009-02-07 16:05:33 +0100313 return ret;
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000314}
315
Francois Gouget9e7b5562009-02-07 16:05:33 +0100316
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000317/*********************************************************************
318 *
Francois Gouget9e7b5562009-02-07 16:05:33 +0100319 * EDIT_CallWordBreakProc
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000320 *
Francois Gouget9e7b5562009-02-07 16:05:33 +0100321 * Call appropriate WordBreakProc (internal or external).
322 *
323 * Note: The "start" argument should always be an index referring
324 * to es->text. The actual wordbreak proc might be
325 * 16 bit, so we can't always pass any 32 bit LPSTR.
326 * Hence we assume that es->text is the buffer that holds
327 * the string under examination (we can decide this for ourselves).
328 *
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000329 */
Francois Gouget9e7b5562009-02-07 16:05:33 +0100330static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000331{
Francois Gouget9e7b5562009-02-07 16:05:33 +0100332 INT ret;
333
Alexandre Julliarddcec3422009-12-11 14:52:28 +0100334 if (es->word_break_proc)
Francois Gouget9e7b5562009-02-07 16:05:33 +0100335 {
336 if(es->is_unicode)
337 {
338 EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc;
339
340 TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
341 es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action);
342 ret = wbpW(es->text + start, index, count, action);
343 }
344 else
345 {
346 EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc;
347 INT countA;
348 CHAR *textA;
349
350 countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL);
351 textA = HeapAlloc(GetProcessHeap(), 0, countA);
352 WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL);
353 TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n",
354 es->word_break_proc, debugstr_an(textA, countA), index, countA, action);
355 ret = wbpA(textA, index, countA, action);
356 HeapFree(GetProcessHeap(), 0, textA);
357 }
358 }
359 else
360 ret = EDIT_WordBreakProc(es->text + start, index, count, action);
361
362 return ret;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000363}
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000364
365/*********************************************************************
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000366 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000367 * EDIT_BuildLineDefs_ML
Alexandre Julliard329f0681996-04-14 13:21:20 +0000368 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000369 * Build linked list of text lines.
370 * Lines can end with '\0' (last line), a character (if it is wrapped),
371 * a soft return '\r\r\n' or a hard return '\r\n'
Alexandre Julliard329f0681996-04-14 13:21:20 +0000372 *
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000373 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000374static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn)
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000375{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000376 HDC dc;
377 HFONT old_font = 0;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000378 LPWSTR current_position, cp;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000379 INT fw;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000380 LINEDEF *current_line;
381 LINEDEF *previous_line;
382 LINEDEF *start_line;
383 INT line_index = 0, nstart_line = 0, nstart_index = 0;
384 INT line_count = es->line_count;
385 INT orig_net_length;
386 RECT rc;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000387
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000388 if (istart == iend && delta == 0)
389 return;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000390
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000391 dc = GetDC(es->hwndSelf);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000392 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000393 old_font = SelectObject(dc, es->font);
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000394
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000395 previous_line = NULL;
396 current_line = es->first_line_def;
397
398 /* Find starting line. istart must lie inside an existing line or
399 * at the end of buffer */
Alexandre Julliard889f7421997-04-15 17:19:52 +0000400 do {
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000401 if (istart < current_line->index + current_line->length ||
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000402 current_line->ending == END_0)
403 break;
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000404
405 previous_line = current_line;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000406 current_line = current_line->next;
407 line_index++;
408 } while (current_line);
409
410 if (!current_line) /* Error occurred start is not inside previous buffer */
411 {
412 FIXME(" modification occurred outside buffer\n");
Christian Costa6e7d78e2003-05-11 03:27:23 +0000413 ReleaseDC(es->hwndSelf, dc);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000414 return;
415 }
416
417 /* Remember start of modifications in order to calculate update region */
418 nstart_line = line_index;
419 nstart_index = current_line->index;
420
421 /* We must start to reformat from the previous line since the modifications
422 * may have caused the line to wrap upwards. */
423 if (!(es->style & ES_AUTOHSCROLL) && line_index > 0)
424 {
425 line_index--;
426 current_line = previous_line;
427 }
428 start_line = current_line;
429
430 fw = es->format_rect.right - es->format_rect.left;
431 current_position = es->text + current_line->index;
432 do {
433 if (current_line != start_line)
434 {
435 if (!current_line || current_line->index + delta > current_position - es->text)
436 {
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000437 /* The buffer has been expanded, create a new line and
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000438 insert it into the link list */
439 LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF));
440 new_line->next = previous_line->next;
441 previous_line->next = new_line;
442 current_line = new_line;
443 es->line_count++;
444 }
445 else if (current_line->index + delta < current_position - es->text)
446 {
447 /* The previous line merged with this line so we delete this extra entry */
448 previous_line->next = current_line->next;
449 HeapFree(GetProcessHeap(), 0, current_line);
450 current_line = previous_line->next;
451 es->line_count--;
452 continue;
453 }
454 else /* current_line->index + delta == current_position */
455 {
456 if (current_position - es->text > iend)
457 break; /* We reached end of line modifications */
Austin English6e59cd22008-04-22 01:18:14 -0500458 /* else recalculate this line */
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000459 }
460 }
461
462 current_line->index = current_position - es->text;
463 orig_net_length = current_line->net_length;
464
465 /* Find end of line */
466 cp = current_position;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000467 while (*cp) {
Chuck Craynece2024c2002-04-22 23:08:19 +0000468 if (*cp == '\n') break;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000469 if ((*cp == '\r') && (*(cp + 1) == '\n'))
470 break;
471 cp++;
472 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000473
474 /* Mark type of line termination */
Alexandre Julliard889f7421997-04-15 17:19:52 +0000475 if (!(*cp)) {
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000476 current_line->ending = END_0;
477 current_line->net_length = strlenW(current_position);
478 } else if ((cp > current_position) && (*(cp - 1) == '\r')) {
479 current_line->ending = END_SOFT;
480 current_line->net_length = cp - current_position - 1;
Chuck Craynece2024c2002-04-22 23:08:19 +0000481 } else if (*cp == '\n') {
482 current_line->ending = END_RICH;
483 current_line->net_length = cp - current_position;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000484 } else {
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000485 current_line->ending = END_HARD;
486 current_line->net_length = cp - current_position;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000487 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000488
489 /* Calculate line width */
490 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
491 current_position, current_line->net_length,
Alexandre Julliard889f7421997-04-15 17:19:52 +0000492 es->tabs_count, es->tabs));
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000493
Alexandre Julliard889f7421997-04-15 17:19:52 +0000494 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */
Ulrich Czekallaa935c2a2004-05-25 18:04:48 +0000495 if (!(es->style & ES_AUTOHSCROLL)) {
496 if (current_line->width > fw) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000497 INT next = 0;
498 INT prev;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000499 do {
500 prev = next;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000501 next = EDIT_CallWordBreakProc(es, current_position - es->text,
502 prev + 1, current_line->net_length, WB_RIGHT);
503 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
504 current_position, next, es->tabs_count, es->tabs));
505 } while (current_line->width <= fw);
506 if (!prev) { /* Didn't find a line break so force a break */
Alexandre Julliard329f0681996-04-14 13:21:20 +0000507 next = 0;
508 do {
509 prev = next;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000510 next++;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000511 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc,
512 current_position, next, es->tabs_count, es->tabs));
513 } while (current_line->width <= fw);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000514 if (!prev)
515 prev = 1;
Alexandre Julliard329f0681996-04-14 13:21:20 +0000516 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000517
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000518 /* If the first line we are calculating, wrapped before istart, we must
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000519 * adjust istart in order for this to be reflected in the update region. */
520 if (current_line->index == nstart_index && istart > current_line->index + prev)
521 istart = current_line->index + prev;
522 /* else if we are updating the previous line before the first line we
Andreas Mohr07216db2001-11-13 21:29:38 +0000523 * are re-calculating and it expanded */
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000524 else if (current_line == start_line &&
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000525 current_line->index != nstart_index && orig_net_length < prev)
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000526 {
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000527 /* Line expanded due to an upwards line wrap so we must partially include
528 * previous line in update region */
529 nstart_line = line_index;
530 nstart_index = current_line->index;
531 istart = current_line->index + orig_net_length;
532 }
533
534 current_line->net_length = prev;
535 current_line->ending = END_WRAP;
536 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position,
537 current_line->net_length, es->tabs_count, es->tabs));
Ulrich Czekallaa935c2a2004-05-25 18:04:48 +0000538 }
Lei Zhang4aef5cb2008-04-14 16:53:42 -0700539 else if (current_line == start_line &&
540 current_line->index != nstart_index &&
541 orig_net_length < current_line->net_length) {
Ulrich Czekallaa935c2a2004-05-25 18:04:48 +0000542 /* The previous line expanded but it's still not as wide as the client rect */
543 /* The expansion is due to an upwards line wrap so we must partially include
544 it in the update region */
545 nstart_line = line_index;
546 nstart_index = current_line->index;
547 istart = current_line->index + orig_net_length;
548 }
Alexandre Julliard889f7421997-04-15 17:19:52 +0000549 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000550
551
552 /* Adjust length to include line termination */
553 switch (current_line->ending) {
Alexandre Julliard889f7421997-04-15 17:19:52 +0000554 case END_SOFT:
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000555 current_line->length = current_line->net_length + 3;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000556 break;
Chuck Craynece2024c2002-04-22 23:08:19 +0000557 case END_RICH:
558 current_line->length = current_line->net_length + 1;
559 break;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000560 case END_HARD:
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000561 current_line->length = current_line->net_length + 2;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000562 break;
563 case END_WRAP:
564 case END_0:
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000565 current_line->length = current_line->net_length;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000566 break;
567 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000568 es->text_width = max(es->text_width, current_line->width);
569 current_position += current_line->length;
570 previous_line = current_line;
571 current_line = current_line->next;
572 line_index++;
573 } while (previous_line->ending != END_0);
574
Andreas Mohr07216db2001-11-13 21:29:38 +0000575 /* Finish adjusting line indexes by delta or remove hanging lines */
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000576 if (previous_line->ending == END_0)
577 {
578 LINEDEF *pnext = NULL;
579
580 previous_line->next = NULL;
581 while (current_line)
582 {
583 pnext = current_line->next;
584 HeapFree(GetProcessHeap(), 0, current_line);
585 current_line = pnext;
586 es->line_count--;
587 }
588 }
Lauri Tulmin7b9fb6f2005-01-19 19:08:25 +0000589 else if (delta != 0)
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000590 {
591 while (current_line)
592 {
593 current_line->index += delta;
594 current_line = current_line->next;
595 }
596 }
597
598 /* Calculate rest of modification rectangle */
599 if (hrgn)
600 {
601 HRGN tmphrgn;
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000602 /*
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000603 * We calculate two rectangles. One for the first line which may have
604 * an indent with respect to the format rect. The other is a format-width
605 * rectangle that spans the rest of the lines that changed or moved.
606 */
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000607 rc.top = es->format_rect.top + nstart_line * es->line_height -
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000608 (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
609 rc.bottom = rc.top + es->line_height;
Ulrich Czekalla7df33752005-02-16 16:28:34 +0000610 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT))
611 rc.left = es->format_rect.left;
612 else
613 rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc,
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000614 es->text + nstart_index, istart - nstart_index,
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000615 es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */
616 rc.right = es->format_rect.right;
617 SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom);
618
619 rc.top = rc.bottom;
620 rc.left = es->format_rect.left;
621 rc.right = es->format_rect.right;
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000622 /*
623 * If lines were added or removed we must re-paint the remainder of the
624 * lines since the remaining lines were either shifted up or down.
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000625 */
626 if (line_count < es->line_count) /* We added lines */
627 rc.bottom = es->line_count * es->line_height;
628 else if (line_count > es->line_count) /* We removed lines */
629 rc.bottom = line_count * es->line_height;
630 else
631 rc.bottom = line_index * es->line_height;
Lauri Tulmin24c73fd2005-06-09 20:40:31 +0000632 rc.bottom += es->format_rect.top;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000633 rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */
634 tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
635 CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR);
636 DeleteObject(tmphrgn);
637 }
638
Alexandre Julliard889f7421997-04-15 17:19:52 +0000639 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000640 SelectObject(dc, old_font);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +0000641
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000642 ReleaseDC(es->hwndSelf, dc);
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000643}
644
Francois Gouget9e7b5562009-02-07 16:05:33 +0100645
646static inline UINT get_text_length(EDITSTATE *es)
647{
648 if(es->text_length == (UINT)-1)
649 es->text_length = strlenW(es->text);
650 return es->text_length;
651}
652
653/*********************************************************************
654 *
655 * EDIT_GetPasswordPointer_SL
656 *
657 * note: caller should free the (optionally) allocated buffer
658 *
659 */
660static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es)
661{
662 if (es->style & ES_PASSWORD) {
663 INT len = get_text_length(es);
664 LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
665 text[len] = '\0';
666 while(len) text[--len] = es->password_char;
667 return text;
668 } else
669 return es->text;
670}
671
672
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +0000673/*********************************************************************
674 *
675 * EDIT_CalcLineWidth_SL
676 *
677 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000678static void EDIT_CalcLineWidth_SL(EDITSTATE *es)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +0000679{
Ulrich Czekalla7df33752005-02-16 16:28:34 +0000680 SIZE size;
681 LPWSTR text;
682 HDC dc;
683 HFONT old_font = 0;
684
685 text = EDIT_GetPasswordPointer_SL(es);
686
687 dc = GetDC(es->hwndSelf);
688 if (es->font)
689 old_font = SelectObject(dc, es->font);
690
691 GetTextExtentPoint32W(dc, text, strlenW(text), &size);
692
693 if (es->font)
694 SelectObject(dc, old_font);
695 ReleaseDC(es->hwndSelf, dc);
696
697 if (es->style & ES_PASSWORD)
698 HeapFree(GetProcessHeap(), 0, text);
699
700 es->text_width = size.cx;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +0000701}
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000702
Alexandre Julliard329f0681996-04-14 13:21:20 +0000703/*********************************************************************
704 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000705 * EDIT_CharFromPos
Alexandre Julliard329f0681996-04-14 13:21:20 +0000706 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000707 * Beware: This is not the function called on EM_CHARFROMPOS
708 * The position _can_ be outside the formatting / client
709 * rectangle
710 * The return value is only the character index
Alexandre Julliard329f0681996-04-14 13:21:20 +0000711 *
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000712 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000713static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000714{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000715 INT index;
716 HDC dc;
717 HFONT old_font = 0;
Lauri Tulminf1248782005-06-14 12:24:48 +0000718 INT x_high = 0, x_low = 0;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000719
Alexandre Julliard889f7421997-04-15 17:19:52 +0000720 if (es->style & ES_MULTILINE) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000721 INT line = (y - es->format_rect.top) / es->line_height + es->y_offset;
722 INT line_index = 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000723 LINEDEF *line_def = es->first_line_def;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000724 INT low, high;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000725 while ((line > 0) && line_def->next) {
726 line_index += line_def->length;
727 line_def = line_def->next;
728 line--;
729 }
730 x += es->x_offset - es->format_rect.left;
Ulrich Czekalla7df33752005-02-16 16:28:34 +0000731 if (es->style & ES_RIGHT)
732 x -= (es->format_rect.right - es->format_rect.left) - line_def->width;
733 else if (es->style & ES_CENTER)
734 x -= ((es->format_rect.right - es->format_rect.left) - line_def->width) / 2;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000735 if (x >= line_def->width) {
736 if (after_wrap)
737 *after_wrap = (line_def->ending == END_WRAP);
738 return line_index + line_def->net_length;
739 }
740 if (x <= 0) {
741 if (after_wrap)
742 *after_wrap = FALSE;
743 return line_index;
744 }
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000745 dc = GetDC(es->hwndSelf);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000746 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000747 old_font = SelectObject(dc, es->font);
Lauri Tulminf1248782005-06-14 12:24:48 +0000748 low = line_index;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000749 high = line_index + line_def->net_length + 1;
750 while (low < high - 1)
751 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000752 INT mid = (low + high) / 2;
Lauri Tulminf1248782005-06-14 12:24:48 +0000753 INT x_now = LOWORD(GetTabbedTextExtentW(dc, es->text + line_index, mid - line_index, es->tabs_count, es->tabs));
754 if (x_now > x) {
755 high = mid;
756 x_high = x_now;
757 } else {
758 low = mid;
759 x_low = x_now;
760 }
Alexandre Julliarde658d821997-11-30 17:45:40 +0000761 }
Vitaliy Margolend30f1fd2005-07-05 14:04:25 +0000762 if (abs(x_high - x) + 1 <= abs(x_low - x))
Lauri Tulminf1248782005-06-14 12:24:48 +0000763 index = high;
764 else
765 index = low;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000766
Alexandre Julliard889f7421997-04-15 17:19:52 +0000767 if (after_wrap)
768 *after_wrap = ((index == line_index + line_def->net_length) &&
769 (line_def->ending == END_WRAP));
770 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000771 LPWSTR text;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000772 SIZE size;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000773 if (after_wrap)
774 *after_wrap = FALSE;
775 x -= es->format_rect.left;
776 if (!x)
777 return es->x_offset;
Ulrich Czekalla7df33752005-02-16 16:28:34 +0000778
779 if (!es->x_offset)
780 {
781 INT indent = (es->format_rect.right - es->format_rect.left) - es->text_width;
782 if (es->style & ES_RIGHT)
783 x -= indent;
784 else if (es->style & ES_CENTER)
785 x -= indent / 2;
786 }
787
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +0000788 text = EDIT_GetPasswordPointer_SL(es);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000789 dc = GetDC(es->hwndSelf);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000790 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000791 old_font = SelectObject(dc, es->font);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000792 if (x < 0)
793 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000794 INT low = 0;
795 INT high = es->x_offset;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000796 while (low < high - 1)
797 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000798 INT mid = (low + high) / 2;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000799 GetTextExtentPoint32W( dc, text + mid,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000800 es->x_offset - mid, &size );
Lauri Tulminf1248782005-06-14 12:24:48 +0000801 if (size.cx > -x) {
802 low = mid;
803 x_low = size.cx;
804 } else {
805 high = mid;
806 x_high = size.cx;
807 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000808 }
Lauri Tulminf1248782005-06-14 12:24:48 +0000809 if (abs(x_high + x) <= abs(x_low + x) + 1)
810 index = high;
811 else
812 index = low;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000813 }
814 else
815 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000816 INT low = es->x_offset;
Huw Daviesa0dbcb22007-04-19 14:52:51 +0100817 INT high = get_text_length(es) + 1;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000818 while (low < high - 1)
819 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000820 INT mid = (low + high) / 2;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000821 GetTextExtentPoint32W( dc, text + es->x_offset,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000822 mid - es->x_offset, &size );
Lauri Tulminf1248782005-06-14 12:24:48 +0000823 if (size.cx > x) {
824 high = mid;
825 x_high = size.cx;
826 } else {
827 low = mid;
828 x_low = size.cx;
829 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000830 }
Lauri Tulminf1248782005-06-14 12:24:48 +0000831 if (abs(x_high - x) <= abs(x_low - x) + 1)
832 index = high;
833 else
834 index = low;
Alexandre Julliard889f7421997-04-15 17:19:52 +0000835 }
836 if (es->style & ES_PASSWORD)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +0000837 HeapFree(GetProcessHeap(), 0, text);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000838 }
839 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000840 SelectObject(dc, old_font);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +0000841 ReleaseDC(es->hwndSelf, dc);
Alexandre Julliard889f7421997-04-15 17:19:52 +0000842 return index;
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000843}
844
Alexandre Julliard329f0681996-04-14 13:21:20 +0000845
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000846/*********************************************************************
Alexandre Julliard02ed4c21996-03-02 19:34:10 +0000847 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000848 * EDIT_ConfinePoint
Alexandre Julliard329f0681996-04-14 13:21:20 +0000849 *
Alexandre Julliard889f7421997-04-15 17:19:52 +0000850 * adjusts the point to be within the formatting rectangle
851 * (so CharFromPos returns the nearest _visible_ character)
Alexandre Julliard329f0681996-04-14 13:21:20 +0000852 *
853 */
Andrew Talbot49c0bd52007-11-19 15:46:20 +0000854static void EDIT_ConfinePoint(const EDITSTATE *es, LPINT x, LPINT y)
Alexandre Julliard329f0681996-04-14 13:21:20 +0000855{
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000856 *x = min(max(*x, es->format_rect.left), es->format_rect.right - 1);
857 *y = min(max(*y, es->format_rect.top), es->format_rect.bottom - 1);
Alexandre Julliard329f0681996-04-14 13:21:20 +0000858}
859
860
861/*********************************************************************
862 *
Francois Gouget9e7b5562009-02-07 16:05:33 +0100863 * EM_LINEFROMCHAR
864 *
865 */
866static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index)
867{
868 INT line;
869 LINEDEF *line_def;
870
871 if (!(es->style & ES_MULTILINE))
872 return 0;
873 if (index > (INT)get_text_length(es))
874 return es->line_count - 1;
875 if (index == -1)
876 index = min(es->selection_start, es->selection_end);
877
878 line = 0;
879 line_def = es->first_line_def;
880 index -= line_def->length;
881 while ((index >= 0) && line_def->next) {
882 line++;
883 line_def = line_def->next;
884 index -= line_def->length;
885 }
886 return line;
887}
888
889
890/*********************************************************************
891 *
892 * EM_LINEINDEX
893 *
894 */
895static INT EDIT_EM_LineIndex(const EDITSTATE *es, INT line)
896{
897 INT line_index;
898 const LINEDEF *line_def;
899
900 if (!(es->style & ES_MULTILINE))
901 return 0;
902 if (line >= es->line_count)
903 return -1;
904
905 line_index = 0;
906 line_def = es->first_line_def;
907 if (line == -1) {
908 INT index = es->selection_end - line_def->length;
909 while ((index >= 0) && line_def->next) {
910 line_index += line_def->length;
911 line_def = line_def->next;
912 index -= line_def->length;
913 }
914 } else {
915 while (line > 0) {
916 line_index += line_def->length;
917 line_def = line_def->next;
918 line--;
919 }
920 }
921 return line_index;
922}
923
924
925/*********************************************************************
926 *
927 * EM_LINELENGTH
928 *
929 */
930static INT EDIT_EM_LineLength(EDITSTATE *es, INT index)
931{
932 LINEDEF *line_def;
933
934 if (!(es->style & ES_MULTILINE))
935 return get_text_length(es);
936
937 if (index == -1) {
938 /* get the number of remaining non-selected chars of selected lines */
939 INT32 l; /* line number */
940 INT32 li; /* index of first char in line */
941 INT32 count;
942 l = EDIT_EM_LineFromChar(es, es->selection_start);
943 /* # chars before start of selection area */
944 count = es->selection_start - EDIT_EM_LineIndex(es, l);
945 l = EDIT_EM_LineFromChar(es, es->selection_end);
946 /* # chars after end of selection */
947 li = EDIT_EM_LineIndex(es, l);
948 count += li + EDIT_EM_LineLength(es, li) - es->selection_end;
949 return count;
950 }
951 line_def = es->first_line_def;
952 index -= line_def->length;
953 while ((index >= 0) && line_def->next) {
954 line_def = line_def->next;
955 index -= line_def->length;
956 }
957 return line_def->net_length;
958}
959
960
961/*********************************************************************
962 *
963 * EM_POSFROMCHAR
964 *
965 */
966static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap)
967{
968 INT len = get_text_length(es);
969 INT l;
970 INT li;
971 INT x;
972 INT y = 0;
973 INT w;
974 INT lw = 0;
975 INT ll = 0;
976 HDC dc;
977 HFONT old_font = 0;
978 SIZE size;
979 LINEDEF *line_def;
980
981 index = min(index, len);
982 dc = GetDC(es->hwndSelf);
983 if (es->font)
984 old_font = SelectObject(dc, es->font);
985 if (es->style & ES_MULTILINE) {
986 l = EDIT_EM_LineFromChar(es, index);
987 y = (l - es->y_offset) * es->line_height;
988 li = EDIT_EM_LineIndex(es, l);
989 if (after_wrap && (li == index) && l) {
990 INT l2 = l - 1;
991 line_def = es->first_line_def;
992 while (l2) {
993 line_def = line_def->next;
994 l2--;
995 }
996 if (line_def->ending == END_WRAP) {
997 l--;
998 y -= es->line_height;
999 li = EDIT_EM_LineIndex(es, l);
1000 }
1001 }
1002
1003 line_def = es->first_line_def;
1004 while (line_def->index != li)
1005 line_def = line_def->next;
1006
1007 ll = line_def->net_length;
1008 lw = line_def->width;
1009
1010 w = es->format_rect.right - es->format_rect.left;
1011 if (es->style & ES_RIGHT)
1012 {
1013 x = LOWORD(GetTabbedTextExtentW(dc, es->text + li + (index - li), ll - (index - li),
1014 es->tabs_count, es->tabs)) - es->x_offset;
1015 x = w - x;
1016 }
1017 else if (es->style & ES_CENTER)
1018 {
1019 x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
1020 es->tabs_count, es->tabs)) - es->x_offset;
1021 x += (w - lw) / 2;
1022 }
1023 else /* ES_LEFT */
1024 {
1025 x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li,
1026 es->tabs_count, es->tabs)) - es->x_offset;
1027 }
1028 } else {
1029 LPWSTR text = EDIT_GetPasswordPointer_SL(es);
1030 if (index < es->x_offset) {
1031 GetTextExtentPoint32W(dc, text + index,
1032 es->x_offset - index, &size);
1033 x = -size.cx;
1034 } else {
1035 GetTextExtentPoint32W(dc, text + es->x_offset,
1036 index - es->x_offset, &size);
1037 x = size.cx;
1038
1039 if (!es->x_offset && (es->style & (ES_RIGHT | ES_CENTER)))
1040 {
1041 w = es->format_rect.right - es->format_rect.left;
1042 if (w > es->text_width)
1043 {
1044 if (es->style & ES_RIGHT)
1045 x += w - es->text_width;
1046 else if (es->style & ES_CENTER)
1047 x += (w - es->text_width) / 2;
1048 }
1049 }
1050 }
1051 y = 0;
1052 if (es->style & ES_PASSWORD)
1053 HeapFree(GetProcessHeap(), 0, text);
1054 }
1055 x += es->format_rect.left;
1056 y += es->format_rect.top;
1057 if (es->font)
1058 SelectObject(dc, old_font);
1059 ReleaseDC(es->hwndSelf, dc);
1060 return MAKELONG((INT16)x, (INT16)y);
1061}
1062
1063
1064/*********************************************************************
1065 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00001066 * EDIT_GetLineRect
1067 *
1068 * Calculates the bounding rectangle for a line from a starting
1069 * column to an ending column.
1070 *
1071 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001072static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001073{
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001074 INT line_index = EDIT_EM_LineIndex(es, line);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001075
1076 if (es->style & ES_MULTILINE)
1077 rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height;
1078 else
1079 rc->top = es->format_rect.top;
1080 rc->bottom = rc->top + es->line_height;
Alexandre Julliard9d615962003-09-17 04:28:28 +00001081 rc->left = (scol == 0) ? es->format_rect.left : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + scol, TRUE));
1082 rc->right = (ecol == -1) ? es->format_rect.right : (short)LOWORD(EDIT_EM_PosFromChar(es, line_index + ecol, TRUE));
Alexandre Julliard329f0681996-04-14 13:21:20 +00001083}
1084
1085
Francois Gouget9e7b5562009-02-07 16:05:33 +01001086static inline void text_buffer_changed(EDITSTATE *es)
Alexandre Julliard889f7421997-04-15 17:19:52 +00001087{
Francois Gouget9e7b5562009-02-07 16:05:33 +01001088 es->text_length = (UINT)-1;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001089}
1090
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001091/*********************************************************************
Detlef Riekenberg2f529c32010-01-05 15:58:01 +01001092 * EDIT_LockBuffer
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001093 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00001094 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001095static void EDIT_LockBuffer(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001096{
Alexandre Julliard889f7421997-04-15 17:19:52 +00001097 if (!es->text) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001098
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001099 if(!es->hloc32W) return;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001100
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001101 if(es->hloc32A)
1102 {
1103 CHAR *textA = LocalLock(es->hloc32A);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001104 HLOCAL hloc32W_new;
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001105 UINT countW_new = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001106 if(countW_new > es->buffer_size + 1)
1107 {
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00001108 UINT alloc_size = ROUND_TO_GROW(countW_new * sizeof(WCHAR));
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001109 TRACE("Resizing 32-bit UNICODE buffer from %d+1 to %d WCHARs\n", es->buffer_size, countW_new);
1110 hloc32W_new = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
1111 if(hloc32W_new)
1112 {
1113 es->hloc32W = hloc32W_new;
1114 es->buffer_size = LocalSize(hloc32W_new)/sizeof(WCHAR) - 1;
1115 TRACE("Real new size %d+1 WCHARs\n", es->buffer_size);
1116 }
1117 else
1118 WARN("FAILED! Will synchronize partially\n");
1119 }
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001120 es->text = LocalLock(es->hloc32W);
1121 MultiByteToWideChar(CP_ACP, 0, textA, -1, es->text, es->buffer_size + 1);
1122 LocalUnlock(es->hloc32A);
Dmitry Timoshkovf77709e2001-01-10 23:55:02 +00001123 }
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001124 else es->text = LocalLock(es->hloc32W);
Alexandre Julliard3051b641996-07-05 17:14:13 +00001125 }
Huw Davies6a945162007-04-19 15:01:13 +01001126 if(es->flags & EF_APP_HAS_HANDLE) text_buffer_changed(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001127 es->lock_count++;
Alexandre Julliard3051b641996-07-05 17:14:13 +00001128}
1129
1130
1131/*********************************************************************
1132 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01001133 * EDIT_UnlockBuffer
1134 *
1135 */
1136static void EDIT_UnlockBuffer(EDITSTATE *es, BOOL force)
1137{
1138
1139 /* Edit window might be already destroyed */
1140 if(!IsWindow(es->hwndSelf))
1141 {
1142 WARN("edit hwnd %p already destroyed\n", es->hwndSelf);
1143 return;
1144 }
1145
1146 if (!es->lock_count) {
1147 ERR("lock_count == 0 ... please report\n");
1148 return;
1149 }
1150 if (!es->text) {
1151 ERR("es->text == 0 ... please report\n");
1152 return;
1153 }
1154
1155 if (force || (es->lock_count == 1)) {
1156 if (es->hloc32W) {
Francois Gouget9e7b5562009-02-07 16:05:33 +01001157 UINT countA = 0;
1158 UINT countW = get_text_length(es) + 1;
Francois Gouget9e7b5562009-02-07 16:05:33 +01001159
1160 if(es->hloc32A)
1161 {
1162 UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL);
1163 TRACE("Synchronizing with 32-bit ANSI buffer\n");
1164 TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new);
1165 countA = LocalSize(es->hloc32A);
1166 if(countA_new > countA)
1167 {
1168 HLOCAL hloc32A_new;
1169 UINT alloc_size = ROUND_TO_GROW(countA_new);
1170 TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size);
1171 hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT);
1172 if(hloc32A_new)
1173 {
1174 es->hloc32A = hloc32A_new;
1175 countA = LocalSize(hloc32A_new);
1176 TRACE("Real new size %d bytes\n", countA);
1177 }
1178 else
1179 WARN("FAILED! Will synchronize partially\n");
1180 }
Alexandre Julliard7e9721f2009-12-11 17:04:59 +01001181 WideCharToMultiByte(CP_ACP, 0, es->text, countW,
1182 LocalLock(es->hloc32A), countA, NULL, NULL);
1183 LocalUnlock(es->hloc32A);
Francois Gouget9e7b5562009-02-07 16:05:33 +01001184 }
1185
Francois Gouget9e7b5562009-02-07 16:05:33 +01001186 LocalUnlock(es->hloc32W);
1187 es->text = NULL;
1188 }
1189 else {
1190 ERR("no buffer ... please report\n");
1191 return;
1192 }
1193 }
1194 es->lock_count--;
1195}
1196
1197
1198/*********************************************************************
1199 *
1200 * EDIT_MakeFit
1201 *
1202 * Try to fit size + 1 characters in the buffer.
1203 */
1204static BOOL EDIT_MakeFit(EDITSTATE *es, UINT size)
1205{
1206 HLOCAL hNew32W;
1207
1208 if (size <= es->buffer_size)
1209 return TRUE;
1210
1211 TRACE("trying to ReAlloc to %d+1 characters\n", size);
1212
1213 /* Force edit to unlock it's buffer. es->text now NULL */
1214 EDIT_UnlockBuffer(es, TRUE);
1215
1216 if (es->hloc32W) {
1217 UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
1218 if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
1219 TRACE("Old 32 bit handle %p, new handle %p\n", es->hloc32W, hNew32W);
1220 es->hloc32W = hNew32W;
1221 es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1;
1222 }
1223 }
1224
1225 EDIT_LockBuffer(es);
1226
1227 if (es->buffer_size < size) {
1228 WARN("FAILED ! We now have %d+1\n", es->buffer_size);
1229 EDIT_NOTIFY_PARENT(es, EN_ERRSPACE);
1230 return FALSE;
1231 } else {
1232 TRACE("We now have %d+1\n", es->buffer_size);
1233 return TRUE;
1234 }
1235}
1236
1237
1238/*********************************************************************
1239 *
1240 * EDIT_MakeUndoFit
1241 *
1242 * Try to fit size + 1 bytes in the undo buffer.
1243 *
1244 */
1245static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size)
1246{
1247 UINT alloc_size;
1248
1249 if (size <= es->undo_buffer_size)
1250 return TRUE;
1251
1252 TRACE("trying to ReAlloc to %d+1\n", size);
1253
1254 alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR));
1255 if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) {
1256 es->undo_buffer_size = alloc_size/sizeof(WCHAR) - 1;
1257 return TRUE;
1258 }
1259 else
1260 {
1261 WARN("FAILED ! We now have %d+1\n", es->undo_buffer_size);
1262 return FALSE;
1263 }
1264}
1265
1266
1267/*********************************************************************
1268 *
1269 * EDIT_UpdateTextRegion
1270 *
1271 */
1272static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase)
1273{
1274 if (es->flags & EF_UPDATE) {
1275 es->flags &= ~EF_UPDATE;
1276 EDIT_NOTIFY_PARENT(es, EN_UPDATE);
1277 }
1278 InvalidateRgn(es->hwndSelf, hrgn, bErase);
1279}
1280
1281
1282/*********************************************************************
1283 *
1284 * EDIT_UpdateText
1285 *
1286 */
1287static void EDIT_UpdateText(EDITSTATE *es, const RECT *rc, BOOL bErase)
1288{
1289 if (es->flags & EF_UPDATE) {
1290 es->flags &= ~EF_UPDATE;
1291 EDIT_NOTIFY_PARENT(es, EN_UPDATE);
1292 }
1293 InvalidateRect(es->hwndSelf, rc, bErase);
1294}
1295
1296/*********************************************************************
1297 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001298 * EDIT_SL_InvalidateText
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001299 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001300 * Called from EDIT_InvalidateText().
1301 * Does the job for single-line controls only.
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001302 *
1303 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001304static void EDIT_SL_InvalidateText(EDITSTATE *es, INT start, INT end)
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001305{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001306 RECT line_rect;
1307 RECT rc;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001308
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001309 EDIT_GetLineRect(es, 0, start, end, &line_rect);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001310 if (IntersectRect(&rc, &line_rect, &es->format_rect))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001311 EDIT_UpdateText(es, &rc, TRUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001312}
1313
1314
Francois Gouget9e7b5562009-02-07 16:05:33 +01001315static inline INT get_vertical_line_count(EDITSTATE *es)
1316{
1317 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
1318 return max(1,vlc);
1319}
1320
Alexandre Julliard329f0681996-04-14 13:21:20 +00001321/*********************************************************************
1322 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001323 * EDIT_ML_InvalidateText
1324 *
1325 * Called from EDIT_InvalidateText().
1326 * Does the job for multi-line controls only.
Alexandre Julliard329f0681996-04-14 13:21:20 +00001327 *
1328 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001329static void EDIT_ML_InvalidateText(EDITSTATE *es, INT start, INT end)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001330{
Aric Stewart7b9e8272008-10-15 07:30:22 -05001331 INT vlc = get_vertical_line_count(es);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001332 INT sl = EDIT_EM_LineFromChar(es, start);
1333 INT el = EDIT_EM_LineFromChar(es, end);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001334 INT sc;
1335 INT ec;
1336 RECT rc1;
1337 RECT rcWnd;
1338 RECT rcLine;
1339 RECT rcUpdate;
1340 INT l;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001341
Alexandre Julliard889f7421997-04-15 17:19:52 +00001342 if ((el < es->y_offset) || (sl > es->y_offset + vlc))
1343 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001344
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001345 sc = start - EDIT_EM_LineIndex(es, sl);
1346 ec = end - EDIT_EM_LineIndex(es, el);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001347 if (sl < es->y_offset) {
1348 sl = es->y_offset;
1349 sc = 0;
1350 }
1351 if (el > es->y_offset + vlc) {
1352 el = es->y_offset + vlc;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001353 ec = EDIT_EM_LineLength(es, EDIT_EM_LineIndex(es, el));
Alexandre Julliard889f7421997-04-15 17:19:52 +00001354 }
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001355 GetClientRect(es->hwndSelf, &rc1);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001356 IntersectRect(&rcWnd, &rc1, &es->format_rect);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001357 if (sl == el) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001358 EDIT_GetLineRect(es, sl, sc, ec, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001359 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001360 EDIT_UpdateText(es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001361 } else {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001362 EDIT_GetLineRect(es, sl, sc,
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001363 EDIT_EM_LineLength(es,
1364 EDIT_EM_LineIndex(es, sl)),
Alexandre Julliard889f7421997-04-15 17:19:52 +00001365 &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001366 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001367 EDIT_UpdateText(es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001368 for (l = sl + 1 ; l < el ; l++) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001369 EDIT_GetLineRect(es, l, 0,
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001370 EDIT_EM_LineLength(es,
1371 EDIT_EM_LineIndex(es, l)),
Alexandre Julliard889f7421997-04-15 17:19:52 +00001372 &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001373 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001374 EDIT_UpdateText(es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001375 }
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001376 EDIT_GetLineRect(es, el, 0, ec, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001377 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001378 EDIT_UpdateText(es, &rcUpdate, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001379 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00001380}
1381
1382
1383/*********************************************************************
1384 *
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001385 * EDIT_InvalidateText
1386 *
Francois Gouget6d442ae2005-11-23 20:14:43 +01001387 * Invalidate the text from offset start up to, but not including,
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001388 * offset end. Useful for (re)painting the selection.
1389 * Regions outside the linewidth are not invalidated.
1390 * end == -1 means end == TextLength.
1391 * start and end need not be ordered.
1392 *
1393 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001394static void EDIT_InvalidateText(EDITSTATE *es, INT start, INT end)
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001395{
Alexandre Julliard01d63461997-01-20 19:43:45 +00001396 if (end == start)
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001397 return;
1398
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001399 if (end == -1)
Huw Daviesa0dbcb22007-04-19 14:52:51 +01001400 end = get_text_length(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001401
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001402 if (end < start) {
1403 INT tmp = start;
1404 start = end;
1405 end = tmp;
1406 }
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001407
Alexandre Julliard889f7421997-04-15 17:19:52 +00001408 if (es->style & ES_MULTILINE)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001409 EDIT_ML_InvalidateText(es, start, end);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001410 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001411 EDIT_SL_InvalidateText(es, start, end);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001412}
1413
1414
1415/*********************************************************************
1416 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01001417 * EDIT_EM_SetSel
Alexandre Julliard329f0681996-04-14 13:21:20 +00001418 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01001419 * note: unlike the specs say: the order of start and end
1420 * _is_ preserved in Windows. (i.e. start can be > end)
1421 * In other words: this handler is OK
1422 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00001423 */
Francois Gouget9e7b5562009-02-07 16:05:33 +01001424static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001425{
Francois Gouget9e7b5562009-02-07 16:05:33 +01001426 UINT old_start = es->selection_start;
1427 UINT old_end = es->selection_end;
1428 UINT len = get_text_length(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001429
Francois Gouget9e7b5562009-02-07 16:05:33 +01001430 if (start == (UINT)-1) {
1431 start = es->selection_end;
1432 end = es->selection_end;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001433 } else {
Francois Gouget9e7b5562009-02-07 16:05:33 +01001434 start = min(start, len);
1435 end = min(end, len);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001436 }
Francois Gouget9e7b5562009-02-07 16:05:33 +01001437 es->selection_start = start;
1438 es->selection_end = end;
1439 if (after_wrap)
1440 es->flags |= EF_AFTER_WRAP;
1441 else
1442 es->flags &= ~EF_AFTER_WRAP;
1443 /* Compute the necessary invalidation region. */
1444 /* Note that we don't need to invalidate regions which have
1445 * "never" been selected, or those which are "still" selected.
1446 * In fact, every time we hit a selection boundary, we can
1447 * *toggle* whether we need to invalidate. Thus we can optimize by
1448 * *sorting* the interval endpoints. Let's assume that we sort them
1449 * in this order:
1450 * start <= end <= old_start <= old_end
1451 * Knuth 5.3.1 (p 183) assures us that this can be done optimally
1452 * in 5 comparisons; i.e. it is impossible to do better than the
1453 * following: */
1454 ORDER_UINT(end, old_end);
1455 ORDER_UINT(start, old_start);
1456 ORDER_UINT(old_start, old_end);
1457 ORDER_UINT(start, end);
1458 /* Note that at this point 'end' and 'old_start' are not in order, but
1459 * start is definitely the min. and old_end is definitely the max. */
1460 if (end != old_start)
1461 {
1462/*
1463 * One can also do
1464 * ORDER_UINT32(end, old_start);
1465 * EDIT_InvalidateText(es, start, end);
1466 * EDIT_InvalidateText(es, old_start, old_end);
1467 * in place of the following if statement.
1468 * (That would complete the optimal five-comparison four-element sort.)
1469 */
1470 if (old_start > end )
1471 {
1472 EDIT_InvalidateText(es, start, end);
1473 EDIT_InvalidateText(es, old_start, old_end);
1474 }
1475 else
1476 {
1477 EDIT_InvalidateText(es, start, old_start);
1478 EDIT_InvalidateText(es, end, old_end);
1479 }
1480 }
1481 else EDIT_InvalidateText(es, start, old_end);
Alexandre Julliard01d63461997-01-20 19:43:45 +00001482}
1483
1484
1485/*********************************************************************
1486 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01001487 * EDIT_UpdateScrollInfo
Alexandre Julliard01d63461997-01-20 19:43:45 +00001488 *
1489 */
Francois Gouget9e7b5562009-02-07 16:05:33 +01001490static void EDIT_UpdateScrollInfo(EDITSTATE *es)
Alexandre Julliard01d63461997-01-20 19:43:45 +00001491{
Francois Gouget9e7b5562009-02-07 16:05:33 +01001492 if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
1493 {
1494 SCROLLINFO si;
1495 si.cbSize = sizeof(SCROLLINFO);
1496 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
1497 si.nMin = 0;
1498 si.nMax = es->line_count - 1;
1499 si.nPage = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
1500 si.nPos = es->y_offset;
1501 TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
1502 si.nMin, si.nMax, si.nPage, si.nPos);
1503 SetScrollInfo(es->hwndSelf, SB_VERT, &si, TRUE);
1504 }
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00001505
Francois Gouget9e7b5562009-02-07 16:05:33 +01001506 if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
1507 {
1508 SCROLLINFO si;
1509 si.cbSize = sizeof(SCROLLINFO);
1510 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
1511 si.nMin = 0;
1512 si.nMax = es->text_width - 1;
1513 si.nPage = es->format_rect.right - es->format_rect.left;
1514 si.nPos = es->x_offset;
1515 TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
1516 si.nMin, si.nMax, si.nPage, si.nPos);
1517 SetScrollInfo(es->hwndSelf, SB_HORZ, &si, TRUE);
1518 }
1519}
Alexandre Julliard01d63461997-01-20 19:43:45 +00001520
Alexandre Julliard01d63461997-01-20 19:43:45 +00001521
Francois Gouget9e7b5562009-02-07 16:05:33 +01001522/*********************************************************************
1523 *
1524 * EDIT_EM_LineScroll_internal
1525 *
1526 * Version of EDIT_EM_LineScroll for internal use.
1527 * It doesn't refuse if ES_MULTILINE is set and assumes that
1528 * dx is in pixels, dy - in lines.
1529 *
1530 */
1531static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
1532{
1533 INT nyoff;
1534 INT x_offset_in_pixels;
1535 INT lines_per_page = (es->format_rect.bottom - es->format_rect.top) /
1536 es->line_height;
1537
1538 if (es->style & ES_MULTILINE)
1539 {
1540 x_offset_in_pixels = es->x_offset;
Alexandre Julliard01d63461997-01-20 19:43:45 +00001541 }
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001542 else
1543 {
Francois Gouget9e7b5562009-02-07 16:05:33 +01001544 dy = 0;
1545 x_offset_in_pixels = (short)LOWORD(EDIT_EM_PosFromChar(es, es->x_offset, FALSE));
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001546 }
Francois Gouget9e7b5562009-02-07 16:05:33 +01001547
1548 if (-dx > x_offset_in_pixels)
1549 dx = -x_offset_in_pixels;
1550 if (dx > es->text_width - x_offset_in_pixels)
1551 dx = es->text_width - x_offset_in_pixels;
1552 nyoff = max(0, es->y_offset + dy);
1553 if (nyoff >= es->line_count - lines_per_page)
1554 nyoff = max(0, es->line_count - lines_per_page);
1555 dy = (es->y_offset - nyoff) * es->line_height;
1556 if (dx || dy) {
1557 RECT rc1;
1558 RECT rc;
1559
1560 es->y_offset = nyoff;
1561 if(es->style & ES_MULTILINE)
1562 es->x_offset += dx;
1563 else
1564 es->x_offset += dx / es->char_width;
1565
1566 GetClientRect(es->hwndSelf, &rc1);
1567 IntersectRect(&rc, &rc1, &es->format_rect);
1568 ScrollWindowEx(es->hwndSelf, -dx, dy,
1569 NULL, &rc, NULL, NULL, SW_INVALIDATE);
1570 /* force scroll info update */
1571 EDIT_UpdateScrollInfo(es);
1572 }
1573 if (dx && !(es->flags & EF_HSCROLL_TRACK))
1574 EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
1575 if (dy && !(es->flags & EF_VSCROLL_TRACK))
1576 EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
1577 return TRUE;
1578}
1579
1580/*********************************************************************
1581 *
1582 * EM_LINESCROLL
1583 *
1584 * NOTE: dx is in average character widths, dy - in lines;
1585 *
1586 */
1587static BOOL EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy)
1588{
1589 if (!(es->style & ES_MULTILINE))
1590 return FALSE;
1591
1592 dx *= es->char_width;
1593 return EDIT_EM_LineScroll_internal(es, dx, dy);
1594}
1595
1596
1597/*********************************************************************
1598 *
1599 * EM_SCROLL
1600 *
1601 */
1602static LRESULT EDIT_EM_Scroll(EDITSTATE *es, INT action)
1603{
1604 INT dy;
1605
1606 if (!(es->style & ES_MULTILINE))
1607 return (LRESULT)FALSE;
1608
1609 dy = 0;
1610
1611 switch (action) {
1612 case SB_LINEUP:
1613 if (es->y_offset)
1614 dy = -1;
1615 break;
1616 case SB_LINEDOWN:
1617 if (es->y_offset < es->line_count - 1)
1618 dy = 1;
1619 break;
1620 case SB_PAGEUP:
1621 if (es->y_offset)
1622 dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height;
1623 break;
1624 case SB_PAGEDOWN:
1625 if (es->y_offset < es->line_count - 1)
1626 dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
1627 break;
1628 default:
1629 return (LRESULT)FALSE;
1630 }
1631 if (dy) {
1632 INT vlc = get_vertical_line_count(es);
1633 /* check if we are going to move too far */
1634 if(es->y_offset + dy > es->line_count - vlc)
David Hedberg5a1f8c52010-03-03 13:19:47 +01001635 dy = max(es->line_count - vlc, 0) - es->y_offset;
Francois Gouget9e7b5562009-02-07 16:05:33 +01001636
1637 /* Notification is done in EDIT_EM_LineScroll */
David Hedberg598052b2010-03-03 13:19:46 +01001638 if(dy) {
Francois Gouget9e7b5562009-02-07 16:05:33 +01001639 EDIT_EM_LineScroll(es, 0, dy);
David Hedberg598052b2010-03-03 13:19:46 +01001640 return MAKELONG(dy, TRUE);
1641 }
1642
Francois Gouget9e7b5562009-02-07 16:05:33 +01001643 }
David Hedberg598052b2010-03-03 13:19:46 +01001644 return (LRESULT)FALSE;
Francois Gouget9e7b5562009-02-07 16:05:33 +01001645}
1646
1647
1648/*********************************************************************
1649 *
1650 * EDIT_SetCaretPos
1651 *
1652 */
1653static void EDIT_SetCaretPos(EDITSTATE *es, INT pos,
1654 BOOL after_wrap)
1655{
1656 LRESULT res = EDIT_EM_PosFromChar(es, pos, after_wrap);
1657 TRACE("%d - %dx%d\n", pos, (short)LOWORD(res), (short)HIWORD(res));
1658 SetCaretPos((short)LOWORD(res), (short)HIWORD(res));
1659}
1660
1661
1662/*********************************************************************
1663 *
1664 * EM_SCROLLCARET
1665 *
1666 */
1667static void EDIT_EM_ScrollCaret(EDITSTATE *es)
1668{
1669 if (es->style & ES_MULTILINE) {
1670 INT l;
1671 INT vlc;
1672 INT ww;
1673 INT cw = es->char_width;
1674 INT x;
1675 INT dy = 0;
1676 INT dx = 0;
1677
1678 l = EDIT_EM_LineFromChar(es, es->selection_end);
1679 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP));
1680 vlc = get_vertical_line_count(es);
1681 if (l >= es->y_offset + vlc)
1682 dy = l - vlc + 1 - es->y_offset;
1683 if (l < es->y_offset)
1684 dy = l - es->y_offset;
1685 ww = es->format_rect.right - es->format_rect.left;
1686 if (x < es->format_rect.left)
1687 dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw;
1688 if (x > es->format_rect.right)
1689 dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
1690 if (dy || dx || (es->y_offset && (es->line_count - es->y_offset < vlc)))
1691 {
1692 /* check if we are going to move too far */
1693 if(es->x_offset + dx + ww > es->text_width)
1694 dx = es->text_width - ww - es->x_offset;
1695 if(dx || dy || (es->y_offset && (es->line_count - es->y_offset < vlc)))
1696 EDIT_EM_LineScroll_internal(es, dx, dy);
1697 }
1698 } else {
1699 INT x;
1700 INT goal;
1701 INT format_width;
1702
1703 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
1704 format_width = es->format_rect.right - es->format_rect.left;
1705 if (x < es->format_rect.left) {
1706 goal = es->format_rect.left + format_width / HSCROLL_FRACTION;
1707 do {
1708 es->x_offset--;
1709 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
1710 } while ((x < goal) && es->x_offset);
1711 /* FIXME: use ScrollWindow() somehow to improve performance */
1712 EDIT_UpdateText(es, NULL, TRUE);
1713 } else if (x > es->format_rect.right) {
1714 INT x_last;
1715 INT len = get_text_length(es);
1716 goal = es->format_rect.right - format_width / HSCROLL_FRACTION;
1717 do {
1718 es->x_offset++;
1719 x = (short)LOWORD(EDIT_EM_PosFromChar(es, es->selection_end, FALSE));
1720 x_last = (short)LOWORD(EDIT_EM_PosFromChar(es, len, FALSE));
1721 } while ((x > goal) && (x_last > es->format_rect.right));
1722 /* FIXME: use ScrollWindow() somehow to improve performance */
1723 EDIT_UpdateText(es, NULL, TRUE);
1724 }
1725 }
1726
1727 if(es->flags & EF_FOCUSED)
1728 EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001729}
1730
1731
1732/*********************************************************************
1733 *
1734 * EDIT_MoveBackward
1735 *
1736 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001737static void EDIT_MoveBackward(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001738{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001739 INT e = es->selection_end;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001740
Alexandre Julliard889f7421997-04-15 17:19:52 +00001741 if (e) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00001742 e--;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001743 if ((es->style & ES_MULTILINE) && e &&
1744 (es->text[e - 1] == '\r') && (es->text[e] == '\n')) {
1745 e--;
1746 if (e && (es->text[e - 1] == '\r'))
1747 e--;
1748 }
1749 }
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001750 EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
1751 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001752}
1753
1754
1755/*********************************************************************
1756 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001757 * EDIT_MoveDown_ML
1758 *
1759 * Only for multi line controls
1760 * Move the caret one line down, on a column with the nearest
1761 * x coordinate on the screen (might be a different column).
Alexandre Julliard329f0681996-04-14 13:21:20 +00001762 *
1763 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001764static void EDIT_MoveDown_ML(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001765{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001766 INT s = es->selection_start;
1767 INT e = es->selection_end;
1768 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001769 LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
Alexandre Julliard9d615962003-09-17 04:28:28 +00001770 INT x = (short)LOWORD(pos);
1771 INT y = (short)HIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001772
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001773 e = EDIT_CharFromPos(es, x, y + es->line_height, &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001774 if (!extend)
1775 s = e;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001776 EDIT_EM_SetSel(es, s, e, after_wrap);
1777 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001778}
1779
1780
1781/*********************************************************************
1782 *
1783 * EDIT_MoveEnd
1784 *
1785 */
Lei Zhang483116a2008-04-14 17:18:40 -07001786static void EDIT_MoveEnd(EDITSTATE *es, BOOL extend, BOOL ctrl)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001787{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001788 BOOL after_wrap = FALSE;
1789 INT e;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001790
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00001791 /* Pass a high value in x to make sure of receiving the end of the line */
Lei Zhang483116a2008-04-14 17:18:40 -07001792 if (!ctrl && (es->style & ES_MULTILINE))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001793 e = EDIT_CharFromPos(es, 0x3fffffff,
1794 HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001795 else
Huw Daviesa0dbcb22007-04-19 14:52:51 +01001796 e = get_text_length(es);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001797 EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, after_wrap);
1798 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001799}
1800
1801
1802/*********************************************************************
1803 *
1804 * EDIT_MoveForward
1805 *
1806 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001807static void EDIT_MoveForward(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001808{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001809 INT e = es->selection_end;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001810
Alexandre Julliard889f7421997-04-15 17:19:52 +00001811 if (es->text[e]) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00001812 e++;
Alexandre Julliard889f7421997-04-15 17:19:52 +00001813 if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) {
1814 if (es->text[e] == '\n')
1815 e++;
1816 else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n'))
1817 e += 2;
1818 }
1819 }
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001820 EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
1821 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001822}
1823
1824
1825/*********************************************************************
1826 *
1827 * EDIT_MoveHome
1828 *
1829 * Home key: move to beginning of line.
1830 *
1831 */
Lei Zhangdfdd9292008-04-14 17:16:36 -07001832static void EDIT_MoveHome(EDITSTATE *es, BOOL extend, BOOL ctrl)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001833{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001834 INT e;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001835
Pascal Lessard3405f5c1999-09-04 10:59:07 +00001836 /* Pass the x_offset in x to make sure of receiving the first position of the line */
Lei Zhangdfdd9292008-04-14 17:16:36 -07001837 if (!ctrl && (es->style & ES_MULTILINE))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001838 e = EDIT_CharFromPos(es, -es->x_offset,
1839 HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
Alexandre Julliard889f7421997-04-15 17:19:52 +00001840 else
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001841 e = 0;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001842 EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
1843 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001844}
1845
1846
1847/*********************************************************************
1848 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001849 * EDIT_MovePageDown_ML
1850 *
1851 * Only for multi line controls
1852 * Move the caret one page down, on a column with the nearest
1853 * x coordinate on the screen (might be a different column).
Alexandre Julliard329f0681996-04-14 13:21:20 +00001854 *
1855 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001856static void EDIT_MovePageDown_ML(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001857{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001858 INT s = es->selection_start;
1859 INT e = es->selection_end;
1860 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001861 LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
Alexandre Julliard9d615962003-09-17 04:28:28 +00001862 INT x = (short)LOWORD(pos);
1863 INT y = (short)HIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001864
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001865 e = EDIT_CharFromPos(es, x,
Alexandre Julliard889f7421997-04-15 17:19:52 +00001866 y + (es->format_rect.bottom - es->format_rect.top),
1867 &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001868 if (!extend)
1869 s = e;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001870 EDIT_EM_SetSel(es, s, e, after_wrap);
1871 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001872}
1873
1874
1875/*********************************************************************
1876 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001877 * EDIT_MovePageUp_ML
1878 *
1879 * Only for multi line controls
1880 * Move the caret one page up, on a column with the nearest
1881 * x coordinate on the screen (might be a different column).
Alexandre Julliard329f0681996-04-14 13:21:20 +00001882 *
1883 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001884static void EDIT_MovePageUp_ML(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001885{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001886 INT s = es->selection_start;
1887 INT e = es->selection_end;
1888 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001889 LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
Alexandre Julliard9d615962003-09-17 04:28:28 +00001890 INT x = (short)LOWORD(pos);
1891 INT y = (short)HIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001892
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001893 e = EDIT_CharFromPos(es, x,
Alexandre Julliard889f7421997-04-15 17:19:52 +00001894 y - (es->format_rect.bottom - es->format_rect.top),
1895 &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001896 if (!extend)
1897 s = e;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001898 EDIT_EM_SetSel(es, s, e, after_wrap);
1899 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001900}
1901
1902
1903/*********************************************************************
1904 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001905 * EDIT_MoveUp_ML
Alexandre Julliard329f0681996-04-14 13:21:20 +00001906 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00001907 * Only for multi line controls
1908 * Move the caret one line up, on a column with the nearest
1909 * x coordinate on the screen (might be a different column).
1910 *
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00001911 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001912static void EDIT_MoveUp_ML(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001913{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001914 INT s = es->selection_start;
1915 INT e = es->selection_end;
1916 BOOL after_wrap = (es->flags & EF_AFTER_WRAP);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001917 LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap);
Alexandre Julliard9d615962003-09-17 04:28:28 +00001918 INT x = (short)LOWORD(pos);
1919 INT y = (short)HIWORD(pos);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001920
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001921 e = EDIT_CharFromPos(es, x, y - es->line_height, &after_wrap);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001922 if (!extend)
1923 s = e;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001924 EDIT_EM_SetSel(es, s, e, after_wrap);
1925 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001926}
1927
1928
1929/*********************************************************************
1930 *
1931 * EDIT_MoveWordBackward
1932 *
1933 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001934static void EDIT_MoveWordBackward(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001935{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001936 INT s = es->selection_start;
1937 INT e = es->selection_end;
1938 INT l;
1939 INT ll;
1940 INT li;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001941
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001942 l = EDIT_EM_LineFromChar(es, e);
1943 ll = EDIT_EM_LineLength(es, e);
1944 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001945 if (e - li == 0) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00001946 if (l) {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001947 li = EDIT_EM_LineIndex(es, l - 1);
1948 e = li + EDIT_EM_LineLength(es, li);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001949 }
1950 } else {
Andrew Talbot3dfaef32008-01-21 20:06:59 +00001951 e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001952 }
1953 if (!extend)
1954 s = e;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001955 EDIT_EM_SetSel(es, s, e, FALSE);
1956 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001957}
1958
1959
1960/*********************************************************************
1961 *
1962 * EDIT_MoveWordForward
1963 *
1964 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001965static void EDIT_MoveWordForward(EDITSTATE *es, BOOL extend)
Alexandre Julliard329f0681996-04-14 13:21:20 +00001966{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001967 INT s = es->selection_start;
1968 INT e = es->selection_end;
1969 INT l;
1970 INT ll;
1971 INT li;
Alexandre Julliard329f0681996-04-14 13:21:20 +00001972
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001973 l = EDIT_EM_LineFromChar(es, e);
1974 ll = EDIT_EM_LineLength(es, e);
1975 li = EDIT_EM_LineIndex(es, l);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00001976 if (e - li == ll) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00001977 if ((es->style & ES_MULTILINE) && (l != es->line_count - 1))
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001978 e = EDIT_EM_LineIndex(es, l + 1);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001979 } else {
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00001980 e = li + EDIT_CallWordBreakProc(es,
Alexandre Julliard889f7421997-04-15 17:19:52 +00001981 li, e - li + 1, ll, WB_RIGHT);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001982 }
1983 if (!extend)
1984 s = e;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00001985 EDIT_EM_SetSel(es, s, e, FALSE);
1986 EDIT_EM_ScrollCaret(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00001987}
1988
1989
1990/*********************************************************************
1991 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00001992 * EDIT_PaintText
1993 *
1994 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00001995static 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 +00001996{
Alexandre Julliard329f0681996-04-14 13:21:20 +00001997 COLORREF BkColor;
1998 COLORREF TextColor;
Aric Stewart314f45d2005-12-19 18:17:51 +01001999 LOGFONTW underline_font;
2000 HFONT hUnderline = 0;
2001 HFONT old_font = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002002 INT ret;
2003 INT li;
Dan Engel7c7a3572001-04-16 19:32:05 +00002004 INT BkMode;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002005 SIZE size;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002006
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00002007 if (!count)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002008 return 0;
Dan Engel7c7a3572001-04-16 19:32:05 +00002009 BkMode = GetBkMode(dc);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002010 BkColor = GetBkColor(dc);
2011 TextColor = GetTextColor(dc);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002012 if (rev) {
Aric Stewart314f45d2005-12-19 18:17:51 +01002013 if (es->composition_len == 0)
2014 {
2015 SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
2016 SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2017 SetBkMode( dc, OPAQUE);
2018 }
2019 else
2020 {
2021 HFONT current = GetCurrentObject(dc,OBJ_FONT);
2022 GetObjectW(current,sizeof(LOGFONTW),&underline_font);
2023 underline_font.lfUnderline = TRUE;
2024 hUnderline = CreateFontIndirectW(&underline_font);
2025 old_font = SelectObject(dc,hUnderline);
2026 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002027 }
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002028 li = EDIT_EM_LineIndex(es, line);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002029 if (es->style & ES_MULTILINE) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002030 ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count,
Alexandre Julliard889f7421997-04-15 17:19:52 +00002031 es->tabs_count, es->tabs, es->format_rect.left - es->x_offset));
2032 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002033 LPWSTR text = EDIT_GetPasswordPointer_SL(es);
2034 TextOutW(dc, x, y, text + li + col, count);
2035 GetTextExtentPoint32W(dc, text + li + col, count, &size);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002036 ret = size.cx;
2037 if (es->style & ES_PASSWORD)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002038 HeapFree(GetProcessHeap(), 0, text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002039 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002040 if (rev) {
Aric Stewart314f45d2005-12-19 18:17:51 +01002041 if (es->composition_len == 0)
2042 {
2043 SetBkColor(dc, BkColor);
2044 SetTextColor(dc, TextColor);
2045 SetBkMode( dc, BkMode);
2046 }
2047 else
2048 {
2049 if (old_font)
2050 SelectObject(dc,old_font);
2051 if (hUnderline)
2052 DeleteObject(hUnderline);
2053 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002054 }
2055 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002056}
Alexandre Julliard329f0681996-04-14 13:21:20 +00002057
2058
2059/*********************************************************************
2060 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01002061 * EDIT_PaintLine
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002062 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002063 */
Francois Gouget9e7b5562009-02-07 16:05:33 +01002064static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002065{
Francois Gouget9e7b5562009-02-07 16:05:33 +01002066 INT s = es->selection_start;
2067 INT e = es->selection_end;
2068 INT li;
2069 INT ll;
2070 INT x;
2071 INT y;
2072 LRESULT pos;
2073
2074 if (es->style & ES_MULTILINE) {
2075 INT vlc = get_vertical_line_count(es);
2076
2077 if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count))
2078 return;
2079 } else if (line)
2080 return;
2081
2082 TRACE("line=%d\n", line);
2083
2084 pos = EDIT_EM_PosFromChar(es, EDIT_EM_LineIndex(es, line), FALSE);
2085 x = (short)LOWORD(pos);
2086 y = (short)HIWORD(pos);
2087 li = EDIT_EM_LineIndex(es, line);
2088 ll = EDIT_EM_LineLength(es, li);
2089 s = min(es->selection_start, es->selection_end);
2090 e = max(es->selection_start, es->selection_end);
2091 s = min(li + ll, max(li, s));
2092 e = min(li + ll, max(li, e));
2093 if (rev && (s != e) &&
2094 ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) {
2095 x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE);
2096 x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE);
2097 x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
2098 } else
2099 x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
Alexandre Julliard01d63461997-01-20 19:43:45 +00002100}
2101
2102
2103/*********************************************************************
2104 *
Michael Kaufmann41a97572005-06-25 18:32:07 +00002105 * EDIT_AdjustFormatRect
Alexandre Julliard329f0681996-04-14 13:21:20 +00002106 *
Michael Kaufmann41a97572005-06-25 18:32:07 +00002107 * Adjusts the format rectangle for the current font and the
2108 * current client rectangle.
Alexandre Julliard329f0681996-04-14 13:21:20 +00002109 *
2110 */
Michael Kaufmann41a97572005-06-25 18:32:07 +00002111static void EDIT_AdjustFormatRect(EDITSTATE *es)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002112{
Ge van Geldorpc33c2da2004-11-28 14:55:42 +00002113 RECT ClientRect;
Huw Daviesc4b44242006-03-22 12:16:44 +00002114
Francois Gouget6d77d3a2000-03-25 21:44:35 +00002115 es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002116 if (es->style & ES_MULTILINE)
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002117 {
2118 INT fw, vlc, max_x_offset, max_y_offset;
2119
Aric Stewart7b9e8272008-10-15 07:30:22 -05002120 vlc = get_vertical_line_count(es);
2121 es->format_rect.bottom = es->format_rect.top + vlc * es->line_height;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002122
2123 /* correct es->x_offset */
2124 fw = es->format_rect.right - es->format_rect.left;
2125 max_x_offset = es->text_width - fw;
2126 if(max_x_offset < 0) max_x_offset = 0;
2127 if(es->x_offset > max_x_offset)
2128 es->x_offset = max_x_offset;
2129
2130 /* correct es->y_offset */
2131 max_y_offset = es->line_count - vlc;
2132 if(max_y_offset < 0) max_y_offset = 0;
2133 if(es->y_offset > max_y_offset)
2134 es->y_offset = max_y_offset;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00002135
2136 /* force scroll info update */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002137 EDIT_UpdateScrollInfo(es);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002138 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002139 else
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002140 /* Windows doesn't care to fix text placement for SL controls */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002141 es->format_rect.bottom = es->format_rect.top + es->line_height;
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002142
Ge van Geldorpc33c2da2004-11-28 14:55:42 +00002143 /* Always stay within the client area */
2144 GetClientRect(es->hwndSelf, &ClientRect);
2145 es->format_rect.bottom = min(es->format_rect.bottom, ClientRect.bottom);
2146
Alexandre Julliard889f7421997-04-15 17:19:52 +00002147 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
Huw Daviesa0dbcb22007-04-19 14:52:51 +01002148 EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL);
Lauri Tulmin78e76cf2005-01-19 20:53:38 +00002149
2150 EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002151}
2152
2153
2154/*********************************************************************
2155 *
Michael Kaufmann41a97572005-06-25 18:32:07 +00002156 * EDIT_SetRectNP
2157 *
2158 * note: this is not (exactly) the handler called on EM_SETRECTNP
2159 * it is also used to set the rect of a single line control
2160 *
2161 */
Andrew Talbot49c0bd52007-11-19 15:46:20 +00002162static void EDIT_SetRectNP(EDITSTATE *es, const RECT *rc)
Michael Kaufmann41a97572005-06-25 18:32:07 +00002163{
2164 LONG_PTR ExStyle;
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00002165 INT bw, bh;
Michael Kaufmann41a97572005-06-25 18:32:07 +00002166 ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00002167
2168 CopyRect(&es->format_rect, rc);
2169
2170 if (ExStyle & WS_EX_CLIENTEDGE) {
2171 es->format_rect.left++;
2172 es->format_rect.right--;
2173
2174 if (es->format_rect.bottom - es->format_rect.top
2175 >= es->line_height + 2)
2176 {
Michael Kaufmann41a97572005-06-25 18:32:07 +00002177 es->format_rect.top++;
2178 es->format_rect.bottom--;
2179 }
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00002180 }
2181 else if (es->style & WS_BORDER) {
2182 bw = GetSystemMetrics(SM_CXBORDER) + 1;
2183 bh = GetSystemMetrics(SM_CYBORDER) + 1;
2184 es->format_rect.left += bw;
2185 es->format_rect.right -= bw;
2186 if (es->format_rect.bottom - es->format_rect.top
2187 >= es->line_height + 2 * bh)
2188 {
2189 es->format_rect.top += bh;
2190 es->format_rect.bottom -= bh;
2191 }
Michael Kaufmann41a97572005-06-25 18:32:07 +00002192 }
2193
2194 es->format_rect.left += es->left_margin;
2195 es->format_rect.right -= es->right_margin;
2196 EDIT_AdjustFormatRect(es);
2197}
2198
2199
2200/*********************************************************************
2201 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002202 * EM_CHARFROMPOS
2203 *
Gerard Patelc9b65341999-01-24 18:57:23 +00002204 * returns line number (not index) in high-order word of result.
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00002205 * NB : Q137805 is unclear about this. POINT * pointer in lParam apply
Gerard Patelc9b65341999-01-24 18:57:23 +00002206 * to Richedit, not to the edit control. Original documentation is valid.
Alexandre Julliard889f7421997-04-15 17:19:52 +00002207 * FIXME: do the specs mean to return -1 if outside client area or
2208 * if outside formatting rectangle ???
2209 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002210 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002211static LRESULT EDIT_EM_CharFromPos(EDITSTATE *es, INT x, INT y)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002212{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002213 POINT pt;
2214 RECT rc;
2215 INT index;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002216
Alexandre Julliard889f7421997-04-15 17:19:52 +00002217 pt.x = x;
2218 pt.y = y;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002219 GetClientRect(es->hwndSelf, &rc);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002220 if (!PtInRect(&rc, pt))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002221 return -1;
2222
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002223 index = EDIT_CharFromPos(es, x, y, NULL);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002224 return MAKELONG(index, EDIT_EM_LineFromChar(es, index));
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00002225}
2226
Alexandre Julliard329f0681996-04-14 13:21:20 +00002227
Alexandre Julliardd2e1c1a1996-03-09 16:12:43 +00002228/*********************************************************************
Alexandre Julliard329f0681996-04-14 13:21:20 +00002229 *
2230 * EM_FMTLINES
2231 *
Alexandre Julliarda845b881998-06-01 10:44:35 +00002232 * Enable or disable soft breaks.
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002233 *
2234 * This means: insert or remove the soft linebreak character (\r\r\n).
2235 * Take care to check if the text still fits the buffer after insertion.
2236 * If not, notify with EN_ERRSPACE.
2237 *
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00002238 */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002239static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol)
Alexandre Julliard58199531994-04-21 01:20:00 +00002240{
Alexandre Julliarda845b881998-06-01 10:44:35 +00002241 es->flags &= ~EF_USE_SOFTBRK;
2242 if (add_eol) {
2243 es->flags |= EF_USE_SOFTBRK;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002244 FIXME("soft break enabled, not implemented\n");
Alexandre Julliarda845b881998-06-01 10:44:35 +00002245 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002246 return add_eol;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002247}
Alexandre Julliard988ca971994-06-21 16:15:21 +00002248
Alexandre Julliard58199531994-04-21 01:20:00 +00002249
Alexandre Julliard329f0681996-04-14 13:21:20 +00002250/*********************************************************************
2251 *
2252 * EM_GETHANDLE
2253 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002254 * Hopefully this won't fire back at us.
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002255 * We always start with a fixed buffer in the local heap.
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00002256 * Despite of the documentation says that the local heap is used
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002257 * only if DS_LOCALEDIT flag is set, NT and 2000 always allocate
2258 * buffer on the local heap.
Alexandre Julliard889f7421997-04-15 17:19:52 +00002259 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002260 */
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00002261static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002262{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002263 HLOCAL hLocal;
Alexandre Julliard58199531994-04-21 01:20:00 +00002264
Alexandre Julliard889f7421997-04-15 17:19:52 +00002265 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002266 return 0;
2267
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002268 if(es->is_unicode)
2269 hLocal = es->hloc32W;
2270 else
2271 {
2272 if(!es->hloc32A)
2273 {
2274 CHAR *textA;
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002275 UINT countA, alloc_size;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002276 TRACE("Allocating 32-bit ANSI alias buffer\n");
James Hathewayba9b9642001-01-10 22:54:33 +00002277 countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL);
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002278 alloc_size = ROUND_TO_GROW(countA);
2279 if(!(es->hloc32A = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002280 {
Dmitry Timoshkovdf793bc2001-01-15 20:20:31 +00002281 ERR("Could not allocate %d bytes for 32-bit ANSI alias buffer\n", alloc_size);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002282 return 0;
2283 }
2284 textA = LocalLock(es->hloc32A);
James Hathewayba9b9642001-01-10 22:54:33 +00002285 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002286 LocalUnlock(es->hloc32A);
2287 }
2288 hLocal = es->hloc32A;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002289 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002290
Huw Daviesc79ce3c2007-04-19 14:47:12 +01002291 es->flags |= EF_APP_HAS_HANDLE;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002292 TRACE("Returning %p, LocalSize() = %ld\n", hLocal, LocalSize(hLocal));
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002293 return hLocal;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002294}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002295
2296
2297/*********************************************************************
2298 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002299 * EM_GETLINE
2300 *
2301 */
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002302static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002303{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002304 LPWSTR src;
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002305 INT line_len, dst_len;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002306 INT i;
Alexandre Julliard58199531994-04-21 01:20:00 +00002307
Alexandre Julliard889f7421997-04-15 17:19:52 +00002308 if (es->style & ES_MULTILINE) {
2309 if (line >= es->line_count)
2310 return 0;
2311 } else
2312 line = 0;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002313 i = EDIT_EM_LineIndex(es, line);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002314 src = es->text + i;
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002315 line_len = EDIT_EM_LineLength(es, i);
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002316 dst_len = *(WORD *)dst;
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002317 if(unicode)
2318 {
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002319 if(dst_len <= line_len)
2320 {
2321 memcpy(dst, src, dst_len * sizeof(WCHAR));
2322 return dst_len;
2323 }
2324 else /* Append 0 if enough space */
2325 {
2326 memcpy(dst, src, line_len * sizeof(WCHAR));
2327 dst[line_len] = 0;
2328 return line_len;
2329 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002330 }
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002331 else
2332 {
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002333 INT ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, (LPSTR)dst, dst_len, NULL, NULL);
Vitaliy Margolencfbd78d2005-10-18 12:01:38 +00002334 if(!ret && line_len) /* Insufficient buffer size */
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002335 return dst_len;
2336 if(ret < dst_len) /* Append 0 if enough space */
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002337 ((LPSTR)dst)[ret] = 0;
Dmitry Timoshkovbf604532001-02-12 19:15:33 +00002338 return ret;
2339 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002340}
Alexandre Julliard58199531994-04-21 01:20:00 +00002341
Alexandre Julliard58199531994-04-21 01:20:00 +00002342
Alexandre Julliard329f0681996-04-14 13:21:20 +00002343/*********************************************************************
2344 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002345 * EM_GETSEL
2346 *
2347 */
Andrew Talbot49c0bd52007-11-19 15:46:20 +00002348static LRESULT EDIT_EM_GetSel(const EDITSTATE *es, PUINT start, PUINT end)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002349{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002350 UINT s = es->selection_start;
2351 UINT e = es->selection_end;
Alexandre Julliard58199531994-04-21 01:20:00 +00002352
Alexandre Julliarda3960291999-02-26 11:11:13 +00002353 ORDER_UINT(s, e);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002354 if (start)
2355 *start = s;
2356 if (end)
2357 *end = e;
2358 return MAKELONG(s, e);
Alexandre Julliard329f0681996-04-14 13:21:20 +00002359}
2360
2361
2362/*********************************************************************
2363 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002364 * EM_REPLACESEL
2365 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002366 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here
2367 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002368 */
Carl Sopchak23b88ef2002-11-21 03:57:05 +00002369static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002370{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002371 UINT strl = strlenW(lpsz_replace);
Huw Daviesa0dbcb22007-04-19 14:52:51 +01002372 UINT tl = get_text_length(es);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002373 UINT utl;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002374 UINT s;
2375 UINT e;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002376 UINT i;
Krishna Murthy4af4ba42004-05-29 00:21:51 +00002377 UINT size;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002378 LPWSTR p;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00002379 HRGN hrgn = 0;
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002380 LPWSTR buf = NULL;
2381 UINT bufl = 0;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002382
2383 TRACE("%s, can_undo %d, send_update %d\n",
2384 debugstr_w(lpsz_replace), can_undo, send_update);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002385
Alexandre Julliard889f7421997-04-15 17:19:52 +00002386 s = es->selection_start;
2387 e = es->selection_end;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002388
2389 if ((s == e) && !strl)
Alexandre Julliard889f7421997-04-15 17:19:52 +00002390 return;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002391
Alexandre Julliarda3960291999-02-26 11:11:13 +00002392 ORDER_UINT(s, e);
Alexandre Julliard01d63461997-01-20 19:43:45 +00002393
Lauri Tulmin914c1382005-02-21 20:39:52 +00002394 size = tl - (e - s) + strl;
2395 if (!size)
2396 es->text_width = 0;
2397
Krishna Murthy4af4ba42004-05-29 00:21:51 +00002398 /* Issue the EN_MAXTEXT notification and continue with replacing text
2399 * such that buffer limit is honored. */
Alex VillacĂ­s Lasso48fd1062007-10-16 15:25:51 -05002400 if ((honor_limit) && (size > es->buffer_limit)) {
Jacek Caban7371c3c2005-06-27 09:42:40 +00002401 EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
Alex Buseniusca625832007-10-21 13:28:17 +02002402 /* Buffer limit can be smaller than the actual length of text in combobox */
2403 if (es->buffer_limit < (tl - (e-s)))
2404 strl = 0;
2405 else
2406 strl = es->buffer_limit - (tl - (e-s));
Krishna Murthy4af4ba42004-05-29 00:21:51 +00002407 }
2408
2409 if (!EDIT_MakeFit(es, tl - (e - s) + strl))
Alexandre Julliard889f7421997-04-15 17:19:52 +00002410 return;
2411
Alexandre Julliard01d63461997-01-20 19:43:45 +00002412 if (e != s) {
2413 /* there is something to be deleted */
Andreas Mohr07216db2001-11-13 21:29:38 +00002414 TRACE("deleting stuff.\n");
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002415 bufl = e - s;
2416 buf = HeapAlloc(GetProcessHeap(), 0, (bufl + 1) * sizeof(WCHAR));
2417 if (!buf) return;
Peter Berg Larsen6e3bcb52005-04-18 10:30:55 +00002418 memcpy(buf, es->text + s, bufl * sizeof(WCHAR));
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002419 buf[bufl] = 0; /* ensure 0 termination */
2420 /* now delete */
2421 strcpyW(es->text + s, es->text + e);
Huw Davies6a945162007-04-19 15:01:13 +01002422 text_buffer_changed(es);
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002423 }
2424 if (strl) {
2425 /* there is an insertion */
Huw Daviesa0dbcb22007-04-19 14:52:51 +01002426 tl = get_text_length(es);
Francois Gougetaab5e582007-01-18 11:40:15 +01002427 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));
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002428 for (p = es->text + tl ; p >= es->text + s ; p--)
2429 p[strl] = p[0];
2430 for (i = 0 , p = es->text + s ; i < strl ; i++)
2431 p[i] = lpsz_replace[i];
2432 if(es->style & ES_UPPERCASE)
2433 CharUpperBuffW(p, strl);
2434 else if(es->style & ES_LOWERCASE)
2435 CharLowerBuffW(p, strl);
Huw Davies6a945162007-04-19 15:01:13 +01002436 text_buffer_changed(es);
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002437 }
2438 if (es->style & ES_MULTILINE)
2439 {
2440 INT st = min(es->selection_start, es->selection_end);
Aric Stewart7b9e8272008-10-15 07:30:22 -05002441 INT vlc = get_vertical_line_count(es);
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002442
2443 hrgn = CreateRectRgn(0, 0, 0, 0);
2444 EDIT_BuildLineDefs_ML(es, st, st + strl,
2445 strl - abs(es->selection_end - es->selection_start), hrgn);
2446 /* if text is too long undo all changes */
Lauri Tulmina8108022005-06-05 19:19:11 +00002447 if (honor_limit && !(es->style & ES_AUTOVSCROLL) && (es->line_count > vlc)) {
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002448 if (strl)
2449 strcpyW(es->text + e, es->text + e + strl);
2450 if (e != s)
2451 for (i = 0 , p = es->text ; i < e - s ; i++)
2452 p[i + s] = buf[i];
Huw Davies6a945162007-04-19 15:01:13 +01002453 text_buffer_changed(es);
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002454 EDIT_BuildLineDefs_ML(es, s, e,
2455 abs(es->selection_end - es->selection_start) - strl, hrgn);
2456 strl = 0;
2457 e = s;
2458 hrgn = CreateRectRgn(0, 0, 0, 0);
Jacek Caban7371c3c2005-06-27 09:42:40 +00002459 EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002460 }
2461 }
2462 else {
2463 INT fw = es->format_rect.right - es->format_rect.left;
2464 EDIT_CalcLineWidth_SL(es);
2465 /* remove chars that don't fit */
Lauri Tulmina8108022005-06-05 19:19:11 +00002466 if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) {
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002467 while ((es->text_width > fw) && s + strl >= s) {
2468 strcpyW(es->text + s + strl - 1, es->text + s + strl);
2469 strl--;
2470 EDIT_CalcLineWidth_SL(es);
2471 }
Huw Davies6a945162007-04-19 15:01:13 +01002472 text_buffer_changed(es);
Jacek Caban7371c3c2005-06-27 09:42:40 +00002473 EDIT_NOTIFY_PARENT(es, EN_MAXTEXT);
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002474 }
2475 }
2476
2477 if (e != s) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00002478 if (can_undo) {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002479 utl = strlenW(es->undo_text);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002480 if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) {
Alexandre Julliard01d63461997-01-20 19:43:45 +00002481 /* undo-buffer is extended to the right */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002482 EDIT_MakeUndoFit(es, utl + e - s);
Peter Berg Larsen6e3bcb52005-04-18 10:30:55 +00002483 memcpy(es->undo_text + utl, buf, (e - s)*sizeof(WCHAR));
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00002484 (es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002485 } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) {
Alexandre Julliard01d63461997-01-20 19:43:45 +00002486 /* undo-buffer is extended to the left */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002487 EDIT_MakeUndoFit(es, utl + e - s);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002488 for (p = es->undo_text + utl ; p >= es->undo_text ; p--)
Alexandre Julliard01d63461997-01-20 19:43:45 +00002489 p[e - s] = p[0];
Alexandre Julliard889f7421997-04-15 17:19:52 +00002490 for (i = 0 , p = es->undo_text ; i < e - s ; i++)
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002491 p[i] = buf[i];
Alexandre Julliard889f7421997-04-15 17:19:52 +00002492 es->undo_position = s;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002493 } else {
2494 /* new undo-buffer */
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002495 EDIT_MakeUndoFit(es, e - s);
Peter Berg Larsen6e3bcb52005-04-18 10:30:55 +00002496 memcpy(es->undo_text, buf, (e - s)*sizeof(WCHAR));
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00002497 es->undo_text[e - s] = 0; /* ensure 0 termination */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002498 es->undo_position = s;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002499 }
2500 /* any deletion makes the old insertion-undo invalid */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002501 es->undo_insert_count = 0;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002502 } else
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002503 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00002504 }
2505 if (strl) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00002506 if (can_undo) {
2507 if ((s == es->undo_position) ||
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002508 ((es->undo_insert_count) &&
2509 (s == es->undo_position + es->undo_insert_count)))
Alexandre Julliard01d63461997-01-20 19:43:45 +00002510 /*
2511 * insertion is new and at delete position or
2512 * an extension to either left or right
2513 */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002514 es->undo_insert_count += strl;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002515 else {
2516 /* new insertion undo */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002517 es->undo_position = s;
2518 es->undo_insert_count = strl;
Alexandre Julliard01d63461997-01-20 19:43:45 +00002519 /* new insertion makes old delete-buffer invalid */
Alexandre Julliard889f7421997-04-15 17:19:52 +00002520 *es->undo_text = '\0';
Alexandre Julliard01d63461997-01-20 19:43:45 +00002521 }
2522 } else
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002523 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002524 }
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00002525
Lauri Tulmin7cb7c6b2005-02-25 13:59:49 +00002526 if (bufl)
2527 HeapFree(GetProcessHeap(), 0, buf);
2528
2529 s += strl;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002530
Ulrich Czekalla7df33752005-02-16 16:28:34 +00002531 /* If text has been deleted and we're right or center aligned then scroll rightward */
2532 if (es->style & (ES_RIGHT | ES_CENTER))
2533 {
2534 INT delta = strl - abs(es->selection_end - es->selection_start);
2535
2536 if (delta < 0 && es->x_offset)
2537 {
2538 if (abs(delta) > es->x_offset)
2539 es->x_offset = 0;
2540 else
2541 es->x_offset += delta;
2542 }
2543 }
2544
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002545 EDIT_EM_SetSel(es, s, s, FALSE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002546 es->flags |= EF_MODIFIED;
Ulrich Weigand6bfbc3d2000-10-23 00:38:10 +00002547 if (send_update) es->flags |= EF_UPDATE;
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00002548 if (hrgn)
2549 {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002550 EDIT_UpdateTextRegion(es, hrgn, TRUE);
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00002551 DeleteObject(hrgn);
2552 }
2553 else
Huw Davies4c7b65d2003-11-11 00:26:53 +00002554 EDIT_UpdateText(es, NULL, TRUE);
2555
2556 EDIT_EM_ScrollCaret(es);
2557
2558 /* force scroll info update */
2559 EDIT_UpdateScrollInfo(es);
2560
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +00002561
C. Scott Ananianaa636742005-03-22 16:40:36 +00002562 if(send_update || (es->flags & EF_UPDATE))
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +00002563 {
2564 es->flags &= ~EF_UPDATE;
Jacek Caban7371c3c2005-06-27 09:42:40 +00002565 EDIT_NOTIFY_PARENT(es, EN_CHANGE);
Dmitry Timoshkova62f06d2001-03-13 23:31:08 +00002566 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002567}
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002568
Alexandre Julliard329f0681996-04-14 13:21:20 +00002569
2570/*********************************************************************
2571 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002572 * EM_SETHANDLE
2573 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00002574 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???
2575 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002576 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002577static void EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002578{
Alexandre Julliard889f7421997-04-15 17:19:52 +00002579 if (!(es->style & ES_MULTILINE))
2580 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002581
Alexandre Julliard889f7421997-04-15 17:19:52 +00002582 if (!hloc) {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002583 WARN("called with NULL handle\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00002584 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002585 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00002586
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002587 EDIT_UnlockBuffer(es, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002588
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002589 if(es->is_unicode)
2590 {
2591 if(es->hloc32A)
2592 {
2593 LocalFree(es->hloc32A);
Francois Gougetd2667a42002-12-02 18:10:57 +00002594 es->hloc32A = NULL;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002595 }
2596 es->hloc32W = hloc;
2597 }
2598 else
2599 {
2600 INT countW, countA;
2601 HLOCAL hloc32W_new;
2602 WCHAR *textW;
2603 CHAR *textA;
2604
2605 countA = LocalSize(hloc);
2606 textA = LocalLock(hloc);
2607 countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0);
2608 if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR))))
2609 {
2610 ERR("Could not allocate new unicode buffer\n");
2611 return;
2612 }
2613 textW = LocalLock(hloc32W_new);
2614 MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW);
2615 LocalUnlock(hloc32W_new);
2616 LocalUnlock(hloc);
2617
2618 if(es->hloc32W)
2619 LocalFree(es->hloc32W);
2620
2621 es->hloc32W = hloc32W_new;
2622 es->hloc32A = hloc;
2623 }
2624
2625 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
2626
Huw Daviesc79ce3c2007-04-19 14:47:12 +01002627 es->flags |= EF_APP_HAS_HANDLE;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002628 EDIT_LockBuffer(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002629
2630 es->x_offset = es->y_offset = 0;
2631 es->selection_start = es->selection_end = 0;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002632 EDIT_EM_EmptyUndoBuffer(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002633 es->flags &= ~EF_MODIFIED;
2634 es->flags &= ~EF_UPDATE;
Huw Daviesa0dbcb22007-04-19 14:52:51 +01002635 EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002636 EDIT_UpdateText(es, NULL, TRUE);
2637 EDIT_EM_ScrollCaret(es);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00002638 /* force scroll info update */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002639 EDIT_UpdateScrollInfo(es);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002640}
2641
2642
2643/*********************************************************************
2644 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002645 * EM_SETLIMITTEXT
2646 *
Alex VillacĂ­s Lasso48fd1062007-10-16 15:25:51 -05002647 * NOTE: this version currently implements WinNT limits
Alexandre Julliard01d63461997-01-20 19:43:45 +00002648 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002649 */
Alex VillacĂ­s Lasso48fd1062007-10-16 15:25:51 -05002650static void EDIT_EM_SetLimitText(EDITSTATE *es, UINT limit)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002651{
Alex VillacĂ­s Lasso48fd1062007-10-16 15:25:51 -05002652 if (!limit) limit = ~0u;
2653 if (!(es->style & ES_MULTILINE)) limit = min(limit, 0x7ffffffe);
2654 es->buffer_limit = limit;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002655}
2656
2657
2658/*********************************************************************
2659 *
2660 * EM_SETMARGINS
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00002661 *
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002662 * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an
Achim Kaiser6d3ce412003-05-06 18:23:17 +00002663 * action wParam despite what the docs say. EC_USEFONTINFO calculates the
2664 * margin according to the textmetrics of the current font.
2665 *
2666 * FIXME - With TrueType or vector fonts EC_USEFONTINFO currently sets one third
2667 * of the char's width as the margin, but this is not how Windows handles this.
2668 * For all other fonts Windows sets the margins to zero.
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002669 *
Huw Daviesc4b44242006-03-22 12:16:44 +00002670 * FIXME - When EC_USEFONTINFO is used the margins only change if the
2671 * edit control is equal to or larger than a certain size.
2672 * Interestingly if one subtracts both the left and right margins from
2673 * this size one always seems to get an even number. The extents of
2674 * the (four character) string "'**'" match this quite closely, so
2675 * we'll use this until we come up with a better idea.
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002676 */
Huw Daviesc4b44242006-03-22 12:16:44 +00002677static int calc_min_set_margin_size(HDC dc, INT left, INT right)
2678{
2679 WCHAR magic_string[] = {'\'','*','*','\'', 0};
2680 SIZE sz;
2681
2682 GetTextExtentPointW(dc, magic_string, sizeof(magic_string)/sizeof(WCHAR) - 1, &sz);
2683 return sz.cx + left + right;
2684}
2685
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002686static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
Huw Daviesc4b44242006-03-22 12:16:44 +00002687 WORD left, WORD right, BOOL repaint)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002688{
Achim Kaiser6d3ce412003-05-06 18:23:17 +00002689 TEXTMETRICW tm;
2690 INT default_left_margin = 0; /* in pixels */
2691 INT default_right_margin = 0; /* in pixels */
2692
2693 /* Set the default margins depending on the font */
2694 if (es->font && (left == EC_USEFONTINFO || right == EC_USEFONTINFO)) {
2695 HDC dc = GetDC(es->hwndSelf);
2696 HFONT old_font = SelectObject(dc, es->font);
2697 GetTextMetricsW(dc, &tm);
2698 /* The default margins are only non zero for TrueType or Vector fonts */
2699 if (tm.tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE )) {
Huw Daviesc4b44242006-03-22 12:16:44 +00002700 int min_size;
2701 RECT rc;
Achim Kaiser6d3ce412003-05-06 18:23:17 +00002702 /* This must be calculated more exactly! But how? */
Huw Daviesc4b44242006-03-22 12:16:44 +00002703 default_left_margin = tm.tmAveCharWidth / 2;
2704 default_right_margin = tm.tmAveCharWidth / 2;
2705 min_size = calc_min_set_margin_size(dc, default_left_margin, default_right_margin);
2706 GetClientRect(es->hwndSelf, &rc);
2707 if(rc.right - rc.left < min_size) {
2708 default_left_margin = es->left_margin;
2709 default_right_margin = es->right_margin;
2710 }
Achim Kaiser6d3ce412003-05-06 18:23:17 +00002711 }
2712 SelectObject(dc, old_font);
2713 ReleaseDC(es->hwndSelf, dc);
2714 }
2715
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002716 if (action & EC_LEFTMARGIN) {
Michael Kaufmann41a97572005-06-25 18:32:07 +00002717 es->format_rect.left -= es->left_margin;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002718 if (left != EC_USEFONTINFO)
Alexandre Julliard889f7421997-04-15 17:19:52 +00002719 es->left_margin = left;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002720 else
Achim Kaiser6d3ce412003-05-06 18:23:17 +00002721 es->left_margin = default_left_margin;
Michael Kaufmann41a97572005-06-25 18:32:07 +00002722 es->format_rect.left += es->left_margin;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002723 }
2724
2725 if (action & EC_RIGHTMARGIN) {
Michael Kaufmann41a97572005-06-25 18:32:07 +00002726 es->format_rect.right += es->right_margin;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002727 if (right != EC_USEFONTINFO)
2728 es->right_margin = right;
2729 else
Achim Kaiser6d3ce412003-05-06 18:23:17 +00002730 es->right_margin = default_right_margin;
Michael Kaufmann41a97572005-06-25 18:32:07 +00002731 es->format_rect.right -= es->right_margin;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002732 }
Michael Kaufmann41a97572005-06-25 18:32:07 +00002733
2734 if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) {
2735 EDIT_AdjustFormatRect(es);
2736 if (repaint) EDIT_UpdateText(es, NULL, TRUE);
2737 }
2738
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002739 TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
Alexandre Julliard58199531994-04-21 01:20:00 +00002740}
2741
Alexandre Julliard329f0681996-04-14 13:21:20 +00002742
2743/*********************************************************************
2744 *
2745 * EM_SETPASSWORDCHAR
2746 *
2747 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002748static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002749{
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002750 LONG style;
Alexandre Julliardde424282001-08-10 22:51:42 +00002751
Alexandre Julliard889f7421997-04-15 17:19:52 +00002752 if (es->style & ES_MULTILINE)
2753 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002754
Alexandre Julliard889f7421997-04-15 17:19:52 +00002755 if (es->password_char == c)
2756 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002757
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002758 style = GetWindowLongW( es->hwndSelf, GWL_STYLE );
Alexandre Julliard889f7421997-04-15 17:19:52 +00002759 es->password_char = c;
2760 if (c) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002761 SetWindowLongW( es->hwndSelf, GWL_STYLE, style | ES_PASSWORD );
Alexandre Julliardde424282001-08-10 22:51:42 +00002762 es->style |= ES_PASSWORD;
Alexandre Julliard889f7421997-04-15 17:19:52 +00002763 } else {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002764 SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD );
Alexandre Julliardde424282001-08-10 22:51:42 +00002765 es->style &= ~ES_PASSWORD;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002766 }
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002767 EDIT_UpdateText(es, NULL, TRUE);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002768}
2769
2770
2771/*********************************************************************
2772 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002773 * EM_SETTABSTOPS
2774 *
2775 */
Andrew Talbot49c0bd52007-11-19 15:46:20 +00002776static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, const INT *tabs)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002777{
Alexandre Julliard889f7421997-04-15 17:19:52 +00002778 if (!(es->style & ES_MULTILINE))
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002779 return FALSE;
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +00002780 HeapFree(GetProcessHeap(), 0, es->tabs);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002781 es->tabs_count = count;
2782 if (!count)
2783 es->tabs = NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002784 else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002785 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT));
Alexandre Julliarda3960291999-02-26 11:11:13 +00002786 memcpy(es->tabs, tabs, count * sizeof(INT));
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002787 }
2788 return TRUE;
2789}
2790
2791
2792/*********************************************************************
2793 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002794 * EM_SETWORDBREAKPROC
2795 *
2796 */
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002797static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002798{
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002799 if (es->word_break_proc == wbp)
Alexandre Julliard889f7421997-04-15 17:19:52 +00002800 return;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002801
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00002802 es->word_break_proc = wbp;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002803
Alexandre Julliard889f7421997-04-15 17:19:52 +00002804 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) {
Huw Daviesa0dbcb22007-04-19 14:52:51 +01002805 EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002806 EDIT_UpdateText(es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00002807 }
2808}
2809
2810
2811/*********************************************************************
2812 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00002813 * EM_UNDO / WM_UNDO
Alexandre Julliard329f0681996-04-14 13:21:20 +00002814 *
2815 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002816static BOOL EDIT_EM_Undo(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002817{
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00002818 INT ulength;
2819 LPWSTR utext;
2820
Krishna Murthya7c31072004-05-07 00:40:18 +00002821 /* As per MSDN spec, for a single-line edit control,
2822 the return value is always TRUE */
2823 if( es->style & ES_READONLY )
2824 return !(es->style & ES_MULTILINE);
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00002825
2826 ulength = strlenW(es->undo_text);
Krishna Murthya7c31072004-05-07 00:40:18 +00002827
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00002828 utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR));
Alexandre Julliard889f7421997-04-15 17:19:52 +00002829
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002830 strcpyW(utext, es->undo_text);
Alexandre Julliard01d63461997-01-20 19:43:45 +00002831
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002832 TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002833 es->undo_insert_count, debugstr_w(utext));
Alexandre Julliard01d63461997-01-20 19:43:45 +00002834
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002835 EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00002836 EDIT_EM_EmptyUndoBuffer(es);
Krishna Murthyca8e3132004-06-18 22:29:05 +00002837 EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002838 EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
Rein Klazes9d4ae0e2001-04-02 19:13:24 +00002839 /* send the notification after the selection start and end are set */
Jacek Caban7371c3c2005-06-27 09:42:40 +00002840 EDIT_NOTIFY_PARENT(es, EN_CHANGE);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002841 EDIT_EM_ScrollCaret(es);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002842 HeapFree(GetProcessHeap(), 0, utext);
Alexandre Julliard01d63461997-01-20 19:43:45 +00002843
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00002844 TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002845 es->undo_insert_count, debugstr_w(es->undo_text));
Alexandre Julliard01d63461997-01-20 19:43:45 +00002846 return TRUE;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002847}
2848
2849
Lei Zhangf704d5c2008-04-09 11:33:03 -07002850/* Helper function for WM_CHAR
2851 *
2852 * According to an MSDN blog article titled "Just because you're a control
2853 * doesn't mean that you're necessarily inside a dialog box," multiline edit
2854 * controls without ES_WANTRETURN would attempt to detect whether it is inside
2855 * a dialog box or not.
2856 */
Sergey Khodych6fa48cd2009-08-24 00:10:01 +03002857static inline BOOL EDIT_IsInsideDialog(EDITSTATE *es)
Lei Zhangf704d5c2008-04-09 11:33:03 -07002858{
Sergey Khodych6fa48cd2009-08-24 00:10:01 +03002859 return (es->flags & EF_DIALOGMODE);
Lei Zhangf704d5c2008-04-09 11:33:03 -07002860}
2861
2862
Alexandre Julliard329f0681996-04-14 13:21:20 +00002863/*********************************************************************
2864 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01002865 * WM_PASTE
2866 *
2867 */
2868static void EDIT_WM_Paste(EDITSTATE *es)
2869{
2870 HGLOBAL hsrc;
2871 LPWSTR src;
2872
2873 /* Protect read-only edit control from modification */
2874 if(es->style & ES_READONLY)
2875 return;
2876
2877 OpenClipboard(es->hwndSelf);
2878 if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
2879 src = GlobalLock(hsrc);
2880 EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE);
2881 GlobalUnlock(hsrc);
2882 }
2883 else if (es->style & ES_PASSWORD) {
2884 /* clear selected text in password edit box even with empty clipboard */
Kusanagi Kouichiccab1772010-02-13 11:38:21 +09002885 EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
Francois Gouget9e7b5562009-02-07 16:05:33 +01002886 }
2887 CloseClipboard();
2888}
2889
2890
2891/*********************************************************************
2892 *
2893 * WM_COPY
2894 *
2895 */
2896static void EDIT_WM_Copy(EDITSTATE *es)
2897{
2898 INT s = min(es->selection_start, es->selection_end);
2899 INT e = max(es->selection_start, es->selection_end);
2900 HGLOBAL hdst;
2901 LPWSTR dst;
2902 DWORD len;
2903
2904 if (e == s) return;
2905
2906 len = e - s;
2907 hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1) * sizeof(WCHAR));
2908 dst = GlobalLock(hdst);
2909 memcpy(dst, es->text + s, len * sizeof(WCHAR));
2910 dst[len] = 0; /* ensure 0 termination */
2911 TRACE("%s\n", debugstr_w(dst));
2912 GlobalUnlock(hdst);
2913 OpenClipboard(es->hwndSelf);
2914 EmptyClipboard();
2915 SetClipboardData(CF_UNICODETEXT, hdst);
2916 CloseClipboard();
2917}
2918
2919
2920/*********************************************************************
2921 *
2922 * WM_CLEAR
2923 *
2924 */
2925static inline void EDIT_WM_Clear(EDITSTATE *es)
2926{
Francois Gouget9e7b5562009-02-07 16:05:33 +01002927 /* Protect read-only edit control from modification */
2928 if(es->style & ES_READONLY)
2929 return;
2930
2931 EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
2932}
2933
2934
2935/*********************************************************************
2936 *
2937 * WM_CUT
2938 *
2939 */
2940static inline void EDIT_WM_Cut(EDITSTATE *es)
2941{
2942 EDIT_WM_Copy(es);
2943 EDIT_WM_Clear(es);
2944}
2945
2946
2947/*********************************************************************
2948 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00002949 * WM_CHAR
2950 *
2951 */
Lei Zhangc8a4bb82008-04-07 14:11:58 -07002952static LRESULT EDIT_WM_Char(EDITSTATE *es, WCHAR c)
Alexandre Julliard329f0681996-04-14 13:21:20 +00002953{
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00002954 BOOL control;
2955
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00002956 control = GetKeyState(VK_CONTROL) & 0x8000;
2957
Alexandre Julliard329f0681996-04-14 13:21:20 +00002958 switch (c) {
2959 case '\r':
Lei Zhangf704d5c2008-04-09 11:33:03 -07002960 /* If it's not a multiline edit box, it would be ignored below.
2961 * For multiline edit without ES_WANTRETURN, we have to make a
2962 * special case.
2963 */
2964 if ((es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN))
2965 if (EDIT_IsInsideDialog(es))
2966 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00002967 case '\n':
Alexandre Julliard889f7421997-04-15 17:19:52 +00002968 if (es->style & ES_MULTILINE) {
2969 if (es->style & ES_READONLY) {
Lei Zhangdfdd9292008-04-14 17:16:36 -07002970 EDIT_MoveHome(es, FALSE, FALSE);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002971 EDIT_MoveDown_ML(es, FALSE);
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00002972 } else {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002973 static const WCHAR cr_lfW[] = {'\r','\n',0};
Carl Sopchak23b88ef2002-11-21 03:57:05 +00002974 EDIT_EM_ReplaceSel(es, TRUE, cr_lfW, TRUE, TRUE);
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00002975 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002976 }
2977 break;
2978 case '\t':
Alexandre Julliard889f7421997-04-15 17:19:52 +00002979 if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00002980 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00002981 static const WCHAR tabW[] = {'\t',0};
Lei Zhangb7ffa862008-04-09 11:33:32 -07002982 if (EDIT_IsInsideDialog(es))
2983 break;
Carl Sopchak23b88ef2002-11-21 03:57:05 +00002984 EDIT_EM_ReplaceSel(es, TRUE, tabW, TRUE, TRUE);
Alexandre Julliardfa2c7932000-05-26 01:24:56 +00002985 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00002986 break;
Pascal Lessard6fe38e51999-09-03 15:02:48 +00002987 case VK_BACK:
2988 if (!(es->style & ES_READONLY) && !control) {
2989 if (es->selection_start != es->selection_end)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002990 EDIT_WM_Clear(es);
Pascal Lessard6fe38e51999-09-03 15:02:48 +00002991 else {
2992 /* delete character left of caret */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00002993 EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
2994 EDIT_MoveBackward(es, TRUE);
2995 EDIT_WM_Clear(es);
Pascal Lessard6fe38e51999-09-03 15:02:48 +00002996 }
2997 }
2998 break;
Ulrich Czekallac804e3e2000-05-23 21:16:07 +00002999 case 0x03: /* ^C */
Lei Zhang7dd98bb2007-06-13 17:22:49 -07003000 if (!(es->style & ES_PASSWORD))
3001 SendMessageW(es->hwndSelf, WM_COPY, 0, 0);
Susan Farley86d0b032000-05-05 18:21:02 +00003002 break;
Ulrich Czekallac804e3e2000-05-23 21:16:07 +00003003 case 0x16: /* ^V */
Ulrich Czekalla322cd5d2004-09-09 19:18:40 +00003004 if (!(es->style & ES_READONLY))
3005 SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
Susan Farley86d0b032000-05-05 18:21:02 +00003006 break;
Ulrich Czekallac804e3e2000-05-23 21:16:07 +00003007 case 0x18: /* ^X */
Lei Zhang7dd98bb2007-06-13 17:22:49 -07003008 if (!((es->style & ES_READONLY) || (es->style & ES_PASSWORD)))
Ulrich Czekalla322cd5d2004-09-09 19:18:40 +00003009 SendMessageW(es->hwndSelf, WM_CUT, 0, 0);
Susan Farley86d0b032000-05-05 18:21:02 +00003010 break;
Lei Zhang5079d202007-09-11 21:34:10 -07003011 case 0x1A: /* ^Z */
3012 if (!(es->style & ES_READONLY))
3013 SendMessageW(es->hwndSelf, WM_UNDO, 0, 0);
3014 break;
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003015
Alexandre Julliard329f0681996-04-14 13:21:20 +00003016 default:
Krishna Murthyfd43a462004-07-24 02:26:24 +00003017 /*If Edit control style is ES_NUMBER allow users to key in only numeric values*/
3018 if( (es->style & ES_NUMBER) && !( c >= '0' && c <= '9') )
3019 break;
3020
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003021 if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) {
3022 WCHAR str[2];
Alexandre Julliard329f0681996-04-14 13:21:20 +00003023 str[0] = c;
3024 str[1] = '\0';
Carl Sopchak23b88ef2002-11-21 03:57:05 +00003025 EDIT_EM_ReplaceSel(es, TRUE, str, TRUE, TRUE);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003026 }
3027 break;
3028 }
Lei Zhangc8a4bb82008-04-07 14:11:58 -07003029 return 1;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003030}
3031
3032
3033/*********************************************************************
3034 *
3035 * WM_COMMAND
3036 *
3037 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003038static void EDIT_WM_Command(EDITSTATE *es, INT code, INT id, HWND control)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003039{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003040 if (code || control)
3041 return;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003042
Alexandre Julliard889f7421997-04-15 17:19:52 +00003043 switch (id) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003044 case EM_UNDO:
Lei Zhangec915362008-10-14 17:56:52 -07003045 SendMessageW(es->hwndSelf, WM_UNDO, 0, 0);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003046 break;
3047 case WM_CUT:
Lei Zhangec915362008-10-14 17:56:52 -07003048 SendMessageW(es->hwndSelf, WM_CUT, 0, 0);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003049 break;
3050 case WM_COPY:
Lei Zhangec915362008-10-14 17:56:52 -07003051 SendMessageW(es->hwndSelf, WM_COPY, 0, 0);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003052 break;
3053 case WM_PASTE:
Lei Zhangec915362008-10-14 17:56:52 -07003054 SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003055 break;
3056 case WM_CLEAR:
Lei Zhangec915362008-10-14 17:56:52 -07003057 SendMessageW(es->hwndSelf, WM_CLEAR, 0, 0);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003058 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003059 case EM_SETSEL:
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003060 EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
3061 EDIT_EM_ScrollCaret(es);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003062 break;
3063 default:
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00003064 ERR("unknown menu item, please report\n");
Alexandre Julliard01d63461997-01-20 19:43:45 +00003065 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003066 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003067}
3068
3069
3070/*********************************************************************
3071 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003072 * WM_CONTEXTMENU
3073 *
3074 * Note: the resource files resource/sysres_??.rc cannot define a
3075 * single popup menu. Hence we use a (dummy) menubar
3076 * containing the single popup menu as its first item.
3077 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003078 * FIXME: the message identifiers have been chosen arbitrarily,
3079 * hence we use MF_BYPOSITION.
3080 * We might as well use the "real" values (anybody knows ?)
3081 * The menu definition is in resources/sysres_??.rc.
3082 * Once these are OK, we better use MF_BYCOMMAND here
3083 * (as we do in EDIT_WM_Command()).
3084 *
3085 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003086static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003087{
Alexandre Julliarda2e2e182004-02-12 00:35:01 +00003088 HMENU menu = LoadMenuA(user32_module, "EDITMENU");
Alexandre Julliarda3960291999-02-26 11:11:13 +00003089 HMENU popup = GetSubMenu(menu, 0);
3090 UINT start = es->selection_start;
3091 UINT end = es->selection_end;
Alexandre Julliard01d63461997-01-20 19:43:45 +00003092
Alexandre Julliarda3960291999-02-26 11:11:13 +00003093 ORDER_UINT(start, end);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003094
3095 /* undo */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003096 EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003097 /* cut */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003098 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 +00003099 /* copy */
Alexandre Julliarda3960291999-02-26 11:11:13 +00003100 EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003101 /* paste */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003102 EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003103 /* delete */
Dmitry Timoshkov9c446a12001-01-22 19:28:27 +00003104 EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003105 /* select all */
Huw Daviesa0dbcb22007-04-19 14:52:51 +01003106 EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != get_text_length(es)) ? MF_ENABLED : MF_GRAYED));
Alexandre Julliard01d63461997-01-20 19:43:45 +00003107
Dmitry Timoshkovb37b72b2006-12-15 15:04:01 +08003108 if (x == -1 && y == -1) /* passed via VK_APPS press/release */
3109 {
3110 RECT rc;
3111 /* Windows places the menu at the edit's center in this case */
3112 GetClientRect(es->hwndSelf, &rc);
3113 MapWindowPoints(es->hwndSelf, 0, (POINT *)&rc, 2);
3114 x = rc.left + (rc.right - rc.left) / 2;
3115 y = rc.top + (rc.bottom - rc.top) / 2;
3116 }
3117
Vincent Povirka5fd32e2010-04-24 14:33:00 -05003118 if (!(es->flags & EF_FOCUSED))
3119 SetFocus(es->hwndSelf);
3120
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003121 TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, es->hwndSelf, NULL);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003122 DestroyMenu(menu);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003123}
3124
Alexandre Julliard889f7421997-04-15 17:19:52 +00003125
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003126/*********************************************************************
3127 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003128 * WM_GETTEXT
3129 *
3130 */
Andrew Talbot49c0bd52007-11-19 15:46:20 +00003131static INT EDIT_WM_GetText(const EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003132{
Dmitry Timoshkovf8b96e22000-12-20 18:39:14 +00003133 if(!count) return 0;
3134
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003135 if(unicode)
3136 {
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003137 lstrcpynW(dst, es->text, count);
3138 return strlenW(dst);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003139 }
3140 else
3141 {
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003142 LPSTR textA = (LPSTR)dst;
Alexandre Julliard331bf3d2002-08-15 23:28:45 +00003143 if (!WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL))
3144 textA[count - 1] = 0; /* ensure 0 termination */
Dmitry Timoshkov785203c2001-01-11 20:17:21 +00003145 return strlen(textA);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003146 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003147}
3148
Alexandre Julliard889f7421997-04-15 17:19:52 +00003149/*********************************************************************
3150 *
Alexandre Julliard889f7421997-04-15 17:19:52 +00003151 * EDIT_CheckCombo
3152 *
3153 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003154static BOOL EDIT_CheckCombo(EDITSTATE *es, UINT msg, INT key)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003155{
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003156 HWND hLBox = es->hwndListBox;
3157 HWND hCombo;
3158 BOOL bDropped;
3159 int nEUI;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003160
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003161 if (!hLBox)
3162 return FALSE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003163
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003164 hCombo = GetParent(es->hwndSelf);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003165 bDropped = TRUE;
3166 nEUI = 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003167
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003168 TRACE_(combo)("[%p]: handling msg %x (%x)\n", es->hwndSelf, msg, key);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003169
3170 if (key == VK_UP || key == VK_DOWN)
3171 {
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003172 if (SendMessageW(hCombo, CB_GETEXTENDEDUI, 0, 0))
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003173 nEUI = 1;
3174
3175 if (msg == WM_KEYDOWN || nEUI)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003176 bDropped = (BOOL)SendMessageW(hCombo, CB_GETDROPPEDSTATE, 0, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003177 }
3178
3179 switch (msg)
3180 {
3181 case WM_KEYDOWN:
3182 if (!bDropped && nEUI && (key == VK_UP || key == VK_DOWN))
3183 {
3184 /* make sure ComboLBox pops up */
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003185 SendMessageW(hCombo, CB_SETEXTENDEDUI, FALSE, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003186 key = VK_F4;
3187 nEUI = 2;
3188 }
3189
Michael Stefaniuc6f3b4942009-12-27 14:40:45 +01003190 SendMessageW(hLBox, WM_KEYDOWN, key, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003191 break;
3192
3193 case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */
3194 if (nEUI)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003195 SendMessageW(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003196 else
Michael Stefaniuc6f3b4942009-12-27 14:40:45 +01003197 SendMessageW(hLBox, WM_KEYDOWN, VK_F4, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003198 break;
3199 }
3200
3201 if(nEUI == 2)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003202 SendMessageW(hCombo, CB_SETEXTENDEDUI, TRUE, 0);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003203
3204 return TRUE;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003205}
3206
3207
Alexandre Julliard01d63461997-01-20 19:43:45 +00003208/*********************************************************************
3209 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003210 * WM_KEYDOWN
3211 *
3212 * Handling of special keys that don't produce a WM_CHAR
3213 * (i.e. non-printable keys) & Backspace & Delete
3214 *
3215 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003216static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003217{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003218 BOOL shift;
3219 BOOL control;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003220
Alexandre Julliarda3960291999-02-26 11:11:13 +00003221 if (GetKeyState(VK_MENU) & 0x8000)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003222 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003223
Alexandre Julliarda3960291999-02-26 11:11:13 +00003224 shift = GetKeyState(VK_SHIFT) & 0x8000;
3225 control = GetKeyState(VK_CONTROL) & 0x8000;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003226
Alexandre Julliard889f7421997-04-15 17:19:52 +00003227 switch (key) {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003228 case VK_F4:
Alexandre Julliard329f0681996-04-14 13:21:20 +00003229 case VK_UP:
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003230 if (EDIT_CheckCombo(es, WM_KEYDOWN, key) || key == VK_F4)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003231 break;
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003232
Alexandre Julliard889f7421997-04-15 17:19:52 +00003233 /* fall through */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003234 case VK_LEFT:
Alexandre Julliard889f7421997-04-15 17:19:52 +00003235 if ((es->style & ES_MULTILINE) && (key == VK_UP))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003236 EDIT_MoveUp_ML(es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003237 else
3238 if (control)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003239 EDIT_MoveWordBackward(es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003240 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003241 EDIT_MoveBackward(es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003242 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003243 case VK_DOWN:
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003244 if (EDIT_CheckCombo(es, WM_KEYDOWN, key))
Alexandre Julliard889f7421997-04-15 17:19:52 +00003245 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003246 /* fall through */
3247 case VK_RIGHT:
Alexandre Julliard889f7421997-04-15 17:19:52 +00003248 if ((es->style & ES_MULTILINE) && (key == VK_DOWN))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003249 EDIT_MoveDown_ML(es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003250 else if (control)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003251 EDIT_MoveWordForward(es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003252 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003253 EDIT_MoveForward(es, shift);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003254 break;
3255 case VK_HOME:
Lei Zhangdfdd9292008-04-14 17:16:36 -07003256 EDIT_MoveHome(es, shift, control);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003257 break;
3258 case VK_END:
Lei Zhang483116a2008-04-14 17:18:40 -07003259 EDIT_MoveEnd(es, shift, control);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003260 break;
3261 case VK_PRIOR:
Alexandre Julliard889f7421997-04-15 17:19:52 +00003262 if (es->style & ES_MULTILINE)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003263 EDIT_MovePageUp_ML(es, shift);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003264 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003265 EDIT_CheckCombo(es, WM_KEYDOWN, key);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003266 break;
3267 case VK_NEXT:
Alexandre Julliard889f7421997-04-15 17:19:52 +00003268 if (es->style & ES_MULTILINE)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003269 EDIT_MovePageDown_ML(es, shift);
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003270 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003271 EDIT_CheckCombo(es, WM_KEYDOWN, key);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003272 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003273 case VK_DELETE:
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00003274 if (!(es->style & ES_READONLY) && !(shift && control)) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00003275 if (es->selection_start != es->selection_end) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00003276 if (shift)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003277 EDIT_WM_Cut(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003278 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003279 EDIT_WM_Clear(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003280 } else {
Alexandre Julliard889f7421997-04-15 17:19:52 +00003281 if (shift) {
3282 /* delete character left of caret */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003283 EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
3284 EDIT_MoveBackward(es, TRUE);
3285 EDIT_WM_Clear(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003286 } else if (control) {
3287 /* delete to end of line */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003288 EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
Lei Zhang483116a2008-04-14 17:18:40 -07003289 EDIT_MoveEnd(es, TRUE, FALSE);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003290 EDIT_WM_Clear(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003291 } else {
3292 /* delete character right of caret */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003293 EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
3294 EDIT_MoveForward(es, TRUE);
3295 EDIT_WM_Clear(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003296 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003297 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00003298 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003299 break;
3300 case VK_INSERT:
3301 if (shift) {
Alexandre Julliard889f7421997-04-15 17:19:52 +00003302 if (!(es->style & ES_READONLY))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003303 EDIT_WM_Paste(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003304 } else if (control)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003305 EDIT_WM_Copy(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003306 break;
Pascal Lessardaed79e51999-09-10 13:58:34 +00003307 case VK_RETURN:
3308 /* If the edit doesn't want the return send a message to the default object */
Lei Zhang7f10fe02008-04-07 14:13:04 -07003309 if(!(es->style & ES_MULTILINE) || !(es->style & ES_WANTRETURN))
Pascal Lessardaed79e51999-09-10 13:58:34 +00003310 {
Sergey Khodych205a7f72009-08-25 18:01:05 +03003311 DWORD dw;
Lei Zhang2f0b1112008-04-23 17:58:30 -07003312
Sergey Khodych205a7f72009-08-25 18:01:05 +03003313 if (!EDIT_IsInsideDialog(es)) break;
Lei Zhangae1b7352008-04-24 22:17:38 -07003314 if (control) break;
Sergey Khodych205a7f72009-08-25 18:01:05 +03003315 dw = SendMessageW(es->hwndParent, DM_GETDEFID, 0, 0);
3316 if (HIWORD(dw) == DC_HASDEFID)
3317 {
3318 HWND hwDefCtrl = GetDlgItem(es->hwndParent, LOWORD(dw));
3319 if (hwDefCtrl)
3320 {
Michael Stefaniuc6f3b4942009-12-27 14:40:45 +01003321 SendMessageW(es->hwndParent, WM_NEXTDLGCTL, (WPARAM)hwDefCtrl, TRUE);
Sergey Khodych205a7f72009-08-25 18:01:05 +03003322 PostMessageW(hwDefCtrl, WM_KEYDOWN, VK_RETURN, 0);
3323 }
3324 }
Pascal Lessardaed79e51999-09-10 13:58:34 +00003325 }
3326 break;
Lei Zhang6736ed82008-04-07 14:18:34 -07003327 case VK_ESCAPE:
Michael Stefaniuc3a7a0eb2009-08-27 00:30:56 +02003328 if ((es->style & ES_MULTILINE) && EDIT_IsInsideDialog(es))
Sergey Khodych3b6ea112009-08-24 00:33:20 +03003329 PostMessageW(es->hwndParent, WM_CLOSE, 0, 0);
Lei Zhang6736ed82008-04-07 14:18:34 -07003330 break;
Lei Zhang95f323e2008-04-09 19:10:38 -07003331 case VK_TAB:
Sergey Khodychd4707db2009-08-24 01:47:15 +03003332 if ((es->style & ES_MULTILINE) && EDIT_IsInsideDialog(es))
3333 SendMessageW(es->hwndParent, WM_NEXTDLGCTL, shift, 0);
Lei Zhang95f323e2008-04-09 19:10:38 -07003334 break;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003335 }
Sergey Khodych3b6ea112009-08-24 00:33:20 +03003336 return TRUE;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003337}
3338
3339
3340/*********************************************************************
3341 *
3342 * WM_KILLFOCUS
3343 *
3344 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003345static LRESULT EDIT_WM_KillFocus(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003346{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003347 es->flags &= ~EF_FOCUSED;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003348 DestroyCaret();
Alexandre Julliard889f7421997-04-15 17:19:52 +00003349 if(!(es->style & ES_NOHIDESEL))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003350 EDIT_InvalidateText(es, es->selection_start, es->selection_end);
Jacek Caban7371c3c2005-06-27 09:42:40 +00003351 EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003352 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003353}
3354
3355
3356/*********************************************************************
3357 *
3358 * WM_LBUTTONDBLCLK
3359 *
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00003360 * The caret position has been set on the WM_LBUTTONDOWN message
3361 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003362 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003363static LRESULT EDIT_WM_LButtonDblClk(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003364{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003365 INT s;
3366 INT e = es->selection_end;
3367 INT l;
3368 INT li;
3369 INT ll;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003370
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +00003371 es->bCaptureState = TRUE;
3372 SetCapture(es->hwndSelf);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003373
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003374 l = EDIT_EM_LineFromChar(es, e);
3375 li = EDIT_EM_LineIndex(es, l);
3376 ll = EDIT_EM_LineLength(es, e);
Dmitry Timoshkov8058ead2000-12-21 20:19:21 +00003377 s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
3378 e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003379 EDIT_EM_SetSel(es, s, e, FALSE);
3380 EDIT_EM_ScrollCaret(es);
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +00003381 es->region_posx = es->region_posy = 0;
3382 SetTimer(es->hwndSelf, 0, 100, NULL);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003383 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003384}
3385
3386
3387/*********************************************************************
3388 *
3389 * WM_LBUTTONDOWN
3390 *
3391 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003392static LRESULT EDIT_WM_LButtonDown(EDITSTATE *es, DWORD keys, INT x, INT y)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003393{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003394 INT e;
3395 BOOL after_wrap;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003396
Abey George6e013e51999-07-27 17:08:26 +00003397 es->bCaptureState = TRUE;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003398 SetCapture(es->hwndSelf);
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003399 EDIT_ConfinePoint(es, &x, &y);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003400 e = EDIT_CharFromPos(es, x, y, &after_wrap);
3401 EDIT_EM_SetSel(es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
3402 EDIT_EM_ScrollCaret(es);
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00003403 es->region_posx = es->region_posy = 0;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003404 SetTimer(es->hwndSelf, 0, 100, NULL);
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +00003405
3406 if (!(es->flags & EF_FOCUSED))
3407 SetFocus(es->hwndSelf);
3408
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003409 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003410}
3411
3412
3413/*********************************************************************
3414 *
3415 * WM_LBUTTONUP
3416 *
3417 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003418static LRESULT EDIT_WM_LButtonUp(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003419{
Alexandre Julliard6356a442003-02-19 22:04:03 +00003420 if (es->bCaptureState) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003421 KillTimer(es->hwndSelf, 0);
Alexandre Julliard6356a442003-02-19 22:04:03 +00003422 if (GetCapture() == es->hwndSelf) ReleaseCapture();
Alexandre Julliard01d63461997-01-20 19:43:45 +00003423 }
Abey George6e013e51999-07-27 17:08:26 +00003424 es->bCaptureState = FALSE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003425 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003426}
3427
3428
3429/*********************************************************************
3430 *
Alexandre Julliardc6166252000-05-25 23:01:39 +00003431 * WM_MBUTTONDOWN
3432 *
3433 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003434static LRESULT EDIT_WM_MButtonDown(EDITSTATE *es)
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003435{
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003436 SendMessageW(es->hwndSelf, WM_PASTE, 0, 0);
Alexandre Julliardc6166252000-05-25 23:01:39 +00003437 return 0;
3438}
3439
3440
3441/*********************************************************************
3442 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003443 * WM_MOUSEMOVE
3444 *
3445 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003446static LRESULT EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003447{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003448 INT e;
3449 BOOL after_wrap;
3450 INT prex, prey;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003451
Kouji Sasaki108390a2005-05-30 11:09:33 +00003452 /* If the mouse has been captured by process other than the edit control itself,
3453 * the windows edit controls will not select the strings with mouse move.
3454 */
3455 if (!es->bCaptureState || GetCapture() != es->hwndSelf)
Alexandre Julliard889f7421997-04-15 17:19:52 +00003456 return 0;
3457
Alexandre Julliard01d63461997-01-20 19:43:45 +00003458 /*
Alexandre Julliard889f7421997-04-15 17:19:52 +00003459 * FIXME: gotta do some scrolling if outside client
Alexandre Julliard01d63461997-01-20 19:43:45 +00003460 * area. Maybe reset the timer ?
3461 */
Alexandre Julliarde658d821997-11-30 17:45:40 +00003462 prex = x; prey = y;
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003463 EDIT_ConfinePoint(es, &x, &y);
Alexandre Julliarde658d821997-11-30 17:45:40 +00003464 es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
3465 es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003466 e = EDIT_CharFromPos(es, x, y, &after_wrap);
3467 EDIT_EM_SetSel(es, es->selection_start, e, after_wrap);
3468 EDIT_SetCaretPos(es,es->selection_end,es->flags & EF_AFTER_WRAP);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00003469 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003470}
3471
3472
3473/*********************************************************************
3474 *
3475 * WM_PAINT
3476 *
3477 */
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003478static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003479{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003480 PAINTSTRUCT ps;
3481 INT i;
3482 HDC dc;
3483 HFONT old_font = 0;
3484 RECT rc;
Robert Shearman85703282004-08-17 22:09:16 +00003485 RECT rcClient;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003486 RECT rcLine;
3487 RECT rcRgn;
Robert Shearman85703282004-08-17 22:09:16 +00003488 HBRUSH brush;
Michael Kaufmann07763aa2005-06-24 11:33:23 +00003489 HBRUSH old_brush;
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003490 INT bw, bh;
Stephane Lussier93805341999-09-03 16:37:00 +00003491 BOOL rev = es->bEnableState &&
Alexandre Julliard889f7421997-04-15 17:19:52 +00003492 ((es->flags & EF_FOCUSED) ||
3493 (es->style & ES_NOHIDESEL));
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003494 dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps);
Robert Shearman85703282004-08-17 22:09:16 +00003495
3496 GetClientRect(es->hwndSelf, &rcClient);
3497
Michael Kaufmann07763aa2005-06-24 11:33:23 +00003498 /* get the background brush */
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +00003499 brush = EDIT_NotifyCtlColor(es, dc);
Robert Shearman85703282004-08-17 22:09:16 +00003500
Michael Kaufmann07763aa2005-06-24 11:33:23 +00003501 /* paint the border and the background */
3502 IntersectClipRect(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003503
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003504 if(es->style & WS_BORDER) {
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003505 bw = GetSystemMetrics(SM_CXBORDER);
3506 bh = GetSystemMetrics(SM_CYBORDER);
Robert Shearman85703282004-08-17 22:09:16 +00003507 rc = rcClient;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003508 if(es->style & ES_MULTILINE) {
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003509 if(es->style & WS_HSCROLL) rc.bottom+=bh;
3510 if(es->style & WS_VSCROLL) rc.right+=bw;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003511 }
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003512
3513 /* Draw the frame. Same code as in nonclient.c */
3514 old_brush = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
3515 PatBlt(dc, rc.left, rc.top, rc.right - rc.left, bh, PATCOPY);
3516 PatBlt(dc, rc.left, rc.top, bw, rc.bottom - rc.top, PATCOPY);
3517 PatBlt(dc, rc.left, rc.bottom - 1, rc.right - rc.left, -bw, PATCOPY);
3518 PatBlt(dc, rc.right - 1, rc.top, -bw, rc.bottom - rc.top, PATCOPY);
Michael Kaufmann07763aa2005-06-24 11:33:23 +00003519 SelectObject(dc, old_brush);
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003520
3521 /* Keep the border clean */
3522 IntersectClipRect(dc, rc.left+bw, rc.top+bh,
3523 max(rc.right-bw, rc.left+bw), max(rc.bottom-bh, rc.top+bh));
Michael Kaufmann07763aa2005-06-24 11:33:23 +00003524 }
Michael Kaufmanne1d7ff92005-09-06 11:40:01 +00003525
3526 GetClipBox(dc, &rc);
3527 FillRect(dc, &rc, brush);
3528
Alexandre Julliarda3960291999-02-26 11:11:13 +00003529 IntersectClipRect(dc, es->format_rect.left,
Alexandre Julliard889f7421997-04-15 17:19:52 +00003530 es->format_rect.top,
3531 es->format_rect.right,
3532 es->format_rect.bottom);
3533 if (es->style & ES_MULTILINE) {
Robert Shearman85703282004-08-17 22:09:16 +00003534 rc = rcClient;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003535 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003536 }
3537 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00003538 old_font = SelectObject(dc, es->font);
Stephane Lussier93805341999-09-03 16:37:00 +00003539
3540 if (!es->bEnableState)
Alexandre Julliarda3960291999-02-26 11:11:13 +00003541 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
3542 GetClipBox(dc, &rcRgn);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003543 if (es->style & ES_MULTILINE) {
Aric Stewart7b9e8272008-10-15 07:30:22 -05003544 INT vlc = get_vertical_line_count(es);
Francois Gouget6d77d3a2000-03-25 21:44:35 +00003545 for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003546 EDIT_GetLineRect(es, i, 0, -1, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003547 if (IntersectRect(&rc, &rcRgn, &rcLine))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003548 EDIT_PaintLine(es, dc, i, rev);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003549 }
3550 } else {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003551 EDIT_GetLineRect(es, 0, 0, -1, &rcLine);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003552 if (IntersectRect(&rc, &rcRgn, &rcLine))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003553 EDIT_PaintLine(es, dc, 0, rev);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003554 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003555 if (es->font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00003556 SelectObject(dc, old_font);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003557
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003558 if (!hdc)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003559 EndPaint(es->hwndSelf, &ps);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003560}
3561
3562
3563/*********************************************************************
3564 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003565 * WM_SETFOCUS
3566 *
3567 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003568static void EDIT_WM_SetFocus(EDITSTATE *es)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003569{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003570 es->flags |= EF_FOCUSED;
Dmitry Timoshkov2ca23be2005-11-16 11:22:54 +00003571
3572 if (!(es->style & ES_NOHIDESEL))
3573 EDIT_InvalidateText(es, es->selection_start, es->selection_end);
3574
3575 /* single line edit updates itself */
3576 if (!(es->style & ES_MULTILINE))
3577 {
3578 HDC hdc = GetDC(es->hwndSelf);
3579 EDIT_WM_Paint(es, hdc);
3580 ReleaseDC(es->hwndSelf, hdc);
3581 }
3582
Nikolay Sivov258d9532009-03-04 18:03:55 -05003583 CreateCaret(es->hwndSelf, 0, 1, es->line_height);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003584 EDIT_SetCaretPos(es, es->selection_end,
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003585 es->flags & EF_AFTER_WRAP);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003586 ShowCaret(es->hwndSelf);
Jacek Caban7371c3c2005-06-27 09:42:40 +00003587 EDIT_NOTIFY_PARENT(es, EN_SETFOCUS);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003588}
3589
3590
3591/*********************************************************************
3592 *
3593 * WM_SETFONT
3594 *
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003595 * With Win95 look the margins are set to default font value unless
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003596 * the system font (font == 0) is being set, in which case they are left
3597 * unchanged.
3598 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003599 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003600static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003601{
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003602 TEXTMETRICW tm;
Alexandre Julliarda3960291999-02-26 11:11:13 +00003603 HDC dc;
3604 HFONT old_font = 0;
Michael Kaufmann41a97572005-06-25 18:32:07 +00003605 RECT clientRect;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003606
Alexandre Julliard889f7421997-04-15 17:19:52 +00003607 es->font = font;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003608 dc = GetDC(es->hwndSelf);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003609 if (font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00003610 old_font = SelectObject(dc, font);
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003611 GetTextMetricsW(dc, &tm);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003612 es->line_height = tm.tmHeight;
3613 es->char_width = tm.tmAveCharWidth;
3614 if (font)
Alexandre Julliarda3960291999-02-26 11:11:13 +00003615 SelectObject(dc, old_font);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003616 ReleaseDC(es->hwndSelf, dc);
Michael Kaufmann41a97572005-06-25 18:32:07 +00003617
3618 /* Reset the format rect and the margins */
3619 GetClientRect(es->hwndSelf, &clientRect);
3620 EDIT_SetRectNP(es, &clientRect);
Dimitrie O. Paun126227a2004-04-01 04:57:12 +00003621 EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
Michael Kaufmann41a97572005-06-25 18:32:07 +00003622 EC_USEFONTINFO, EC_USEFONTINFO, FALSE);
Pascal Lessard3405f5c1999-09-04 10:59:07 +00003623
Alexandre Julliard889f7421997-04-15 17:19:52 +00003624 if (es->style & ES_MULTILINE)
Huw Daviesa0dbcb22007-04-19 14:52:51 +01003625 EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL);
Dmitry Timoshkov11dbda62001-01-05 03:40:35 +00003626 else
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003627 EDIT_CalcLineWidth_SL(es);
Pascal Lessard3405f5c1999-09-04 10:59:07 +00003628
Alexandre Julliarde658d821997-11-30 17:45:40 +00003629 if (redraw)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003630 EDIT_UpdateText(es, NULL, TRUE);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003631 if (es->flags & EF_FOCUSED) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003632 DestroyCaret();
Nikolay Sivov258d9532009-03-04 18:03:55 -05003633 CreateCaret(es->hwndSelf, 0, 1, es->line_height);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003634 EDIT_SetCaretPos(es, es->selection_end,
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00003635 es->flags & EF_AFTER_WRAP);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003636 ShowCaret(es->hwndSelf);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003637 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003638}
3639
3640
3641/*********************************************************************
3642 *
3643 * WM_SETTEXT
3644 *
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00003645 * NOTES
3646 * For multiline controls (ES_MULTILINE), reception of WM_SETTEXT triggers:
3647 * The modified flag is reset. No notifications are sent.
3648 *
3649 * For single-line controls, reception of WM_SETTEXT triggers:
3650 * The modified flag is reset. EN_UPDATE and EN_CHANGE notifications are sent.
3651 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003652 */
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003653static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003654{
Andrew Talbotbc95bfd2006-11-18 14:22:13 +00003655 LPWSTR textW = NULL;
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003656 if (!unicode && text)
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003657 {
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003658 LPCSTR textA = (LPCSTR)text;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003659 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
Andrew Talbotbc95bfd2006-11-18 14:22:13 +00003660 textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR));
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003661 if (textW)
3662 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
3663 text = textW;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003664 }
3665
C. Scott Ananianaa636742005-03-22 16:40:36 +00003666 if (es->flags & EF_UPDATE)
3667 /* fixed this bug once; complain if we see it about to happen again. */
3668 ERR("SetSel may generate UPDATE message whose handler may reset "
3669 "selection.\n");
3670
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003671 EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
3672 if (text)
3673 {
3674 TRACE("%s\n", debugstr_w(text));
3675 EDIT_EM_ReplaceSel(es, FALSE, text, FALSE, FALSE);
3676 if(!unicode)
Andrew Talbotbc95bfd2006-11-18 14:22:13 +00003677 HeapFree(GetProcessHeap(), 0, textW);
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003678 }
3679 else
3680 {
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003681 TRACE("<NULL>\n");
3682 EDIT_EM_ReplaceSel(es, FALSE, empty_stringW, FALSE, FALSE);
3683 }
3684 es->x_offset = 0;
3685 es->flags &= ~EF_MODIFIED;
3686 EDIT_EM_SetSel(es, 0, 0, FALSE);
3687
3688 /* Send the notification after the selection start and end have been set
3689 * edit control doesn't send notification on WM_SETTEXT
3690 * if it is multiline, or it is part of combobox
3691 */
3692 if( !((es->style & ES_MULTILINE) || es->hwndListBox))
3693 {
Jacek Caban7371c3c2005-06-27 09:42:40 +00003694 EDIT_NOTIFY_PARENT(es, EN_UPDATE);
3695 EDIT_NOTIFY_PARENT(es, EN_CHANGE);
Dimitrie O. Paun438ac9d2004-10-25 21:49:30 +00003696 }
3697 EDIT_EM_ScrollCaret(es);
Lauri Tulmincaa43fe2005-02-14 11:51:52 +00003698 EDIT_UpdateScrollInfo(es);
Alexandre Julliard329f0681996-04-14 13:21:20 +00003699}
3700
3701
3702/*********************************************************************
3703 *
3704 * WM_SIZE
3705 *
3706 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003707static void EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003708{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003709 if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003710 RECT rc;
Dmitry Timoshkov4e62b9d2000-12-19 19:36:49 +00003711 TRACE("width = %d, height = %d\n", width, height);
Alexandre Julliarda3960291999-02-26 11:11:13 +00003712 SetRect(&rc, 0, 0, width, height);
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003713 EDIT_SetRectNP(es, &rc);
3714 EDIT_UpdateText(es, NULL, TRUE);
Alexandre Julliardcdcdede1996-04-21 14:57:41 +00003715 }
Alexandre Julliard329f0681996-04-14 13:21:20 +00003716}
3717
3718
3719/*********************************************************************
3720 *
Bill Medland86bfa4c2001-06-28 18:01:00 +00003721 * WM_STYLECHANGED
3722 *
3723 * This message is sent by SetWindowLong on having changed either the Style
3724 * or the extended style.
3725 *
3726 * We ensure that the window's version of the styles and the EDITSTATE's agree.
3727 *
3728 * See also EDIT_WM_NCCreate
3729 *
3730 * It appears that the Windows version of the edit control allows the style
3731 * (as retrieved by GetWindowLong) to be any value and maintains an internal
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003732 * style variable which will generally be different. In this function we
Bill Medland86bfa4c2001-06-28 18:01:00 +00003733 * update the internal style based on what changed in the externally visible
3734 * style.
3735 *
3736 * Much of this content as based upon the MSDN, especially:
3737 * Platform SDK Documentation -> User Interface Services ->
3738 * Windows User Interface -> Edit Controls -> Edit Control Reference ->
3739 * Edit Control Styles
3740 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003741static LRESULT EDIT_WM_StyleChanged ( EDITSTATE *es, WPARAM which, const STYLESTRUCT *style)
Bill Medland86bfa4c2001-06-28 18:01:00 +00003742{
3743 if (GWL_STYLE == which) {
3744 DWORD style_change_mask;
3745 DWORD new_style;
3746 /* Only a subset of changes can be applied after the control
3747 * has been created.
3748 */
3749 style_change_mask = ES_UPPERCASE | ES_LOWERCASE |
3750 ES_NUMBER;
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003751 if (es->style & ES_MULTILINE)
Bill Medland86bfa4c2001-06-28 18:01:00 +00003752 style_change_mask |= ES_WANTRETURN;
3753
3754 new_style = style->styleNew & style_change_mask;
3755
3756 /* Number overrides lowercase overrides uppercase (at least it
3757 * does in Win95). However I'll bet that ES_NUMBER would be
3758 * invalid under Win 3.1.
3759 */
3760 if (new_style & ES_NUMBER) {
3761 ; /* do not override the ES_NUMBER */
3762 } else if (new_style & ES_LOWERCASE) {
3763 new_style &= ~ES_UPPERCASE;
3764 }
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003765
Bill Medland86bfa4c2001-06-28 18:01:00 +00003766 es->style = (es->style & ~style_change_mask) | new_style;
3767 } else if (GWL_EXSTYLE == which) {
3768 ; /* FIXME - what is needed here */
3769 } else {
Dmitry Timoshkov3c9e7a72007-05-24 23:41:17 +09003770 WARN ("Invalid style change %ld\n",which);
Bill Medland86bfa4c2001-06-28 18:01:00 +00003771 }
3772
3773 return 0;
3774}
3775
3776/*********************************************************************
3777 *
Alexandre Julliard01d63461997-01-20 19:43:45 +00003778 * WM_SYSKEYDOWN
3779 *
3780 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003781static LRESULT EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003782{
Alexandre Julliard889f7421997-04-15 17:19:52 +00003783 if ((key == VK_BACK) && (key_data & 0x2000)) {
Dmitry Timoshkov7a947b32000-11-27 01:34:25 +00003784 if (EDIT_EM_CanUndo(es))
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003785 EDIT_EM_Undo(es);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003786 return 0;
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003787 } else if (key == VK_UP || key == VK_DOWN) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003788 if (EDIT_CheckCombo(es, WM_SYSKEYDOWN, key))
Alexandre Julliard889f7421997-04-15 17:19:52 +00003789 return 0;
Serge Ivanov9eedcf52000-06-07 03:47:34 +00003790 }
Michael Stefaniuc6f3b4942009-12-27 14:40:45 +01003791 return DefWindowProcW(es->hwndSelf, WM_SYSKEYDOWN, key, key_data);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003792}
3793
3794
3795/*********************************************************************
3796 *
3797 * WM_TIMER
3798 *
3799 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003800static void EDIT_WM_Timer(EDITSTATE *es)
Alexandre Julliard01d63461997-01-20 19:43:45 +00003801{
Alexandre Julliarde658d821997-11-30 17:45:40 +00003802 if (es->region_posx < 0) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003803 EDIT_MoveBackward(es, TRUE);
Alexandre Julliarde658d821997-11-30 17:45:40 +00003804 } else if (es->region_posx > 0) {
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003805 EDIT_MoveForward(es, TRUE);
Alexandre Julliarde658d821997-11-30 17:45:40 +00003806 }
Alexandre Julliard01d63461997-01-20 19:43:45 +00003807/*
Alexandre Julliarde658d821997-11-30 17:45:40 +00003808 * FIXME: gotta do some vertical scrolling here, like
Alexandre Julliardde424282001-08-10 22:51:42 +00003809 * EDIT_EM_LineScroll(hwnd, 0, 1);
Alexandre Julliard01d63461997-01-20 19:43:45 +00003810 */
Alexandre Julliard889f7421997-04-15 17:19:52 +00003811}
3812
Alexandre Julliard01d63461997-01-20 19:43:45 +00003813/*********************************************************************
3814 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01003815 * WM_HSCROLL
3816 *
3817 */
3818static LRESULT EDIT_WM_HScroll(EDITSTATE *es, INT action, INT pos)
3819{
3820 INT dx;
3821 INT fw;
3822
3823 if (!(es->style & ES_MULTILINE))
3824 return 0;
3825
3826 if (!(es->style & ES_AUTOHSCROLL))
3827 return 0;
3828
3829 dx = 0;
3830 fw = es->format_rect.right - es->format_rect.left;
3831 switch (action) {
3832 case SB_LINELEFT:
3833 TRACE("SB_LINELEFT\n");
3834 if (es->x_offset)
3835 dx = -es->char_width;
3836 break;
3837 case SB_LINERIGHT:
3838 TRACE("SB_LINERIGHT\n");
3839 if (es->x_offset < es->text_width)
3840 dx = es->char_width;
3841 break;
3842 case SB_PAGELEFT:
3843 TRACE("SB_PAGELEFT\n");
3844 if (es->x_offset)
3845 dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
3846 break;
3847 case SB_PAGERIGHT:
3848 TRACE("SB_PAGERIGHT\n");
3849 if (es->x_offset < es->text_width)
3850 dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
3851 break;
3852 case SB_LEFT:
3853 TRACE("SB_LEFT\n");
3854 if (es->x_offset)
3855 dx = -es->x_offset;
3856 break;
3857 case SB_RIGHT:
3858 TRACE("SB_RIGHT\n");
3859 if (es->x_offset < es->text_width)
3860 dx = es->text_width - es->x_offset;
3861 break;
3862 case SB_THUMBTRACK:
3863 TRACE("SB_THUMBTRACK %d\n", pos);
3864 es->flags |= EF_HSCROLL_TRACK;
3865 if(es->style & WS_HSCROLL)
3866 dx = pos - es->x_offset;
3867 else
3868 {
3869 INT fw, new_x;
3870 /* Sanity check */
3871 if(pos < 0 || pos > 100) return 0;
3872 /* Assume default scroll range 0-100 */
3873 fw = es->format_rect.right - es->format_rect.left;
3874 new_x = pos * (es->text_width - fw) / 100;
3875 dx = es->text_width ? (new_x - es->x_offset) : 0;
3876 }
3877 break;
3878 case SB_THUMBPOSITION:
3879 TRACE("SB_THUMBPOSITION %d\n", pos);
3880 es->flags &= ~EF_HSCROLL_TRACK;
3881 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
3882 dx = pos - es->x_offset;
3883 else
3884 {
3885 INT fw, new_x;
3886 /* Sanity check */
3887 if(pos < 0 || pos > 100) return 0;
3888 /* Assume default scroll range 0-100 */
3889 fw = es->format_rect.right - es->format_rect.left;
3890 new_x = pos * (es->text_width - fw) / 100;
3891 dx = es->text_width ? (new_x - es->x_offset) : 0;
3892 }
3893 if (!dx) {
3894 /* force scroll info update */
3895 EDIT_UpdateScrollInfo(es);
3896 EDIT_NOTIFY_PARENT(es, EN_HSCROLL);
3897 }
3898 break;
3899 case SB_ENDSCROLL:
3900 TRACE("SB_ENDSCROLL\n");
3901 break;
3902 /*
3903 * FIXME : the next two are undocumented !
3904 * Are we doing the right thing ?
3905 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
3906 * although it's also a regular control message.
3907 */
3908 case EM_GETTHUMB: /* this one is used by NT notepad */
Francois Gouget9e7b5562009-02-07 16:05:33 +01003909 {
3910 LRESULT ret;
3911 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_HSCROLL)
3912 ret = GetScrollPos(es->hwndSelf, SB_HORZ);
3913 else
3914 {
3915 /* Assume default scroll range 0-100 */
3916 INT fw = es->format_rect.right - es->format_rect.left;
3917 ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
3918 }
3919 TRACE("EM_GETTHUMB: returning %ld\n", ret);
3920 return ret;
3921 }
Alexandre Julliard6af1df82009-12-15 13:22:45 +01003922 case EM_LINESCROLL:
Francois Gouget9e7b5562009-02-07 16:05:33 +01003923 TRACE("EM_LINESCROLL16\n");
3924 dx = pos;
3925 break;
3926
3927 default:
3928 ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
3929 action, action);
3930 return 0;
3931 }
3932 if (dx)
3933 {
3934 INT fw = es->format_rect.right - es->format_rect.left;
3935 /* check if we are going to move too far */
3936 if(es->x_offset + dx + fw > es->text_width)
3937 dx = es->text_width - fw - es->x_offset;
3938 if(dx)
3939 EDIT_EM_LineScroll_internal(es, dx, 0);
3940 }
3941 return 0;
3942}
3943
3944
3945/*********************************************************************
3946 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003947 * WM_VSCROLL
3948 *
Alexandre Julliard329f0681996-04-14 13:21:20 +00003949 */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003950static LRESULT EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos)
Alexandre Julliard329f0681996-04-14 13:21:20 +00003951{
Alexandre Julliarda3960291999-02-26 11:11:13 +00003952 INT dy;
Alexandre Julliard329f0681996-04-14 13:21:20 +00003953
Alexandre Julliard889f7421997-04-15 17:19:52 +00003954 if (!(es->style & ES_MULTILINE))
3955 return 0;
3956
3957 if (!(es->style & ES_AUTOVSCROLL))
3958 return 0;
3959
Alexandre Julliard889f7421997-04-15 17:19:52 +00003960 dy = 0;
3961 switch (action) {
Alexandre Julliard329f0681996-04-14 13:21:20 +00003962 case SB_LINEUP:
Alexandre Julliard329f0681996-04-14 13:21:20 +00003963 case SB_LINEDOWN:
Alexandre Julliard329f0681996-04-14 13:21:20 +00003964 case SB_PAGEUP:
Alexandre Julliard329f0681996-04-14 13:21:20 +00003965 case SB_PAGEDOWN:
Lionel Ulmer28d9aaf2004-03-29 22:54:05 +00003966 TRACE("action %d (%s)\n", action, (action == SB_LINEUP ? "SB_LINEUP" :
3967 (action == SB_LINEDOWN ? "SB_LINEDOWN" :
3968 (action == SB_PAGEUP ? "SB_PAGEUP" :
3969 "SB_PAGEDOWN"))));
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00003970 EDIT_EM_Scroll(es, action);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003971 return 0;
Alexandre Julliard889f7421997-04-15 17:19:52 +00003972 case SB_TOP:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003973 TRACE("SB_TOP\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00003974 dy = -es->y_offset;
3975 break;
3976 case SB_BOTTOM:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003977 TRACE("SB_BOTTOM\n");
Alexandre Julliard889f7421997-04-15 17:19:52 +00003978 dy = es->line_count - 1 - es->y_offset;
3979 break;
3980 case SB_THUMBTRACK:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003981 TRACE("SB_THUMBTRACK %d\n", pos);
Alexandre Julliard889f7421997-04-15 17:19:52 +00003982 es->flags |= EF_VSCROLL_TRACK;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003983 if(es->style & WS_VSCROLL)
3984 dy = pos - es->y_offset;
3985 else
3986 {
3987 /* Assume default scroll range 0-100 */
3988 INT vlc, new_y;
3989 /* Sanity check */
3990 if(pos < 0 || pos > 100) return 0;
Aric Stewart7b9e8272008-10-15 07:30:22 -05003991 vlc = get_vertical_line_count(es);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003992 new_y = pos * (es->line_count - vlc) / 100;
3993 dy = es->line_count ? (new_y - es->y_offset) : 0;
3994 TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
3995 es->line_count, es->y_offset, pos, dy);
3996 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00003997 break;
3998 case SB_THUMBPOSITION:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00003999 TRACE("SB_THUMBPOSITION %d\n", pos);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004000 es->flags &= ~EF_VSCROLL_TRACK;
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004001 if(es->style & WS_VSCROLL)
4002 dy = pos - es->y_offset;
4003 else
4004 {
4005 /* Assume default scroll range 0-100 */
4006 INT vlc, new_y;
4007 /* Sanity check */
4008 if(pos < 0 || pos > 100) return 0;
Aric Stewart7b9e8272008-10-15 07:30:22 -05004009 vlc = get_vertical_line_count(es);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004010 new_y = pos * (es->line_count - vlc) / 100;
4011 dy = es->line_count ? (new_y - es->y_offset) : 0;
4012 TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
4013 es->line_count, es->y_offset, pos, dy);
4014 }
4015 if (!dy)
4016 {
4017 /* force scroll info update */
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00004018 EDIT_UpdateScrollInfo(es);
Jacek Caban7371c3c2005-06-27 09:42:40 +00004019 EDIT_NOTIFY_PARENT(es, EN_VSCROLL);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004020 }
4021 break;
4022 case SB_ENDSCROLL:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004023 TRACE("SB_ENDSCROLL\n");
4024 break;
4025 /*
4026 * FIXME : the next two are undocumented !
4027 * Are we doing the right thing ?
4028 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
4029 * although it's also a regular control message.
4030 */
4031 case EM_GETTHUMB: /* this one is used by NT notepad */
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004032 {
4033 LRESULT ret;
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00004034 if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_VSCROLL)
4035 ret = GetScrollPos(es->hwndSelf, SB_VERT);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004036 else
4037 {
4038 /* Assume default scroll range 0-100 */
Aric Stewart7b9e8272008-10-15 07:30:22 -05004039 INT vlc = get_vertical_line_count(es);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004040 ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0;
4041 }
4042 TRACE("EM_GETTHUMB: returning %ld\n", ret);
4043 return ret;
4044 }
Alexandre Julliard6af1df82009-12-15 13:22:45 +01004045 case EM_LINESCROLL:
4046 TRACE("EM_LINESCROLL %d\n", pos);
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004047 dy = pos;
Alexandre Julliard889f7421997-04-15 17:19:52 +00004048 break;
4049
Alexandre Julliard329f0681996-04-14 13:21:20 +00004050 default:
Dmitry Timoshkova234db82001-01-19 20:49:54 +00004051 ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n",
4052 action, action);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004053 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004054 }
Alexandre Julliard889f7421997-04-15 17:19:52 +00004055 if (dy)
Dimitrie O. Pauna4273ca2002-09-25 03:24:53 +00004056 EDIT_EM_LineScroll(es, 0, dy);
Alexandre Julliard889f7421997-04-15 17:19:52 +00004057 return 0;
Alexandre Julliard329f0681996-04-14 13:21:20 +00004058}
Ulrich Czekalla70d5a952000-05-26 01:17:34 +00004059
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004060/*********************************************************************
4061 *
Francois Gouget9e7b5562009-02-07 16:05:33 +01004062 * EM_GETTHUMB
4063 *
4064 * FIXME: is this right ? (or should it be only VSCROLL)
4065 * (and maybe only for edit controls that really have their
4066 * own scrollbars) (and maybe only for multiline controls ?)
4067 * All in all: very poorly documented
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004068 *
4069 */
Francois Gouget9e7b5562009-02-07 16:05:33 +01004070static LRESULT EDIT_EM_GetThumb(EDITSTATE *es)
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004071{
Alexandre Julliard6af1df82009-12-15 13:22:45 +01004072 return MAKELONG(EDIT_WM_VScroll(es, EM_GETTHUMB, 0),
4073 EDIT_WM_HScroll(es, EM_GETTHUMB, 0));
Ulrich Czekallaf11ff2a2001-03-31 00:51:10 +00004074}
4075
Ulrich Czekalla70d5a952000-05-26 01:17:34 +00004076
Aric Stewart314f45d2005-12-19 18:17:51 +01004077/********************************************************************
4078 *
4079 * The Following code is to handle inline editing from IMEs
4080 */
4081
Kusanagi Kouichid79dff42008-04-18 08:39:31 +09004082static void EDIT_GetCompositionStr(HIMC hIMC, LPARAM CompFlag, EDITSTATE *es)
Aric Stewart314f45d2005-12-19 18:17:51 +01004083{
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004084 LONG buflen;
Aric Stewart314f45d2005-12-19 18:17:51 +01004085 LPWSTR lpCompStr = NULL;
Aric Stewart314f45d2005-12-19 18:17:51 +01004086 LPSTR lpCompStrAttr = NULL;
4087 DWORD dwBufLenAttr;
4088
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004089 buflen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
Aric Stewart314f45d2005-12-19 18:17:51 +01004090
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004091 if (buflen < 0)
Aric Stewart314f45d2005-12-19 18:17:51 +01004092 {
Aric Stewart314f45d2005-12-19 18:17:51 +01004093 return;
4094 }
4095
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004096 lpCompStr = HeapAlloc(GetProcessHeap(),0,buflen + sizeof(WCHAR));
Aric Stewart314f45d2005-12-19 18:17:51 +01004097 if (!lpCompStr)
4098 {
4099 ERR("Unable to allocate IME CompositionString\n");
Aric Stewart314f45d2005-12-19 18:17:51 +01004100 return;
4101 }
4102
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004103 if (buflen)
4104 ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, buflen);
4105 lpCompStr[buflen/sizeof(WCHAR)] = 0;
Aric Stewart314f45d2005-12-19 18:17:51 +01004106
4107 if (CompFlag & GCS_COMPATTR)
4108 {
4109 /*
4110 * We do not use the attributes yet. it would tell us what characters
4111 * are in transition and which are converted or decided upon
4112 */
4113 dwBufLenAttr = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0);
4114 if (dwBufLenAttr)
4115 {
4116 dwBufLenAttr ++;
Aric Stewart5537fbb2006-09-21 09:43:00 -05004117 lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr+1);
Aric Stewart314f45d2005-12-19 18:17:51 +01004118 if (!lpCompStrAttr)
4119 {
4120 ERR("Unable to allocate IME Attribute String\n");
4121 HeapFree(GetProcessHeap(),0,lpCompStr);
Aric Stewart314f45d2005-12-19 18:17:51 +01004122 return;
4123 }
4124 ImmGetCompositionStringW(hIMC,GCS_COMPATTR, lpCompStrAttr,
4125 dwBufLenAttr);
4126 lpCompStrAttr[dwBufLenAttr] = 0;
4127 }
4128 else
4129 lpCompStrAttr = NULL;
4130 }
4131
4132 /* check for change in composition start */
4133 if (es->selection_end < es->composition_start)
4134 es->composition_start = es->selection_end;
4135
4136 /* replace existing selection string */
4137 es->selection_start = es->composition_start;
4138
4139 if (es->composition_len > 0)
4140 es->selection_end = es->composition_start + es->composition_len;
4141 else
4142 es->selection_end = es->selection_start;
4143
4144 EDIT_EM_ReplaceSel(es, FALSE, lpCompStr, TRUE, TRUE);
4145 es->composition_len = abs(es->composition_start - es->selection_end);
4146
4147 es->selection_start = es->composition_start;
4148 es->selection_end = es->selection_start + es->composition_len;
4149
4150 HeapFree(GetProcessHeap(),0,lpCompStrAttr);
4151 HeapFree(GetProcessHeap(),0,lpCompStr);
Aric Stewart314f45d2005-12-19 18:17:51 +01004152}
4153
Kusanagi Kouichid79dff42008-04-18 08:39:31 +09004154static void EDIT_GetResultStr(HIMC hIMC, EDITSTATE *es)
Aric Stewart314f45d2005-12-19 18:17:51 +01004155{
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004156 LONG buflen;
Aric Stewart314f45d2005-12-19 18:17:51 +01004157 LPWSTR lpResultStr;
Aric Stewart314f45d2005-12-19 18:17:51 +01004158
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004159 buflen = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
4160 if (buflen <= 0)
Aric Stewart314f45d2005-12-19 18:17:51 +01004161 {
Aric Stewart314f45d2005-12-19 18:17:51 +01004162 return;
4163 }
4164
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004165 lpResultStr = HeapAlloc(GetProcessHeap(),0, buflen+sizeof(WCHAR));
Aric Stewart314f45d2005-12-19 18:17:51 +01004166 if (!lpResultStr)
4167 {
4168 ERR("Unable to alloc buffer for IME string\n");
Aric Stewart314f45d2005-12-19 18:17:51 +01004169 return;
4170 }
4171
Marcus Meissnerf09f03a2008-02-17 15:58:06 +01004172 ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, buflen);
4173 lpResultStr[buflen/sizeof(WCHAR)] = 0;
Aric Stewart314f45d2005-12-19 18:17:51 +01004174
4175 /* check for change in composition start */
4176 if (es->selection_end < es->composition_start)
4177 es->composition_start = es->selection_end;
4178
4179 es->selection_start = es->composition_start;
4180 es->selection_end = es->composition_start + es->composition_len;
4181 EDIT_EM_ReplaceSel(es, TRUE, lpResultStr, TRUE, TRUE);
4182 es->composition_start = es->selection_end;
4183 es->composition_len = 0;
4184
4185 HeapFree(GetProcessHeap(),0,lpResultStr);
Aric Stewart314f45d2005-12-19 18:17:51 +01004186}
4187
4188static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es)
4189{
Kusanagi Kouichid79dff42008-04-18 08:39:31 +09004190 HIMC hIMC;
4191 int cursor;
4192
4193 if (es->composition_len == 0 && es->selection_start != es->selection_end)
4194 {
Kusanagi Kouichid79dff42008-04-18 08:39:31 +09004195 EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
4196 es->composition_start = es->selection_end;
4197 }
4198
4199 hIMC = ImmGetContext(hwnd);
4200 if (!hIMC)
4201 return;
4202
Aric Stewart314f45d2005-12-19 18:17:51 +01004203 if (CompFlag & GCS_RESULTSTR)
Kusanagi Kouichid79dff42008-04-18 08:39:31 +09004204 EDIT_GetResultStr(hIMC, es);
Aric Stewart314f45d2005-12-19 18:17:51 +01004205 if (CompFlag & GCS_COMPSTR)
Kusanagi Kouichid79dff42008-04-18 08:39:31 +09004206 EDIT_GetCompositionStr(hIMC, CompFlag, es);
4207 cursor = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, 0, 0);
4208 ImmReleaseContext(hwnd, hIMC);
4209 EDIT_SetCaretPos(es, es->selection_start + cursor, es->flags & EF_AFTER_WRAP);
Aric Stewart314f45d2005-12-19 18:17:51 +01004210}
Francois Gouget9e7b5562009-02-07 16:05:33 +01004211
4212
4213/*********************************************************************
4214 *
4215 * WM_NCCREATE
4216 *
4217 * See also EDIT_WM_StyleChanged
4218 */
4219static LRESULT EDIT_WM_NCCreate(HWND hwnd, LPCREATESTRUCTW lpcs, BOOL unicode)
4220{
4221 EDITSTATE *es;
4222 UINT alloc_size;
4223
4224 TRACE("Creating %s edit control, style = %08x\n",
4225 unicode ? "Unicode" : "ANSI", lpcs->style);
4226
4227 if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es))))
4228 return FALSE;
4229 SetWindowLongPtrW( hwnd, 0, (LONG_PTR)es );
4230
4231 /*
4232 * Note: since the EDITSTATE has not been fully initialized yet,
4233 * we can't use any API calls that may send
4234 * WM_XXX messages before WM_NCCREATE is completed.
4235 */
4236
4237 es->is_unicode = unicode;
4238 es->style = lpcs->style;
4239
4240 es->bEnableState = !(es->style & WS_DISABLED);
4241
4242 es->hwndSelf = hwnd;
4243 /* Save parent, which will be notified by EN_* messages */
4244 es->hwndParent = lpcs->hwndParent;
4245
4246 if (es->style & ES_COMBO)
4247 es->hwndListBox = GetDlgItem(es->hwndParent, ID_CB_LISTBOX);
4248
4249 /* FIXME: should we handle changes to WS_EX_RIGHT style after creation? */
4250 if (lpcs->dwExStyle & WS_EX_RIGHT) es->style |= ES_RIGHT;
4251
4252 /* Number overrides lowercase overrides uppercase (at least it
4253 * does in Win95). However I'll bet that ES_NUMBER would be
4254 * invalid under Win 3.1.
4255 */
4256 if (es->style & ES_NUMBER) {
4257 ; /* do not override the ES_NUMBER */
4258 } else if (es->style & ES_LOWERCASE) {
4259 es->style &= ~ES_UPPERCASE;
4260 }
4261 if (es->style & ES_MULTILINE) {
4262 es->buffer_limit = BUFLIMIT_INITIAL;
4263 if (es->style & WS_VSCROLL)
4264 es->style |= ES_AUTOVSCROLL;
4265 if (es->style & WS_HSCROLL)
4266 es->style |= ES_AUTOHSCROLL;
4267 es->style &= ~ES_PASSWORD;
4268 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) {
4269 /* Confirmed - RIGHT overrides CENTER */
4270 if (es->style & ES_RIGHT)
4271 es->style &= ~ES_CENTER;
4272 es->style &= ~WS_HSCROLL;
4273 es->style &= ~ES_AUTOHSCROLL;
4274 }
4275 } else {
4276 es->buffer_limit = BUFLIMIT_INITIAL;
4277 if ((es->style & ES_RIGHT) && (es->style & ES_CENTER))
4278 es->style &= ~ES_CENTER;
4279 es->style &= ~WS_HSCROLL;
4280 es->style &= ~WS_VSCROLL;
4281 if (es->style & ES_PASSWORD)
4282 es->password_char = '*';
4283 }
4284
4285 alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR));
4286 if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size)))
Nikolay Sivove72ed1c2009-10-20 21:56:44 +04004287 goto cleanup;
Francois Gouget9e7b5562009-02-07 16:05:33 +01004288 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1;
4289
4290 if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR))))
Nikolay Sivove72ed1c2009-10-20 21:56:44 +04004291 goto cleanup;
Francois Gouget9e7b5562009-02-07 16:05:33 +01004292 es->undo_buffer_size = es->buffer_size;
4293
4294 if (es->style & ES_MULTILINE)
4295 if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF))))
Nikolay Sivove72ed1c2009-10-20 21:56:44 +04004296 goto cleanup;
Francois Gouget9e7b5562009-02-07 16:05:33 +01004297 es->line_count = 1;
4298
4299 /*
4300 * In Win95 look and feel, the WS_BORDER style is replaced by the
4301 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit
4302 * control a nonclient area so we don't need to draw the border.
4303 * If WS_BORDER without WS_EX_CLIENTEDGE is specified we shouldn't have
4304 * a nonclient area and we should handle painting the border ourselves.
4305 *
4306 * When making modifications please ensure that the code still works
4307 * for edit controls created directly with style 0x50800000, exStyle 0
4308 * (which should have a single pixel border)
4309 */
4310 if (lpcs->dwExStyle & WS_EX_CLIENTEDGE)
4311 es->style &= ~WS_BORDER;
4312 else if (es->style & WS_BORDER)
4313 SetWindowLongW(hwnd, GWL_STYLE, es->style & ~WS_BORDER);
4314
4315 return TRUE;
Nikolay Sivove72ed1c2009-10-20 21:56:44 +04004316
4317cleanup:
4318 SetWindowLongPtrW(es->hwndSelf, 0, 0);
4319 HeapFree(GetProcessHeap(), 0, es->first_line_def);
4320 HeapFree(GetProcessHeap(), 0, es->undo_text);
4321 if (es->hloc32W) LocalFree(es->hloc32W);
4322 HeapFree(GetProcessHeap(), 0, es);
4323 return FALSE;
Francois Gouget9e7b5562009-02-07 16:05:33 +01004324}
4325
4326
4327/*********************************************************************
4328 *
4329 * WM_CREATE
4330 *
4331 */
4332static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
4333{
4334 RECT clientRect;
4335
4336 TRACE("%s\n", debugstr_w(name));
4337 /*
4338 * To initialize some final structure members, we call some helper
4339 * functions. However, since the EDITSTATE is not consistent (i.e.
4340 * not fully initialized), we should be very careful which
4341 * functions can be called, and in what order.
4342 */
4343 EDIT_WM_SetFont(es, 0, FALSE);
4344 EDIT_EM_EmptyUndoBuffer(es);
4345
4346 /* We need to calculate the format rect
4347 (applications may send EM_SETMARGINS before the control gets visible) */
4348 GetClientRect(es->hwndSelf, &clientRect);
4349 EDIT_SetRectNP(es, &clientRect);
4350
4351 if (name && *name) {
4352 EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, FALSE);
4353 /* if we insert text to the editline, the text scrolls out
4354 * of the window, as the caret is placed after the insert
4355 * pos normally; thus we reset es->selection... to 0 and
4356 * update caret
4357 */
4358 es->selection_start = es->selection_end = 0;
4359 /* Adobe Photoshop does NOT like this. and MSDN says that EN_CHANGE
4360 * Messages are only to be sent when the USER does something to
4361 * change the contents. So I am removing this EN_CHANGE
4362 *
4363 * EDIT_NOTIFY_PARENT(es, EN_CHANGE);
4364 */
4365 EDIT_EM_ScrollCaret(es);
4366 }
4367 /* force scroll info update */
4368 EDIT_UpdateScrollInfo(es);
4369 /* The rule seems to return 1 here for success */
4370 /* Power Builder masked edit controls will crash */
4371 /* if not. */
4372 /* FIXME: is that in all cases so ? */
4373 return 1;
4374}
4375
4376
4377/*********************************************************************
4378 *
Ilya Shpigorda9c5232009-11-15 13:33:38 +03004379 * WM_NCDESTROY
Francois Gouget9e7b5562009-02-07 16:05:33 +01004380 *
4381 */
Ilya Shpigorda9c5232009-11-15 13:33:38 +03004382static LRESULT EDIT_WM_NCDestroy(EDITSTATE *es)
Francois Gouget9e7b5562009-02-07 16:05:33 +01004383{
4384 LINEDEF *pc, *pp;
4385
4386 if (es->hloc32W) {
4387 LocalFree(es->hloc32W);
4388 }
4389 if (es->hloc32A) {
4390 LocalFree(es->hloc32A);
4391 }
Francois Gouget9e7b5562009-02-07 16:05:33 +01004392 pc = es->first_line_def;
4393 while (pc)
4394 {
4395 pp = pc->next;
4396 HeapFree(GetProcessHeap(), 0, pc);
4397 pc = pp;
4398 }
4399
Nikolay Sivova6096602009-10-20 21:56:23 +04004400 SetWindowLongPtrW( es->hwndSelf, 0, 0 );
4401 HeapFree(GetProcessHeap(), 0, es->undo_text);
Francois Gouget9e7b5562009-02-07 16:05:33 +01004402 HeapFree(GetProcessHeap(), 0, es);
4403
4404 return 0;
4405}
4406
4407
4408static inline LRESULT DefWindowProcT(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode)
4409{
4410 if(unicode)
4411 return DefWindowProcW(hwnd, msg, wParam, lParam);
4412 else
4413 return DefWindowProcA(hwnd, msg, wParam, lParam);
4414}
4415
4416/*********************************************************************
4417 *
4418 * EditWndProc_common
4419 *
4420 * The messages are in the order of the actual integer values
4421 * (which can be found in include/windows.h)
Francois Gouget9e7b5562009-02-07 16:05:33 +01004422 */
Alexandre Julliard57e5c8f2009-12-15 13:19:03 +01004423LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode )
Francois Gouget9e7b5562009-02-07 16:05:33 +01004424{
4425 EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 );
4426 LRESULT result = 0;
4427
4428 TRACE("hwnd=%p msg=%x (%s) wparam=%lx lparam=%lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam);
4429
4430 if (!es && msg != WM_NCCREATE)
4431 return DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
4432
Ilya Shpigorda9c5232009-11-15 13:33:38 +03004433 if (es && (msg != WM_NCDESTROY)) EDIT_LockBuffer(es);
Francois Gouget9e7b5562009-02-07 16:05:33 +01004434
4435 switch (msg) {
Francois Gouget9e7b5562009-02-07 16:05:33 +01004436 case EM_GETSEL:
4437 result = EDIT_EM_GetSel(es, (PUINT)wParam, (PUINT)lParam);
4438 break;
4439
Francois Gouget9e7b5562009-02-07 16:05:33 +01004440 case EM_SETSEL:
4441 EDIT_EM_SetSel(es, wParam, lParam, FALSE);
4442 EDIT_EM_ScrollCaret(es);
4443 result = 1;
4444 break;
4445
Francois Gouget9e7b5562009-02-07 16:05:33 +01004446 case EM_GETRECT:
4447 if (lParam)
4448 CopyRect((LPRECT)lParam, &es->format_rect);
4449 break;
4450
Francois Gouget9e7b5562009-02-07 16:05:33 +01004451 case EM_SETRECT:
4452 if ((es->style & ES_MULTILINE) && lParam) {
4453 EDIT_SetRectNP(es, (LPRECT)lParam);
4454 EDIT_UpdateText(es, NULL, TRUE);
4455 }
4456 break;
4457
Francois Gouget9e7b5562009-02-07 16:05:33 +01004458 case EM_SETRECTNP:
4459 if ((es->style & ES_MULTILINE) && lParam)
4460 EDIT_SetRectNP(es, (LPRECT)lParam);
4461 break;
4462
Francois Gouget9e7b5562009-02-07 16:05:33 +01004463 case EM_SCROLL:
4464 result = EDIT_EM_Scroll(es, (INT)wParam);
4465 break;
4466
Francois Gouget9e7b5562009-02-07 16:05:33 +01004467 case EM_LINESCROLL:
4468 result = (LRESULT)EDIT_EM_LineScroll(es, (INT)wParam, (INT)lParam);
4469 break;
4470
Francois Gouget9e7b5562009-02-07 16:05:33 +01004471 case EM_SCROLLCARET:
4472 EDIT_EM_ScrollCaret(es);
4473 result = 1;
4474 break;
4475
Francois Gouget9e7b5562009-02-07 16:05:33 +01004476 case EM_GETMODIFY:
4477 result = ((es->flags & EF_MODIFIED) != 0);
4478 break;
4479
Francois Gouget9e7b5562009-02-07 16:05:33 +01004480 case EM_SETMODIFY:
4481 if (wParam)
4482 es->flags |= EF_MODIFIED;
4483 else
4484 es->flags &= ~(EF_MODIFIED | EF_UPDATE); /* reset pending updates */
4485 break;
4486
Francois Gouget9e7b5562009-02-07 16:05:33 +01004487 case EM_GETLINECOUNT:
4488 result = (es->style & ES_MULTILINE) ? es->line_count : 1;
4489 break;
4490
Francois Gouget9e7b5562009-02-07 16:05:33 +01004491 case EM_LINEINDEX:
4492 result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam);
4493 break;
4494
Francois Gouget9e7b5562009-02-07 16:05:33 +01004495 case EM_SETHANDLE:
4496 EDIT_EM_SetHandle(es, (HLOCAL)wParam);
4497 break;
4498
Francois Gouget9e7b5562009-02-07 16:05:33 +01004499 case EM_GETHANDLE:
4500 result = (LRESULT)EDIT_EM_GetHandle(es);
4501 break;
4502
Francois Gouget9e7b5562009-02-07 16:05:33 +01004503 case EM_GETTHUMB:
4504 result = EDIT_EM_GetThumb(es);
4505 break;
4506
4507 /* these messages missing from specs */
Francois Gouget9e7b5562009-02-07 16:05:33 +01004508 case 0x00bf:
Francois Gouget9e7b5562009-02-07 16:05:33 +01004509 case 0x00c0:
Francois Gouget9e7b5562009-02-07 16:05:33 +01004510 case 0x00c3:
Francois Gouget9e7b5562009-02-07 16:05:33 +01004511 case 0x00ca:
4512 FIXME("undocumented message 0x%x, please report\n", msg);
4513 result = DefWindowProcW(hwnd, msg, wParam, lParam);
4514 break;
4515
Francois Gouget9e7b5562009-02-07 16:05:33 +01004516 case EM_LINELENGTH:
4517 result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam);
4518 break;
4519
Francois Gouget9e7b5562009-02-07 16:05:33 +01004520 case EM_REPLACESEL:
4521 {
4522 LPWSTR textW;
4523
4524 if(unicode)
4525 textW = (LPWSTR)lParam;
4526 else
4527 {
4528 LPSTR textA = (LPSTR)lParam;
4529 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
Marcus Meissner69bf1852010-01-06 16:52:46 +01004530 if (!(textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) break;
4531 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
Francois Gouget9e7b5562009-02-07 16:05:33 +01004532 }
4533
4534 EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE);
4535 result = 1;
4536
4537 if(!unicode)
4538 HeapFree(GetProcessHeap(), 0, textW);
4539 break;
4540 }
4541
Francois Gouget9e7b5562009-02-07 16:05:33 +01004542 case EM_GETLINE:
4543 result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode);
4544 break;
4545
Francois Gouget9e7b5562009-02-07 16:05:33 +01004546 case EM_SETLIMITTEXT:
4547 EDIT_EM_SetLimitText(es, wParam);
4548 break;
4549
Francois Gouget9e7b5562009-02-07 16:05:33 +01004550 case EM_CANUNDO:
4551 result = (LRESULT)EDIT_EM_CanUndo(es);
4552 break;
4553
Francois Gouget9e7b5562009-02-07 16:05:33 +01004554 case EM_UNDO:
4555 case WM_UNDO:
4556 result = (LRESULT)EDIT_EM_Undo(es);
4557 break;
4558
Francois Gouget9e7b5562009-02-07 16:05:33 +01004559 case EM_FMTLINES:
4560 result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam);
4561 break;
4562
Francois Gouget9e7b5562009-02-07 16:05:33 +01004563 case EM_LINEFROMCHAR:
4564 result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam);
4565 break;
4566
Francois Gouget9e7b5562009-02-07 16:05:33 +01004567 case EM_SETTABSTOPS:
4568 result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam);
4569 break;
4570
Francois Gouget9e7b5562009-02-07 16:05:33 +01004571 case EM_SETPASSWORDCHAR:
4572 {
4573 WCHAR charW = 0;
4574
4575 if(unicode)
4576 charW = (WCHAR)wParam;
4577 else
4578 {
4579 CHAR charA = wParam;
4580 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
4581 }
4582
4583 EDIT_EM_SetPasswordChar(es, charW);
4584 break;
4585 }
4586
Francois Gouget9e7b5562009-02-07 16:05:33 +01004587 case EM_EMPTYUNDOBUFFER:
4588 EDIT_EM_EmptyUndoBuffer(es);
4589 break;
4590
Francois Gouget9e7b5562009-02-07 16:05:33 +01004591 case EM_GETFIRSTVISIBLELINE:
4592 result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset;
4593 break;
4594
Francois Gouget9e7b5562009-02-07 16:05:33 +01004595 case EM_SETREADONLY:
Nikolay Sivov0209b022009-09-19 22:32:04 +04004596 {
4597 DWORD old_style = es->style;
4598
Francois Gouget9e7b5562009-02-07 16:05:33 +01004599 if (wParam) {
4600 SetWindowLongW( hwnd, GWL_STYLE,
4601 GetWindowLongW( hwnd, GWL_STYLE ) | ES_READONLY );
4602 es->style |= ES_READONLY;
4603 } else {
4604 SetWindowLongW( hwnd, GWL_STYLE,
4605 GetWindowLongW( hwnd, GWL_STYLE ) & ~ES_READONLY );
4606 es->style &= ~ES_READONLY;
4607 }
Nikolay Sivov0209b022009-09-19 22:32:04 +04004608
4609 if (old_style ^ es->style)
4610 InvalidateRect(es->hwndSelf, NULL, TRUE);
4611
4612 result = 1;
Francois Gouget9e7b5562009-02-07 16:05:33 +01004613 break;
Nikolay Sivov0209b022009-09-19 22:32:04 +04004614 }
Francois Gouget9e7b5562009-02-07 16:05:33 +01004615
Francois Gouget9e7b5562009-02-07 16:05:33 +01004616 case EM_SETWORDBREAKPROC:
4617 EDIT_EM_SetWordBreakProc(es, (void *)lParam);
4618 break;
4619
Francois Gouget9e7b5562009-02-07 16:05:33 +01004620 case EM_GETWORDBREAKPROC:
4621 result = (LRESULT)es->word_break_proc;
4622 break;
4623
Francois Gouget9e7b5562009-02-07 16:05:33 +01004624 case EM_GETPASSWORDCHAR:
4625 {
4626 if(unicode)
4627 result = es->password_char;
4628 else
4629 {
4630 WCHAR charW = es->password_char;
4631 CHAR charA = 0;
4632 WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL);
4633 result = charA;
4634 }
4635 break;
4636 }
4637
Francois Gouget9e7b5562009-02-07 16:05:33 +01004638 case EM_SETMARGINS:
4639 EDIT_EM_SetMargins(es, (INT)wParam, LOWORD(lParam), HIWORD(lParam), TRUE);
4640 break;
4641
4642 case EM_GETMARGINS:
4643 result = MAKELONG(es->left_margin, es->right_margin);
4644 break;
4645
4646 case EM_GETLIMITTEXT:
4647 result = es->buffer_limit;
4648 break;
4649
4650 case EM_POSFROMCHAR:
4651 if ((INT)wParam >= get_text_length(es)) result = -1;
4652 else result = EDIT_EM_PosFromChar(es, (INT)wParam, FALSE);
4653 break;
4654
4655 case EM_CHARFROMPOS:
4656 result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
4657 break;
4658
4659 /* End of the EM_ messages which were in numerical order; what order
4660 * are these in? vaguely alphabetical?
4661 */
4662
4663 case WM_NCCREATE:
4664 result = EDIT_WM_NCCreate(hwnd, (LPCREATESTRUCTW)lParam, unicode);
4665 break;
4666
Ilya Shpigorda9c5232009-11-15 13:33:38 +03004667 case WM_NCDESTROY:
4668 result = EDIT_WM_NCDestroy(es);
Francois Gouget9e7b5562009-02-07 16:05:33 +01004669 es = NULL;
4670 break;
4671
4672 case WM_GETDLGCODE:
4673 result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
4674
4675 if (es->style & ES_MULTILINE)
4676 result |= DLGC_WANTALLKEYS;
4677
Sergey Khodych6fa48cd2009-08-24 00:10:01 +03004678 if (lParam)
4679 {
4680 es->flags|=EF_DIALOGMODE;
Francois Gouget9e7b5562009-02-07 16:05:33 +01004681
Sergey Khodych6fa48cd2009-08-24 00:10:01 +03004682 if (((LPMSG)lParam)->message == WM_KEYDOWN)
4683 {
4684 int vk = (int)((LPMSG)lParam)->wParam;
4685
4686 if (es->hwndListBox)
4687 {
4688 if (vk == VK_RETURN || vk == VK_ESCAPE)
4689 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
4690 result |= DLGC_WANTMESSAGE;
4691 }
Sergey Khodych6fa48cd2009-08-24 00:10:01 +03004692 }
Francois Gouget9e7b5562009-02-07 16:05:33 +01004693 }
4694 break;
4695
4696 case WM_IME_CHAR:
4697 if (!unicode)
4698 {
4699 WCHAR charW;
4700 CHAR strng[2];
4701
4702 strng[0] = wParam >> 8;
4703 strng[1] = wParam & 0xff;
4704 if (strng[0]) MultiByteToWideChar(CP_ACP, 0, strng, 2, &charW, 1);
4705 else MultiByteToWideChar(CP_ACP, 0, &strng[1], 1, &charW, 1);
4706 result = EDIT_WM_Char(es, charW);
4707 break;
4708 }
4709 /* fall through */
4710 case WM_CHAR:
4711 {
4712 WCHAR charW;
4713
4714 if(unicode)
4715 charW = wParam;
4716 else
4717 {
4718 CHAR charA = wParam;
4719 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
4720 }
4721
4722 if (es->hwndListBox)
4723 {
4724 if (charW == VK_RETURN || charW == VK_ESCAPE)
4725 {
4726 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0))
4727 SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0);
4728 break;
4729 }
4730 }
4731 result = EDIT_WM_Char(es, charW);
4732 break;
4733 }
4734
4735 case WM_UNICHAR:
4736 if (unicode)
4737 {
4738 if (wParam == UNICODE_NOCHAR) return TRUE;
4739 if (wParam <= 0x000fffff)
4740 {
4741 if(wParam > 0xffff) /* convert to surrogates */
4742 {
4743 wParam -= 0x10000;
4744 EDIT_WM_Char(es, (wParam >> 10) + 0xd800);
4745 EDIT_WM_Char(es, (wParam & 0x03ff) + 0xdc00);
4746 }
4747 else EDIT_WM_Char(es, wParam);
4748 }
4749 return 0;
4750 }
4751 break;
4752
4753 case WM_CLEAR:
4754 EDIT_WM_Clear(es);
4755 break;
4756
4757 case WM_COMMAND:
4758 EDIT_WM_Command(es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
4759 break;
4760
4761 case WM_CONTEXTMENU:
4762 EDIT_WM_ContextMenu(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
4763 break;
4764
4765 case WM_COPY:
4766 EDIT_WM_Copy(es);
4767 break;
4768
4769 case WM_CREATE:
4770 if(unicode)
4771 result = EDIT_WM_Create(es, ((LPCREATESTRUCTW)lParam)->lpszName);
4772 else
4773 {
4774 LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName;
4775 LPWSTR nameW = NULL;
4776 if(nameA)
4777 {
4778 INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0);
4779 if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
4780 MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW);
4781 }
4782 result = EDIT_WM_Create(es, nameW);
4783 HeapFree(GetProcessHeap(), 0, nameW);
4784 }
4785 break;
4786
4787 case WM_CUT:
4788 EDIT_WM_Cut(es);
4789 break;
4790
4791 case WM_ENABLE:
4792 es->bEnableState = (BOOL) wParam;
4793 EDIT_UpdateText(es, NULL, TRUE);
4794 break;
4795
4796 case WM_ERASEBKGND:
4797 /* we do the proper erase in EDIT_WM_Paint */
4798 result = 1;
4799 break;
4800
4801 case WM_GETFONT:
4802 result = (LRESULT)es->font;
4803 break;
4804
4805 case WM_GETTEXT:
4806 result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, (LPWSTR)lParam, unicode);
4807 break;
4808
4809 case WM_GETTEXTLENGTH:
4810 if (unicode) result = get_text_length(es);
4811 else result = WideCharToMultiByte( CP_ACP, 0, es->text, get_text_length(es),
4812 NULL, 0, NULL, NULL );
4813 break;
4814
4815 case WM_HSCROLL:
4816 result = EDIT_WM_HScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
4817 break;
4818
4819 case WM_KEYDOWN:
4820 result = EDIT_WM_KeyDown(es, (INT)wParam);
4821 break;
4822
4823 case WM_KILLFOCUS:
4824 result = EDIT_WM_KillFocus(es);
4825 break;
4826
4827 case WM_LBUTTONDBLCLK:
4828 result = EDIT_WM_LButtonDblClk(es);
4829 break;
4830
4831 case WM_LBUTTONDOWN:
4832 result = EDIT_WM_LButtonDown(es, wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
4833 break;
4834
4835 case WM_LBUTTONUP:
4836 result = EDIT_WM_LButtonUp(es);
4837 break;
4838
4839 case WM_MBUTTONDOWN:
4840 result = EDIT_WM_MButtonDown(es);
4841 break;
4842
4843 case WM_MOUSEMOVE:
4844 result = EDIT_WM_MouseMove(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
4845 break;
4846
4847 case WM_PRINTCLIENT:
4848 case WM_PAINT:
4849 EDIT_WM_Paint(es, (HDC)wParam);
4850 break;
4851
4852 case WM_PASTE:
4853 EDIT_WM_Paste(es);
4854 break;
4855
4856 case WM_SETFOCUS:
4857 EDIT_WM_SetFocus(es);
4858 break;
4859
4860 case WM_SETFONT:
4861 EDIT_WM_SetFont(es, (HFONT)wParam, LOWORD(lParam) != 0);
4862 break;
4863
4864 case WM_SETREDRAW:
4865 /* FIXME: actually set an internal flag and behave accordingly */
4866 break;
4867
4868 case WM_SETTEXT:
4869 EDIT_WM_SetText(es, (LPCWSTR)lParam, unicode);
4870 result = TRUE;
4871 break;
4872
4873 case WM_SIZE:
4874 EDIT_WM_Size(es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam));
4875 break;
4876
4877 case WM_STYLECHANGED:
4878 result = EDIT_WM_StyleChanged(es, wParam, (const STYLESTRUCT *)lParam);
4879 break;
4880
4881 case WM_STYLECHANGING:
4882 result = 0; /* See EDIT_WM_StyleChanged */
4883 break;
4884
4885 case WM_SYSKEYDOWN:
4886 result = EDIT_WM_SysKeyDown(es, (INT)wParam, (DWORD)lParam);
4887 break;
4888
4889 case WM_TIMER:
4890 EDIT_WM_Timer(es);
4891 break;
4892
4893 case WM_VSCROLL:
4894 result = EDIT_WM_VScroll(es, LOWORD(wParam), (short)HIWORD(wParam));
4895 break;
4896
4897 case WM_MOUSEWHEEL:
4898 {
4899 int gcWheelDelta = 0;
4900 UINT pulScrollLines = 3;
4901 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
4902
4903 if (wParam & (MK_SHIFT | MK_CONTROL)) {
4904 result = DefWindowProcW(hwnd, msg, wParam, lParam);
4905 break;
4906 }
4907 gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
4908 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
4909 {
4910 int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines);
4911 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
4912 result = EDIT_EM_LineScroll(es, 0, cLineScroll);
4913 }
4914 }
4915 break;
4916
4917
4918 /* IME messages to make the edit control IME aware */
4919 case WM_IME_SETCONTEXT:
4920 break;
4921
4922 case WM_IME_STARTCOMPOSITION:
4923 es->composition_start = es->selection_end;
4924 es->composition_len = 0;
4925 break;
4926
4927 case WM_IME_COMPOSITION:
4928 EDIT_ImeComposition(hwnd, lParam, es);
4929 break;
4930
4931 case WM_IME_ENDCOMPOSITION:
4932 if (es->composition_len > 0)
4933 {
Francois Gouget9e7b5562009-02-07 16:05:33 +01004934 EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
4935 es->selection_end = es->selection_start;
4936 es->composition_len= 0;
4937 }
4938 break;
4939
4940 case WM_IME_COMPOSITIONFULL:
4941 break;
4942
4943 case WM_IME_SELECT:
4944 break;
4945
4946 case WM_IME_CONTROL:
4947 break;
4948
4949 default:
4950 result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode);
4951 break;
4952 }
4953
Nikolay Sivovaa737172009-12-02 23:22:12 +03004954 if (IsWindow(hwnd) && es) EDIT_UnlockBuffer(es, FALSE);
Francois Gouget9e7b5562009-02-07 16:05:33 +01004955
4956 TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result);
4957
4958 return result;
4959}
4960
Alexandre Julliard68656c02009-12-11 15:51:34 +01004961
4962/*********************************************************************
Francois Gouget9e7b5562009-02-07 16:05:33 +01004963 * edit class descriptor
4964 */
4965static const WCHAR editW[] = {'E','d','i','t',0};
4966const struct builtin_class_descr EDIT_builtin_class =
4967{
4968 editW, /* name */
4969 CS_DBLCLKS | CS_PARENTDC, /* style */
Alexandre Julliardd081a732009-12-18 12:39:13 +01004970 WINPROC_EDIT, /* proc */
Alexandre Julliard810e7012009-12-11 18:13:03 +01004971#ifdef __i386__
Alexandre Julliard8aa83d32009-12-23 20:01:37 +01004972 sizeof(EDITSTATE *) + sizeof(WORD), /* extra */
Julius Schwartzenberg8e899e02009-10-11 15:27:44 +02004973#else
Alexandre Julliard810e7012009-12-11 18:13:03 +01004974 sizeof(EDITSTATE *), /* extra */
Julius Schwartzenberg8e899e02009-10-11 15:27:44 +02004975#endif
Francois Gouget9e7b5562009-02-07 16:05:33 +01004976 IDC_IBEAM, /* cursor */
4977 0 /* brush */
4978};