Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 1 | /* |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2 | * Edit control |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 3 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 4 | * Copyright David W. Metcalfe, 1994 |
| 5 | * Copyright William Magro, 1995, 1996 |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 6 | * Copyright Frans van Dorsselaer, 1996, 1997 |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 7 | * |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 8 | * |
| 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 Ernst | 360a3f9 | 2006-05-18 14:49:52 +0200 | [diff] [blame] | 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 22 | * |
Dimitrie O. Paun | 91e7437 | 2004-10-08 20:50:52 +0000 | [diff] [blame] | 23 | * 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 32 | * TODO: |
Dimitrie O. Paun | 91e7437 | 2004-10-08 20:50:52 +0000 | [diff] [blame] | 33 | * - 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 41 | * - ES_OEMCONVERT |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 42 | * |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 43 | */ |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 44 | |
Patrik Stridvall | 1bb9403 | 1999-05-08 15:47:44 +0000 | [diff] [blame] | 45 | #include "config.h" |
| 46 | |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 47 | #include <stdarg.h> |
Jeff Garzik | c3e1f72 | 1999-02-19 15:42:11 +0000 | [diff] [blame] | 48 | #include <string.h> |
Alexandre Julliard | 908464d | 2000-11-01 03:11:12 +0000 | [diff] [blame] | 49 | #include <stdlib.h> |
Patrik Stridvall | 6cc47d4 | 2000-03-08 18:26:56 +0000 | [diff] [blame] | 50 | |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 51 | #include "windef.h" |
Patrik Stridvall | 6cc47d4 | 2000-03-08 18:26:56 +0000 | [diff] [blame] | 52 | #include "winbase.h" |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 53 | #include "winnt.h" |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 54 | #include "win.h" |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 55 | #include "imm.h" |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 56 | #include "wine/unicode.h" |
Alexandre Julliard | 91222da | 2000-12-10 23:01:33 +0000 | [diff] [blame] | 57 | #include "controls.h" |
Alexandre Julliard | 6a78c16 | 2004-12-08 18:06:14 +0000 | [diff] [blame] | 58 | #include "user_private.h" |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 59 | #include "wine/debug.h" |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 60 | |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 61 | WINE_DEFAULT_DEBUG_CHANNEL(edit); |
| 62 | WINE_DECLARE_DEBUG_CHANNEL(combo); |
| 63 | WINE_DECLARE_DEBUG_CHANNEL(relay); |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 64 | |
Alex VillacĂs Lasso | 48fd106 | 2007-10-16 15:25:51 -0500 | [diff] [blame] | 65 | #define BUFLIMIT_INITIAL 30000 /* initial buffer size */ |
Dmitry Timoshkov | f8b96e2 | 2000-12-20 18:39:14 +0000 | [diff] [blame] | 66 | #define GROWLENGTH 32 /* buffers granularity in bytes: must be power of 2 */ |
Dmitry Timoshkov | df793bc | 2001-01-15 20:20:31 +0000 | [diff] [blame] | 67 | #define ROUND_TO_GROW(size) (((size) + (GROWLENGTH - 1)) & ~(GROWLENGTH - 1)) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 68 | #define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */ |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 69 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 70 | /* |
| 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 Timoshkov | a62f06d | 2001-03-13 23:31:08 +0000 | [diff] [blame] | 75 | #define EF_UPDATE 0x0004 /* notify parent of changed state */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 76 | #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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 78 | #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 Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 80 | #define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */ |
Huw Davies | c79ce3c | 2007-04-19 14:47:12 +0100 | [diff] [blame] | 81 | #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 Khodych | 6fa48cd | 2009-08-24 00:10:01 +0300 | [diff] [blame] | 83 | #define EF_DIALOGMODE 0x0400 /* Indicates that we are inside a dialog window */ |
| 84 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 85 | typedef enum |
| 86 | { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 87 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 92 | } LINE_END; |
| 93 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 94 | typedef struct tagLINEDEF { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 95 | INT length; /* bruto length of a line in bytes */ |
| 96 | INT net_length; /* netto length of a line in visible characters */ |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 97 | LINE_END ending; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 98 | INT width; /* width of the line in pixels */ |
| 99 | INT index; /* line index into the buffer */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 100 | struct tagLINEDEF *next; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 101 | } LINEDEF; |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 102 | |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 103 | typedef struct |
| 104 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 105 | BOOL is_unicode; /* how the control was created */ |
| 106 | LPWSTR text; /* the actual contents of the control */ |
Huw Davies | 6a94516 | 2007-04-19 15:01:13 +0100 | [diff] [blame] | 107 | UINT text_length; /* cached length of text buffer (in WCHARs) - use get_text_length() to retrieve */ |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 108 | 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 Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 110 | HFONT font; /* NULL means standard system font */ |
| 111 | INT x_offset; /* scroll offset for multi lines this is in pixels |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 112 | for single lines it's in characters */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 113 | INT line_height; /* height of a screen line in pixels */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 114 | INT char_width; /* average character width in pixels */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 115 | DWORD style; /* sane version of wnd->dwStyle */ |
| 116 | WORD flags; /* flags that are not in es->style or wnd->flags (EF_XXX) */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 117 | INT undo_insert_count; /* number of characters inserted in sequence */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 118 | UINT undo_position; /* character index of the insertion and deletion */ |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 119 | LPWSTR undo_text; /* deleted text */ |
Dmitry Timoshkov | 366c0a1 | 2000-12-22 20:28:05 +0000 | [diff] [blame] | 120 | UINT undo_buffer_size; /* size of the deleted text buffer */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 121 | INT selection_start; /* == selection_end if no selection */ |
| 122 | INT selection_end; /* == current caret position */ |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 123 | WCHAR password_char; /* == 0 if no password char, and for multi line controls */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 124 | INT left_margin; /* in pixels */ |
| 125 | INT right_margin; /* in pixels */ |
| 126 | RECT format_rect; |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 127 | INT text_width; /* width of the widest line in pixels for multi line controls |
| 128 | and just line width for single line controls */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 129 | INT region_posx; /* Position of cursor relative to region: */ |
| 130 | INT region_posy; /* -1: to left, 0: within, 1: to right */ |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 131 | void *word_break_proc; /* 32-bit word break proc: ANSI or Unicode */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 132 | INT line_count; /* number of lines */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 133 | INT y_offset; /* scroll offset in number of lines */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 134 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 141 | /* |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 142 | * only for multi line controls |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 143 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 144 | INT lock_count; /* amount of re-entries in the EditWndProc */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 145 | INT tabs_count; |
| 146 | LPINT tabs; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 147 | LINEDEF *first_line_def; /* linked list of (soft) linebreaks */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 148 | HLOCAL hloc32W; /* our unicode local memory block */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 149 | HLOCAL hloc32A; /* alias for ANSI control receiving EM_GETHANDLE |
| 150 | or EM_SETHANDLE */ |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 151 | /* |
| 152 | * IME Data |
| 153 | */ |
Francois Gouget | 8ca1f3f | 2006-01-03 12:10:50 +0100 | [diff] [blame] | 154 | UINT composition_len; /* length of composition, 0 == no composition */ |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 155 | int composition_start; /* the character position for the composition */ |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 156 | } EDITSTATE; |
| 157 | |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 158 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 159 | #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 Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 161 | |
Luc Tourangeau | df5fbc7 | 1999-04-03 11:14:30 +0000 | [diff] [blame] | 162 | /* used for disabled or read-only edit control */ |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 163 | #define EDIT_NOTIFY_PARENT(es, wNotifyCode) \ |
Dmitry Timoshkov | 87880c5 | 2001-03-10 19:16:46 +0000 | [diff] [blame] | 164 | do \ |
Dmitry Timoshkov | a62f06d | 2001-03-13 23:31:08 +0000 | [diff] [blame] | 165 | { /* Notify parent which has created this edit control */ \ |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 166 | TRACE("notification " #wNotifyCode " sent to hwnd=%p\n", es->hwndParent); \ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 167 | SendMessageW(es->hwndParent, WM_COMMAND, \ |
Robert Shearman | 2e9436c | 2004-08-17 22:29:29 +0000 | [diff] [blame] | 168 | MAKEWPARAM(GetWindowLongPtrW((es->hwndSelf),GWLP_ID), wNotifyCode), \ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 169 | (LPARAM)(es->hwndSelf)); \ |
Dmitry Timoshkov | 87880c5 | 2001-03-10 19:16:46 +0000 | [diff] [blame] | 170 | } while(0) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 171 | |
Kusanagi Kouichi | ccab177 | 2010-02-13 11:38:21 +0900 | [diff] [blame] | 172 | static const WCHAR empty_stringW[] = {0}; |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 173 | |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 174 | /********************************************************************* |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 175 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 176 | * EM_CANUNDO |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 177 | * |
| 178 | */ |
Andrew Talbot | 49c0bd5 | 2007-11-19 15:46:20 +0000 | [diff] [blame] | 179 | static inline BOOL EDIT_EM_CanUndo(const EDITSTATE *es) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 180 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 181 | return (es->undo_insert_count || strlenW(es->undo_text)); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | |
| 185 | /********************************************************************* |
| 186 | * |
| 187 | * EM_EMPTYUNDOBUFFER |
| 188 | * |
| 189 | */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 190 | static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 191 | { |
| 192 | es->undo_insert_count = 0; |
| 193 | *es->undo_text = '\0'; |
| 194 | } |
| 195 | |
| 196 | |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 197 | /********************************************************************** |
| 198 | * get_app_version |
| 199 | * |
| 200 | * Returns the window version in case Wine emulates a later version |
Francois Gouget | 61aac4e | 2003-06-04 20:29:05 +0000 | [diff] [blame] | 201 | * of windows than the application expects. |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 202 | * |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 203 | * 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 206 | * |
| 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 Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 210 | * applications with an expected version 0f 4.0 or higher. |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 211 | * |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 212 | */ |
| 213 | static DWORD get_app_version(void) |
| 214 | { |
| 215 | static DWORD version; |
| 216 | if (!version) |
| 217 | { |
| 218 | DWORD dwEmulatedVersion; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 219 | OSVERSIONINFOW info; |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 220 | DWORD dwProcVersion = GetProcessVersion(0); |
| 221 | |
James Juran | 75c525c | 2001-05-18 20:56:37 +0000 | [diff] [blame] | 222 | info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 223 | GetVersionExW( &info ); |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 224 | dwEmulatedVersion = MAKELONG( info.dwMinorVersion, info.dwMajorVersion ); |
Dimitrie O. Paun | 693cca5 | 2002-01-29 03:12:19 +0000 | [diff] [blame] | 225 | /* FIXME: this may not be 100% correct; see discussion on the |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 226 | * wine developer list in Nov 1999 */ |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 227 | version = dwProcVersion < dwEmulatedVersion ? dwProcVersion : dwEmulatedVersion; |
Alexandre Julliard | 198746d | 2000-08-14 14:29:22 +0000 | [diff] [blame] | 228 | } |
| 229 | return version; |
| 230 | } |
| 231 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 232 | static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc) |
| 233 | { |
Dmitry Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 234 | HBRUSH hbrush; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 235 | 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 Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 243 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 247 | } |
| 248 | |
Aric Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 249 | |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 250 | /********************************************************************* |
| 251 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 252 | * EDIT_WordBreakProc |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 253 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 254 | * 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 259 | * |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 260 | */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 261 | static INT EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action) |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 262 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 263 | INT ret = 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 264 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 265 | TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action); |
Francois Boisvert | 6b1b41c | 1999-03-14 17:25:32 +0000 | [diff] [blame] | 266 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 267 | if(!s) return 0; |
Alexandre Julliard | bf9130a | 1996-10-13 17:45:47 +0000 | [diff] [blame] | 268 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 269 | 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 284 | } else { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 285 | while (index && (s[index] != ' ')) |
| 286 | index--; |
| 287 | if (s[index] == ' ') |
| 288 | index++; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 289 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 290 | ret = index; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 291 | break; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 292 | 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 Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 303 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 304 | ret = index; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 305 | break; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 306 | case WB_ISDELIMITER: |
| 307 | ret = (s[index] == ' '); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 308 | break; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 309 | default: |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 310 | ERR("unknown action code, please report !\n"); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 311 | break; |
| 312 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 313 | return ret; |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 314 | } |
| 315 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 316 | |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 317 | /********************************************************************* |
| 318 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 319 | * EDIT_CallWordBreakProc |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 320 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 321 | * 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 Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 329 | */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 330 | static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 331 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 332 | INT ret; |
| 333 | |
Alexandre Julliard | dcec342 | 2009-12-11 14:52:28 +0100 | [diff] [blame] | 334 | if (es->word_break_proc) |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 335 | { |
| 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 Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 363 | } |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 364 | |
| 365 | /********************************************************************* |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 366 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 367 | * EDIT_BuildLineDefs_ML |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 368 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 369 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 372 | * |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 373 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 374 | static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn) |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 375 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 376 | HDC dc; |
| 377 | HFONT old_font = 0; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 378 | LPWSTR current_position, cp; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 379 | INT fw; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 380 | 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 Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 387 | |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 388 | if (istart == iend && delta == 0) |
| 389 | return; |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 390 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 391 | dc = GetDC(es->hwndSelf); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 392 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 393 | old_font = SelectObject(dc, es->font); |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 394 | |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 395 | 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 400 | do { |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 401 | if (istart < current_line->index + current_line->length || |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 402 | current_line->ending == END_0) |
| 403 | break; |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 404 | |
| 405 | previous_line = current_line; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 406 | 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 Costa | 6e7d78e | 2003-05-11 03:27:23 +0000 | [diff] [blame] | 413 | ReleaseDC(es->hwndSelf, dc); |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 414 | 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 437 | /* The buffer has been expanded, create a new line and |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 438 | 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 English | 6e59cd2 | 2008-04-22 01:18:14 -0500 | [diff] [blame] | 458 | /* else recalculate this line */ |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 459 | } |
| 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 467 | while (*cp) { |
Chuck Crayne | ce2024c | 2002-04-22 23:08:19 +0000 | [diff] [blame] | 468 | if (*cp == '\n') break; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 469 | if ((*cp == '\r') && (*(cp + 1) == '\n')) |
| 470 | break; |
| 471 | cp++; |
| 472 | } |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 473 | |
| 474 | /* Mark type of line termination */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 475 | if (!(*cp)) { |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 476 | 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 Crayne | ce2024c | 2002-04-22 23:08:19 +0000 | [diff] [blame] | 481 | } else if (*cp == '\n') { |
| 482 | current_line->ending = END_RICH; |
| 483 | current_line->net_length = cp - current_position; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 484 | } else { |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 485 | current_line->ending = END_HARD; |
| 486 | current_line->net_length = cp - current_position; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 487 | } |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 488 | |
| 489 | /* Calculate line width */ |
| 490 | current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, |
| 491 | current_position, current_line->net_length, |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 492 | es->tabs_count, es->tabs)); |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 493 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 494 | /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */ |
Ulrich Czekalla | a935c2a | 2004-05-25 18:04:48 +0000 | [diff] [blame] | 495 | if (!(es->style & ES_AUTOHSCROLL)) { |
| 496 | if (current_line->width > fw) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 497 | INT next = 0; |
| 498 | INT prev; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 499 | do { |
| 500 | prev = next; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 501 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 507 | next = 0; |
| 508 | do { |
| 509 | prev = next; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 510 | next++; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 511 | current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, |
| 512 | current_position, next, es->tabs_count, es->tabs)); |
| 513 | } while (current_line->width <= fw); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 514 | if (!prev) |
| 515 | prev = 1; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 516 | } |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 517 | |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 518 | /* If the first line we are calculating, wrapped before istart, we must |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 519 | * 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 Mohr | 07216db | 2001-11-13 21:29:38 +0000 | [diff] [blame] | 523 | * are re-calculating and it expanded */ |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 524 | else if (current_line == start_line && |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 525 | current_line->index != nstart_index && orig_net_length < prev) |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 526 | { |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 527 | /* 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 Czekalla | a935c2a | 2004-05-25 18:04:48 +0000 | [diff] [blame] | 538 | } |
Lei Zhang | 4aef5cb | 2008-04-14 16:53:42 -0700 | [diff] [blame] | 539 | else if (current_line == start_line && |
| 540 | current_line->index != nstart_index && |
| 541 | orig_net_length < current_line->net_length) { |
Ulrich Czekalla | a935c2a | 2004-05-25 18:04:48 +0000 | [diff] [blame] | 542 | /* 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 549 | } |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 550 | |
| 551 | |
| 552 | /* Adjust length to include line termination */ |
| 553 | switch (current_line->ending) { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 554 | case END_SOFT: |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 555 | current_line->length = current_line->net_length + 3; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 556 | break; |
Chuck Crayne | ce2024c | 2002-04-22 23:08:19 +0000 | [diff] [blame] | 557 | case END_RICH: |
| 558 | current_line->length = current_line->net_length + 1; |
| 559 | break; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 560 | case END_HARD: |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 561 | current_line->length = current_line->net_length + 2; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 562 | break; |
| 563 | case END_WRAP: |
| 564 | case END_0: |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 565 | current_line->length = current_line->net_length; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 566 | break; |
| 567 | } |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 568 | 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 Mohr | 07216db | 2001-11-13 21:29:38 +0000 | [diff] [blame] | 575 | /* Finish adjusting line indexes by delta or remove hanging lines */ |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 576 | 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 Tulmin | 7b9fb6f | 2005-01-19 19:08:25 +0000 | [diff] [blame] | 589 | else if (delta != 0) |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 590 | { |
| 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 602 | /* |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 603 | * 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 607 | rc.top = es->format_rect.top + nstart_line * es->line_height - |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 608 | (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */ |
| 609 | rc.bottom = rc.top + es->line_height; |
Ulrich Czekalla | 7df3375 | 2005-02-16 16:28:34 +0000 | [diff] [blame] | 610 | 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 614 | es->text + nstart_index, istart - nstart_index, |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 615 | 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 622 | /* |
| 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 Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 625 | */ |
| 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 Tulmin | 24c73fd | 2005-06-09 20:40:31 +0000 | [diff] [blame] | 632 | rc.bottom += es->format_rect.top; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 633 | 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 639 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 640 | SelectObject(dc, old_font); |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 641 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 642 | ReleaseDC(es->hwndSelf, dc); |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 643 | } |
| 644 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 645 | |
| 646 | static 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 | */ |
| 660 | static 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 Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 673 | /********************************************************************* |
| 674 | * |
| 675 | * EDIT_CalcLineWidth_SL |
| 676 | * |
| 677 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 678 | static void EDIT_CalcLineWidth_SL(EDITSTATE *es) |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 679 | { |
Ulrich Czekalla | 7df3375 | 2005-02-16 16:28:34 +0000 | [diff] [blame] | 680 | 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 Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 701 | } |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 702 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 703 | /********************************************************************* |
| 704 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 705 | * EDIT_CharFromPos |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 706 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 707 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 711 | * |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 712 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 713 | static INT EDIT_CharFromPos(EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 714 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 715 | INT index; |
| 716 | HDC dc; |
| 717 | HFONT old_font = 0; |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 718 | INT x_high = 0, x_low = 0; |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 719 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 720 | if (es->style & ES_MULTILINE) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 721 | INT line = (y - es->format_rect.top) / es->line_height + es->y_offset; |
| 722 | INT line_index = 0; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 723 | LINEDEF *line_def = es->first_line_def; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 724 | INT low, high; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 725 | 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 Czekalla | 7df3375 | 2005-02-16 16:28:34 +0000 | [diff] [blame] | 731 | 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 735 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 745 | dc = GetDC(es->hwndSelf); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 746 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 747 | old_font = SelectObject(dc, es->font); |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 748 | low = line_index; |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 749 | high = line_index + line_def->net_length + 1; |
| 750 | while (low < high - 1) |
| 751 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 752 | INT mid = (low + high) / 2; |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 753 | 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 Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 761 | } |
Vitaliy Margolen | d30f1fd | 2005-07-05 14:04:25 +0000 | [diff] [blame] | 762 | if (abs(x_high - x) + 1 <= abs(x_low - x)) |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 763 | index = high; |
| 764 | else |
| 765 | index = low; |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 766 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 767 | if (after_wrap) |
| 768 | *after_wrap = ((index == line_index + line_def->net_length) && |
| 769 | (line_def->ending == END_WRAP)); |
| 770 | } else { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 771 | LPWSTR text; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 772 | SIZE size; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 773 | if (after_wrap) |
| 774 | *after_wrap = FALSE; |
| 775 | x -= es->format_rect.left; |
| 776 | if (!x) |
| 777 | return es->x_offset; |
Ulrich Czekalla | 7df3375 | 2005-02-16 16:28:34 +0000 | [diff] [blame] | 778 | |
| 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 Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 788 | text = EDIT_GetPasswordPointer_SL(es); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 789 | dc = GetDC(es->hwndSelf); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 790 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 791 | old_font = SelectObject(dc, es->font); |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 792 | if (x < 0) |
| 793 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 794 | INT low = 0; |
| 795 | INT high = es->x_offset; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 796 | while (low < high - 1) |
| 797 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 798 | INT mid = (low + high) / 2; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 799 | GetTextExtentPoint32W( dc, text + mid, |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 800 | es->x_offset - mid, &size ); |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 801 | if (size.cx > -x) { |
| 802 | low = mid; |
| 803 | x_low = size.cx; |
| 804 | } else { |
| 805 | high = mid; |
| 806 | x_high = size.cx; |
| 807 | } |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 808 | } |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 809 | if (abs(x_high + x) <= abs(x_low + x) + 1) |
| 810 | index = high; |
| 811 | else |
| 812 | index = low; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 813 | } |
| 814 | else |
| 815 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 816 | INT low = es->x_offset; |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 817 | INT high = get_text_length(es) + 1; |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 818 | while (low < high - 1) |
| 819 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 820 | INT mid = (low + high) / 2; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 821 | GetTextExtentPoint32W( dc, text + es->x_offset, |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 822 | mid - es->x_offset, &size ); |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 823 | if (size.cx > x) { |
| 824 | high = mid; |
| 825 | x_high = size.cx; |
| 826 | } else { |
| 827 | low = mid; |
| 828 | x_low = size.cx; |
| 829 | } |
Alexandre Julliard | a0b2b1d | 1997-11-16 17:38:29 +0000 | [diff] [blame] | 830 | } |
Lauri Tulmin | f124878 | 2005-06-14 12:24:48 +0000 | [diff] [blame] | 831 | if (abs(x_high - x) <= abs(x_low - x) + 1) |
| 832 | index = high; |
| 833 | else |
| 834 | index = low; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 835 | } |
| 836 | if (es->style & ES_PASSWORD) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 837 | HeapFree(GetProcessHeap(), 0, text); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 838 | } |
| 839 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 840 | SelectObject(dc, old_font); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 841 | ReleaseDC(es->hwndSelf, dc); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 842 | return index; |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 843 | } |
| 844 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 845 | |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 846 | /********************************************************************* |
Alexandre Julliard | 02ed4c2 | 1996-03-02 19:34:10 +0000 | [diff] [blame] | 847 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 848 | * EDIT_ConfinePoint |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 849 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 850 | * adjusts the point to be within the formatting rectangle |
| 851 | * (so CharFromPos returns the nearest _visible_ character) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 852 | * |
| 853 | */ |
Andrew Talbot | 49c0bd5 | 2007-11-19 15:46:20 +0000 | [diff] [blame] | 854 | static void EDIT_ConfinePoint(const EDITSTATE *es, LPINT x, LPINT y) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 855 | { |
Francois Gouget | 6d77d3a | 2000-03-25 21:44:35 +0000 | [diff] [blame] | 856 | *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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 858 | } |
| 859 | |
| 860 | |
| 861 | /********************************************************************* |
| 862 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 863 | * EM_LINEFROMCHAR |
| 864 | * |
| 865 | */ |
| 866 | static 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 | */ |
| 895 | static 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 | */ |
| 930 | static 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 | */ |
| 966 | static 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1066 | * EDIT_GetLineRect |
| 1067 | * |
| 1068 | * Calculates the bounding rectangle for a line from a starting |
| 1069 | * column to an ending column. |
| 1070 | * |
| 1071 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1072 | static void EDIT_GetLineRect(EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1073 | { |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1074 | INT line_index = EDIT_EM_LineIndex(es, line); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1075 | |
| 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 Julliard | 9d61596 | 2003-09-17 04:28:28 +0000 | [diff] [blame] | 1081 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1083 | } |
| 1084 | |
| 1085 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1086 | static inline void text_buffer_changed(EDITSTATE *es) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1087 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1088 | es->text_length = (UINT)-1; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1089 | } |
| 1090 | |
Alexandre Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1091 | /********************************************************************* |
Detlef Riekenberg | 2f529c3 | 2010-01-05 15:58:01 +0100 | [diff] [blame] | 1092 | * EDIT_LockBuffer |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1093 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1094 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1095 | static void EDIT_LockBuffer(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1096 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1097 | if (!es->text) { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 1098 | |
Alexandre Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1099 | if(!es->hloc32W) return; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 1100 | |
Alexandre Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1101 | if(es->hloc32A) |
| 1102 | { |
| 1103 | CHAR *textA = LocalLock(es->hloc32A); |
Dmitry Timoshkov | f77709e | 2001-01-10 23:55:02 +0000 | [diff] [blame] | 1104 | HLOCAL hloc32W_new; |
Alexandre Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1105 | UINT countW_new = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0); |
Dmitry Timoshkov | f77709e | 2001-01-10 23:55:02 +0000 | [diff] [blame] | 1106 | if(countW_new > es->buffer_size + 1) |
| 1107 | { |
Dmitry Timoshkov | df793bc | 2001-01-15 20:20:31 +0000 | [diff] [blame] | 1108 | UINT alloc_size = ROUND_TO_GROW(countW_new * sizeof(WCHAR)); |
Dmitry Timoshkov | f77709e | 2001-01-10 23:55:02 +0000 | [diff] [blame] | 1109 | 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 Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1120 | es->text = LocalLock(es->hloc32W); |
| 1121 | MultiByteToWideChar(CP_ACP, 0, textA, -1, es->text, es->buffer_size + 1); |
| 1122 | LocalUnlock(es->hloc32A); |
Dmitry Timoshkov | f77709e | 2001-01-10 23:55:02 +0000 | [diff] [blame] | 1123 | } |
Alexandre Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1124 | else es->text = LocalLock(es->hloc32W); |
Alexandre Julliard | 3051b64 | 1996-07-05 17:14:13 +0000 | [diff] [blame] | 1125 | } |
Huw Davies | 6a94516 | 2007-04-19 15:01:13 +0100 | [diff] [blame] | 1126 | if(es->flags & EF_APP_HAS_HANDLE) text_buffer_changed(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1127 | es->lock_count++; |
Alexandre Julliard | 3051b64 | 1996-07-05 17:14:13 +0000 | [diff] [blame] | 1128 | } |
| 1129 | |
| 1130 | |
| 1131 | /********************************************************************* |
| 1132 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1133 | * EDIT_UnlockBuffer |
| 1134 | * |
| 1135 | */ |
| 1136 | static 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1157 | UINT countA = 0; |
| 1158 | UINT countW = get_text_length(es) + 1; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1159 | |
| 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 Julliard | 7e9721f | 2009-12-11 17:04:59 +0100 | [diff] [blame] | 1181 | WideCharToMultiByte(CP_ACP, 0, es->text, countW, |
| 1182 | LocalLock(es->hloc32A), countA, NULL, NULL); |
| 1183 | LocalUnlock(es->hloc32A); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1184 | } |
| 1185 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1186 | 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 | */ |
| 1204 | static 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 | */ |
| 1245 | static 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 | */ |
| 1272 | static 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 | */ |
| 1287 | static 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1298 | * EDIT_SL_InvalidateText |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1299 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1300 | * Called from EDIT_InvalidateText(). |
| 1301 | * Does the job for single-line controls only. |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1302 | * |
| 1303 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1304 | static void EDIT_SL_InvalidateText(EDITSTATE *es, INT start, INT end) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1305 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1306 | RECT line_rect; |
| 1307 | RECT rc; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1308 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1309 | EDIT_GetLineRect(es, 0, start, end, &line_rect); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1310 | if (IntersectRect(&rc, &line_rect, &es->format_rect)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1311 | EDIT_UpdateText(es, &rc, TRUE); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1312 | } |
| 1313 | |
| 1314 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1315 | static 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1321 | /********************************************************************* |
| 1322 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1323 | * EDIT_ML_InvalidateText |
| 1324 | * |
| 1325 | * Called from EDIT_InvalidateText(). |
| 1326 | * Does the job for multi-line controls only. |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1327 | * |
| 1328 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1329 | static void EDIT_ML_InvalidateText(EDITSTATE *es, INT start, INT end) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1330 | { |
Aric Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 1331 | INT vlc = get_vertical_line_count(es); |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1332 | INT sl = EDIT_EM_LineFromChar(es, start); |
| 1333 | INT el = EDIT_EM_LineFromChar(es, end); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1334 | INT sc; |
| 1335 | INT ec; |
| 1336 | RECT rc1; |
| 1337 | RECT rcWnd; |
| 1338 | RECT rcLine; |
| 1339 | RECT rcUpdate; |
| 1340 | INT l; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1341 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1342 | if ((el < es->y_offset) || (sl > es->y_offset + vlc)) |
| 1343 | return; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1344 | |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1345 | sc = start - EDIT_EM_LineIndex(es, sl); |
| 1346 | ec = end - EDIT_EM_LineIndex(es, el); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1347 | 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 Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1353 | ec = EDIT_EM_LineLength(es, EDIT_EM_LineIndex(es, el)); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1354 | } |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1355 | GetClientRect(es->hwndSelf, &rc1); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1356 | IntersectRect(&rcWnd, &rc1, &es->format_rect); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1357 | if (sl == el) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1358 | EDIT_GetLineRect(es, sl, sc, ec, &rcLine); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1359 | if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1360 | EDIT_UpdateText(es, &rcUpdate, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1361 | } else { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1362 | EDIT_GetLineRect(es, sl, sc, |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1363 | EDIT_EM_LineLength(es, |
| 1364 | EDIT_EM_LineIndex(es, sl)), |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1365 | &rcLine); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1366 | if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1367 | EDIT_UpdateText(es, &rcUpdate, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1368 | for (l = sl + 1 ; l < el ; l++) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1369 | EDIT_GetLineRect(es, l, 0, |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1370 | EDIT_EM_LineLength(es, |
| 1371 | EDIT_EM_LineIndex(es, l)), |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1372 | &rcLine); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1373 | if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1374 | EDIT_UpdateText(es, &rcUpdate, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1375 | } |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1376 | EDIT_GetLineRect(es, el, 0, ec, &rcLine); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1377 | if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1378 | EDIT_UpdateText(es, &rcUpdate, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1379 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1380 | } |
| 1381 | |
| 1382 | |
| 1383 | /********************************************************************* |
| 1384 | * |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1385 | * EDIT_InvalidateText |
| 1386 | * |
Francois Gouget | 6d442ae | 2005-11-23 20:14:43 +0100 | [diff] [blame] | 1387 | * Invalidate the text from offset start up to, but not including, |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1388 | * 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1394 | static void EDIT_InvalidateText(EDITSTATE *es, INT start, INT end) |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1395 | { |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1396 | if (end == start) |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1397 | return; |
| 1398 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1399 | if (end == -1) |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 1400 | end = get_text_length(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1401 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1402 | if (end < start) { |
| 1403 | INT tmp = start; |
| 1404 | start = end; |
| 1405 | end = tmp; |
| 1406 | } |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1407 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1408 | if (es->style & ES_MULTILINE) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1409 | EDIT_ML_InvalidateText(es, start, end); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1410 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1411 | EDIT_SL_InvalidateText(es, start, end); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1412 | } |
| 1413 | |
| 1414 | |
| 1415 | /********************************************************************* |
| 1416 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1417 | * EDIT_EM_SetSel |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1418 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1419 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1423 | */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1424 | static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1425 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1426 | UINT old_start = es->selection_start; |
| 1427 | UINT old_end = es->selection_end; |
| 1428 | UINT len = get_text_length(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1429 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1430 | if (start == (UINT)-1) { |
| 1431 | start = es->selection_end; |
| 1432 | end = es->selection_end; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1433 | } else { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1434 | start = min(start, len); |
| 1435 | end = min(end, len); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1436 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1437 | 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 Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1482 | } |
| 1483 | |
| 1484 | |
| 1485 | /********************************************************************* |
| 1486 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1487 | * EDIT_UpdateScrollInfo |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1488 | * |
| 1489 | */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1490 | static void EDIT_UpdateScrollInfo(EDITSTATE *es) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1491 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1492 | 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 Timoshkov | f8b96e2 | 2000-12-20 18:39:14 +0000 | [diff] [blame] | 1505 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1506 | 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 Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1520 | |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1521 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1522 | /********************************************************************* |
| 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 | */ |
| 1531 | static 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 Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1541 | } |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 1542 | else |
| 1543 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1544 | dy = 0; |
| 1545 | x_offset_in_pixels = (short)LOWORD(EDIT_EM_PosFromChar(es, es->x_offset, FALSE)); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 1546 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1547 | |
| 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 | */ |
| 1587 | static 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 | */ |
| 1602 | static 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 Hedberg | 5a1f8c5 | 2010-03-03 13:19:47 +0100 | [diff] [blame] | 1635 | dy = max(es->line_count - vlc, 0) - es->y_offset; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1636 | |
| 1637 | /* Notification is done in EDIT_EM_LineScroll */ |
David Hedberg | 598052b | 2010-03-03 13:19:46 +0100 | [diff] [blame] | 1638 | if(dy) { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1639 | EDIT_EM_LineScroll(es, 0, dy); |
David Hedberg | 598052b | 2010-03-03 13:19:46 +0100 | [diff] [blame] | 1640 | return MAKELONG(dy, TRUE); |
| 1641 | } |
| 1642 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1643 | } |
David Hedberg | 598052b | 2010-03-03 13:19:46 +0100 | [diff] [blame] | 1644 | return (LRESULT)FALSE; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 1645 | } |
| 1646 | |
| 1647 | |
| 1648 | /********************************************************************* |
| 1649 | * |
| 1650 | * EDIT_SetCaretPos |
| 1651 | * |
| 1652 | */ |
| 1653 | static 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 | */ |
| 1667 | static 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1729 | } |
| 1730 | |
| 1731 | |
| 1732 | /********************************************************************* |
| 1733 | * |
| 1734 | * EDIT_MoveBackward |
| 1735 | * |
| 1736 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1737 | static void EDIT_MoveBackward(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1738 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1739 | INT e = es->selection_end; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1740 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1741 | if (e) { |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1742 | e--; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1743 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1750 | EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE); |
| 1751 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1752 | } |
| 1753 | |
| 1754 | |
| 1755 | /********************************************************************* |
| 1756 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1757 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1762 | * |
| 1763 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1764 | static void EDIT_MoveDown_ML(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1765 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1766 | INT s = es->selection_start; |
| 1767 | INT e = es->selection_end; |
| 1768 | BOOL after_wrap = (es->flags & EF_AFTER_WRAP); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1769 | LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap); |
Alexandre Julliard | 9d61596 | 2003-09-17 04:28:28 +0000 | [diff] [blame] | 1770 | INT x = (short)LOWORD(pos); |
| 1771 | INT y = (short)HIWORD(pos); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1772 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1773 | e = EDIT_CharFromPos(es, x, y + es->line_height, &after_wrap); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1774 | if (!extend) |
| 1775 | s = e; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1776 | EDIT_EM_SetSel(es, s, e, after_wrap); |
| 1777 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1778 | } |
| 1779 | |
| 1780 | |
| 1781 | /********************************************************************* |
| 1782 | * |
| 1783 | * EDIT_MoveEnd |
| 1784 | * |
| 1785 | */ |
Lei Zhang | 483116a | 2008-04-14 17:18:40 -0700 | [diff] [blame] | 1786 | static void EDIT_MoveEnd(EDITSTATE *es, BOOL extend, BOOL ctrl) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1787 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1788 | BOOL after_wrap = FALSE; |
| 1789 | INT e; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1790 | |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 1791 | /* Pass a high value in x to make sure of receiving the end of the line */ |
Lei Zhang | 483116a | 2008-04-14 17:18:40 -0700 | [diff] [blame] | 1792 | if (!ctrl && (es->style & ES_MULTILINE)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1793 | e = EDIT_CharFromPos(es, 0x3fffffff, |
| 1794 | HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1795 | else |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 1796 | e = get_text_length(es); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1797 | EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, after_wrap); |
| 1798 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1799 | } |
| 1800 | |
| 1801 | |
| 1802 | /********************************************************************* |
| 1803 | * |
| 1804 | * EDIT_MoveForward |
| 1805 | * |
| 1806 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1807 | static void EDIT_MoveForward(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1808 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1809 | INT e = es->selection_end; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1810 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1811 | if (es->text[e]) { |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1812 | e++; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1813 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1820 | EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE); |
| 1821 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1822 | } |
| 1823 | |
| 1824 | |
| 1825 | /********************************************************************* |
| 1826 | * |
| 1827 | * EDIT_MoveHome |
| 1828 | * |
| 1829 | * Home key: move to beginning of line. |
| 1830 | * |
| 1831 | */ |
Lei Zhang | dfdd929 | 2008-04-14 17:16:36 -0700 | [diff] [blame] | 1832 | static void EDIT_MoveHome(EDITSTATE *es, BOOL extend, BOOL ctrl) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1833 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1834 | INT e; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1835 | |
Pascal Lessard | 3405f5c | 1999-09-04 10:59:07 +0000 | [diff] [blame] | 1836 | /* Pass the x_offset in x to make sure of receiving the first position of the line */ |
Lei Zhang | dfdd929 | 2008-04-14 17:16:36 -0700 | [diff] [blame] | 1837 | if (!ctrl && (es->style & ES_MULTILINE)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1838 | e = EDIT_CharFromPos(es, -es->x_offset, |
| 1839 | HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1840 | else |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1841 | e = 0; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1842 | EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE); |
| 1843 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1844 | } |
| 1845 | |
| 1846 | |
| 1847 | /********************************************************************* |
| 1848 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1849 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1854 | * |
| 1855 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1856 | static void EDIT_MovePageDown_ML(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1857 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1858 | INT s = es->selection_start; |
| 1859 | INT e = es->selection_end; |
| 1860 | BOOL after_wrap = (es->flags & EF_AFTER_WRAP); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1861 | LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap); |
Alexandre Julliard | 9d61596 | 2003-09-17 04:28:28 +0000 | [diff] [blame] | 1862 | INT x = (short)LOWORD(pos); |
| 1863 | INT y = (short)HIWORD(pos); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1864 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1865 | e = EDIT_CharFromPos(es, x, |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1866 | y + (es->format_rect.bottom - es->format_rect.top), |
| 1867 | &after_wrap); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1868 | if (!extend) |
| 1869 | s = e; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1870 | EDIT_EM_SetSel(es, s, e, after_wrap); |
| 1871 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1872 | } |
| 1873 | |
| 1874 | |
| 1875 | /********************************************************************* |
| 1876 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1877 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1882 | * |
| 1883 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1884 | static void EDIT_MovePageUp_ML(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1885 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1886 | INT s = es->selection_start; |
| 1887 | INT e = es->selection_end; |
| 1888 | BOOL after_wrap = (es->flags & EF_AFTER_WRAP); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1889 | LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap); |
Alexandre Julliard | 9d61596 | 2003-09-17 04:28:28 +0000 | [diff] [blame] | 1890 | INT x = (short)LOWORD(pos); |
| 1891 | INT y = (short)HIWORD(pos); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1892 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1893 | e = EDIT_CharFromPos(es, x, |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1894 | y - (es->format_rect.bottom - es->format_rect.top), |
| 1895 | &after_wrap); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1896 | if (!extend) |
| 1897 | s = e; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1898 | EDIT_EM_SetSel(es, s, e, after_wrap); |
| 1899 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1900 | } |
| 1901 | |
| 1902 | |
| 1903 | /********************************************************************* |
| 1904 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1905 | * EDIT_MoveUp_ML |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1906 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1907 | * 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1911 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1912 | static void EDIT_MoveUp_ML(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1913 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1914 | INT s = es->selection_start; |
| 1915 | INT e = es->selection_end; |
| 1916 | BOOL after_wrap = (es->flags & EF_AFTER_WRAP); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1917 | LRESULT pos = EDIT_EM_PosFromChar(es, e, after_wrap); |
Alexandre Julliard | 9d61596 | 2003-09-17 04:28:28 +0000 | [diff] [blame] | 1918 | INT x = (short)LOWORD(pos); |
| 1919 | INT y = (short)HIWORD(pos); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1920 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1921 | e = EDIT_CharFromPos(es, x, y - es->line_height, &after_wrap); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1922 | if (!extend) |
| 1923 | s = e; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1924 | EDIT_EM_SetSel(es, s, e, after_wrap); |
| 1925 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1926 | } |
| 1927 | |
| 1928 | |
| 1929 | /********************************************************************* |
| 1930 | * |
| 1931 | * EDIT_MoveWordBackward |
| 1932 | * |
| 1933 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1934 | static void EDIT_MoveWordBackward(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1935 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1936 | INT s = es->selection_start; |
| 1937 | INT e = es->selection_end; |
| 1938 | INT l; |
| 1939 | INT ll; |
| 1940 | INT li; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1941 | |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1942 | l = EDIT_EM_LineFromChar(es, e); |
| 1943 | ll = EDIT_EM_LineLength(es, e); |
| 1944 | li = EDIT_EM_LineIndex(es, l); |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1945 | if (e - li == 0) { |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1946 | if (l) { |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1947 | li = EDIT_EM_LineIndex(es, l - 1); |
| 1948 | e = li + EDIT_EM_LineLength(es, li); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1949 | } |
| 1950 | } else { |
Andrew Talbot | 3dfaef3 | 2008-01-21 20:06:59 +0000 | [diff] [blame] | 1951 | e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1952 | } |
| 1953 | if (!extend) |
| 1954 | s = e; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1955 | EDIT_EM_SetSel(es, s, e, FALSE); |
| 1956 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1957 | } |
| 1958 | |
| 1959 | |
| 1960 | /********************************************************************* |
| 1961 | * |
| 1962 | * EDIT_MoveWordForward |
| 1963 | * |
| 1964 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1965 | static void EDIT_MoveWordForward(EDITSTATE *es, BOOL extend) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1966 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1967 | INT s = es->selection_start; |
| 1968 | INT e = es->selection_end; |
| 1969 | INT l; |
| 1970 | INT ll; |
| 1971 | INT li; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1972 | |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1973 | l = EDIT_EM_LineFromChar(es, e); |
| 1974 | ll = EDIT_EM_LineLength(es, e); |
| 1975 | li = EDIT_EM_LineIndex(es, l); |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 1976 | if (e - li == ll) { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1977 | if ((es->style & ES_MULTILINE) && (l != es->line_count - 1)) |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1978 | e = EDIT_EM_LineIndex(es, l + 1); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1979 | } else { |
Dmitry Timoshkov | 8058ead | 2000-12-21 20:19:21 +0000 | [diff] [blame] | 1980 | e = li + EDIT_CallWordBreakProc(es, |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 1981 | li, e - li + 1, ll, WB_RIGHT); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1982 | } |
| 1983 | if (!extend) |
| 1984 | s = e; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 1985 | EDIT_EM_SetSel(es, s, e, FALSE); |
| 1986 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1987 | } |
| 1988 | |
| 1989 | |
| 1990 | /********************************************************************* |
| 1991 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1992 | * EDIT_PaintText |
| 1993 | * |
| 1994 | */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 1995 | static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1996 | { |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 1997 | COLORREF BkColor; |
| 1998 | COLORREF TextColor; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 1999 | LOGFONTW underline_font; |
| 2000 | HFONT hUnderline = 0; |
| 2001 | HFONT old_font = 0; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2002 | INT ret; |
| 2003 | INT li; |
Dan Engel | 7c7a357 | 2001-04-16 19:32:05 +0000 | [diff] [blame] | 2004 | INT BkMode; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2005 | SIZE size; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2006 | |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 2007 | if (!count) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2008 | return 0; |
Dan Engel | 7c7a357 | 2001-04-16 19:32:05 +0000 | [diff] [blame] | 2009 | BkMode = GetBkMode(dc); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2010 | BkColor = GetBkColor(dc); |
| 2011 | TextColor = GetTextColor(dc); |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 2012 | if (rev) { |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 2013 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2027 | } |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2028 | li = EDIT_EM_LineIndex(es, line); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2029 | if (es->style & ES_MULTILINE) { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2030 | ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count, |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2031 | es->tabs_count, es->tabs, es->format_rect.left - es->x_offset)); |
| 2032 | } else { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2033 | LPWSTR text = EDIT_GetPasswordPointer_SL(es); |
| 2034 | TextOutW(dc, x, y, text + li + col, count); |
| 2035 | GetTextExtentPoint32W(dc, text + li + col, count, &size); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2036 | ret = size.cx; |
| 2037 | if (es->style & ES_PASSWORD) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2038 | HeapFree(GetProcessHeap(), 0, text); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2039 | } |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 2040 | if (rev) { |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 2041 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2054 | } |
| 2055 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2056 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2057 | |
| 2058 | |
| 2059 | /********************************************************************* |
| 2060 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 2061 | * EDIT_PaintLine |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2062 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2063 | */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 2064 | static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2065 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 2066 | 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 Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2100 | } |
| 2101 | |
| 2102 | |
| 2103 | /********************************************************************* |
| 2104 | * |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2105 | * EDIT_AdjustFormatRect |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2106 | * |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2107 | * Adjusts the format rectangle for the current font and the |
| 2108 | * current client rectangle. |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2109 | * |
| 2110 | */ |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2111 | static void EDIT_AdjustFormatRect(EDITSTATE *es) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2112 | { |
Ge van Geldorp | c33c2da | 2004-11-28 14:55:42 +0000 | [diff] [blame] | 2113 | RECT ClientRect; |
Huw Davies | c4b4424 | 2006-03-22 12:16:44 +0000 | [diff] [blame] | 2114 | |
Francois Gouget | 6d77d3a | 2000-03-25 21:44:35 +0000 | [diff] [blame] | 2115 | es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2116 | if (es->style & ES_MULTILINE) |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 2117 | { |
| 2118 | INT fw, vlc, max_x_offset, max_y_offset; |
| 2119 | |
Aric Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 2120 | vlc = get_vertical_line_count(es); |
| 2121 | es->format_rect.bottom = es->format_rect.top + vlc * es->line_height; |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 2122 | |
| 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 Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 2135 | |
| 2136 | /* force scroll info update */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2137 | EDIT_UpdateScrollInfo(es); |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 2138 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2139 | else |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 2140 | /* Windows doesn't care to fix text placement for SL controls */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2141 | es->format_rect.bottom = es->format_rect.top + es->line_height; |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 2142 | |
Ge van Geldorp | c33c2da | 2004-11-28 14:55:42 +0000 | [diff] [blame] | 2143 | /* 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2147 | if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 2148 | EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL); |
Lauri Tulmin | 78e76cf | 2005-01-19 20:53:38 +0000 | [diff] [blame] | 2149 | |
| 2150 | EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2151 | } |
| 2152 | |
| 2153 | |
| 2154 | /********************************************************************* |
| 2155 | * |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2156 | * 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 Talbot | 49c0bd5 | 2007-11-19 15:46:20 +0000 | [diff] [blame] | 2162 | static void EDIT_SetRectNP(EDITSTATE *es, const RECT *rc) |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2163 | { |
| 2164 | LONG_PTR ExStyle; |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 2165 | INT bw, bh; |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2166 | ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE); |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 2167 | |
| 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 Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2177 | es->format_rect.top++; |
| 2178 | es->format_rect.bottom--; |
| 2179 | } |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 2180 | } |
| 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 Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2192 | } |
| 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2202 | * EM_CHARFROMPOS |
| 2203 | * |
Gerard Patel | c9b6534 | 1999-01-24 18:57:23 +0000 | [diff] [blame] | 2204 | * returns line number (not index) in high-order word of result. |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2205 | * NB : Q137805 is unclear about this. POINT * pointer in lParam apply |
Gerard Patel | c9b6534 | 1999-01-24 18:57:23 +0000 | [diff] [blame] | 2206 | * to Richedit, not to the edit control. Original documentation is valid. |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2207 | * FIXME: do the specs mean to return -1 if outside client area or |
| 2208 | * if outside formatting rectangle ??? |
| 2209 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2210 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2211 | static LRESULT EDIT_EM_CharFromPos(EDITSTATE *es, INT x, INT y) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2212 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2213 | POINT pt; |
| 2214 | RECT rc; |
| 2215 | INT index; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2216 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2217 | pt.x = x; |
| 2218 | pt.y = y; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2219 | GetClientRect(es->hwndSelf, &rc); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2220 | if (!PtInRect(&rc, pt)) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2221 | return -1; |
| 2222 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2223 | index = EDIT_CharFromPos(es, x, y, NULL); |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2224 | return MAKELONG(index, EDIT_EM_LineFromChar(es, index)); |
Alexandre Julliard | d2e1c1a | 1996-03-09 16:12:43 +0000 | [diff] [blame] | 2225 | } |
| 2226 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2227 | |
Alexandre Julliard | d2e1c1a | 1996-03-09 16:12:43 +0000 | [diff] [blame] | 2228 | /********************************************************************* |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2229 | * |
| 2230 | * EM_FMTLINES |
| 2231 | * |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 2232 | * Enable or disable soft breaks. |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2233 | * |
| 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 Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 2238 | */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2239 | static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol) |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2240 | { |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 2241 | es->flags &= ~EF_USE_SOFTBRK; |
| 2242 | if (add_eol) { |
| 2243 | es->flags |= EF_USE_SOFTBRK; |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2244 | FIXME("soft break enabled, not implemented\n"); |
Alexandre Julliard | a845b88 | 1998-06-01 10:44:35 +0000 | [diff] [blame] | 2245 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2246 | return add_eol; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2247 | } |
Alexandre Julliard | 988ca97 | 1994-06-21 16:15:21 +0000 | [diff] [blame] | 2248 | |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2249 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2250 | /********************************************************************* |
| 2251 | * |
| 2252 | * EM_GETHANDLE |
| 2253 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2254 | * Hopefully this won't fire back at us. |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2255 | * We always start with a fixed buffer in the local heap. |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 2256 | * Despite of the documentation says that the local heap is used |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2257 | * only if DS_LOCALEDIT flag is set, NT and 2000 always allocate |
| 2258 | * buffer on the local heap. |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2259 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2260 | */ |
Dmitry Timoshkov | 8058ead | 2000-12-21 20:19:21 +0000 | [diff] [blame] | 2261 | static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2262 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2263 | HLOCAL hLocal; |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2264 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2265 | if (!(es->style & ES_MULTILINE)) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2266 | return 0; |
| 2267 | |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2268 | if(es->is_unicode) |
| 2269 | hLocal = es->hloc32W; |
| 2270 | else |
| 2271 | { |
| 2272 | if(!es->hloc32A) |
| 2273 | { |
| 2274 | CHAR *textA; |
Dmitry Timoshkov | df793bc | 2001-01-15 20:20:31 +0000 | [diff] [blame] | 2275 | UINT countA, alloc_size; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2276 | TRACE("Allocating 32-bit ANSI alias buffer\n"); |
James Hatheway | ba9b964 | 2001-01-10 22:54:33 +0000 | [diff] [blame] | 2277 | countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL); |
Dmitry Timoshkov | df793bc | 2001-01-15 20:20:31 +0000 | [diff] [blame] | 2278 | alloc_size = ROUND_TO_GROW(countA); |
| 2279 | if(!(es->hloc32A = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2280 | { |
Dmitry Timoshkov | df793bc | 2001-01-15 20:20:31 +0000 | [diff] [blame] | 2281 | ERR("Could not allocate %d bytes for 32-bit ANSI alias buffer\n", alloc_size); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2282 | return 0; |
| 2283 | } |
| 2284 | textA = LocalLock(es->hloc32A); |
James Hatheway | ba9b964 | 2001-01-10 22:54:33 +0000 | [diff] [blame] | 2285 | WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2286 | LocalUnlock(es->hloc32A); |
| 2287 | } |
| 2288 | hLocal = es->hloc32A; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2289 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2290 | |
Huw Davies | c79ce3c | 2007-04-19 14:47:12 +0100 | [diff] [blame] | 2291 | es->flags |= EF_APP_HAS_HANDLE; |
Alexandre Julliard | aff7dda | 2002-11-22 21:22:14 +0000 | [diff] [blame] | 2292 | TRACE("Returning %p, LocalSize() = %ld\n", hLocal, LocalSize(hLocal)); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2293 | return hLocal; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2294 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2295 | |
| 2296 | |
| 2297 | /********************************************************************* |
| 2298 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2299 | * EM_GETLINE |
| 2300 | * |
| 2301 | */ |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2302 | static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPWSTR dst, BOOL unicode) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2303 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2304 | LPWSTR src; |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2305 | INT line_len, dst_len; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2306 | INT i; |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2307 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2308 | if (es->style & ES_MULTILINE) { |
| 2309 | if (line >= es->line_count) |
| 2310 | return 0; |
| 2311 | } else |
| 2312 | line = 0; |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2313 | i = EDIT_EM_LineIndex(es, line); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 2314 | src = es->text + i; |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2315 | line_len = EDIT_EM_LineLength(es, i); |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2316 | dst_len = *(WORD *)dst; |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2317 | if(unicode) |
| 2318 | { |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2319 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2330 | } |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2331 | else |
| 2332 | { |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2333 | INT ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, (LPSTR)dst, dst_len, NULL, NULL); |
Vitaliy Margolen | cfbd78d | 2005-10-18 12:01:38 +0000 | [diff] [blame] | 2334 | if(!ret && line_len) /* Insufficient buffer size */ |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2335 | return dst_len; |
| 2336 | if(ret < dst_len) /* Append 0 if enough space */ |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2337 | ((LPSTR)dst)[ret] = 0; |
Dmitry Timoshkov | bf60453 | 2001-02-12 19:15:33 +0000 | [diff] [blame] | 2338 | return ret; |
| 2339 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2340 | } |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2341 | |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2342 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2343 | /********************************************************************* |
| 2344 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2345 | * EM_GETSEL |
| 2346 | * |
| 2347 | */ |
Andrew Talbot | 49c0bd5 | 2007-11-19 15:46:20 +0000 | [diff] [blame] | 2348 | static LRESULT EDIT_EM_GetSel(const EDITSTATE *es, PUINT start, PUINT end) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2349 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2350 | UINT s = es->selection_start; |
| 2351 | UINT e = es->selection_end; |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2352 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2353 | ORDER_UINT(s, e); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2354 | if (start) |
| 2355 | *start = s; |
| 2356 | if (end) |
| 2357 | *end = e; |
| 2358 | return MAKELONG(s, e); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2359 | } |
| 2360 | |
| 2361 | |
| 2362 | /********************************************************************* |
| 2363 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2364 | * EM_REPLACESEL |
| 2365 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2366 | * FIXME: handle ES_NUMBER and ES_OEMCONVERT here |
| 2367 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2368 | */ |
Carl Sopchak | 23b88ef | 2002-11-21 03:57:05 +0000 | [diff] [blame] | 2369 | static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2370 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2371 | UINT strl = strlenW(lpsz_replace); |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 2372 | UINT tl = get_text_length(es); |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2373 | UINT utl; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2374 | UINT s; |
| 2375 | UINT e; |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2376 | UINT i; |
Krishna Murthy | 4af4ba4 | 2004-05-29 00:21:51 +0000 | [diff] [blame] | 2377 | UINT size; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2378 | LPWSTR p; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 2379 | HRGN hrgn = 0; |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2380 | LPWSTR buf = NULL; |
| 2381 | UINT bufl = 0; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2382 | |
| 2383 | TRACE("%s, can_undo %d, send_update %d\n", |
| 2384 | debugstr_w(lpsz_replace), can_undo, send_update); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2385 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2386 | s = es->selection_start; |
| 2387 | e = es->selection_end; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2388 | |
| 2389 | if ((s == e) && !strl) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2390 | return; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2391 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2392 | ORDER_UINT(s, e); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2393 | |
Lauri Tulmin | 914c138 | 2005-02-21 20:39:52 +0000 | [diff] [blame] | 2394 | size = tl - (e - s) + strl; |
| 2395 | if (!size) |
| 2396 | es->text_width = 0; |
| 2397 | |
Krishna Murthy | 4af4ba4 | 2004-05-29 00:21:51 +0000 | [diff] [blame] | 2398 | /* Issue the EN_MAXTEXT notification and continue with replacing text |
| 2399 | * such that buffer limit is honored. */ |
Alex VillacĂs Lasso | 48fd106 | 2007-10-16 15:25:51 -0500 | [diff] [blame] | 2400 | if ((honor_limit) && (size > es->buffer_limit)) { |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 2401 | EDIT_NOTIFY_PARENT(es, EN_MAXTEXT); |
Alex Busenius | ca62583 | 2007-10-21 13:28:17 +0200 | [diff] [blame] | 2402 | /* 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 Murthy | 4af4ba4 | 2004-05-29 00:21:51 +0000 | [diff] [blame] | 2407 | } |
| 2408 | |
| 2409 | if (!EDIT_MakeFit(es, tl - (e - s) + strl)) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2410 | return; |
| 2411 | |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2412 | if (e != s) { |
| 2413 | /* there is something to be deleted */ |
Andreas Mohr | 07216db | 2001-11-13 21:29:38 +0000 | [diff] [blame] | 2414 | TRACE("deleting stuff.\n"); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2415 | bufl = e - s; |
| 2416 | buf = HeapAlloc(GetProcessHeap(), 0, (bufl + 1) * sizeof(WCHAR)); |
| 2417 | if (!buf) return; |
Peter Berg Larsen | 6e3bcb5 | 2005-04-18 10:30:55 +0000 | [diff] [blame] | 2418 | memcpy(buf, es->text + s, bufl * sizeof(WCHAR)); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2419 | buf[bufl] = 0; /* ensure 0 termination */ |
| 2420 | /* now delete */ |
| 2421 | strcpyW(es->text + s, es->text + e); |
Huw Davies | 6a94516 | 2007-04-19 15:01:13 +0100 | [diff] [blame] | 2422 | text_buffer_changed(es); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2423 | } |
| 2424 | if (strl) { |
| 2425 | /* there is an insertion */ |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 2426 | tl = get_text_length(es); |
Francois Gouget | aab5e58 | 2007-01-18 11:40:15 +0100 | [diff] [blame] | 2427 | 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 Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2428 | 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 Davies | 6a94516 | 2007-04-19 15:01:13 +0100 | [diff] [blame] | 2436 | text_buffer_changed(es); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2437 | } |
| 2438 | if (es->style & ES_MULTILINE) |
| 2439 | { |
| 2440 | INT st = min(es->selection_start, es->selection_end); |
Aric Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 2441 | INT vlc = get_vertical_line_count(es); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2442 | |
| 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 Tulmin | a810802 | 2005-06-05 19:19:11 +0000 | [diff] [blame] | 2447 | if (honor_limit && !(es->style & ES_AUTOVSCROLL) && (es->line_count > vlc)) { |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2448 | 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 Davies | 6a94516 | 2007-04-19 15:01:13 +0100 | [diff] [blame] | 2453 | text_buffer_changed(es); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2454 | 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 Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 2459 | EDIT_NOTIFY_PARENT(es, EN_MAXTEXT); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2460 | } |
| 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 Tulmin | a810802 | 2005-06-05 19:19:11 +0000 | [diff] [blame] | 2466 | if (honor_limit && !(es->style & ES_AUTOHSCROLL) && (es->text_width > fw)) { |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2467 | 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 Davies | 6a94516 | 2007-04-19 15:01:13 +0100 | [diff] [blame] | 2472 | text_buffer_changed(es); |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 2473 | EDIT_NOTIFY_PARENT(es, EN_MAXTEXT); |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2474 | } |
| 2475 | } |
| 2476 | |
| 2477 | if (e != s) { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2478 | if (can_undo) { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2479 | utl = strlenW(es->undo_text); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2480 | if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) { |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2481 | /* undo-buffer is extended to the right */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2482 | EDIT_MakeUndoFit(es, utl + e - s); |
Peter Berg Larsen | 6e3bcb5 | 2005-04-18 10:30:55 +0000 | [diff] [blame] | 2483 | memcpy(es->undo_text + utl, buf, (e - s)*sizeof(WCHAR)); |
Dmitry Timoshkov | f8b96e2 | 2000-12-20 18:39:14 +0000 | [diff] [blame] | 2484 | (es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2485 | } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) { |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2486 | /* undo-buffer is extended to the left */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2487 | EDIT_MakeUndoFit(es, utl + e - s); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2488 | for (p = es->undo_text + utl ; p >= es->undo_text ; p--) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2489 | p[e - s] = p[0]; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2490 | for (i = 0 , p = es->undo_text ; i < e - s ; i++) |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2491 | p[i] = buf[i]; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2492 | es->undo_position = s; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2493 | } else { |
| 2494 | /* new undo-buffer */ |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2495 | EDIT_MakeUndoFit(es, e - s); |
Peter Berg Larsen | 6e3bcb5 | 2005-04-18 10:30:55 +0000 | [diff] [blame] | 2496 | memcpy(es->undo_text, buf, (e - s)*sizeof(WCHAR)); |
Dmitry Timoshkov | f8b96e2 | 2000-12-20 18:39:14 +0000 | [diff] [blame] | 2497 | es->undo_text[e - s] = 0; /* ensure 0 termination */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2498 | es->undo_position = s; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2499 | } |
| 2500 | /* any deletion makes the old insertion-undo invalid */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2501 | es->undo_insert_count = 0; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2502 | } else |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2503 | EDIT_EM_EmptyUndoBuffer(es); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2504 | } |
| 2505 | if (strl) { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2506 | if (can_undo) { |
| 2507 | if ((s == es->undo_position) || |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2508 | ((es->undo_insert_count) && |
| 2509 | (s == es->undo_position + es->undo_insert_count))) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2510 | /* |
| 2511 | * insertion is new and at delete position or |
| 2512 | * an extension to either left or right |
| 2513 | */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2514 | es->undo_insert_count += strl; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2515 | else { |
| 2516 | /* new insertion undo */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2517 | es->undo_position = s; |
| 2518 | es->undo_insert_count = strl; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2519 | /* new insertion makes old delete-buffer invalid */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2520 | *es->undo_text = '\0'; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2521 | } |
| 2522 | } else |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2523 | EDIT_EM_EmptyUndoBuffer(es); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2524 | } |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 2525 | |
Lauri Tulmin | 7cb7c6b | 2005-02-25 13:59:49 +0000 | [diff] [blame] | 2526 | if (bufl) |
| 2527 | HeapFree(GetProcessHeap(), 0, buf); |
| 2528 | |
| 2529 | s += strl; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2530 | |
Ulrich Czekalla | 7df3375 | 2005-02-16 16:28:34 +0000 | [diff] [blame] | 2531 | /* 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2545 | EDIT_EM_SetSel(es, s, s, FALSE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2546 | es->flags |= EF_MODIFIED; |
Ulrich Weigand | 6bfbc3d | 2000-10-23 00:38:10 +0000 | [diff] [blame] | 2547 | if (send_update) es->flags |= EF_UPDATE; |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 2548 | if (hrgn) |
| 2549 | { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2550 | EDIT_UpdateTextRegion(es, hrgn, TRUE); |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 2551 | DeleteObject(hrgn); |
| 2552 | } |
| 2553 | else |
Huw Davies | 4c7b65d | 2003-11-11 00:26:53 +0000 | [diff] [blame] | 2554 | EDIT_UpdateText(es, NULL, TRUE); |
| 2555 | |
| 2556 | EDIT_EM_ScrollCaret(es); |
| 2557 | |
| 2558 | /* force scroll info update */ |
| 2559 | EDIT_UpdateScrollInfo(es); |
| 2560 | |
Dmitry Timoshkov | a62f06d | 2001-03-13 23:31:08 +0000 | [diff] [blame] | 2561 | |
C. Scott Ananian | aa63674 | 2005-03-22 16:40:36 +0000 | [diff] [blame] | 2562 | if(send_update || (es->flags & EF_UPDATE)) |
Dmitry Timoshkov | a62f06d | 2001-03-13 23:31:08 +0000 | [diff] [blame] | 2563 | { |
| 2564 | es->flags &= ~EF_UPDATE; |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 2565 | EDIT_NOTIFY_PARENT(es, EN_CHANGE); |
Dmitry Timoshkov | a62f06d | 2001-03-13 23:31:08 +0000 | [diff] [blame] | 2566 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2567 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2568 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2569 | |
| 2570 | /********************************************************************* |
| 2571 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2572 | * EM_SETHANDLE |
| 2573 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2574 | * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ??? |
| 2575 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2576 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2577 | static void EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2578 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2579 | if (!(es->style & ES_MULTILINE)) |
| 2580 | return; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2581 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2582 | if (!hloc) { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2583 | WARN("called with NULL handle\n"); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2584 | return; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2585 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2586 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2587 | EDIT_UnlockBuffer(es, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2588 | |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2589 | if(es->is_unicode) |
| 2590 | { |
| 2591 | if(es->hloc32A) |
| 2592 | { |
| 2593 | LocalFree(es->hloc32A); |
Francois Gouget | d2667a4 | 2002-12-02 18:10:57 +0000 | [diff] [blame] | 2594 | es->hloc32A = NULL; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2595 | } |
| 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 Davies | c79ce3c | 2007-04-19 14:47:12 +0100 | [diff] [blame] | 2627 | es->flags |= EF_APP_HAS_HANDLE; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2628 | EDIT_LockBuffer(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2629 | |
| 2630 | es->x_offset = es->y_offset = 0; |
| 2631 | es->selection_start = es->selection_end = 0; |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2632 | EDIT_EM_EmptyUndoBuffer(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2633 | es->flags &= ~EF_MODIFIED; |
| 2634 | es->flags &= ~EF_UPDATE; |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 2635 | EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2636 | EDIT_UpdateText(es, NULL, TRUE); |
| 2637 | EDIT_EM_ScrollCaret(es); |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 2638 | /* force scroll info update */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2639 | EDIT_UpdateScrollInfo(es); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2640 | } |
| 2641 | |
| 2642 | |
| 2643 | /********************************************************************* |
| 2644 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2645 | * EM_SETLIMITTEXT |
| 2646 | * |
Alex VillacĂs Lasso | 48fd106 | 2007-10-16 15:25:51 -0500 | [diff] [blame] | 2647 | * NOTE: this version currently implements WinNT limits |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2648 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2649 | */ |
Alex VillacĂs Lasso | 48fd106 | 2007-10-16 15:25:51 -0500 | [diff] [blame] | 2650 | static void EDIT_EM_SetLimitText(EDITSTATE *es, UINT limit) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2651 | { |
Alex VillacĂs Lasso | 48fd106 | 2007-10-16 15:25:51 -0500 | [diff] [blame] | 2652 | if (!limit) limit = ~0u; |
| 2653 | if (!(es->style & ES_MULTILINE)) limit = min(limit, 0x7ffffffe); |
| 2654 | es->buffer_limit = limit; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2655 | } |
| 2656 | |
| 2657 | |
| 2658 | /********************************************************************* |
| 2659 | * |
| 2660 | * EM_SETMARGINS |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 2661 | * |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 2662 | * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an |
Achim Kaiser | 6d3ce41 | 2003-05-06 18:23:17 +0000 | [diff] [blame] | 2663 | * 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2669 | * |
Huw Davies | c4b4424 | 2006-03-22 12:16:44 +0000 | [diff] [blame] | 2670 | * 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2676 | */ |
Huw Davies | c4b4424 | 2006-03-22 12:16:44 +0000 | [diff] [blame] | 2677 | static 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 Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2686 | static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, |
Huw Davies | c4b4424 | 2006-03-22 12:16:44 +0000 | [diff] [blame] | 2687 | WORD left, WORD right, BOOL repaint) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2688 | { |
Achim Kaiser | 6d3ce41 | 2003-05-06 18:23:17 +0000 | [diff] [blame] | 2689 | 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 Davies | c4b4424 | 2006-03-22 12:16:44 +0000 | [diff] [blame] | 2700 | int min_size; |
| 2701 | RECT rc; |
Achim Kaiser | 6d3ce41 | 2003-05-06 18:23:17 +0000 | [diff] [blame] | 2702 | /* This must be calculated more exactly! But how? */ |
Huw Davies | c4b4424 | 2006-03-22 12:16:44 +0000 | [diff] [blame] | 2703 | 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 Kaiser | 6d3ce41 | 2003-05-06 18:23:17 +0000 | [diff] [blame] | 2711 | } |
| 2712 | SelectObject(dc, old_font); |
| 2713 | ReleaseDC(es->hwndSelf, dc); |
| 2714 | } |
| 2715 | |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 2716 | if (action & EC_LEFTMARGIN) { |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2717 | es->format_rect.left -= es->left_margin; |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 2718 | if (left != EC_USEFONTINFO) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2719 | es->left_margin = left; |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 2720 | else |
Achim Kaiser | 6d3ce41 | 2003-05-06 18:23:17 +0000 | [diff] [blame] | 2721 | es->left_margin = default_left_margin; |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2722 | es->format_rect.left += es->left_margin; |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 2723 | } |
| 2724 | |
| 2725 | if (action & EC_RIGHTMARGIN) { |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2726 | es->format_rect.right += es->right_margin; |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 2727 | if (right != EC_USEFONTINFO) |
| 2728 | es->right_margin = right; |
| 2729 | else |
Achim Kaiser | 6d3ce41 | 2003-05-06 18:23:17 +0000 | [diff] [blame] | 2730 | es->right_margin = default_right_margin; |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2731 | es->format_rect.right -= es->right_margin; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2732 | } |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 2733 | |
| 2734 | if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) { |
| 2735 | EDIT_AdjustFormatRect(es); |
| 2736 | if (repaint) EDIT_UpdateText(es, NULL, TRUE); |
| 2737 | } |
| 2738 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2739 | TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin); |
Alexandre Julliard | 5819953 | 1994-04-21 01:20:00 +0000 | [diff] [blame] | 2740 | } |
| 2741 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2742 | |
| 2743 | /********************************************************************* |
| 2744 | * |
| 2745 | * EM_SETPASSWORDCHAR |
| 2746 | * |
| 2747 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2748 | static void EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2749 | { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2750 | LONG style; |
Alexandre Julliard | de42428 | 2001-08-10 22:51:42 +0000 | [diff] [blame] | 2751 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2752 | if (es->style & ES_MULTILINE) |
| 2753 | return; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2754 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2755 | if (es->password_char == c) |
| 2756 | return; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2757 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2758 | style = GetWindowLongW( es->hwndSelf, GWL_STYLE ); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2759 | es->password_char = c; |
| 2760 | if (c) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2761 | SetWindowLongW( es->hwndSelf, GWL_STYLE, style | ES_PASSWORD ); |
Alexandre Julliard | de42428 | 2001-08-10 22:51:42 +0000 | [diff] [blame] | 2762 | es->style |= ES_PASSWORD; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2763 | } else { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2764 | SetWindowLongW( es->hwndSelf, GWL_STYLE, style & ~ES_PASSWORD ); |
Alexandre Julliard | de42428 | 2001-08-10 22:51:42 +0000 | [diff] [blame] | 2765 | es->style &= ~ES_PASSWORD; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2766 | } |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2767 | EDIT_UpdateText(es, NULL, TRUE); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2768 | } |
| 2769 | |
| 2770 | |
| 2771 | /********************************************************************* |
| 2772 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2773 | * EM_SETTABSTOPS |
| 2774 | * |
| 2775 | */ |
Andrew Talbot | 49c0bd5 | 2007-11-19 15:46:20 +0000 | [diff] [blame] | 2776 | static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, const INT *tabs) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2777 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2778 | if (!(es->style & ES_MULTILINE)) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2779 | return FALSE; |
Michael Stefaniuc | 5ad7d85 | 2004-12-23 17:06:43 +0000 | [diff] [blame] | 2780 | HeapFree(GetProcessHeap(), 0, es->tabs); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2781 | es->tabs_count = count; |
| 2782 | if (!count) |
| 2783 | es->tabs = NULL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2784 | else { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2785 | es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2786 | memcpy(es->tabs, tabs, count * sizeof(INT)); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2787 | } |
| 2788 | return TRUE; |
| 2789 | } |
| 2790 | |
| 2791 | |
| 2792 | /********************************************************************* |
| 2793 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2794 | * EM_SETWORDBREAKPROC |
| 2795 | * |
| 2796 | */ |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2797 | static void EDIT_EM_SetWordBreakProc(EDITSTATE *es, void *wbp) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2798 | { |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2799 | if (es->word_break_proc == wbp) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2800 | return; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2801 | |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 2802 | es->word_break_proc = wbp; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2803 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2804 | if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) { |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 2805 | EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2806 | EDIT_UpdateText(es, NULL, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2807 | } |
| 2808 | } |
| 2809 | |
| 2810 | |
| 2811 | /********************************************************************* |
| 2812 | * |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2813 | * EM_UNDO / WM_UNDO |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2814 | * |
| 2815 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2816 | static BOOL EDIT_EM_Undo(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2817 | { |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 2818 | INT ulength; |
| 2819 | LPWSTR utext; |
| 2820 | |
Krishna Murthy | a7c3107 | 2004-05-07 00:40:18 +0000 | [diff] [blame] | 2821 | /* 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 Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 2825 | |
| 2826 | ulength = strlenW(es->undo_text); |
Krishna Murthy | a7c3107 | 2004-05-07 00:40:18 +0000 | [diff] [blame] | 2827 | |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 2828 | utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR)); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2829 | |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2830 | strcpyW(utext, es->undo_text); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2831 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2832 | TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n", |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2833 | es->undo_insert_count, debugstr_w(utext)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2834 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2835 | EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE); |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 2836 | EDIT_EM_EmptyUndoBuffer(es); |
Krishna Murthy | ca8e313 | 2004-06-18 22:29:05 +0000 | [diff] [blame] | 2837 | EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2838 | EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE); |
Rein Klazes | 9d4ae0e | 2001-04-02 19:13:24 +0000 | [diff] [blame] | 2839 | /* send the notification after the selection start and end are set */ |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 2840 | EDIT_NOTIFY_PARENT(es, EN_CHANGE); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2841 | EDIT_EM_ScrollCaret(es); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2842 | HeapFree(GetProcessHeap(), 0, utext); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2843 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2844 | TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n", |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2845 | es->undo_insert_count, debugstr_w(es->undo_text)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 2846 | return TRUE; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2847 | } |
| 2848 | |
| 2849 | |
Lei Zhang | f704d5c | 2008-04-09 11:33:03 -0700 | [diff] [blame] | 2850 | /* 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 Khodych | 6fa48cd | 2009-08-24 00:10:01 +0300 | [diff] [blame] | 2857 | static inline BOOL EDIT_IsInsideDialog(EDITSTATE *es) |
Lei Zhang | f704d5c | 2008-04-09 11:33:03 -0700 | [diff] [blame] | 2858 | { |
Sergey Khodych | 6fa48cd | 2009-08-24 00:10:01 +0300 | [diff] [blame] | 2859 | return (es->flags & EF_DIALOGMODE); |
Lei Zhang | f704d5c | 2008-04-09 11:33:03 -0700 | [diff] [blame] | 2860 | } |
| 2861 | |
| 2862 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2863 | /********************************************************************* |
| 2864 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 2865 | * WM_PASTE |
| 2866 | * |
| 2867 | */ |
| 2868 | static 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 Kouichi | ccab177 | 2010-02-13 11:38:21 +0900 | [diff] [blame] | 2885 | EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 2886 | } |
| 2887 | CloseClipboard(); |
| 2888 | } |
| 2889 | |
| 2890 | |
| 2891 | /********************************************************************* |
| 2892 | * |
| 2893 | * WM_COPY |
| 2894 | * |
| 2895 | */ |
| 2896 | static 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 | */ |
| 2925 | static inline void EDIT_WM_Clear(EDITSTATE *es) |
| 2926 | { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 2927 | /* 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 | */ |
| 2940 | static inline void EDIT_WM_Cut(EDITSTATE *es) |
| 2941 | { |
| 2942 | EDIT_WM_Copy(es); |
| 2943 | EDIT_WM_Clear(es); |
| 2944 | } |
| 2945 | |
| 2946 | |
| 2947 | /********************************************************************* |
| 2948 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2949 | * WM_CHAR |
| 2950 | * |
| 2951 | */ |
Lei Zhang | c8a4bb8 | 2008-04-07 14:11:58 -0700 | [diff] [blame] | 2952 | static LRESULT EDIT_WM_Char(EDITSTATE *es, WCHAR c) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2953 | { |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 2954 | BOOL control; |
| 2955 | |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 2956 | control = GetKeyState(VK_CONTROL) & 0x8000; |
| 2957 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2958 | switch (c) { |
| 2959 | case '\r': |
Lei Zhang | f704d5c | 2008-04-09 11:33:03 -0700 | [diff] [blame] | 2960 | /* 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2967 | case '\n': |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2968 | if (es->style & ES_MULTILINE) { |
| 2969 | if (es->style & ES_READONLY) { |
Lei Zhang | dfdd929 | 2008-04-14 17:16:36 -0700 | [diff] [blame] | 2970 | EDIT_MoveHome(es, FALSE, FALSE); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2971 | EDIT_MoveDown_ML(es, FALSE); |
Alexandre Julliard | fa2c793 | 2000-05-26 01:24:56 +0000 | [diff] [blame] | 2972 | } else { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2973 | static const WCHAR cr_lfW[] = {'\r','\n',0}; |
Carl Sopchak | 23b88ef | 2002-11-21 03:57:05 +0000 | [diff] [blame] | 2974 | EDIT_EM_ReplaceSel(es, TRUE, cr_lfW, TRUE, TRUE); |
Alexandre Julliard | fa2c793 | 2000-05-26 01:24:56 +0000 | [diff] [blame] | 2975 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2976 | } |
| 2977 | break; |
| 2978 | case '\t': |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 2979 | if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY)) |
Alexandre Julliard | fa2c793 | 2000-05-26 01:24:56 +0000 | [diff] [blame] | 2980 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 2981 | static const WCHAR tabW[] = {'\t',0}; |
Lei Zhang | b7ffa86 | 2008-04-09 11:33:32 -0700 | [diff] [blame] | 2982 | if (EDIT_IsInsideDialog(es)) |
| 2983 | break; |
Carl Sopchak | 23b88ef | 2002-11-21 03:57:05 +0000 | [diff] [blame] | 2984 | EDIT_EM_ReplaceSel(es, TRUE, tabW, TRUE, TRUE); |
Alexandre Julliard | fa2c793 | 2000-05-26 01:24:56 +0000 | [diff] [blame] | 2985 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 2986 | break; |
Pascal Lessard | 6fe38e5 | 1999-09-03 15:02:48 +0000 | [diff] [blame] | 2987 | case VK_BACK: |
| 2988 | if (!(es->style & ES_READONLY) && !control) { |
| 2989 | if (es->selection_start != es->selection_end) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2990 | EDIT_WM_Clear(es); |
Pascal Lessard | 6fe38e5 | 1999-09-03 15:02:48 +0000 | [diff] [blame] | 2991 | else { |
| 2992 | /* delete character left of caret */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 2993 | EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE); |
| 2994 | EDIT_MoveBackward(es, TRUE); |
| 2995 | EDIT_WM_Clear(es); |
Pascal Lessard | 6fe38e5 | 1999-09-03 15:02:48 +0000 | [diff] [blame] | 2996 | } |
| 2997 | } |
| 2998 | break; |
Ulrich Czekalla | c804e3e | 2000-05-23 21:16:07 +0000 | [diff] [blame] | 2999 | case 0x03: /* ^C */ |
Lei Zhang | 7dd98bb | 2007-06-13 17:22:49 -0700 | [diff] [blame] | 3000 | if (!(es->style & ES_PASSWORD)) |
| 3001 | SendMessageW(es->hwndSelf, WM_COPY, 0, 0); |
Susan Farley | 86d0b03 | 2000-05-05 18:21:02 +0000 | [diff] [blame] | 3002 | break; |
Ulrich Czekalla | c804e3e | 2000-05-23 21:16:07 +0000 | [diff] [blame] | 3003 | case 0x16: /* ^V */ |
Ulrich Czekalla | 322cd5d | 2004-09-09 19:18:40 +0000 | [diff] [blame] | 3004 | if (!(es->style & ES_READONLY)) |
| 3005 | SendMessageW(es->hwndSelf, WM_PASTE, 0, 0); |
Susan Farley | 86d0b03 | 2000-05-05 18:21:02 +0000 | [diff] [blame] | 3006 | break; |
Ulrich Czekalla | c804e3e | 2000-05-23 21:16:07 +0000 | [diff] [blame] | 3007 | case 0x18: /* ^X */ |
Lei Zhang | 7dd98bb | 2007-06-13 17:22:49 -0700 | [diff] [blame] | 3008 | if (!((es->style & ES_READONLY) || (es->style & ES_PASSWORD))) |
Ulrich Czekalla | 322cd5d | 2004-09-09 19:18:40 +0000 | [diff] [blame] | 3009 | SendMessageW(es->hwndSelf, WM_CUT, 0, 0); |
Susan Farley | 86d0b03 | 2000-05-05 18:21:02 +0000 | [diff] [blame] | 3010 | break; |
Lei Zhang | 5079d20 | 2007-09-11 21:34:10 -0700 | [diff] [blame] | 3011 | case 0x1A: /* ^Z */ |
| 3012 | if (!(es->style & ES_READONLY)) |
| 3013 | SendMessageW(es->hwndSelf, WM_UNDO, 0, 0); |
| 3014 | break; |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3015 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3016 | default: |
Krishna Murthy | fd43a46 | 2004-07-24 02:26:24 +0000 | [diff] [blame] | 3017 | /*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 Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3021 | if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) { |
| 3022 | WCHAR str[2]; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3023 | str[0] = c; |
| 3024 | str[1] = '\0'; |
Carl Sopchak | 23b88ef | 2002-11-21 03:57:05 +0000 | [diff] [blame] | 3025 | EDIT_EM_ReplaceSel(es, TRUE, str, TRUE, TRUE); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3026 | } |
| 3027 | break; |
| 3028 | } |
Lei Zhang | c8a4bb8 | 2008-04-07 14:11:58 -0700 | [diff] [blame] | 3029 | return 1; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3030 | } |
| 3031 | |
| 3032 | |
| 3033 | /********************************************************************* |
| 3034 | * |
| 3035 | * WM_COMMAND |
| 3036 | * |
| 3037 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3038 | static void EDIT_WM_Command(EDITSTATE *es, INT code, INT id, HWND control) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3039 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3040 | if (code || control) |
| 3041 | return; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3042 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3043 | switch (id) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3044 | case EM_UNDO: |
Lei Zhang | ec91536 | 2008-10-14 17:56:52 -0700 | [diff] [blame] | 3045 | SendMessageW(es->hwndSelf, WM_UNDO, 0, 0); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3046 | break; |
| 3047 | case WM_CUT: |
Lei Zhang | ec91536 | 2008-10-14 17:56:52 -0700 | [diff] [blame] | 3048 | SendMessageW(es->hwndSelf, WM_CUT, 0, 0); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3049 | break; |
| 3050 | case WM_COPY: |
Lei Zhang | ec91536 | 2008-10-14 17:56:52 -0700 | [diff] [blame] | 3051 | SendMessageW(es->hwndSelf, WM_COPY, 0, 0); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3052 | break; |
| 3053 | case WM_PASTE: |
Lei Zhang | ec91536 | 2008-10-14 17:56:52 -0700 | [diff] [blame] | 3054 | SendMessageW(es->hwndSelf, WM_PASTE, 0, 0); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3055 | break; |
| 3056 | case WM_CLEAR: |
Lei Zhang | ec91536 | 2008-10-14 17:56:52 -0700 | [diff] [blame] | 3057 | SendMessageW(es->hwndSelf, WM_CLEAR, 0, 0); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3058 | break; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3059 | case EM_SETSEL: |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3060 | EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE); |
| 3061 | EDIT_EM_ScrollCaret(es); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3062 | break; |
| 3063 | default: |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 3064 | ERR("unknown menu item, please report\n"); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3065 | break; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3066 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3067 | } |
| 3068 | |
| 3069 | |
| 3070 | /********************************************************************* |
| 3071 | * |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3072 | * 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 Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3078 | * 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3086 | static void EDIT_WM_ContextMenu(EDITSTATE *es, INT x, INT y) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3087 | { |
Alexandre Julliard | a2e2e18 | 2004-02-12 00:35:01 +0000 | [diff] [blame] | 3088 | HMENU menu = LoadMenuA(user32_module, "EDITMENU"); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3089 | HMENU popup = GetSubMenu(menu, 0); |
| 3090 | UINT start = es->selection_start; |
| 3091 | UINT end = es->selection_end; |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3092 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3093 | ORDER_UINT(start, end); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3094 | |
| 3095 | /* undo */ |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 3096 | EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3097 | /* cut */ |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 3098 | EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3099 | /* copy */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3100 | EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3101 | /* paste */ |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 3102 | EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3103 | /* delete */ |
Dmitry Timoshkov | 9c446a1 | 2001-01-22 19:28:27 +0000 | [diff] [blame] | 3104 | EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3105 | /* select all */ |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 3106 | EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != get_text_length(es)) ? MF_ENABLED : MF_GRAYED)); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3107 | |
Dmitry Timoshkov | b37b72b | 2006-12-15 15:04:01 +0800 | [diff] [blame] | 3108 | 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 Povirk | a5fd32e | 2010-04-24 14:33:00 -0500 | [diff] [blame] | 3118 | if (!(es->flags & EF_FOCUSED)) |
| 3119 | SetFocus(es->hwndSelf); |
| 3120 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3121 | TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, es->hwndSelf, NULL); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3122 | DestroyMenu(menu); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3123 | } |
| 3124 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3125 | |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 3126 | /********************************************************************* |
| 3127 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3128 | * WM_GETTEXT |
| 3129 | * |
| 3130 | */ |
Andrew Talbot | 49c0bd5 | 2007-11-19 15:46:20 +0000 | [diff] [blame] | 3131 | static INT EDIT_WM_GetText(const EDITSTATE *es, INT count, LPWSTR dst, BOOL unicode) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3132 | { |
Dmitry Timoshkov | f8b96e2 | 2000-12-20 18:39:14 +0000 | [diff] [blame] | 3133 | if(!count) return 0; |
| 3134 | |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3135 | if(unicode) |
| 3136 | { |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3137 | lstrcpynW(dst, es->text, count); |
| 3138 | return strlenW(dst); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3139 | } |
| 3140 | else |
| 3141 | { |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3142 | LPSTR textA = (LPSTR)dst; |
Alexandre Julliard | 331bf3d | 2002-08-15 23:28:45 +0000 | [diff] [blame] | 3143 | if (!WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL)) |
| 3144 | textA[count - 1] = 0; /* ensure 0 termination */ |
Dmitry Timoshkov | 785203c | 2001-01-11 20:17:21 +0000 | [diff] [blame] | 3145 | return strlen(textA); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3146 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3147 | } |
| 3148 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3149 | /********************************************************************* |
| 3150 | * |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3151 | * EDIT_CheckCombo |
| 3152 | * |
| 3153 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3154 | static BOOL EDIT_CheckCombo(EDITSTATE *es, UINT msg, INT key) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3155 | { |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3156 | HWND hLBox = es->hwndListBox; |
| 3157 | HWND hCombo; |
| 3158 | BOOL bDropped; |
| 3159 | int nEUI; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3160 | |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3161 | if (!hLBox) |
| 3162 | return FALSE; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3163 | |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3164 | hCombo = GetParent(es->hwndSelf); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3165 | bDropped = TRUE; |
| 3166 | nEUI = 0; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3167 | |
Alexandre Julliard | aff7dda | 2002-11-22 21:22:14 +0000 | [diff] [blame] | 3168 | TRACE_(combo)("[%p]: handling msg %x (%x)\n", es->hwndSelf, msg, key); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3169 | |
| 3170 | if (key == VK_UP || key == VK_DOWN) |
| 3171 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3172 | if (SendMessageW(hCombo, CB_GETEXTENDEDUI, 0, 0)) |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3173 | nEUI = 1; |
| 3174 | |
| 3175 | if (msg == WM_KEYDOWN || nEUI) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3176 | bDropped = (BOOL)SendMessageW(hCombo, CB_GETDROPPEDSTATE, 0, 0); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3177 | } |
| 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 Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3185 | SendMessageW(hCombo, CB_SETEXTENDEDUI, FALSE, 0); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3186 | key = VK_F4; |
| 3187 | nEUI = 2; |
| 3188 | } |
| 3189 | |
Michael Stefaniuc | 6f3b494 | 2009-12-27 14:40:45 +0100 | [diff] [blame] | 3190 | SendMessageW(hLBox, WM_KEYDOWN, key, 0); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3191 | break; |
| 3192 | |
| 3193 | case WM_SYSKEYDOWN: /* Handle Alt+up/down arrows */ |
| 3194 | if (nEUI) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3195 | SendMessageW(hCombo, CB_SHOWDROPDOWN, bDropped ? FALSE : TRUE, 0); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3196 | else |
Michael Stefaniuc | 6f3b494 | 2009-12-27 14:40:45 +0100 | [diff] [blame] | 3197 | SendMessageW(hLBox, WM_KEYDOWN, VK_F4, 0); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3198 | break; |
| 3199 | } |
| 3200 | |
| 3201 | if(nEUI == 2) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3202 | SendMessageW(hCombo, CB_SETEXTENDEDUI, TRUE, 0); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3203 | |
| 3204 | return TRUE; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3205 | } |
| 3206 | |
| 3207 | |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3208 | /********************************************************************* |
| 3209 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3210 | * 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3216 | static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3217 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3218 | BOOL shift; |
| 3219 | BOOL control; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3220 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3221 | if (GetKeyState(VK_MENU) & 0x8000) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 3222 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3223 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3224 | shift = GetKeyState(VK_SHIFT) & 0x8000; |
| 3225 | control = GetKeyState(VK_CONTROL) & 0x8000; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3226 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3227 | switch (key) { |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 3228 | case VK_F4: |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3229 | case VK_UP: |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3230 | if (EDIT_CheckCombo(es, WM_KEYDOWN, key) || key == VK_F4) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3231 | break; |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3232 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3233 | /* fall through */ |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 3234 | case VK_LEFT: |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3235 | if ((es->style & ES_MULTILINE) && (key == VK_UP)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3236 | EDIT_MoveUp_ML(es, shift); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3237 | else |
| 3238 | if (control) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3239 | EDIT_MoveWordBackward(es, shift); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3240 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3241 | EDIT_MoveBackward(es, shift); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3242 | break; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3243 | case VK_DOWN: |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3244 | if (EDIT_CheckCombo(es, WM_KEYDOWN, key)) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3245 | break; |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 3246 | /* fall through */ |
| 3247 | case VK_RIGHT: |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3248 | if ((es->style & ES_MULTILINE) && (key == VK_DOWN)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3249 | EDIT_MoveDown_ML(es, shift); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3250 | else if (control) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3251 | EDIT_MoveWordForward(es, shift); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3252 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3253 | EDIT_MoveForward(es, shift); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3254 | break; |
| 3255 | case VK_HOME: |
Lei Zhang | dfdd929 | 2008-04-14 17:16:36 -0700 | [diff] [blame] | 3256 | EDIT_MoveHome(es, shift, control); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3257 | break; |
| 3258 | case VK_END: |
Lei Zhang | 483116a | 2008-04-14 17:18:40 -0700 | [diff] [blame] | 3259 | EDIT_MoveEnd(es, shift, control); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3260 | break; |
| 3261 | case VK_PRIOR: |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3262 | if (es->style & ES_MULTILINE) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3263 | EDIT_MovePageUp_ML(es, shift); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3264 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3265 | EDIT_CheckCombo(es, WM_KEYDOWN, key); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3266 | break; |
| 3267 | case VK_NEXT: |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3268 | if (es->style & ES_MULTILINE) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3269 | EDIT_MovePageDown_ML(es, shift); |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3270 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3271 | EDIT_CheckCombo(es, WM_KEYDOWN, key); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3272 | break; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3273 | case VK_DELETE: |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 3274 | if (!(es->style & ES_READONLY) && !(shift && control)) { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3275 | if (es->selection_start != es->selection_end) { |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3276 | if (shift) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3277 | EDIT_WM_Cut(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3278 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3279 | EDIT_WM_Clear(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3280 | } else { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3281 | if (shift) { |
| 3282 | /* delete character left of caret */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3283 | EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE); |
| 3284 | EDIT_MoveBackward(es, TRUE); |
| 3285 | EDIT_WM_Clear(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3286 | } else if (control) { |
| 3287 | /* delete to end of line */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3288 | EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE); |
Lei Zhang | 483116a | 2008-04-14 17:18:40 -0700 | [diff] [blame] | 3289 | EDIT_MoveEnd(es, TRUE, FALSE); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3290 | EDIT_WM_Clear(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3291 | } else { |
| 3292 | /* delete character right of caret */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3293 | EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE); |
| 3294 | EDIT_MoveForward(es, TRUE); |
| 3295 | EDIT_WM_Clear(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3296 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3297 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 3298 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3299 | break; |
| 3300 | case VK_INSERT: |
| 3301 | if (shift) { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3302 | if (!(es->style & ES_READONLY)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3303 | EDIT_WM_Paste(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3304 | } else if (control) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3305 | EDIT_WM_Copy(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3306 | break; |
Pascal Lessard | aed79e5 | 1999-09-10 13:58:34 +0000 | [diff] [blame] | 3307 | case VK_RETURN: |
| 3308 | /* If the edit doesn't want the return send a message to the default object */ |
Lei Zhang | 7f10fe0 | 2008-04-07 14:13:04 -0700 | [diff] [blame] | 3309 | if(!(es->style & ES_MULTILINE) || !(es->style & ES_WANTRETURN)) |
Pascal Lessard | aed79e5 | 1999-09-10 13:58:34 +0000 | [diff] [blame] | 3310 | { |
Sergey Khodych | 205a7f7 | 2009-08-25 18:01:05 +0300 | [diff] [blame] | 3311 | DWORD dw; |
Lei Zhang | 2f0b111 | 2008-04-23 17:58:30 -0700 | [diff] [blame] | 3312 | |
Sergey Khodych | 205a7f7 | 2009-08-25 18:01:05 +0300 | [diff] [blame] | 3313 | if (!EDIT_IsInsideDialog(es)) break; |
Lei Zhang | ae1b735 | 2008-04-24 22:17:38 -0700 | [diff] [blame] | 3314 | if (control) break; |
Sergey Khodych | 205a7f7 | 2009-08-25 18:01:05 +0300 | [diff] [blame] | 3315 | 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 Stefaniuc | 6f3b494 | 2009-12-27 14:40:45 +0100 | [diff] [blame] | 3321 | SendMessageW(es->hwndParent, WM_NEXTDLGCTL, (WPARAM)hwDefCtrl, TRUE); |
Sergey Khodych | 205a7f7 | 2009-08-25 18:01:05 +0300 | [diff] [blame] | 3322 | PostMessageW(hwDefCtrl, WM_KEYDOWN, VK_RETURN, 0); |
| 3323 | } |
| 3324 | } |
Pascal Lessard | aed79e5 | 1999-09-10 13:58:34 +0000 | [diff] [blame] | 3325 | } |
| 3326 | break; |
Lei Zhang | 6736ed8 | 2008-04-07 14:18:34 -0700 | [diff] [blame] | 3327 | case VK_ESCAPE: |
Michael Stefaniuc | 3a7a0eb | 2009-08-27 00:30:56 +0200 | [diff] [blame] | 3328 | if ((es->style & ES_MULTILINE) && EDIT_IsInsideDialog(es)) |
Sergey Khodych | 3b6ea11 | 2009-08-24 00:33:20 +0300 | [diff] [blame] | 3329 | PostMessageW(es->hwndParent, WM_CLOSE, 0, 0); |
Lei Zhang | 6736ed8 | 2008-04-07 14:18:34 -0700 | [diff] [blame] | 3330 | break; |
Lei Zhang | 95f323e | 2008-04-09 19:10:38 -0700 | [diff] [blame] | 3331 | case VK_TAB: |
Sergey Khodych | d4707db | 2009-08-24 01:47:15 +0300 | [diff] [blame] | 3332 | if ((es->style & ES_MULTILINE) && EDIT_IsInsideDialog(es)) |
| 3333 | SendMessageW(es->hwndParent, WM_NEXTDLGCTL, shift, 0); |
Lei Zhang | 95f323e | 2008-04-09 19:10:38 -0700 | [diff] [blame] | 3334 | break; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3335 | } |
Sergey Khodych | 3b6ea11 | 2009-08-24 00:33:20 +0300 | [diff] [blame] | 3336 | return TRUE; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3337 | } |
| 3338 | |
| 3339 | |
| 3340 | /********************************************************************* |
| 3341 | * |
| 3342 | * WM_KILLFOCUS |
| 3343 | * |
| 3344 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3345 | static LRESULT EDIT_WM_KillFocus(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3346 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3347 | es->flags &= ~EF_FOCUSED; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3348 | DestroyCaret(); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3349 | if(!(es->style & ES_NOHIDESEL)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3350 | EDIT_InvalidateText(es, es->selection_start, es->selection_end); |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 3351 | EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 3352 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3353 | } |
| 3354 | |
| 3355 | |
| 3356 | /********************************************************************* |
| 3357 | * |
| 3358 | * WM_LBUTTONDBLCLK |
| 3359 | * |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 3360 | * The caret position has been set on the WM_LBUTTONDOWN message |
| 3361 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3362 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3363 | static LRESULT EDIT_WM_LButtonDblClk(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3364 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3365 | INT s; |
| 3366 | INT e = es->selection_end; |
| 3367 | INT l; |
| 3368 | INT li; |
| 3369 | INT ll; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3370 | |
Dmitry Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 3371 | es->bCaptureState = TRUE; |
| 3372 | SetCapture(es->hwndSelf); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3373 | |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 3374 | l = EDIT_EM_LineFromChar(es, e); |
| 3375 | li = EDIT_EM_LineIndex(es, l); |
| 3376 | ll = EDIT_EM_LineLength(es, e); |
Dmitry Timoshkov | 8058ead | 2000-12-21 20:19:21 +0000 | [diff] [blame] | 3377 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3379 | EDIT_EM_SetSel(es, s, e, FALSE); |
| 3380 | EDIT_EM_ScrollCaret(es); |
Dmitry Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 3381 | es->region_posx = es->region_posy = 0; |
| 3382 | SetTimer(es->hwndSelf, 0, 100, NULL); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 3383 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3384 | } |
| 3385 | |
| 3386 | |
| 3387 | /********************************************************************* |
| 3388 | * |
| 3389 | * WM_LBUTTONDOWN |
| 3390 | * |
| 3391 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3392 | static LRESULT EDIT_WM_LButtonDown(EDITSTATE *es, DWORD keys, INT x, INT y) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3393 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3394 | INT e; |
| 3395 | BOOL after_wrap; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3396 | |
Abey George | 6e013e5 | 1999-07-27 17:08:26 +0000 | [diff] [blame] | 3397 | es->bCaptureState = TRUE; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3398 | SetCapture(es->hwndSelf); |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 3399 | EDIT_ConfinePoint(es, &x, &y); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3400 | 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 Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 3403 | es->region_posx = es->region_posy = 0; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3404 | SetTimer(es->hwndSelf, 0, 100, NULL); |
Dmitry Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 3405 | |
| 3406 | if (!(es->flags & EF_FOCUSED)) |
| 3407 | SetFocus(es->hwndSelf); |
| 3408 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 3409 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3410 | } |
| 3411 | |
| 3412 | |
| 3413 | /********************************************************************* |
| 3414 | * |
| 3415 | * WM_LBUTTONUP |
| 3416 | * |
| 3417 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3418 | static LRESULT EDIT_WM_LButtonUp(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3419 | { |
Alexandre Julliard | 6356a44 | 2003-02-19 22:04:03 +0000 | [diff] [blame] | 3420 | if (es->bCaptureState) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3421 | KillTimer(es->hwndSelf, 0); |
Alexandre Julliard | 6356a44 | 2003-02-19 22:04:03 +0000 | [diff] [blame] | 3422 | if (GetCapture() == es->hwndSelf) ReleaseCapture(); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3423 | } |
Abey George | 6e013e5 | 1999-07-27 17:08:26 +0000 | [diff] [blame] | 3424 | es->bCaptureState = FALSE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 3425 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3426 | } |
| 3427 | |
| 3428 | |
| 3429 | /********************************************************************* |
| 3430 | * |
Alexandre Julliard | c616625 | 2000-05-25 23:01:39 +0000 | [diff] [blame] | 3431 | * WM_MBUTTONDOWN |
| 3432 | * |
| 3433 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3434 | static LRESULT EDIT_WM_MButtonDown(EDITSTATE *es) |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3435 | { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3436 | SendMessageW(es->hwndSelf, WM_PASTE, 0, 0); |
Alexandre Julliard | c616625 | 2000-05-25 23:01:39 +0000 | [diff] [blame] | 3437 | return 0; |
| 3438 | } |
| 3439 | |
| 3440 | |
| 3441 | /********************************************************************* |
| 3442 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3443 | * WM_MOUSEMOVE |
| 3444 | * |
| 3445 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3446 | static LRESULT EDIT_WM_MouseMove(EDITSTATE *es, INT x, INT y) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3447 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3448 | INT e; |
| 3449 | BOOL after_wrap; |
| 3450 | INT prex, prey; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3451 | |
Kouji Sasaki | 108390a | 2005-05-30 11:09:33 +0000 | [diff] [blame] | 3452 | /* 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3456 | return 0; |
| 3457 | |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3458 | /* |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3459 | * FIXME: gotta do some scrolling if outside client |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3460 | * area. Maybe reset the timer ? |
| 3461 | */ |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3462 | prex = x; prey = y; |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 3463 | EDIT_ConfinePoint(es, &x, &y); |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3464 | es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0); |
| 3465 | es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3466 | 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 Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 3469 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3470 | } |
| 3471 | |
| 3472 | |
| 3473 | /********************************************************************* |
| 3474 | * |
| 3475 | * WM_PAINT |
| 3476 | * |
| 3477 | */ |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3478 | static void EDIT_WM_Paint(EDITSTATE *es, HDC hdc) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3479 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3480 | PAINTSTRUCT ps; |
| 3481 | INT i; |
| 3482 | HDC dc; |
| 3483 | HFONT old_font = 0; |
| 3484 | RECT rc; |
Robert Shearman | 8570328 | 2004-08-17 22:09:16 +0000 | [diff] [blame] | 3485 | RECT rcClient; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3486 | RECT rcLine; |
| 3487 | RECT rcRgn; |
Robert Shearman | 8570328 | 2004-08-17 22:09:16 +0000 | [diff] [blame] | 3488 | HBRUSH brush; |
Michael Kaufmann | 07763aa | 2005-06-24 11:33:23 +0000 | [diff] [blame] | 3489 | HBRUSH old_brush; |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3490 | INT bw, bh; |
Stephane Lussier | 9380534 | 1999-09-03 16:37:00 +0000 | [diff] [blame] | 3491 | BOOL rev = es->bEnableState && |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3492 | ((es->flags & EF_FOCUSED) || |
| 3493 | (es->style & ES_NOHIDESEL)); |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3494 | dc = hdc ? hdc : BeginPaint(es->hwndSelf, &ps); |
Robert Shearman | 8570328 | 2004-08-17 22:09:16 +0000 | [diff] [blame] | 3495 | |
| 3496 | GetClientRect(es->hwndSelf, &rcClient); |
| 3497 | |
Michael Kaufmann | 07763aa | 2005-06-24 11:33:23 +0000 | [diff] [blame] | 3498 | /* get the background brush */ |
Dmitry Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 3499 | brush = EDIT_NotifyCtlColor(es, dc); |
Robert Shearman | 8570328 | 2004-08-17 22:09:16 +0000 | [diff] [blame] | 3500 | |
Michael Kaufmann | 07763aa | 2005-06-24 11:33:23 +0000 | [diff] [blame] | 3501 | /* paint the border and the background */ |
| 3502 | IntersectClipRect(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3503 | |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 3504 | if(es->style & WS_BORDER) { |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3505 | bw = GetSystemMetrics(SM_CXBORDER); |
| 3506 | bh = GetSystemMetrics(SM_CYBORDER); |
Robert Shearman | 8570328 | 2004-08-17 22:09:16 +0000 | [diff] [blame] | 3507 | rc = rcClient; |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 3508 | if(es->style & ES_MULTILINE) { |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3509 | if(es->style & WS_HSCROLL) rc.bottom+=bh; |
| 3510 | if(es->style & WS_VSCROLL) rc.right+=bw; |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 3511 | } |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3512 | |
| 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 Kaufmann | 07763aa | 2005-06-24 11:33:23 +0000 | [diff] [blame] | 3519 | SelectObject(dc, old_brush); |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3520 | |
| 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 Kaufmann | 07763aa | 2005-06-24 11:33:23 +0000 | [diff] [blame] | 3524 | } |
Michael Kaufmann | e1d7ff9 | 2005-09-06 11:40:01 +0000 | [diff] [blame] | 3525 | |
| 3526 | GetClipBox(dc, &rc); |
| 3527 | FillRect(dc, &rc, brush); |
| 3528 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3529 | IntersectClipRect(dc, es->format_rect.left, |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3530 | es->format_rect.top, |
| 3531 | es->format_rect.right, |
| 3532 | es->format_rect.bottom); |
| 3533 | if (es->style & ES_MULTILINE) { |
Robert Shearman | 8570328 | 2004-08-17 22:09:16 +0000 | [diff] [blame] | 3534 | rc = rcClient; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3535 | IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3536 | } |
| 3537 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3538 | old_font = SelectObject(dc, es->font); |
Stephane Lussier | 9380534 | 1999-09-03 16:37:00 +0000 | [diff] [blame] | 3539 | |
| 3540 | if (!es->bEnableState) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3541 | SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT)); |
| 3542 | GetClipBox(dc, &rcRgn); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3543 | if (es->style & ES_MULTILINE) { |
Aric Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 3544 | INT vlc = get_vertical_line_count(es); |
Francois Gouget | 6d77d3a | 2000-03-25 21:44:35 +0000 | [diff] [blame] | 3545 | for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3546 | EDIT_GetLineRect(es, i, 0, -1, &rcLine); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3547 | if (IntersectRect(&rc, &rcRgn, &rcLine)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3548 | EDIT_PaintLine(es, dc, i, rev); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3549 | } |
| 3550 | } else { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3551 | EDIT_GetLineRect(es, 0, 0, -1, &rcLine); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3552 | if (IntersectRect(&rc, &rcRgn, &rcLine)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3553 | EDIT_PaintLine(es, dc, 0, rev); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3554 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3555 | if (es->font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3556 | SelectObject(dc, old_font); |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 3557 | |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3558 | if (!hdc) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3559 | EndPaint(es->hwndSelf, &ps); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3560 | } |
| 3561 | |
| 3562 | |
| 3563 | /********************************************************************* |
| 3564 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3565 | * WM_SETFOCUS |
| 3566 | * |
| 3567 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3568 | static void EDIT_WM_SetFocus(EDITSTATE *es) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3569 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3570 | es->flags |= EF_FOCUSED; |
Dmitry Timoshkov | 2ca23be | 2005-11-16 11:22:54 +0000 | [diff] [blame] | 3571 | |
| 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 Sivov | 258d953 | 2009-03-04 18:03:55 -0500 | [diff] [blame] | 3583 | CreateCaret(es->hwndSelf, 0, 1, es->line_height); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3584 | EDIT_SetCaretPos(es, es->selection_end, |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 3585 | es->flags & EF_AFTER_WRAP); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3586 | ShowCaret(es->hwndSelf); |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 3587 | EDIT_NOTIFY_PARENT(es, EN_SETFOCUS); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3588 | } |
| 3589 | |
| 3590 | |
| 3591 | /********************************************************************* |
| 3592 | * |
| 3593 | * WM_SETFONT |
| 3594 | * |
Vincent BĂ©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3595 | * With Win95 look the margins are set to default font value unless |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 3596 | * the system font (font == 0) is being set, in which case they are left |
| 3597 | * unchanged. |
| 3598 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3599 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3600 | static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3601 | { |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3602 | TEXTMETRICW tm; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3603 | HDC dc; |
| 3604 | HFONT old_font = 0; |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 3605 | RECT clientRect; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3606 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3607 | es->font = font; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3608 | dc = GetDC(es->hwndSelf); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3609 | if (font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3610 | old_font = SelectObject(dc, font); |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3611 | GetTextMetricsW(dc, &tm); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3612 | es->line_height = tm.tmHeight; |
| 3613 | es->char_width = tm.tmAveCharWidth; |
| 3614 | if (font) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3615 | SelectObject(dc, old_font); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3616 | ReleaseDC(es->hwndSelf, dc); |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 3617 | |
| 3618 | /* Reset the format rect and the margins */ |
| 3619 | GetClientRect(es->hwndSelf, &clientRect); |
| 3620 | EDIT_SetRectNP(es, &clientRect); |
Dimitrie O. Paun | 126227a | 2004-04-01 04:57:12 +0000 | [diff] [blame] | 3621 | EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN, |
Michael Kaufmann | 41a9757 | 2005-06-25 18:32:07 +0000 | [diff] [blame] | 3622 | EC_USEFONTINFO, EC_USEFONTINFO, FALSE); |
Pascal Lessard | 3405f5c | 1999-09-04 10:59:07 +0000 | [diff] [blame] | 3623 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3624 | if (es->style & ES_MULTILINE) |
Huw Davies | a0dbcb2 | 2007-04-19 14:52:51 +0100 | [diff] [blame] | 3625 | EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL); |
Dmitry Timoshkov | 11dbda6 | 2001-01-05 03:40:35 +0000 | [diff] [blame] | 3626 | else |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3627 | EDIT_CalcLineWidth_SL(es); |
Pascal Lessard | 3405f5c | 1999-09-04 10:59:07 +0000 | [diff] [blame] | 3628 | |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3629 | if (redraw) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3630 | EDIT_UpdateText(es, NULL, TRUE); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3631 | if (es->flags & EF_FOCUSED) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3632 | DestroyCaret(); |
Nikolay Sivov | 258d953 | 2009-03-04 18:03:55 -0500 | [diff] [blame] | 3633 | CreateCaret(es->hwndSelf, 0, 1, es->line_height); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3634 | EDIT_SetCaretPos(es, es->selection_end, |
Alexandre Julliard | ebfc0fe | 1998-06-28 18:40:26 +0000 | [diff] [blame] | 3635 | es->flags & EF_AFTER_WRAP); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3636 | ShowCaret(es->hwndSelf); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3637 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3638 | } |
| 3639 | |
| 3640 | |
| 3641 | /********************************************************************* |
| 3642 | * |
| 3643 | * WM_SETTEXT |
| 3644 | * |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 3645 | * 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3652 | */ |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3653 | static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text, BOOL unicode) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3654 | { |
Andrew Talbot | bc95bfd | 2006-11-18 14:22:13 +0000 | [diff] [blame] | 3655 | LPWSTR textW = NULL; |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3656 | if (!unicode && text) |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3657 | { |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3658 | LPCSTR textA = (LPCSTR)text; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3659 | INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0); |
Andrew Talbot | bc95bfd | 2006-11-18 14:22:13 +0000 | [diff] [blame] | 3660 | textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)); |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3661 | if (textW) |
| 3662 | MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW); |
| 3663 | text = textW; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3664 | } |
| 3665 | |
C. Scott Ananian | aa63674 | 2005-03-22 16:40:36 +0000 | [diff] [blame] | 3666 | 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. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3671 | 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 Talbot | bc95bfd | 2006-11-18 14:22:13 +0000 | [diff] [blame] | 3677 | HeapFree(GetProcessHeap(), 0, textW); |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3678 | } |
| 3679 | else |
| 3680 | { |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3681 | 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 Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 3694 | EDIT_NOTIFY_PARENT(es, EN_UPDATE); |
| 3695 | EDIT_NOTIFY_PARENT(es, EN_CHANGE); |
Dimitrie O. Paun | 438ac9d | 2004-10-25 21:49:30 +0000 | [diff] [blame] | 3696 | } |
| 3697 | EDIT_EM_ScrollCaret(es); |
Lauri Tulmin | caa43fe | 2005-02-14 11:51:52 +0000 | [diff] [blame] | 3698 | EDIT_UpdateScrollInfo(es); |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3699 | } |
| 3700 | |
| 3701 | |
| 3702 | /********************************************************************* |
| 3703 | * |
| 3704 | * WM_SIZE |
| 3705 | * |
| 3706 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3707 | static void EDIT_WM_Size(EDITSTATE *es, UINT action, INT width, INT height) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3708 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3709 | if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3710 | RECT rc; |
Dmitry Timoshkov | 4e62b9d | 2000-12-19 19:36:49 +0000 | [diff] [blame] | 3711 | TRACE("width = %d, height = %d\n", width, height); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3712 | SetRect(&rc, 0, 0, width, height); |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3713 | EDIT_SetRectNP(es, &rc); |
| 3714 | EDIT_UpdateText(es, NULL, TRUE); |
Alexandre Julliard | cdcdede | 1996-04-21 14:57:41 +0000 | [diff] [blame] | 3715 | } |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3716 | } |
| 3717 | |
| 3718 | |
| 3719 | /********************************************************************* |
| 3720 | * |
Bill Medland | 86bfa4c | 2001-06-28 18:01:00 +0000 | [diff] [blame] | 3721 | * 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3732 | * style variable which will generally be different. In this function we |
Bill Medland | 86bfa4c | 2001-06-28 18:01:00 +0000 | [diff] [blame] | 3733 | * 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3741 | static LRESULT EDIT_WM_StyleChanged ( EDITSTATE *es, WPARAM which, const STYLESTRUCT *style) |
Bill Medland | 86bfa4c | 2001-06-28 18:01:00 +0000 | [diff] [blame] | 3742 | { |
| 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3751 | if (es->style & ES_MULTILINE) |
Bill Medland | 86bfa4c | 2001-06-28 18:01:00 +0000 | [diff] [blame] | 3752 | 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Ă©ron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 3765 | |
Bill Medland | 86bfa4c | 2001-06-28 18:01:00 +0000 | [diff] [blame] | 3766 | es->style = (es->style & ~style_change_mask) | new_style; |
| 3767 | } else if (GWL_EXSTYLE == which) { |
| 3768 | ; /* FIXME - what is needed here */ |
| 3769 | } else { |
Dmitry Timoshkov | 3c9e7a7 | 2007-05-24 23:41:17 +0900 | [diff] [blame] | 3770 | WARN ("Invalid style change %ld\n",which); |
Bill Medland | 86bfa4c | 2001-06-28 18:01:00 +0000 | [diff] [blame] | 3771 | } |
| 3772 | |
| 3773 | return 0; |
| 3774 | } |
| 3775 | |
| 3776 | /********************************************************************* |
| 3777 | * |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3778 | * WM_SYSKEYDOWN |
| 3779 | * |
| 3780 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3781 | static LRESULT EDIT_WM_SysKeyDown(EDITSTATE *es, INT key, DWORD key_data) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3782 | { |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3783 | if ((key == VK_BACK) && (key_data & 0x2000)) { |
Dmitry Timoshkov | 7a947b3 | 2000-11-27 01:34:25 +0000 | [diff] [blame] | 3784 | if (EDIT_EM_CanUndo(es)) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3785 | EDIT_EM_Undo(es); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3786 | return 0; |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3787 | } else if (key == VK_UP || key == VK_DOWN) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3788 | if (EDIT_CheckCombo(es, WM_SYSKEYDOWN, key)) |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3789 | return 0; |
Serge Ivanov | 9eedcf5 | 2000-06-07 03:47:34 +0000 | [diff] [blame] | 3790 | } |
Michael Stefaniuc | 6f3b494 | 2009-12-27 14:40:45 +0100 | [diff] [blame] | 3791 | return DefWindowProcW(es->hwndSelf, WM_SYSKEYDOWN, key, key_data); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3792 | } |
| 3793 | |
| 3794 | |
| 3795 | /********************************************************************* |
| 3796 | * |
| 3797 | * WM_TIMER |
| 3798 | * |
| 3799 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3800 | static void EDIT_WM_Timer(EDITSTATE *es) |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3801 | { |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3802 | if (es->region_posx < 0) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3803 | EDIT_MoveBackward(es, TRUE); |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3804 | } else if (es->region_posx > 0) { |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3805 | EDIT_MoveForward(es, TRUE); |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3806 | } |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3807 | /* |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 3808 | * FIXME: gotta do some vertical scrolling here, like |
Alexandre Julliard | de42428 | 2001-08-10 22:51:42 +0000 | [diff] [blame] | 3809 | * EDIT_EM_LineScroll(hwnd, 0, 1); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3810 | */ |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3811 | } |
| 3812 | |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 3813 | /********************************************************************* |
| 3814 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 3815 | * WM_HSCROLL |
| 3816 | * |
| 3817 | */ |
| 3818 | static 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 3909 | { |
| 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 Julliard | 6af1df8 | 2009-12-15 13:22:45 +0100 | [diff] [blame] | 3922 | case EM_LINESCROLL: |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 3923 | 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 Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3947 | * WM_VSCROLL |
| 3948 | * |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3949 | */ |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3950 | static LRESULT EDIT_WM_VScroll(EDITSTATE *es, INT action, INT pos) |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3951 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 3952 | INT dy; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3953 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3954 | if (!(es->style & ES_MULTILINE)) |
| 3955 | return 0; |
| 3956 | |
| 3957 | if (!(es->style & ES_AUTOVSCROLL)) |
| 3958 | return 0; |
| 3959 | |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3960 | dy = 0; |
| 3961 | switch (action) { |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3962 | case SB_LINEUP: |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3963 | case SB_LINEDOWN: |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3964 | case SB_PAGEUP: |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 3965 | case SB_PAGEDOWN: |
Lionel Ulmer | 28d9aaf | 2004-03-29 22:54:05 +0000 | [diff] [blame] | 3966 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 3970 | EDIT_EM_Scroll(es, action); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3971 | return 0; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3972 | case SB_TOP: |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 3973 | TRACE("SB_TOP\n"); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3974 | dy = -es->y_offset; |
| 3975 | break; |
| 3976 | case SB_BOTTOM: |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 3977 | TRACE("SB_BOTTOM\n"); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3978 | dy = es->line_count - 1 - es->y_offset; |
| 3979 | break; |
| 3980 | case SB_THUMBTRACK: |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 3981 | TRACE("SB_THUMBTRACK %d\n", pos); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3982 | es->flags |= EF_VSCROLL_TRACK; |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 3983 | 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 Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 3991 | vlc = get_vertical_line_count(es); |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 3992 | 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 Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 3997 | break; |
| 3998 | case SB_THUMBPOSITION: |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 3999 | TRACE("SB_THUMBPOSITION %d\n", pos); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 4000 | es->flags &= ~EF_VSCROLL_TRACK; |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4001 | 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 Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 4009 | vlc = get_vertical_line_count(es); |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4010 | 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. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 4018 | EDIT_UpdateScrollInfo(es); |
Jacek Caban | 7371c3c | 2005-06-27 09:42:40 +0000 | [diff] [blame] | 4019 | EDIT_NOTIFY_PARENT(es, EN_VSCROLL); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 4020 | } |
| 4021 | break; |
| 4022 | case SB_ENDSCROLL: |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4023 | 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 Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4032 | { |
| 4033 | LRESULT ret; |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 4034 | if(GetWindowLongW( es->hwndSelf, GWL_STYLE ) & WS_VSCROLL) |
| 4035 | ret = GetScrollPos(es->hwndSelf, SB_VERT); |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4036 | else |
| 4037 | { |
| 4038 | /* Assume default scroll range 0-100 */ |
Aric Stewart | 7b9e827 | 2008-10-15 07:30:22 -0500 | [diff] [blame] | 4039 | INT vlc = get_vertical_line_count(es); |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4040 | 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 Julliard | 6af1df8 | 2009-12-15 13:22:45 +0100 | [diff] [blame] | 4045 | case EM_LINESCROLL: |
| 4046 | TRACE("EM_LINESCROLL %d\n", pos); |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4047 | dy = pos; |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 4048 | break; |
| 4049 | |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 4050 | default: |
Dmitry Timoshkov | a234db8 | 2001-01-19 20:49:54 +0000 | [diff] [blame] | 4051 | ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n", |
| 4052 | action, action); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 4053 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 4054 | } |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 4055 | if (dy) |
Dimitrie O. Paun | a4273ca | 2002-09-25 03:24:53 +0000 | [diff] [blame] | 4056 | EDIT_EM_LineScroll(es, 0, dy); |
Alexandre Julliard | 889f742 | 1997-04-15 17:19:52 +0000 | [diff] [blame] | 4057 | return 0; |
Alexandre Julliard | 329f068 | 1996-04-14 13:21:20 +0000 | [diff] [blame] | 4058 | } |
Ulrich Czekalla | 70d5a95 | 2000-05-26 01:17:34 +0000 | [diff] [blame] | 4059 | |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 4060 | /********************************************************************* |
| 4061 | * |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4062 | * 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 Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 4068 | * |
| 4069 | */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4070 | static LRESULT EDIT_EM_GetThumb(EDITSTATE *es) |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 4071 | { |
Alexandre Julliard | 6af1df8 | 2009-12-15 13:22:45 +0100 | [diff] [blame] | 4072 | return MAKELONG(EDIT_WM_VScroll(es, EM_GETTHUMB, 0), |
| 4073 | EDIT_WM_HScroll(es, EM_GETTHUMB, 0)); |
Ulrich Czekalla | f11ff2a | 2001-03-31 00:51:10 +0000 | [diff] [blame] | 4074 | } |
| 4075 | |
Ulrich Czekalla | 70d5a95 | 2000-05-26 01:17:34 +0000 | [diff] [blame] | 4076 | |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4077 | /******************************************************************** |
| 4078 | * |
| 4079 | * The Following code is to handle inline editing from IMEs |
| 4080 | */ |
| 4081 | |
Kusanagi Kouichi | d79dff4 | 2008-04-18 08:39:31 +0900 | [diff] [blame] | 4082 | static void EDIT_GetCompositionStr(HIMC hIMC, LPARAM CompFlag, EDITSTATE *es) |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4083 | { |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4084 | LONG buflen; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4085 | LPWSTR lpCompStr = NULL; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4086 | LPSTR lpCompStrAttr = NULL; |
| 4087 | DWORD dwBufLenAttr; |
| 4088 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4089 | buflen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4090 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4091 | if (buflen < 0) |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4092 | { |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4093 | return; |
| 4094 | } |
| 4095 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4096 | lpCompStr = HeapAlloc(GetProcessHeap(),0,buflen + sizeof(WCHAR)); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4097 | if (!lpCompStr) |
| 4098 | { |
| 4099 | ERR("Unable to allocate IME CompositionString\n"); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4100 | return; |
| 4101 | } |
| 4102 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4103 | if (buflen) |
| 4104 | ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, buflen); |
| 4105 | lpCompStr[buflen/sizeof(WCHAR)] = 0; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4106 | |
| 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 Stewart | 5537fbb | 2006-09-21 09:43:00 -0500 | [diff] [blame] | 4117 | lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr+1); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4118 | if (!lpCompStrAttr) |
| 4119 | { |
| 4120 | ERR("Unable to allocate IME Attribute String\n"); |
| 4121 | HeapFree(GetProcessHeap(),0,lpCompStr); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4122 | 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 Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4152 | } |
| 4153 | |
Kusanagi Kouichi | d79dff4 | 2008-04-18 08:39:31 +0900 | [diff] [blame] | 4154 | static void EDIT_GetResultStr(HIMC hIMC, EDITSTATE *es) |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4155 | { |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4156 | LONG buflen; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4157 | LPWSTR lpResultStr; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4158 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4159 | buflen = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0); |
| 4160 | if (buflen <= 0) |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4161 | { |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4162 | return; |
| 4163 | } |
| 4164 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4165 | lpResultStr = HeapAlloc(GetProcessHeap(),0, buflen+sizeof(WCHAR)); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4166 | if (!lpResultStr) |
| 4167 | { |
| 4168 | ERR("Unable to alloc buffer for IME string\n"); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4169 | return; |
| 4170 | } |
| 4171 | |
Marcus Meissner | f09f03a | 2008-02-17 15:58:06 +0100 | [diff] [blame] | 4172 | ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, buflen); |
| 4173 | lpResultStr[buflen/sizeof(WCHAR)] = 0; |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4174 | |
| 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 Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4186 | } |
| 4187 | |
| 4188 | static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es) |
| 4189 | { |
Kusanagi Kouichi | d79dff4 | 2008-04-18 08:39:31 +0900 | [diff] [blame] | 4190 | HIMC hIMC; |
| 4191 | int cursor; |
| 4192 | |
| 4193 | if (es->composition_len == 0 && es->selection_start != es->selection_end) |
| 4194 | { |
Kusanagi Kouichi | d79dff4 | 2008-04-18 08:39:31 +0900 | [diff] [blame] | 4195 | 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 Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4203 | if (CompFlag & GCS_RESULTSTR) |
Kusanagi Kouichi | d79dff4 | 2008-04-18 08:39:31 +0900 | [diff] [blame] | 4204 | EDIT_GetResultStr(hIMC, es); |
Aric Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4205 | if (CompFlag & GCS_COMPSTR) |
Kusanagi Kouichi | d79dff4 | 2008-04-18 08:39:31 +0900 | [diff] [blame] | 4206 | 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 Stewart | 314f45d | 2005-12-19 18:17:51 +0100 | [diff] [blame] | 4210 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4211 | |
| 4212 | |
| 4213 | /********************************************************************* |
| 4214 | * |
| 4215 | * WM_NCCREATE |
| 4216 | * |
| 4217 | * See also EDIT_WM_StyleChanged |
| 4218 | */ |
| 4219 | static 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 Sivov | e72ed1c | 2009-10-20 21:56:44 +0400 | [diff] [blame] | 4287 | goto cleanup; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4288 | 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 Sivov | e72ed1c | 2009-10-20 21:56:44 +0400 | [diff] [blame] | 4291 | goto cleanup; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4292 | 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 Sivov | e72ed1c | 2009-10-20 21:56:44 +0400 | [diff] [blame] | 4296 | goto cleanup; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4297 | 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 Sivov | e72ed1c | 2009-10-20 21:56:44 +0400 | [diff] [blame] | 4316 | |
| 4317 | cleanup: |
| 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4324 | } |
| 4325 | |
| 4326 | |
| 4327 | /********************************************************************* |
| 4328 | * |
| 4329 | * WM_CREATE |
| 4330 | * |
| 4331 | */ |
| 4332 | static 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 Shpigor | da9c523 | 2009-11-15 13:33:38 +0300 | [diff] [blame] | 4379 | * WM_NCDESTROY |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4380 | * |
| 4381 | */ |
Ilya Shpigor | da9c523 | 2009-11-15 13:33:38 +0300 | [diff] [blame] | 4382 | static LRESULT EDIT_WM_NCDestroy(EDITSTATE *es) |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4383 | { |
| 4384 | LINEDEF *pc, *pp; |
| 4385 | |
| 4386 | if (es->hloc32W) { |
| 4387 | LocalFree(es->hloc32W); |
| 4388 | } |
| 4389 | if (es->hloc32A) { |
| 4390 | LocalFree(es->hloc32A); |
| 4391 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4392 | pc = es->first_line_def; |
| 4393 | while (pc) |
| 4394 | { |
| 4395 | pp = pc->next; |
| 4396 | HeapFree(GetProcessHeap(), 0, pc); |
| 4397 | pc = pp; |
| 4398 | } |
| 4399 | |
Nikolay Sivov | a609660 | 2009-10-20 21:56:23 +0400 | [diff] [blame] | 4400 | SetWindowLongPtrW( es->hwndSelf, 0, 0 ); |
| 4401 | HeapFree(GetProcessHeap(), 0, es->undo_text); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4402 | HeapFree(GetProcessHeap(), 0, es); |
| 4403 | |
| 4404 | return 0; |
| 4405 | } |
| 4406 | |
| 4407 | |
| 4408 | static 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4422 | */ |
Alexandre Julliard | 57e5c8f | 2009-12-15 13:19:03 +0100 | [diff] [blame] | 4423 | LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode ) |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4424 | { |
| 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 Shpigor | da9c523 | 2009-11-15 13:33:38 +0300 | [diff] [blame] | 4433 | if (es && (msg != WM_NCDESTROY)) EDIT_LockBuffer(es); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4434 | |
| 4435 | switch (msg) { |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4436 | case EM_GETSEL: |
| 4437 | result = EDIT_EM_GetSel(es, (PUINT)wParam, (PUINT)lParam); |
| 4438 | break; |
| 4439 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4440 | case EM_SETSEL: |
| 4441 | EDIT_EM_SetSel(es, wParam, lParam, FALSE); |
| 4442 | EDIT_EM_ScrollCaret(es); |
| 4443 | result = 1; |
| 4444 | break; |
| 4445 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4446 | case EM_GETRECT: |
| 4447 | if (lParam) |
| 4448 | CopyRect((LPRECT)lParam, &es->format_rect); |
| 4449 | break; |
| 4450 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4451 | 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4458 | case EM_SETRECTNP: |
| 4459 | if ((es->style & ES_MULTILINE) && lParam) |
| 4460 | EDIT_SetRectNP(es, (LPRECT)lParam); |
| 4461 | break; |
| 4462 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4463 | case EM_SCROLL: |
| 4464 | result = EDIT_EM_Scroll(es, (INT)wParam); |
| 4465 | break; |
| 4466 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4467 | case EM_LINESCROLL: |
| 4468 | result = (LRESULT)EDIT_EM_LineScroll(es, (INT)wParam, (INT)lParam); |
| 4469 | break; |
| 4470 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4471 | case EM_SCROLLCARET: |
| 4472 | EDIT_EM_ScrollCaret(es); |
| 4473 | result = 1; |
| 4474 | break; |
| 4475 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4476 | case EM_GETMODIFY: |
| 4477 | result = ((es->flags & EF_MODIFIED) != 0); |
| 4478 | break; |
| 4479 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4480 | 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4487 | case EM_GETLINECOUNT: |
| 4488 | result = (es->style & ES_MULTILINE) ? es->line_count : 1; |
| 4489 | break; |
| 4490 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4491 | case EM_LINEINDEX: |
| 4492 | result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam); |
| 4493 | break; |
| 4494 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4495 | case EM_SETHANDLE: |
| 4496 | EDIT_EM_SetHandle(es, (HLOCAL)wParam); |
| 4497 | break; |
| 4498 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4499 | case EM_GETHANDLE: |
| 4500 | result = (LRESULT)EDIT_EM_GetHandle(es); |
| 4501 | break; |
| 4502 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4503 | case EM_GETTHUMB: |
| 4504 | result = EDIT_EM_GetThumb(es); |
| 4505 | break; |
| 4506 | |
| 4507 | /* these messages missing from specs */ |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4508 | case 0x00bf: |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4509 | case 0x00c0: |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4510 | case 0x00c3: |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4511 | case 0x00ca: |
| 4512 | FIXME("undocumented message 0x%x, please report\n", msg); |
| 4513 | result = DefWindowProcW(hwnd, msg, wParam, lParam); |
| 4514 | break; |
| 4515 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4516 | case EM_LINELENGTH: |
| 4517 | result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam); |
| 4518 | break; |
| 4519 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4520 | 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 Meissner | 69bf185 | 2010-01-06 16:52:46 +0100 | [diff] [blame] | 4530 | if (!(textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) break; |
| 4531 | MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4532 | } |
| 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4542 | case EM_GETLINE: |
| 4543 | result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, (LPWSTR)lParam, unicode); |
| 4544 | break; |
| 4545 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4546 | case EM_SETLIMITTEXT: |
| 4547 | EDIT_EM_SetLimitText(es, wParam); |
| 4548 | break; |
| 4549 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4550 | case EM_CANUNDO: |
| 4551 | result = (LRESULT)EDIT_EM_CanUndo(es); |
| 4552 | break; |
| 4553 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4554 | case EM_UNDO: |
| 4555 | case WM_UNDO: |
| 4556 | result = (LRESULT)EDIT_EM_Undo(es); |
| 4557 | break; |
| 4558 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4559 | case EM_FMTLINES: |
| 4560 | result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam); |
| 4561 | break; |
| 4562 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4563 | case EM_LINEFROMCHAR: |
| 4564 | result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam); |
| 4565 | break; |
| 4566 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4567 | case EM_SETTABSTOPS: |
| 4568 | result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam); |
| 4569 | break; |
| 4570 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4571 | 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4587 | case EM_EMPTYUNDOBUFFER: |
| 4588 | EDIT_EM_EmptyUndoBuffer(es); |
| 4589 | break; |
| 4590 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4591 | case EM_GETFIRSTVISIBLELINE: |
| 4592 | result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset; |
| 4593 | break; |
| 4594 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4595 | case EM_SETREADONLY: |
Nikolay Sivov | 0209b02 | 2009-09-19 22:32:04 +0400 | [diff] [blame] | 4596 | { |
| 4597 | DWORD old_style = es->style; |
| 4598 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4599 | 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 Sivov | 0209b02 | 2009-09-19 22:32:04 +0400 | [diff] [blame] | 4608 | |
| 4609 | if (old_style ^ es->style) |
| 4610 | InvalidateRect(es->hwndSelf, NULL, TRUE); |
| 4611 | |
| 4612 | result = 1; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4613 | break; |
Nikolay Sivov | 0209b02 | 2009-09-19 22:32:04 +0400 | [diff] [blame] | 4614 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4615 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4616 | case EM_SETWORDBREAKPROC: |
| 4617 | EDIT_EM_SetWordBreakProc(es, (void *)lParam); |
| 4618 | break; |
| 4619 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4620 | case EM_GETWORDBREAKPROC: |
| 4621 | result = (LRESULT)es->word_break_proc; |
| 4622 | break; |
| 4623 | |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4624 | 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4638 | 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 Shpigor | da9c523 | 2009-11-15 13:33:38 +0300 | [diff] [blame] | 4667 | case WM_NCDESTROY: |
| 4668 | result = EDIT_WM_NCDestroy(es); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4669 | 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 Khodych | 6fa48cd | 2009-08-24 00:10:01 +0300 | [diff] [blame] | 4678 | if (lParam) |
| 4679 | { |
| 4680 | es->flags|=EF_DIALOGMODE; |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4681 | |
Sergey Khodych | 6fa48cd | 2009-08-24 00:10:01 +0300 | [diff] [blame] | 4682 | 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 Khodych | 6fa48cd | 2009-08-24 00:10:01 +0300 | [diff] [blame] | 4692 | } |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4693 | } |
| 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 Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4934 | 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 Sivov | aa73717 | 2009-12-02 23:22:12 +0300 | [diff] [blame] | 4954 | if (IsWindow(hwnd) && es) EDIT_UnlockBuffer(es, FALSE); |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4955 | |
| 4956 | TRACE("hwnd=%p msg=%x (%s) -- 0x%08lx\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), result); |
| 4957 | |
| 4958 | return result; |
| 4959 | } |
| 4960 | |
Alexandre Julliard | 68656c0 | 2009-12-11 15:51:34 +0100 | [diff] [blame] | 4961 | |
| 4962 | /********************************************************************* |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4963 | * edit class descriptor |
| 4964 | */ |
| 4965 | static const WCHAR editW[] = {'E','d','i','t',0}; |
| 4966 | const struct builtin_class_descr EDIT_builtin_class = |
| 4967 | { |
| 4968 | editW, /* name */ |
| 4969 | CS_DBLCLKS | CS_PARENTDC, /* style */ |
Alexandre Julliard | d081a73 | 2009-12-18 12:39:13 +0100 | [diff] [blame] | 4970 | WINPROC_EDIT, /* proc */ |
Alexandre Julliard | 810e701 | 2009-12-11 18:13:03 +0100 | [diff] [blame] | 4971 | #ifdef __i386__ |
Alexandre Julliard | 8aa83d3 | 2009-12-23 20:01:37 +0100 | [diff] [blame] | 4972 | sizeof(EDITSTATE *) + sizeof(WORD), /* extra */ |
Julius Schwartzenberg | 8e899e0 | 2009-10-11 15:27:44 +0200 | [diff] [blame] | 4973 | #else |
Alexandre Julliard | 810e701 | 2009-12-11 18:13:03 +0100 | [diff] [blame] | 4974 | sizeof(EDITSTATE *), /* extra */ |
Julius Schwartzenberg | 8e899e0 | 2009-10-11 15:27:44 +0200 | [diff] [blame] | 4975 | #endif |
Francois Gouget | 9e7b556 | 2009-02-07 16:05:33 +0100 | [diff] [blame] | 4976 | IDC_IBEAM, /* cursor */ |
| 4977 | 0 /* brush */ |
| 4978 | }; |