Changeset 10195 for trunk/src/user32/edit.c
- Timestamp:
- Jul 31, 2003, 6:07:57 PM (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/user32/edit.c
r9760 r10195 1 1 /* 2 * 3 * 4 * 5 * 6 * 2 * Edit control 3 * 4 * Copyright David W. Metcalfe, 1994 5 * Copyright William Magro, 1995, 1996 6 * Copyright Frans van Dorsselaer, 1996, 1997 7 7 * 8 8 */ 9 9 10 10 /* 11 * 11 * please read EDIT.TODO (and update it when you change things) 12 12 */ 13 13 … … 30 30 #ifdef __WIN32OS2__ 31 31 #include "ctrlconf.h" 32 #include <heapstring.h> 32 33 #endif 33 34 … … 37 38 DECLARE_DEBUG_CHANNEL(relay); 38 39 39 #define BUFLIMIT_MULTI 0x7FFFFFF/* maximum buffer size (not including '\0')40 #define BUFLIMIT_SINGLE 0x7FFFFFF/* maximum buffer size (not including '\0') */40 #define BUFLIMIT_MULTI 0x7FFFFFF /* maximum buffer size (not including '\0') 41 #define BUFLIMIT_SINGLE 0x7FFFFFF /* maximum buffer size (not including '\0') */ 41 42 #else 42 #define BUFLIMIT_MULTI 65534/* maximum buffer size (not including '\0')43 44 #define BUFLIMIT_SINGLE 32766/* maximum buffer size (not including '\0') */43 #define BUFLIMIT_MULTI 65534 /* maximum buffer size (not including '\0') 44 FIXME: BTW, new specs say 65535 (do you dare ???) */ 45 #define BUFLIMIT_SINGLE 32766 /* maximum buffer size (not including '\0') */ 45 46 #endif 46 47 47 #define GROWLENGTH 32/* buffers granularity in bytes: must be power of 2 */48 #define ROUND_TO_GROW(size) 49 #define HSCROLL_FRACTION 3/* scroll window by 1/3 width */48 #define GROWLENGTH 32 /* buffers granularity in bytes: must be power of 2 */ 49 #define ROUND_TO_GROW(size) (((size) + (GROWLENGTH - 1)) & ~(GROWLENGTH - 1)) 50 #define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */ 50 51 51 52 /* 52 * 53 */ 54 #define EF_MODIFIED 0x0001/* text has been modified */55 #define EF_FOCUSED 0x0002/* we have input focus */56 #define EF_UPDATE 0x0004/* notify parent of changed state */57 #define EF_VSCROLL_TRACK 0x0008/* don't SetScrollPos() since we are tracking the thumb */58 #define EF_HSCROLL_TRACK 0x0010/* don't SetScrollPos() since we are tracking the thumb */59 #define EF_AFTER_WRAP 0x0080/* the caret is displayed after the last character of a60 61 #define EF_USE_SOFTBRK 0x0100/* Enable soft breaks in text. */53 * extra flags for EDITSTATE.flags field 54 */ 55 #define EF_MODIFIED 0x0001 /* text has been modified */ 56 #define EF_FOCUSED 0x0002 /* we have input focus */ 57 #define EF_UPDATE 0x0004 /* notify parent of changed state */ 58 #define EF_VSCROLL_TRACK 0x0008 /* don't SetScrollPos() since we are tracking the thumb */ 59 #define EF_HSCROLL_TRACK 0x0010 /* don't SetScrollPos() since we are tracking the thumb */ 60 #define EF_AFTER_WRAP 0x0080 /* the caret is displayed after the last character of a 61 wrapped line, instead of in front of the next character */ 62 #define EF_USE_SOFTBRK 0x0100 /* Enable soft breaks in text. */ 62 63 63 64 typedef enum 64 65 { 65 END_0 = 0,/* line ends with terminating '\0' character */66 END_WRAP,/* line is wrapped */67 END_HARD,/* line ends with a hard return '\r\n' */68 END_SOFT/* line ends with a soft return '\r\r\n' */66 END_0 = 0, /* line ends with terminating '\0' character */ 67 END_WRAP, /* line is wrapped */ 68 END_HARD, /* line ends with a hard return '\r\n' */ 69 END_SOFT /* line ends with a soft return '\r\r\n' */ 69 70 } LINE_END; 70 71 71 72 typedef struct tagLINEDEF { 72 INT length;/* bruto length of a line in bytes */73 INT net_length;/* netto length of a line in visible characters */74 75 INT width;/* width of the line in pixels */76 77 73 INT length; /* bruto length of a line in bytes */ 74 INT net_length; /* netto length of a line in visible characters */ 75 LINE_END ending; 76 INT width; /* width of the line in pixels */ 77 INT index; /* line index into the buffer */ 78 struct tagLINEDEF *next; 78 79 } LINEDEF; 79 80 80 81 typedef struct 81 82 { 82 BOOL is_unicode;/* how the control was created */83 LPWSTR text;/* the actual contents of the control */84 UINT buffer_size;/* the size of the buffer in characters */85 UINT buffer_limit;/* the maximum size to which the buffer may grow in characters */86 HFONT font;/* NULL means standard system font */87 INT x_offset; /* scroll offsetfor multi lines this is in pixels88 89 INT line_height;/* height of a screen line in pixels */90 INT char_width;/* average character width in pixels */91 DWORD style;/* sane version of wnd->dwStyle */92 WORD flags;/* flags that are not in es->style or wnd->flags (EF_XXX) */93 INT undo_insert_count;/* number of characters inserted in sequence */94 UINT undo_position;/* character index of the insertion and deletion */95 LPWSTR undo_text;/* deleted text */96 UINT undo_buffer_size;/* size of the deleted text buffer */97 INT selection_start;/* == selection_end if no selection */98 INT selection_end;/* == current caret position */99 WCHAR password_char;/* == 0 if no password char, and for multi line controls */100 INT left_margin;/* in pixels */101 INT right_margin;/* in pixels */102 103 INT text_width;/* width of the widest line in pixels for multi line controls104 and just line width for single line controls*/105 INT region_posx;/* Position of cursor relative to region: */106 INT region_posy;/* -1: to left, 0: within, 1: to right */107 108 void *word_break_proc;/* 32-bit word break proc: ANSI or Unicode */109 INT line_count;/* number of lines */110 INT y_offset;/* scroll offset in number of lines */111 112 113 114 115 116 117 118 *only for multi line controls119 120 INT lock_count;/* amount of re-entries in the EditWndProc */121 122 123 LINEDEF *first_line_def;/* linked list of (soft) linebreaks */124 HLOCAL hloc32W;/* our unicode local memory block */125 HLOCAL16 hloc16;/* alias for 16-bit control receiving EM_GETHANDLE16126 127 HLOCAL hloc32A;/* alias for ANSI control receiving EM_GETHANDLE128 83 BOOL is_unicode; /* how the control was created */ 84 LPWSTR text; /* the actual contents of the control */ 85 UINT buffer_size; /* the size of the buffer in characters */ 86 UINT buffer_limit; /* the maximum size to which the buffer may grow in characters */ 87 HFONT font; /* NULL means standard system font */ 88 INT x_offset; /* scroll offset for multi lines this is in pixels 89 for single lines it's in characters */ 90 INT line_height; /* height of a screen line in pixels */ 91 INT char_width; /* average character width in pixels */ 92 DWORD style; /* sane version of wnd->dwStyle */ 93 WORD flags; /* flags that are not in es->style or wnd->flags (EF_XXX) */ 94 INT undo_insert_count; /* number of characters inserted in sequence */ 95 UINT undo_position; /* character index of the insertion and deletion */ 96 LPWSTR undo_text; /* deleted text */ 97 UINT undo_buffer_size; /* size of the deleted text buffer */ 98 INT selection_start; /* == selection_end if no selection */ 99 INT selection_end; /* == current caret position */ 100 WCHAR password_char; /* == 0 if no password char, and for multi line controls */ 101 INT left_margin; /* in pixels */ 102 INT right_margin; /* in pixels */ 103 RECT format_rect; 104 INT text_width; /* width of the widest line in pixels for multi line controls 105 and just line width for single line controls */ 106 INT region_posx; /* Position of cursor relative to region: */ 107 INT region_posy; /* -1: to left, 0: within, 1: to right */ 108 EDITWORDBREAKPROC16 word_break_proc16; 109 void *word_break_proc; /* 32-bit word break proc: ANSI or Unicode */ 110 INT line_count; /* number of lines */ 111 INT y_offset; /* scroll offset in number of lines */ 112 BOOL bCaptureState; /* flag indicating whether mouse was captured */ 113 BOOL bEnableState; /* flag keeping the enable state */ 114 HWND hwndParent; /* Handle of parent for sending EN_* messages. 115 Even if parent will change, EN_* messages 116 should be sent to the first parent. */ 117 HWND hwndListBox; /* handle of ComboBox's listbox or NULL */ 118 /* 119 * only for multi line controls 120 */ 121 INT lock_count; /* amount of re-entries in the EditWndProc */ 122 INT tabs_count; 123 LPINT tabs; 124 LINEDEF *first_line_def; /* linked list of (soft) linebreaks */ 125 HLOCAL hloc32W; /* our unicode local memory block */ 126 HLOCAL16 hloc16; /* alias for 16-bit control receiving EM_GETHANDLE16 127 or EM_SETHANDLE16 */ 128 HLOCAL hloc32A; /* alias for ANSI control receiving EM_GETHANDLE 129 or EM_SETHANDLE */ 129 130 } EDITSTATE; 130 131 … … 137 138 138 139 #define DPRINTF_EDIT_NOTIFY(hwnd, str) \ 139 140 140 do {TRACE("notification " str " sent to hwnd=%08x\n", \ 141 (UINT)(hwnd));} while(0) 141 142 142 143 /* used for disabled or read-only edit control */ 143 144 #define EDIT_SEND_CTLCOLORSTATIC(hwnd,hdc) \ 144 145 145 (SendMessageW(GetParent(hwnd), WM_CTLCOLORSTATIC, \ 146 (WPARAM)(hdc), (LPARAM)(hwnd))) 146 147 #define EDIT_SEND_CTLCOLOR(hwnd,hdc) \ 147 148 148 (SendMessageW(GetParent(hwnd), WM_CTLCOLOREDIT, \ 149 (WPARAM)(hdc), (LPARAM)(hwnd))) 149 150 #define EDIT_NOTIFY_PARENT(hwnd, es, wNotifyCode, str) \ 150 151 152 153 154 155 156 151 do \ 152 { /* Notify parent which has created this edit control */ \ 153 DPRINTF_EDIT_NOTIFY((es)->hwndParent, str); \ 154 SendMessageW((es)->hwndParent, WM_COMMAND, \ 155 MAKEWPARAM(GetWindowLongA((hwnd),GWL_ID), wNotifyCode), \ 156 (LPARAM)(hwnd)); \ 157 } while(0) 157 158 #define DPRINTF_EDIT_MSG16(str) \ 158 159 160 159 TRACE(\ 160 "16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \ 161 hwnd, (UINT)wParam, (UINT)lParam) 161 162 #define DPRINTF_EDIT_MSG32(str) \ 162 163 164 165 166 167 /********************************************************************* 168 * 169 * 163 TRACE(\ 164 "32 bit %c : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \ 165 unicode ? 'W' : 'A', \ 166 hwnd, (UINT)wParam, (UINT)lParam) 167 168 /********************************************************************* 169 * 170 * Declarations 170 171 * 171 172 */ 172 173 173 174 /* 174 * 175 * 176 * 177 */ 178 static inline BOOL 179 static inline void 180 static inline void 181 static inline void 175 * These functions have trivial implementations 176 * We still like to call them internally 177 * "static inline" makes them more like macro's 178 */ 179 static inline BOOL EDIT_EM_CanUndo(EDITSTATE *es); 180 static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es); 181 static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es); 182 static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es); 182 183 183 184 /* 184 * 185 */ 186 static void 187 static void 188 static LPWSTR 189 static void 190 static void 191 static void 192 static void 185 * Helper functions only valid for one type of control 186 */ 187 static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es, INT iStart, INT iEnd, INT delta, HRGN hrgn); 188 static void EDIT_CalcLineWidth_SL(HWND hwnd, EDITSTATE *es); 189 static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es); 190 static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend); 191 static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend); 192 static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend); 193 static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend); 193 194 /* 194 * 195 */ 196 static INT 197 static INT 198 static void 199 static void 200 static void 201 static void 202 static BOOL 203 static BOOL 204 static void 205 static void 206 static void 207 static void 208 static void 209 static void 210 static void 211 static INT 212 static void 213 static void 214 static void 215 static void 195 * Helper functions valid for both single line _and_ multi line controls 196 */ 197 static INT EDIT_CallWordBreakProc(EDITSTATE *es, INT start, INT index, INT count, INT action); 198 static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap); 199 static void EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y); 200 static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc); 201 static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end); 202 static void EDIT_LockBuffer(HWND hwnd, EDITSTATE *es); 203 static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, UINT size); 204 static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size); 205 static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend); 206 static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend); 207 static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend); 208 static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend); 209 static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend); 210 static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend); 211 static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC hdc, INT line, BOOL rev); 212 static INT EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev); 213 static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos, BOOL after_wrap); 214 static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT lprc); 215 static void EDIT_UnlockBuffer(HWND hwnd, EDITSTATE *es, BOOL force); 216 static void EDIT_UpdateScrollInfo(HWND hwnd, EDITSTATE *es); 216 217 static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action); 217 218 /* 218 * 219 */ 220 static LRESULT 221 static BOOL 222 static HLOCAL 219 * EM_XXX message handlers 220 */ 221 static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y); 222 static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol); 223 static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es); 223 224 #ifndef __WIN32OS2__ 224 static HLOCAL16 225 static HLOCAL16 EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es); 225 226 #endif 226 static INT 227 static LRESULT 228 static LRESULT 229 static INT 230 static INT 231 static INT 232 static BOOL 233 static BOOL 234 static LRESULT 235 static void 236 static LRESULT 237 static void 238 static void 227 static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode); 228 static LRESULT EDIT_EM_GetSel(EDITSTATE *es, LPUINT start, LPUINT end); 229 static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es); 230 static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index); 231 static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line); 232 static INT EDIT_EM_LineLength(EDITSTATE *es, INT index); 233 static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy); 234 static BOOL EDIT_EM_LineScroll_internal(HWND hwnd, EDITSTATE *es, INT dx, INT dy); 235 static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap); 236 static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update); 237 static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action); 238 static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es); 239 static void EDIT_EM_SetHandle(HWND hwnd, EDITSTATE *es, HLOCAL hloc); 239 240 #ifndef __WIN32OS2__ 240 static void 241 static void EDIT_EM_SetHandle16(HWND hwnd, EDITSTATE *es, HLOCAL16 hloc); 241 242 #endif 242 static void 243 static void 244 static void 245 static void 246 static BOOL 247 static BOOL 248 static void 243 static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit); 244 static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right); 245 static void EDIT_EM_SetPasswordChar(HWND hwnd, EDITSTATE *es, WCHAR c); 246 static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap); 247 static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs); 248 static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs); 249 static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, LPARAM lParam); 249 250 #ifndef __WIN32OS2__ 250 static void 251 static void EDIT_EM_SetWordBreakProc16(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROC16 wbp); 251 252 #endif 252 static BOOL 253 static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es); 253 254 /* 254 * 255 */ 256 static void 257 static void 258 static void 259 static void 260 static LRESULT 261 static void 262 static LRESULT 263 static INT 264 static LRESULT 265 static LRESULT 266 static LRESULT 267 static LRESULT 268 static LRESULT 269 static LRESULT 270 static LRESULT 271 static LRESULT 272 static LRESULT 273 static void 274 static void 275 static void 276 static void 277 static void 278 static void 255 * WM_XXX message handlers 256 */ 257 static void EDIT_WM_Char(HWND hwnd, EDITSTATE *es, WCHAR c); 258 static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND conrtol); 259 static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, INT x, INT y); 260 static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es); 261 static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCWSTR name); 262 static void EDIT_WM_Destroy(HWND hwnd, EDITSTATE *es); 263 static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc); 264 static INT EDIT_WM_GetText(EDITSTATE *es, INT count, LPARAM lParam, BOOL unicode); 265 static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos); 266 static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key); 267 static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es); 268 static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es); 269 static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y); 270 static LRESULT EDIT_WM_LButtonUp(HWND hwndSelf, EDITSTATE *es); 271 static LRESULT EDIT_WM_MButtonDown(HWND hwnd); 272 static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, INT x, INT y); 273 static LRESULT EDIT_WM_NCCreate(HWND hwnd, DWORD style, HWND hwndParent, BOOL unicode); 274 static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es, WPARAM wParam); 275 static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es); 276 static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es); 277 static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw); 278 static void EDIT_WM_SetText(HWND hwnd, EDITSTATE *es, LPARAM lParam, BOOL unicode); 279 static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height); 279 280 static LRESULT EDIT_WM_StyleChanged (HWND hwnd, EDITSTATE *es, WPARAM which, const STYLESTRUCT *style); 280 static LRESULT 281 static void 282 static LRESULT 281 static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data); 282 static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es); 283 static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos); 283 284 static void EDIT_UpdateText(HWND hwnd, EDITSTATE *es, LPRECT rc, BOOL bErase); 284 285 static void EDIT_UpdateTextRegion(HWND hwnd, EDITSTATE *es, HRGN hrgn, BOOL bErase); … … 304 305 /********************************************************************* 305 306 * 306 * 307 * EM_CANUNDO 307 308 * 308 309 */ 309 310 static inline BOOL EDIT_EM_CanUndo(EDITSTATE *es) 310 311 { 311 312 } 313 314 315 /********************************************************************* 316 * 317 * 312 return (es->undo_insert_count || strlenW(es->undo_text)); 313 } 314 315 316 /********************************************************************* 317 * 318 * EM_EMPTYUNDOBUFFER 318 319 * 319 320 */ 320 321 static inline void EDIT_EM_EmptyUndoBuffer(EDITSTATE *es) 321 322 { 322 323 324 } 325 326 327 /********************************************************************* 328 * 329 * 323 es->undo_insert_count = 0; 324 *es->undo_text = '\0'; 325 } 326 327 328 /********************************************************************* 329 * 330 * WM_CLEAR 330 331 * 331 332 */ 332 333 static inline void EDIT_WM_Clear(HWND hwnd, EDITSTATE *es) 333 334 { 334 335 336 337 338 339 340 341 } 342 343 344 /********************************************************************* 345 * 346 * 335 static const WCHAR empty_stringW[] = {0}; 336 337 /* Protect read-only edit control from modification */ 338 if(es->style & ES_READONLY) 339 return; 340 341 EDIT_EM_ReplaceSel(hwnd, es, TRUE, empty_stringW, TRUE); 342 } 343 344 345 /********************************************************************* 346 * 347 * WM_CUT 347 348 * 348 349 */ 349 350 static inline void EDIT_WM_Cut(HWND hwnd, EDITSTATE *es) 350 351 { 351 352 352 EDIT_WM_Copy(hwnd, es); 353 EDIT_WM_Clear(hwnd, es); 353 354 } 354 355 … … 379 380 DWORD dwProcVersion = GetProcessVersion(0); 380 381 381 382 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); 382 383 GetVersionExW( &info ); 383 384 dwEmulatedVersion = MAKELONG( info.dwMinorVersion, info.dwMajorVersion ); … … 392 393 /********************************************************************* 393 394 * 394 * 395 * 396 * 397 * 398 * 399 * 400 * 401 * 402 * 395 * EditWndProc_common 396 * 397 * The messages are in the order of the actual integer values 398 * (which can be found in include/windows.h) 399 * Wherever possible the 16 bit versions are converted to 400 * the 32 bit ones, so that we can 'fall through' to the 401 * helper functions. These are mostly 32 bit (with a few 402 * exceptions, clearly indicated by a '16' extension to their 403 * names). 403 404 * 404 405 */ … … 406 407 WPARAM wParam, LPARAM lParam, BOOL unicode ) 407 408 { 408 409 410 411 412 413 414 409 EDITSTATE *es = (EDITSTATE *)GetWindowLongA( hwnd, 0 ); 410 LRESULT result = 0; 411 412 switch (msg) { 413 case WM_DESTROY: 414 DPRINTF_EDIT_MSG32("WM_DESTROY"); 415 if (es) EDIT_WM_Destroy(hwnd, es); 415 416 result = 0; 416 417 goto END; 417 418 418 419 420 421 422 423 424 425 426 427 428 429 419 case WM_NCCREATE: 420 DPRINTF_EDIT_MSG32("WM_NCCREATE"); 421 if(unicode) 422 { 423 LPCREATESTRUCTW cs = (LPCREATESTRUCTW)lParam; 424 result = EDIT_WM_NCCreate(hwnd, cs->style, cs->hwndParent, TRUE); 425 } 426 else 427 { 428 LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam; 429 result = EDIT_WM_NCCreate(hwnd, cs->style, cs->hwndParent, FALSE); 430 } 430 431 goto END; 431 432 433 432 } 433 434 if (!es) 434 435 { 435 436 437 438 436 if(unicode) 437 result = DefWindowProcW(hwnd, msg, wParam, lParam); 438 else 439 result = DefWindowProcA(hwnd, msg, wParam, lParam); 439 440 goto END; 440 441 } 441 442 442 443 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 444 EDIT_LockBuffer(hwnd, es); 445 switch (msg) { 446 case EM_GETSEL16: 447 DPRINTF_EDIT_MSG16("EM_GETSEL"); 448 wParam = 0; 449 lParam = 0; 450 /* fall through */ 451 case EM_GETSEL: 452 DPRINTF_EDIT_MSG32("EM_GETSEL"); 453 result = EDIT_EM_GetSel(es, (LPUINT)wParam, (LPUINT)lParam); 454 break; 455 456 case EM_SETSEL16: 457 DPRINTF_EDIT_MSG16("EM_SETSEL"); 458 if (SLOWORD(lParam) == -1) 459 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE); 460 else 461 EDIT_EM_SetSel(hwnd, es, LOWORD(lParam), HIWORD(lParam), FALSE); 462 if (!wParam) 463 EDIT_EM_ScrollCaret(hwnd, es); 464 result = 1; 465 break; 466 case EM_SETSEL: 467 DPRINTF_EDIT_MSG32("EM_SETSEL"); 468 EDIT_EM_SetSel(hwnd, es, wParam, lParam, FALSE); 469 EDIT_EM_ScrollCaret(hwnd, es); 470 result = 1; 471 break; 472 473 case EM_GETRECT16: 474 DPRINTF_EDIT_MSG16("EM_GETRECT"); 475 if (lParam) 476 CONV_RECT32TO16(&es->format_rect, MapSL(lParam)); 477 break; 478 case EM_GETRECT: 479 DPRINTF_EDIT_MSG32("EM_GETRECT"); 480 if (lParam) 481 CopyRect((LPRECT)lParam, &es->format_rect); 482 break; 483 484 case EM_SETRECT16: 485 DPRINTF_EDIT_MSG16("EM_SETRECT"); 486 if ((es->style & ES_MULTILINE) && lParam) { 487 RECT rc; 488 CONV_RECT16TO32(MapSL(lParam), &rc); 489 EDIT_SetRectNP(hwnd, es, &rc); 490 EDIT_UpdateText(hwnd, es, NULL, TRUE); 491 } 492 break; 493 case EM_SETRECT: 494 DPRINTF_EDIT_MSG32("EM_SETRECT"); 495 if ((es->style & ES_MULTILINE) && lParam) { 496 EDIT_SetRectNP(hwnd, es, (LPRECT)lParam); 497 EDIT_UpdateText(hwnd, es, NULL, TRUE); 498 } 499 break; 500 501 case EM_SETRECTNP16: 502 DPRINTF_EDIT_MSG16("EM_SETRECTNP"); 503 if ((es->style & ES_MULTILINE) && lParam) { 504 RECT rc; 505 CONV_RECT16TO32(MapSL(lParam), &rc); 506 EDIT_SetRectNP(hwnd, es, &rc); 507 } 508 break; 509 case EM_SETRECTNP: 510 DPRINTF_EDIT_MSG32("EM_SETRECTNP"); 511 if ((es->style & ES_MULTILINE) && lParam) 512 EDIT_SetRectNP(hwnd, es, (LPRECT)lParam); 513 break; 514 515 case EM_SCROLL16: 516 DPRINTF_EDIT_MSG16("EM_SCROLL"); 517 /* fall through */ 518 case EM_SCROLL: 519 DPRINTF_EDIT_MSG32("EM_SCROLL"); 520 result = EDIT_EM_Scroll(hwnd, es, (INT)wParam); 521 break; 522 523 case EM_LINESCROLL16: 524 DPRINTF_EDIT_MSG16("EM_LINESCROLL"); 525 wParam = (WPARAM)(INT)SHIWORD(lParam); 526 lParam = (LPARAM)(INT)SLOWORD(lParam); 527 /* fall through */ 528 case EM_LINESCROLL: 529 DPRINTF_EDIT_MSG32("EM_LINESCROLL"); 530 result = (LRESULT)EDIT_EM_LineScroll(hwnd, es, (INT)wParam, (INT)lParam); 531 break; 532 533 case EM_SCROLLCARET16: 534 DPRINTF_EDIT_MSG16("EM_SCROLLCARET"); 535 /* fall through */ 536 case EM_SCROLLCARET: 537 DPRINTF_EDIT_MSG32("EM_SCROLLCARET"); 538 EDIT_EM_ScrollCaret(hwnd, es); 539 result = 1; 540 break; 541 542 case EM_GETMODIFY16: 543 DPRINTF_EDIT_MSG16("EM_GETMODIFY"); 544 /* fall through */ 545 case EM_GETMODIFY: 546 DPRINTF_EDIT_MSG32("EM_GETMODIFY"); 547 result = ((es->flags & EF_MODIFIED) != 0); 548 break; 549 550 case EM_SETMODIFY16: 551 DPRINTF_EDIT_MSG16("EM_SETMODIFY"); 552 /* fall through */ 553 case EM_SETMODIFY: 554 DPRINTF_EDIT_MSG32("EM_SETMODIFY"); 555 if (wParam) 556 es->flags |= EF_MODIFIED; 557 else 557 558 es->flags &= ~(EF_MODIFIED | EF_UPDATE); /* reset pending updates */ 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 559 break; 560 561 case EM_GETLINECOUNT16: 562 DPRINTF_EDIT_MSG16("EM_GETLINECOUNT"); 563 /* fall through */ 564 case EM_GETLINECOUNT: 565 DPRINTF_EDIT_MSG32("EM_GETLINECOUNT"); 566 result = (es->style & ES_MULTILINE) ? es->line_count : 1; 567 break; 568 569 case EM_LINEINDEX16: 570 DPRINTF_EDIT_MSG16("EM_LINEINDEX"); 571 if ((INT16)wParam == -1) 572 wParam = (WPARAM)-1; 573 /* fall through */ 574 case EM_LINEINDEX: 575 DPRINTF_EDIT_MSG32("EM_LINEINDEX"); 576 result = (LRESULT)EDIT_EM_LineIndex(es, (INT)wParam); 577 break; 577 578 578 579 #ifndef __WIN32OS2__ 579 580 581 582 580 case EM_SETHANDLE16: 581 DPRINTF_EDIT_MSG16("EM_SETHANDLE"); 582 EDIT_EM_SetHandle16(hwnd, es, (HLOCAL16)wParam); 583 break; 583 584 #endif 584 585 586 587 585 case EM_SETHANDLE: 586 DPRINTF_EDIT_MSG32("EM_SETHANDLE"); 587 EDIT_EM_SetHandle(hwnd, es, (HLOCAL)wParam); 588 break; 588 589 589 590 #ifndef __WIN32OS2__ 590 591 592 593 591 case EM_GETHANDLE16: 592 DPRINTF_EDIT_MSG16("EM_GETHANDLE"); 593 result = (LRESULT)EDIT_EM_GetHandle16(hwnd, es); 594 break; 594 595 #endif 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 596 case EM_GETHANDLE: 597 DPRINTF_EDIT_MSG32("EM_GETHANDLE"); 598 result = (LRESULT)EDIT_EM_GetHandle(es); 599 break; 600 601 case EM_GETTHUMB16: 602 DPRINTF_EDIT_MSG16("EM_GETTHUMB"); 603 /* fall through */ 604 case EM_GETTHUMB: 605 DPRINTF_EDIT_MSG32("EM_GETTHUMB"); 606 result = EDIT_EM_GetThumb(hwnd, es); 607 break; 608 609 /* messages 0x00bf and 0x00c0 missing from specs */ 610 611 case WM_USER+15: 612 DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report"); 613 /* fall through */ 614 case 0x00bf: 615 DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report"); 616 result = DefWindowProcW(hwnd, msg, wParam, lParam); 617 break; 618 619 case WM_USER+16: 620 DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report"); 621 /* fall through */ 622 case 0x00c0: 623 DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report"); 624 result = DefWindowProcW(hwnd, msg, wParam, lParam); 625 break; 626 627 case EM_LINELENGTH16: 628 DPRINTF_EDIT_MSG16("EM_LINELENGTH"); 629 /* fall through */ 630 case EM_LINELENGTH: 631 DPRINTF_EDIT_MSG32("EM_LINELENGTH"); 632 result = (LRESULT)EDIT_EM_LineLength(es, (INT)wParam); 633 break; 634 635 case EM_REPLACESEL16: 636 DPRINTF_EDIT_MSG16("EM_REPLACESEL"); 637 lParam = (LPARAM)MapSL(lParam); 638 unicode = FALSE; /* 16-bit message is always ascii */ 639 /* fall through */ 640 case EM_REPLACESEL: 641 { 642 LPWSTR textW; 643 DPRINTF_EDIT_MSG32("EM_REPLACESEL"); 644 645 if(unicode) 646 textW = (LPWSTR)lParam; 647 else 648 { 649 LPSTR textA = (LPSTR)lParam; 650 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0); 651 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) 652 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW); 653 } 654 655 EDIT_EM_ReplaceSel(hwnd, es, (BOOL)wParam, textW, TRUE); 656 result = 1; 657 658 if(!unicode) 659 HeapFree(GetProcessHeap(), 0, textW); 660 break; 661 } 662 /* message 0x00c3 missing from specs */ 663 664 case WM_USER+19: 665 DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report"); 666 /* fall through */ 667 case 0x00c3: 668 DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report"); 669 result = DefWindowProcW(hwnd, msg, wParam, lParam); 670 break; 671 672 case EM_GETLINE16: 673 DPRINTF_EDIT_MSG16("EM_GETLINE"); 674 lParam = (LPARAM)MapSL(lParam); 675 unicode = FALSE; /* 16-bit message is always ascii */ 676 /* fall through */ 677 case EM_GETLINE: 678 DPRINTF_EDIT_MSG32("EM_GETLINE"); 679 result = (LRESULT)EDIT_EM_GetLine(es, (INT)wParam, lParam, unicode); 680 break; 681 682 case EM_LIMITTEXT16: 683 DPRINTF_EDIT_MSG16("EM_LIMITTEXT"); 684 /* fall through */ 685 case EM_SETLIMITTEXT: 686 DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT"); 687 EDIT_EM_SetLimitText(es, (INT)wParam); 688 break; 689 690 case EM_CANUNDO16: 691 DPRINTF_EDIT_MSG16("EM_CANUNDO"); 692 /* fall through */ 693 case EM_CANUNDO: 694 DPRINTF_EDIT_MSG32("EM_CANUNDO"); 695 result = (LRESULT)EDIT_EM_CanUndo(es); 696 break; 697 698 case EM_UNDO16: 699 DPRINTF_EDIT_MSG16("EM_UNDO"); 700 /* fall through */ 701 case EM_UNDO: 702 /* fall through */ 703 case WM_UNDO: 704 DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO"); 705 result = (LRESULT)EDIT_EM_Undo(hwnd, es); 706 break; 707 708 case EM_FMTLINES16: 709 DPRINTF_EDIT_MSG16("EM_FMTLINES"); 710 /* fall through */ 711 case EM_FMTLINES: 712 DPRINTF_EDIT_MSG32("EM_FMTLINES"); 713 result = (LRESULT)EDIT_EM_FmtLines(es, (BOOL)wParam); 714 break; 715 716 case EM_LINEFROMCHAR16: 717 DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR"); 718 /* fall through */ 719 case EM_LINEFROMCHAR: 720 DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR"); 721 result = (LRESULT)EDIT_EM_LineFromChar(es, (INT)wParam); 722 break; 723 724 /* message 0x00ca missing from specs */ 725 726 case WM_USER+26: 727 DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report"); 728 /* fall through */ 729 case 0x00ca: 730 DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report"); 731 result = DefWindowProcW(hwnd, msg, wParam, lParam); 732 break; 733 734 case EM_SETTABSTOPS16: 735 DPRINTF_EDIT_MSG16("EM_SETTABSTOPS"); 736 result = (LRESULT)EDIT_EM_SetTabStops16(es, (INT)wParam, MapSL(lParam)); 737 break; 738 case EM_SETTABSTOPS: 739 DPRINTF_EDIT_MSG32("EM_SETTABSTOPS"); 740 result = (LRESULT)EDIT_EM_SetTabStops(es, (INT)wParam, (LPINT)lParam); 741 break; 742 743 case EM_SETPASSWORDCHAR16: 744 DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR"); 745 unicode = FALSE; /* 16-bit message is always ascii */ 746 /* fall through */ 747 case EM_SETPASSWORDCHAR: 748 { 749 WCHAR charW = 0; 750 DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR"); 751 752 if(unicode) 753 charW = (WCHAR)wParam; 754 else 755 { 756 CHAR charA = wParam; 757 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1); 758 } 759 760 EDIT_EM_SetPasswordChar(hwnd, es, charW); 761 break; 762 } 763 764 case EM_EMPTYUNDOBUFFER16: 765 DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER"); 766 /* fall through */ 767 case EM_EMPTYUNDOBUFFER: 768 DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER"); 769 EDIT_EM_EmptyUndoBuffer(es); 770 break; 771 772 case EM_GETFIRSTVISIBLELINE16: 773 DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE"); 774 result = es->y_offset; 775 break; 776 case EM_GETFIRSTVISIBLELINE: 777 DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE"); 778 result = (es->style & ES_MULTILINE) ? es->y_offset : es->x_offset; 779 break; 780 781 case EM_SETREADONLY16: 782 DPRINTF_EDIT_MSG16("EM_SETREADONLY"); 783 /* fall through */ 784 case EM_SETREADONLY: 785 DPRINTF_EDIT_MSG32("EM_SETREADONLY"); 786 if (wParam) { 786 787 SetWindowLongA( hwnd, GWL_STYLE, 787 788 GetWindowLongA( hwnd, GWL_STYLE ) | ES_READONLY ); 788 789 es->style |= ES_READONLY; 789 790 } else { 790 791 SetWindowLongA( hwnd, GWL_STYLE, 791 792 GetWindowLongA( hwnd, GWL_STYLE ) & ~ES_READONLY ); 792 793 es->style &= ~ES_READONLY; 793 794 } 794 795 result = 1; 795 796 break; 796 797 #ifndef __WIN32OS2__ 797 798 799 800 798 case EM_SETWORDBREAKPROC16: 799 DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC"); 800 EDIT_EM_SetWordBreakProc16(hwnd, es, (EDITWORDBREAKPROC16)lParam); 801 break; 801 802 #endif 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 803 case EM_SETWORDBREAKPROC: 804 DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC"); 805 EDIT_EM_SetWordBreakProc(hwnd, es, lParam); 806 break; 807 808 case EM_GETWORDBREAKPROC16: 809 DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC"); 810 result = (LRESULT)es->word_break_proc16; 811 break; 812 case EM_GETWORDBREAKPROC: 813 DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC"); 814 result = (LRESULT)es->word_break_proc; 815 break; 816 817 case EM_GETPASSWORDCHAR16: 818 DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR"); 819 unicode = FALSE; /* 16-bit message is always ascii */ 820 /* fall through */ 821 case EM_GETPASSWORDCHAR: 822 { 823 DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR"); 824 825 if(unicode) 826 result = es->password_char; 827 else 828 { 829 WCHAR charW = es->password_char; 830 CHAR charA = 0; 831 WideCharToMultiByte(CP_ACP, 0, &charW, 1, &charA, 1, NULL, NULL); 832 result = charA; 833 } 834 break; 835 } 836 837 /* The following EM_xxx are new to win95 and don't exist for 16 bit */ 838 839 case EM_SETMARGINS: 840 DPRINTF_EDIT_MSG32("EM_SETMARGINS"); 841 EDIT_EM_SetMargins(es, (INT)wParam, SLOWORD(lParam), SHIWORD(lParam)); 842 break; 843 844 case EM_GETMARGINS: 845 DPRINTF_EDIT_MSG32("EM_GETMARGINS"); 846 result = MAKELONG(es->left_margin, es->right_margin); 847 break; 848 849 case EM_GETLIMITTEXT: 850 DPRINTF_EDIT_MSG32("EM_GETLIMITTEXT"); 851 result = es->buffer_limit; 852 break; 853 854 case EM_POSFROMCHAR: 855 DPRINTF_EDIT_MSG32("EM_POSFROMCHAR"); 856 result = EDIT_EM_PosFromChar(hwnd, es, (INT)wParam, FALSE); 857 break; 858 859 case EM_CHARFROMPOS: 860 DPRINTF_EDIT_MSG32("EM_CHARFROMPOS"); 861 result = EDIT_EM_CharFromPos(hwnd, es, SLOWORD(lParam), SHIWORD(lParam)); 862 break; 862 863 863 864 /* End of the EM_ messages which were in numerical order; what order … … 865 866 */ 866 867 867 case WM_GETDLGCODE: 868 DPRINTF_EDIT_MSG32("WM_GETDLGCODE"); 869 result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS; 870 871 if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN)) 872 { 873 int vk = (int)((LPMSG)lParam)->wParam; 874 875 if (vk == VK_RETURN && (GetWindowLongA( hwnd, GWL_STYLE ) & ES_WANTRETURN)) 876 { 877 result |= DLGC_WANTMESSAGE; 878 } 879 else if (es->hwndListBox && (vk == VK_RETURN || vk == VK_ESCAPE)) 880 { 881 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0)) 882 result |= DLGC_WANTMESSAGE; 883 } 884 } 885 break; 886 887 case WM_CHAR: 888 { 868 case WM_GETDLGCODE: 869 DPRINTF_EDIT_MSG32("WM_GETDLGCODE"); 870 result = DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS; 871 872 if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN)) 873 { 874 int vk = (int)((LPMSG)lParam)->wParam; 875 876 if (vk == VK_RETURN && (GetWindowLongA( hwnd, GWL_STYLE ) & ES_WANTRETURN)) 877 { 878 result |= DLGC_WANTMESSAGE; 879 } 880 else if (es->hwndListBox && (vk == VK_RETURN || vk == VK_ESCAPE)) 881 { 882 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0)) 883 result |= DLGC_WANTMESSAGE; 884 } 885 } 886 break; 887 888 case WM_CHAR: 889 { 890 #ifdef __WIN32OS2__ 891 static BOOL bDbcsLead = FALSE; 892 static CHAR cDbcsLead = 0; 893 894 WCHAR charW; 895 DPRINTF_EDIT_MSG32("WM_CHAR"); 896 897 if(unicode) 898 charW = wParam; 899 else 900 { 901 WCHAR charA = bDbcsLead ? (( wParam << 8 ) | cDbcsLead ) : wParam; 902 int size = bDbcsLead ? 2 : 1; 903 904 bDbcsLead = !bDbcsLead && IsDBCSLeadByte( wParam ); 905 906 if( bDbcsLead ) 907 cDbcsLead = wParam; 908 else 909 MultiByteToWideChar(CP_ACP, 0, (LPSTR)&charA, size, &charW, 1); 910 } 911 912 if ((charW == VK_RETURN || charW == VK_ESCAPE) && es->hwndListBox) 913 { 914 if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0)) 915 SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0); 916 break; 917 } 918 if( !bDbcsLead ) 919 EDIT_WM_Char(hwnd, es, charW); 920 #else 889 921 WCHAR charW; 890 922 DPRINTF_EDIT_MSG32("WM_CHAR"); … … 905 937 } 906 938 EDIT_WM_Char(hwnd, es, charW); 907 break; 908 } 909 910 case WM_CLEAR: 911 DPRINTF_EDIT_MSG32("WM_CLEAR"); 912 EDIT_WM_Clear(hwnd, es); 913 break; 914 915 case WM_COMMAND: 916 DPRINTF_EDIT_MSG32("WM_COMMAND"); 917 EDIT_WM_Command(hwnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); 918 break; 919 920 case WM_CONTEXTMENU: 921 DPRINTF_EDIT_MSG32("WM_CONTEXTMENU"); 922 EDIT_WM_ContextMenu(hwnd, es, SLOWORD(lParam), SHIWORD(lParam)); 923 break; 924 925 case WM_COPY: 926 DPRINTF_EDIT_MSG32("WM_COPY"); 927 EDIT_WM_Copy(hwnd, es); 928 break; 929 930 case WM_CREATE: 931 DPRINTF_EDIT_MSG32("WM_CREATE"); 932 if(unicode) 933 result = EDIT_WM_Create(hwnd, es, ((LPCREATESTRUCTW)lParam)->lpszName); 934 else 935 { 936 LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName; 937 LPWSTR nameW = NULL; 938 if(nameA) 939 { 940 INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0); 941 if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) 942 MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW); 943 } 944 result = EDIT_WM_Create(hwnd, es, nameW); 945 if(nameW) 946 HeapFree(GetProcessHeap(), 0, nameW); 947 } 948 break; 949 950 case WM_CUT: 951 DPRINTF_EDIT_MSG32("WM_CUT"); 952 EDIT_WM_Cut(hwnd, es); 953 break; 954 955 case WM_ENABLE: 956 DPRINTF_EDIT_MSG32("WM_ENABLE"); 939 #endif 940 break; 941 } 942 943 case WM_CLEAR: 944 DPRINTF_EDIT_MSG32("WM_CLEAR"); 945 EDIT_WM_Clear(hwnd, es); 946 break; 947 948 case WM_COMMAND: 949 DPRINTF_EDIT_MSG32("WM_COMMAND"); 950 EDIT_WM_Command(hwnd, es, HIWORD(wParam), LOWORD(wParam), (HWND)lParam); 951 break; 952 953 case WM_CONTEXTMENU: 954 DPRINTF_EDIT_MSG32("WM_CONTEXTMENU"); 955 EDIT_WM_ContextMenu(hwnd, es, SLOWORD(lParam), SHIWORD(lParam)); 956 break; 957 958 case WM_COPY: 959 DPRINTF_EDIT_MSG32("WM_COPY"); 960 EDIT_WM_Copy(hwnd, es); 961 break; 962 963 case WM_CREATE: 964 DPRINTF_EDIT_MSG32("WM_CREATE"); 965 if(unicode) 966 result = EDIT_WM_Create(hwnd, es, ((LPCREATESTRUCTW)lParam)->lpszName); 967 else 968 { 969 LPCSTR nameA = ((LPCREATESTRUCTA)lParam)->lpszName; 970 LPWSTR nameW = NULL; 971 if(nameA) 972 { 973 INT countW = MultiByteToWideChar(CP_ACP, 0, nameA, -1, NULL, 0); 974 if((nameW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) 975 MultiByteToWideChar(CP_ACP, 0, nameA, -1, nameW, countW); 976 } 977 result = EDIT_WM_Create(hwnd, es, nameW); 978 if(nameW) 979 HeapFree(GetProcessHeap(), 0, nameW); 980 } 981 break; 982 983 case WM_CUT: 984 DPRINTF_EDIT_MSG32("WM_CUT"); 985 EDIT_WM_Cut(hwnd, es); 986 break; 987 988 case WM_ENABLE: 989 DPRINTF_EDIT_MSG32("WM_ENABLE"); 957 990 es->bEnableState = (BOOL) wParam; 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 *FIXME: maybe DefWindowProc() screws up, but it seems that1019 *modeless dialog boxes need this. If we don't do this, the focus1020 *will _not_ be set by DefWindowProc() for edit controls in a1021 *modeless dialog box ???1022 1023 1024 1025 1026 1027 1028 1029 1030 *DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 991 EDIT_UpdateText(hwnd, es, NULL, TRUE); 992 break; 993 994 case WM_ERASEBKGND: 995 DPRINTF_EDIT_MSG32("WM_ERASEBKGND"); 996 result = EDIT_WM_EraseBkGnd(hwnd, es, (HDC)wParam); 997 break; 998 999 case WM_GETFONT: 1000 DPRINTF_EDIT_MSG32("WM_GETFONT"); 1001 result = (LRESULT)es->font; 1002 break; 1003 1004 case WM_GETTEXT: 1005 DPRINTF_EDIT_MSG32("WM_GETTEXT"); 1006 result = (LRESULT)EDIT_WM_GetText(es, (INT)wParam, lParam, unicode); 1007 break; 1008 1009 case WM_GETTEXTLENGTH: 1010 DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH"); 1011 result = strlenW(es->text); 1012 break; 1013 1014 case WM_HSCROLL: 1015 DPRINTF_EDIT_MSG32("WM_HSCROLL"); 1016 result = EDIT_WM_HScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam)); 1017 break; 1018 1019 case WM_KEYDOWN: 1020 DPRINTF_EDIT_MSG32("WM_KEYDOWN"); 1021 result = EDIT_WM_KeyDown(hwnd, es, (INT)wParam); 1022 break; 1023 1024 case WM_KILLFOCUS: 1025 DPRINTF_EDIT_MSG32("WM_KILLFOCUS"); 1026 result = EDIT_WM_KillFocus(hwnd, es); 1027 break; 1028 1029 case WM_LBUTTONDBLCLK: 1030 DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK"); 1031 result = EDIT_WM_LButtonDblClk(hwnd, es); 1032 break; 1033 1034 case WM_LBUTTONDOWN: 1035 DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN"); 1036 result = EDIT_WM_LButtonDown(hwnd, es, (DWORD)wParam, SLOWORD(lParam), SHIWORD(lParam)); 1037 break; 1038 1039 case WM_LBUTTONUP: 1040 DPRINTF_EDIT_MSG32("WM_LBUTTONUP"); 1041 result = EDIT_WM_LButtonUp(hwnd, es); 1042 break; 1043 1044 case WM_MBUTTONDOWN: 1045 DPRINTF_EDIT_MSG32("WM_MBUTTONDOWN"); 1046 result = EDIT_WM_MButtonDown(hwnd); 1047 break; 1048 1049 case WM_MOUSEACTIVATE: 1050 /* 1051 * FIXME: maybe DefWindowProc() screws up, but it seems that 1052 * modeless dialog boxes need this. If we don't do this, the focus 1053 * will _not_ be set by DefWindowProc() for edit controls in a 1054 * modeless dialog box ??? 1055 */ 1056 DPRINTF_EDIT_MSG32("WM_MOUSEACTIVATE"); 1057 SetFocus(hwnd); 1058 result = MA_ACTIVATE; 1059 break; 1060 1061 case WM_MOUSEMOVE: 1062 /* 1063 * DPRINTF_EDIT_MSG32("WM_MOUSEMOVE"); 1064 */ 1065 result = EDIT_WM_MouseMove(hwnd, es, SLOWORD(lParam), SHIWORD(lParam)); 1066 break; 1067 1068 case WM_PAINT: 1069 DPRINTF_EDIT_MSG32("WM_PAINT"); 1070 EDIT_WM_Paint(hwnd, es, wParam); 1071 break; 1072 1073 case WM_PASTE: 1074 DPRINTF_EDIT_MSG32("WM_PASTE"); 1075 EDIT_WM_Paste(hwnd, es); 1076 break; 1077 1078 case WM_SETFOCUS: 1079 DPRINTF_EDIT_MSG32("WM_SETFOCUS"); 1080 EDIT_WM_SetFocus(hwnd, es); 1081 break; 1082 1083 case WM_SETFONT: 1084 DPRINTF_EDIT_MSG32("WM_SETFONT"); 1085 EDIT_WM_SetFont(hwnd, es, (HFONT)wParam, LOWORD(lParam) != 0); 1086 break; 1087 1088 case WM_SETREDRAW: 1089 /* FIXME: actually set an internal flag and behave accordingly */ 1090 break; 1091 1092 case WM_SETTEXT: 1093 DPRINTF_EDIT_MSG32("WM_SETTEXT"); 1094 EDIT_WM_SetText(hwnd, es, lParam, unicode); 1095 result = TRUE; 1096 break; 1097 1098 case WM_SIZE: 1099 DPRINTF_EDIT_MSG32("WM_SIZE"); 1100 EDIT_WM_Size(hwnd, es, (UINT)wParam, LOWORD(lParam), HIWORD(lParam)); 1101 break; 1069 1102 1070 1103 case WM_STYLECHANGED: 1071 1104 DPRINTF_EDIT_MSG32("WM_STYLECHANGED"); 1072 1105 result = EDIT_WM_StyleChanged (hwnd, es, wParam, (const STYLESTRUCT *)lParam); 1073 1106 break; 1074 1107 1075 1108 case WM_STYLECHANGING: 1076 1109 DPRINTF_EDIT_MSG32("WM_STYLECHANGING"); 1077 1110 result = 0; /* See EDIT_WM_StyleChanged */ 1078 1111 break; 1079 1112 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1113 case WM_SYSKEYDOWN: 1114 DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN"); 1115 result = EDIT_WM_SysKeyDown(hwnd, es, (INT)wParam, (DWORD)lParam); 1116 break; 1117 1118 case WM_TIMER: 1119 DPRINTF_EDIT_MSG32("WM_TIMER"); 1120 EDIT_WM_Timer(hwnd, es); 1121 break; 1122 1123 case WM_VSCROLL: 1124 DPRINTF_EDIT_MSG32("WM_VSCROLL"); 1125 result = EDIT_WM_VScroll(hwnd, es, LOWORD(wParam), SHIWORD(wParam)); 1126 break; 1094 1127 1095 1128 case WM_MOUSEWHEEL: … … 1108 1141 int cLineScroll= (int) min((UINT) es->line_count, pulScrollLines); 1109 1142 cLineScroll *= (gcWheelDelta / WHEEL_DELTA); 1110 1143 result = EDIT_EM_LineScroll(hwnd, es, 0, cLineScroll); 1111 1144 } 1112 1145 } 1113 1146 break; 1114 1115 1116 1117 1118 1119 1120 1121 1147 default: 1148 if(unicode) 1149 result = DefWindowProcW(hwnd, msg, wParam, lParam); 1150 else 1151 result = DefWindowProcA(hwnd, msg, wParam, lParam); 1152 break; 1153 } 1154 EDIT_UnlockBuffer(hwnd, es, FALSE); 1122 1155 END: 1123 1124 } 1125 1126 /********************************************************************* 1127 * 1128 * 1156 return result; 1157 } 1158 1159 /********************************************************************* 1160 * 1161 * EditWndProcW (USER32.@) 1129 1162 */ 1130 1163 LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) … … 1136 1169 /********************************************************************* 1137 1170 * 1138 * 1171 * EditWndProc (USER32.@) 1139 1172 */ 1140 1173 LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) … … 1146 1179 /********************************************************************* 1147 1180 * 1148 * 1149 * 1150 * 1151 * 1152 * 1181 * EDIT_BuildLineDefs_ML 1182 * 1183 * Build linked list of text lines. 1184 * Lines can end with '\0' (last line), a character (if it is wrapped), 1185 * a soft return '\r\r\n' or a hard return '\r\n' 1153 1186 * 1154 1187 */ 1155 1188 static void EDIT_BuildLineDefs_ML(HWND hwnd, EDITSTATE *es, INT istart, INT iend, INT delta, HRGN hrgn) 1156 1189 { 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 } 1401 1402 /********************************************************************* 1403 * 1404 * 1190 HDC dc; 1191 HFONT old_font = 0; 1192 LPWSTR current_position, cp; 1193 INT fw; 1194 LINEDEF *current_line; 1195 LINEDEF *previous_line; 1196 LINEDEF *start_line; 1197 INT line_index = 0, nstart_line = 0, nstart_index = 0; 1198 INT line_count = es->line_count; 1199 INT orig_net_length; 1200 RECT rc; 1201 1202 if (istart == iend && delta == 0) 1203 return; 1204 1205 dc = GetDC(hwnd); 1206 if (es->font) 1207 old_font = SelectObject(dc, es->font); 1208 1209 previous_line = NULL; 1210 current_line = es->first_line_def; 1211 1212 /* Find starting line. istart must lie inside an existing line or 1213 * at the end of buffer */ 1214 do { 1215 if (istart < current_line->index + current_line->length || 1216 current_line->ending == END_0) 1217 break; 1218 1219 previous_line = current_line; 1220 current_line = current_line->next; 1221 line_index++; 1222 } while (current_line); 1223 1224 if (!current_line) /* Error occurred start is not inside previous buffer */ 1225 { 1226 FIXME(" modification occurred outside buffer\n"); 1227 return; 1228 } 1229 1230 /* Remember start of modifications in order to calculate update region */ 1231 nstart_line = line_index; 1232 nstart_index = current_line->index; 1233 1234 /* We must start to reformat from the previous line since the modifications 1235 * may have caused the line to wrap upwards. */ 1236 if (!(es->style & ES_AUTOHSCROLL) && line_index > 0) 1237 { 1238 line_index--; 1239 current_line = previous_line; 1240 } 1241 start_line = current_line; 1242 1243 fw = es->format_rect.right - es->format_rect.left; 1244 current_position = es->text + current_line->index; 1245 do { 1246 if (current_line != start_line) 1247 { 1248 if (!current_line || current_line->index + delta > current_position - es->text) 1249 { 1250 /* The buffer has been expanded, create a new line and 1251 insert it into the link list */ 1252 LINEDEF *new_line = HeapAlloc(GetProcessHeap(), 0, sizeof(LINEDEF)); 1253 new_line->next = previous_line->next; 1254 previous_line->next = new_line; 1255 current_line = new_line; 1256 es->line_count++; 1257 } 1258 else if (current_line->index + delta < current_position - es->text) 1259 { 1260 /* The previous line merged with this line so we delete this extra entry */ 1261 previous_line->next = current_line->next; 1262 HeapFree(GetProcessHeap(), 0, current_line); 1263 current_line = previous_line->next; 1264 es->line_count--; 1265 continue; 1266 } 1267 else /* current_line->index + delta == current_position */ 1268 { 1269 if (current_position - es->text > iend) 1270 break; /* We reached end of line modifications */ 1271 /* else recalulate this line */ 1272 } 1273 } 1274 1275 current_line->index = current_position - es->text; 1276 orig_net_length = current_line->net_length; 1277 1278 /* Find end of line */ 1279 cp = current_position; 1280 while (*cp) { 1281 if ((*cp == '\r') && (*(cp + 1) == '\n')) 1282 break; 1283 cp++; 1284 } 1285 1286 /* Mark type of line termination */ 1287 if (!(*cp)) { 1288 current_line->ending = END_0; 1289 current_line->net_length = strlenW(current_position); 1290 } else if ((cp > current_position) && (*(cp - 1) == '\r')) { 1291 current_line->ending = END_SOFT; 1292 current_line->net_length = cp - current_position - 1; 1293 } else { 1294 current_line->ending = END_HARD; 1295 current_line->net_length = cp - current_position; 1296 } 1297 1298 /* Calculate line width */ 1299 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, 1300 current_position, current_line->net_length, 1301 es->tabs_count, es->tabs)); 1302 1303 /* FIXME: check here for lines that are too wide even in AUTOHSCROLL (> 32767 ???) */ 1304 if ((!(es->style & ES_AUTOHSCROLL)) && (current_line->width > fw)) { 1305 INT next = 0; 1306 INT prev; 1307 do { 1308 prev = next; 1309 next = EDIT_CallWordBreakProc(es, current_position - es->text, 1310 prev + 1, current_line->net_length, WB_RIGHT); 1311 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, 1312 current_position, next, es->tabs_count, es->tabs)); 1313 } while (current_line->width <= fw); 1314 if (!prev) { /* Didn't find a line break so force a break */ 1315 next = 0; 1316 do { 1317 prev = next; 1318 next++; 1319 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, 1320 current_position, next, es->tabs_count, es->tabs)); 1321 } while (current_line->width <= fw); 1322 if (!prev) 1323 prev = 1; 1324 } 1325 1326 /* If the first line we are calculating, wrapped before istart, we must 1327 * adjust istart in order for this to be reflected in the update region. */ 1328 if (current_line->index == nstart_index && istart > current_line->index + prev) 1329 istart = current_line->index + prev; 1330 /* else if we are updating the previous line before the first line we 1331 * are re-calculating and it expanded */ 1332 else if (current_line == start_line && 1333 current_line->index != nstart_index && orig_net_length < prev) 1334 { 1335 /* Line expanded due to an upwards line wrap so we must partially include 1336 * previous line in update region */ 1337 nstart_line = line_index; 1338 nstart_index = current_line->index; 1339 istart = current_line->index + orig_net_length; 1340 } 1341 1342 current_line->net_length = prev; 1343 current_line->ending = END_WRAP; 1344 current_line->width = (INT)LOWORD(GetTabbedTextExtentW(dc, current_position, 1345 current_line->net_length, es->tabs_count, es->tabs)); 1346 } 1347 1348 1349 /* Adjust length to include line termination */ 1350 switch (current_line->ending) { 1351 case END_SOFT: 1352 current_line->length = current_line->net_length + 3; 1353 break; 1354 case END_HARD: 1355 current_line->length = current_line->net_length + 2; 1356 break; 1357 case END_WRAP: 1358 case END_0: 1359 current_line->length = current_line->net_length; 1360 break; 1361 } 1362 es->text_width = max(es->text_width, current_line->width); 1363 current_position += current_line->length; 1364 previous_line = current_line; 1365 current_line = current_line->next; 1366 line_index++; 1367 } while (previous_line->ending != END_0); 1368 1369 /* Finish adjusting line indexes by delta or remove hanging lines */ 1370 if (previous_line->ending == END_0) 1371 { 1372 LINEDEF *pnext = NULL; 1373 1374 previous_line->next = NULL; 1375 while (current_line) 1376 { 1377 pnext = current_line->next; 1378 HeapFree(GetProcessHeap(), 0, current_line); 1379 current_line = pnext; 1380 es->line_count--; 1381 } 1382 } 1383 else 1384 { 1385 while (current_line) 1386 { 1387 current_line->index += delta; 1388 current_line = current_line->next; 1389 } 1390 } 1391 1392 /* Calculate rest of modification rectangle */ 1393 if (hrgn) 1394 { 1395 HRGN tmphrgn; 1396 /* 1397 * We calculate two rectangles. One for the first line which may have 1398 * an indent with respect to the format rect. The other is a format-width 1399 * rectangle that spans the rest of the lines that changed or moved. 1400 */ 1401 rc.top = es->format_rect.top + nstart_line * es->line_height - 1402 (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */ 1403 rc.bottom = rc.top + es->line_height; 1404 rc.left = es->format_rect.left + (INT)LOWORD(GetTabbedTextExtentW(dc, 1405 es->text + nstart_index, istart - nstart_index, 1406 es->tabs_count, es->tabs)) - es->x_offset; /* Adjust for horz scroll */ 1407 rc.right = es->format_rect.right; 1408 SetRectRgn(hrgn, rc.left, rc.top, rc.right, rc.bottom); 1409 1410 rc.top = rc.bottom; 1411 rc.left = es->format_rect.left; 1412 rc.right = es->format_rect.right; 1413 /* 1414 * If lines were added or removed we must re-paint the remainder of the 1415 * lines since the remaining lines were either shifted up or down. 1416 */ 1417 if (line_count < es->line_count) /* We added lines */ 1418 rc.bottom = es->line_count * es->line_height; 1419 else if (line_count > es->line_count) /* We removed lines */ 1420 rc.bottom = line_count * es->line_height; 1421 else 1422 rc.bottom = line_index * es->line_height; 1423 rc.bottom -= (es->y_offset * es->line_height); /* Adjust for vertical scrollbar */ 1424 tmphrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom); 1425 CombineRgn(hrgn, hrgn, tmphrgn, RGN_OR); 1426 DeleteObject(tmphrgn); 1427 } 1428 1429 if (es->font) 1430 SelectObject(dc, old_font); 1431 1432 ReleaseDC(hwnd, dc); 1433 } 1434 1435 /********************************************************************* 1436 * 1437 * EDIT_CalcLineWidth_SL 1405 1438 * 1406 1439 */ … … 1412 1445 /********************************************************************* 1413 1446 * 1414 * 1415 * 1416 * 1417 * 1418 * 1419 * 1420 * 1421 * 1422 * 1447 * EDIT_CallWordBreakProc 1448 * 1449 * Call appropriate WordBreakProc (internal or external). 1450 * 1451 * Note: The "start" argument should always be an index referring 1452 * to es->text. The actual wordbreak proc might be 1453 * 16 bit, so we can't always pass any 32 bit LPSTR. 1454 * Hence we assume that es->text is the buffer that holds 1455 * the string under examination (we can decide this for ourselves). 1423 1456 * 1424 1457 */ … … 1435 1468 1436 1469 #ifndef __WIN32OS2__ 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 else 1470 if (es->word_break_proc16) { 1471 HGLOBAL16 hglob16; 1472 SEGPTR segptr; 1473 INT countA; 1474 1475 countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL); 1476 hglob16 = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, countA); 1477 segptr = K32WOWGlobalLock16(hglob16); 1478 WideCharToMultiByte(CP_ACP, 0, es->text + start, count, MapSL(segptr), countA, NULL, NULL); 1479 ret = (INT)EDIT_CallTo16_word_lwww(es->word_break_proc16, 1480 segptr, index, countA, action); 1481 GlobalUnlock16(hglob16); 1482 GlobalFree16(hglob16); 1483 } 1484 else 1452 1485 #endif 1453 1486 if (es->word_break_proc) 1454 1487 { 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 } 1478 1488 if(es->is_unicode) 1489 { 1490 EDITWORDBREAKPROCW wbpW = (EDITWORDBREAKPROCW)es->word_break_proc; 1491 1492 TRACE_(relay)("(UNICODE wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n", 1493 es->word_break_proc, debugstr_wn(es->text + start, count), index, count, action); 1494 ret = wbpW(es->text + start, index, count, action); 1495 } 1496 else 1497 { 1498 EDITWORDBREAKPROCA wbpA = (EDITWORDBREAKPROCA)es->word_break_proc; 1499 INT countA; 1500 CHAR *textA; 1501 1502 countA = WideCharToMultiByte(CP_ACP, 0, es->text + start, count, NULL, 0, NULL, NULL); 1503 textA = HeapAlloc(GetProcessHeap(), 0, countA); 1504 WideCharToMultiByte(CP_ACP, 0, es->text + start, count, textA, countA, NULL, NULL); 1505 TRACE_(relay)("(ANSI wordbrk=%p,str=%s,idx=%d,cnt=%d,act=%d)\n", 1506 es->word_break_proc, debugstr_an(textA, countA), index, countA, action); 1507 ret = wbpA(textA, index, countA, action); 1508 HeapFree(GetProcessHeap(), 0, textA); 1509 } 1510 } 1511 else 1479 1512 ret = EDIT_WordBreakProc(es->text + start, index, count, action); 1480 1513 … … 1486 1519 /********************************************************************* 1487 1520 * 1488 * 1489 * 1490 * 1491 * 1492 * 1493 * 1521 * EDIT_CharFromPos 1522 * 1523 * Beware: This is not the function called on EM_CHARFROMPOS 1524 * The position _can_ be outside the formatting / client 1525 * rectangle 1526 * The return value is only the character index 1494 1527 * 1495 1528 */ 1496 1529 static INT EDIT_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y, LPBOOL after_wrap) 1497 1530 { 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1531 INT index; 1532 HDC dc; 1533 HFONT old_font = 0; 1534 1535 if (es->style & ES_MULTILINE) { 1536 INT line = (y - es->format_rect.top) / es->line_height + es->y_offset; 1537 INT line_index = 0; 1538 LINEDEF *line_def = es->first_line_def; 1539 INT low, high; 1540 while ((line > 0) && line_def->next) { 1541 line_index += line_def->length; 1542 line_def = line_def->next; 1543 line--; 1544 } 1545 x += es->x_offset - es->format_rect.left; 1546 if (x >= line_def->width) { 1547 if (after_wrap) 1548 *after_wrap = (line_def->ending == END_WRAP); 1549 return line_index + line_def->net_length; 1550 } 1551 if (x <= 0) { 1552 if (after_wrap) 1553 *after_wrap = FALSE; 1554 return line_index; 1555 } 1556 dc = GetDC(hwnd); 1557 if (es->font) 1558 old_font = SelectObject(dc, es->font); 1526 1559 low = line_index + 1; 1527 1560 high = line_index + line_def->net_length + 1; … … 1529 1562 { 1530 1563 INT mid = (low + high) / 2; 1531 1564 if (LOWORD(GetTabbedTextExtentW(dc, es->text + line_index,mid - line_index, es->tabs_count, es->tabs)) > x) high = mid; 1532 1565 else low = mid; 1533 1566 } 1534 1567 index = low; 1535 1568 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1569 if (after_wrap) 1570 *after_wrap = ((index == line_index + line_def->net_length) && 1571 (line_def->ending == END_WRAP)); 1572 } else { 1573 LPWSTR text; 1574 SIZE size; 1575 if (after_wrap) 1576 *after_wrap = FALSE; 1577 x -= es->format_rect.left; 1578 if (!x) 1579 return es->x_offset; 1580 text = EDIT_GetPasswordPointer_SL(es); 1581 dc = GetDC(hwnd); 1582 if (es->font) 1583 old_font = SelectObject(dc, es->font); 1584 if (x < 0) 1552 1585 { 1553 1586 INT low = 0; … … 1562 1595 } 1563 1596 index = low; 1564 1597 } 1565 1598 else 1566 1599 { … … 1576 1609 } 1577 1610 index = low; 1578 1579 1580 1581 1582 1583 1584 1585 1586 } 1587 1588 1589 /********************************************************************* 1590 * 1591 * 1592 * 1593 * 1594 * 1611 } 1612 if (es->style & ES_PASSWORD) 1613 HeapFree(GetProcessHeap(), 0, text); 1614 } 1615 if (es->font) 1616 SelectObject(dc, old_font); 1617 ReleaseDC(hwnd, dc); 1618 return index; 1619 } 1620 1621 1622 /********************************************************************* 1623 * 1624 * EDIT_ConfinePoint 1625 * 1626 * adjusts the point to be within the formatting rectangle 1627 * (so CharFromPos returns the nearest _visible_ character) 1595 1628 * 1596 1629 */ 1597 1630 static void EDIT_ConfinePoint(EDITSTATE *es, LPINT x, LPINT y) 1598 1631 { 1599 1600 1601 } 1602 1603 1604 /********************************************************************* 1605 * 1606 * 1607 * 1608 * 1609 * 1632 *x = min(max(*x, es->format_rect.left), es->format_rect.right - 1); 1633 *y = min(max(*y, es->format_rect.top), es->format_rect.bottom - 1); 1634 } 1635 1636 1637 /********************************************************************* 1638 * 1639 * EDIT_GetLineRect 1640 * 1641 * Calculates the bounding rectangle for a line from a starting 1642 * column to an ending column. 1610 1643 * 1611 1644 */ 1612 1645 static void EDIT_GetLineRect(HWND hwnd, EDITSTATE *es, INT line, INT scol, INT ecol, LPRECT rc) 1613 1646 { 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 } 1624 1625 1626 /********************************************************************* 1627 * 1628 * 1629 * 1630 * 1647 INT line_index = EDIT_EM_LineIndex(es, line); 1648 1649 if (es->style & ES_MULTILINE) 1650 rc->top = es->format_rect.top + (line - es->y_offset) * es->line_height; 1651 else 1652 rc->top = es->format_rect.top; 1653 rc->bottom = rc->top + es->line_height; 1654 rc->left = (scol == 0) ? es->format_rect.left : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + scol, TRUE)); 1655 rc->right = (ecol == -1) ? es->format_rect.right : SLOWORD(EDIT_EM_PosFromChar(hwnd, es, line_index + ecol, TRUE)); 1656 } 1657 1658 1659 /********************************************************************* 1660 * 1661 * EDIT_GetPasswordPointer_SL 1662 * 1663 * note: caller should free the (optionally) allocated buffer 1631 1664 * 1632 1665 */ 1633 1666 static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es) 1634 1667 { 1635 1636 1637 1638 1639 1640 1641 1642 1643 } 1644 1645 1646 /********************************************************************* 1647 * 1648 * 1649 * 1650 * 1651 * 1668 if (es->style & ES_PASSWORD) { 1669 INT len = strlenW(es->text); 1670 LPWSTR text = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 1671 text[len] = '\0'; 1672 while(len) text[--len] = es->password_char; 1673 return text; 1674 } else 1675 return es->text; 1676 } 1677 1678 1679 /********************************************************************* 1680 * 1681 * EDIT_LockBuffer 1682 * 1683 * This acts as a LOCAL_Lock(), but it locks only once. This way 1684 * you can call it whenever you like, without unlocking. 1652 1685 * 1653 1686 */ … … 1655 1688 { 1656 1689 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE ); 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 } 1722 1723 1724 /********************************************************************* 1725 * 1726 * 1727 * 1728 * 1729 * 1690 if (!es) { 1691 ERR("no EDITSTATE ... please report\n"); 1692 return; 1693 } 1694 if (!es->text) { 1695 CHAR *textA = NULL; 1696 UINT countA = 0; 1697 BOOL _16bit = FALSE; 1698 1699 if(es->hloc32W) 1700 { 1701 if(es->hloc32A) 1702 { 1703 TRACE("Synchronizing with 32-bit ANSI buffer\n"); 1704 textA = LocalLock(es->hloc32A); 1705 countA = strlen(textA) + 1; 1706 } 1707 else if(es->hloc16) 1708 { 1709 TRACE("Synchronizing with 16-bit ANSI buffer\n"); 1710 textA = LOCAL_Lock(hInstance, es->hloc16); 1711 countA = strlen(textA) + 1; 1712 _16bit = TRUE; 1713 } 1714 } 1715 else { 1716 ERR("no buffer ... please report\n"); 1717 return; 1718 } 1719 1720 if(textA) 1721 { 1722 HLOCAL hloc32W_new; 1723 UINT countW_new = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0); 1724 TRACE("%d bytes translated to %d WCHARs\n", countA, countW_new); 1725 if(countW_new > es->buffer_size + 1) 1726 { 1727 UINT alloc_size = ROUND_TO_GROW(countW_new * sizeof(WCHAR)); 1728 TRACE("Resizing 32-bit UNICODE buffer from %d+1 to %d WCHARs\n", es->buffer_size, countW_new); 1729 hloc32W_new = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT); 1730 if(hloc32W_new) 1731 { 1732 es->hloc32W = hloc32W_new; 1733 es->buffer_size = LocalSize(hloc32W_new)/sizeof(WCHAR) - 1; 1734 TRACE("Real new size %d+1 WCHARs\n", es->buffer_size); 1735 } 1736 else 1737 WARN("FAILED! Will synchronize partially\n"); 1738 } 1739 } 1740 1741 /*TRACE("Locking 32-bit UNICODE buffer\n");*/ 1742 es->text = LocalLock(es->hloc32W); 1743 1744 if(textA) 1745 { 1746 MultiByteToWideChar(CP_ACP, 0, textA, countA, es->text, es->buffer_size + 1); 1747 if(_16bit) 1748 LOCAL_Unlock(hInstance, es->hloc16); 1749 else 1750 LocalUnlock(es->hloc32A); 1751 } 1752 } 1753 es->lock_count++; 1754 } 1755 1756 1757 /********************************************************************* 1758 * 1759 * EDIT_SL_InvalidateText 1760 * 1761 * Called from EDIT_InvalidateText(). 1762 * Does the job for single-line controls only. 1730 1763 * 1731 1764 */ 1732 1765 static void EDIT_SL_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end) 1733 1766 { 1734 1735 1736 1737 1738 1739 1740 } 1741 1742 1743 /********************************************************************* 1744 * 1745 * 1746 * 1747 * 1748 * 1767 RECT line_rect; 1768 RECT rc; 1769 1770 EDIT_GetLineRect(hwnd, es, 0, start, end, &line_rect); 1771 if (IntersectRect(&rc, &line_rect, &es->format_rect)) 1772 EDIT_UpdateText(hwnd, es, &rc, FALSE); 1773 } 1774 1775 1776 /********************************************************************* 1777 * 1778 * EDIT_ML_InvalidateText 1779 * 1780 * Called from EDIT_InvalidateText(). 1781 * Does the job for multi-line controls only. 1749 1782 * 1750 1783 */ 1751 1784 static void EDIT_ML_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end) 1752 1785 { 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 } 1803 1804 1805 /********************************************************************* 1806 * 1807 * 1808 * 1809 * 1810 * 1811 * 1812 * 1813 * 1786 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 1787 INT sl = EDIT_EM_LineFromChar(es, start); 1788 INT el = EDIT_EM_LineFromChar(es, end); 1789 INT sc; 1790 INT ec; 1791 RECT rc1; 1792 RECT rcWnd; 1793 RECT rcLine; 1794 RECT rcUpdate; 1795 INT l; 1796 1797 if ((el < es->y_offset) || (sl > es->y_offset + vlc)) 1798 return; 1799 1800 sc = start - EDIT_EM_LineIndex(es, sl); 1801 ec = end - EDIT_EM_LineIndex(es, el); 1802 if (sl < es->y_offset) { 1803 sl = es->y_offset; 1804 sc = 0; 1805 } 1806 if (el > es->y_offset + vlc) { 1807 el = es->y_offset + vlc; 1808 ec = EDIT_EM_LineLength(es, EDIT_EM_LineIndex(es, el)); 1809 } 1810 GetClientRect(hwnd, &rc1); 1811 IntersectRect(&rcWnd, &rc1, &es->format_rect); 1812 if (sl == el) { 1813 EDIT_GetLineRect(hwnd, es, sl, sc, ec, &rcLine); 1814 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) 1815 EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE); 1816 } else { 1817 EDIT_GetLineRect(hwnd, es, sl, sc, 1818 EDIT_EM_LineLength(es, 1819 EDIT_EM_LineIndex(es, sl)), 1820 &rcLine); 1821 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) 1822 EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE); 1823 for (l = sl + 1 ; l < el ; l++) { 1824 EDIT_GetLineRect(hwnd, es, l, 0, 1825 EDIT_EM_LineLength(es, 1826 EDIT_EM_LineIndex(es, l)), 1827 &rcLine); 1828 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) 1829 EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE); 1830 } 1831 EDIT_GetLineRect(hwnd, es, el, 0, ec, &rcLine); 1832 if (IntersectRect(&rcUpdate, &rcWnd, &rcLine)) 1833 EDIT_UpdateText(hwnd, es, &rcUpdate, FALSE); 1834 } 1835 } 1836 1837 1838 /********************************************************************* 1839 * 1840 * EDIT_InvalidateText 1841 * 1842 * Invalidate the text from offset start upto, but not including, 1843 * offset end. Useful for (re)painting the selection. 1844 * Regions outside the linewidth are not invalidated. 1845 * end == -1 means end == TextLength. 1846 * start and end need not be ordered. 1814 1847 * 1815 1848 */ 1816 1849 static void EDIT_InvalidateText(HWND hwnd, EDITSTATE *es, INT start, INT end) 1817 1850 { 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 } 1831 1832 1833 /********************************************************************* 1834 * 1835 * 1836 * 1837 * 1851 if (end == start) 1852 return; 1853 1854 if (end == -1) 1855 end = strlenW(es->text); 1856 1857 ORDER_INT(start, end); 1858 1859 if (es->style & ES_MULTILINE) 1860 EDIT_ML_InvalidateText(hwnd, es, start, end); 1861 else 1862 EDIT_SL_InvalidateText(hwnd, es, start, end); 1863 } 1864 1865 1866 /********************************************************************* 1867 * 1868 * EDIT_MakeFit 1869 * 1870 * Try to fit size + 1 characters in the buffer. Constrain to limits. 1838 1871 * 1839 1872 */ 1840 1873 static BOOL EDIT_MakeFit(HWND hwnd, EDITSTATE *es, UINT size) 1841 1874 { 1842 1843 1844 1845 1875 HLOCAL hNew32W; 1876 1877 if (size <= es->buffer_size) 1878 return TRUE; 1846 1879 #ifndef __WIN32OS2__ 1847 //SvL: EM_SETTEXTLIMIT has no effect in 1880 //SvL: EM_SETTEXTLIMIT has no effect in 1848 1881 // NT4, SP6 (EM_GETTEXTLIMIT only returns that value). 1849 1882 // Limits are simply ignored, no EN_MAXTEXT notification is ever sent. 1850 1883 // (fixes license edit control in Microsoft Visual C++ 4.2 install) 1851 1884 1852 1853 1854 1855 1856 1857 1885 if (size > es->buffer_limit) { 1886 EDIT_NOTIFY_PARENT(hwnd, es, EN_MAXTEXT, "EN_MAXTEXT"); 1887 return FALSE; 1888 } 1889 if (size > es->buffer_limit) 1890 size = es->buffer_limit; 1858 1891 #endif 1859 1892 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 } 1885 1886 1887 /********************************************************************* 1888 * 1889 * 1890 * 1891 * 1893 TRACE("trying to ReAlloc to %d+1 characters\n", size); 1894 1895 /* Force edit to unlock it's buffer. es->text now NULL */ 1896 EDIT_UnlockBuffer(hwnd, es, TRUE); 1897 1898 if (es->hloc32W) { 1899 UINT alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR)); 1900 if ((hNew32W = LocalReAlloc(es->hloc32W, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT))) { 1901 TRACE("Old 32 bit handle %08x, new handle %08x\n", es->hloc32W, hNew32W); 1902 es->hloc32W = hNew32W; 1903 es->buffer_size = LocalSize(hNew32W)/sizeof(WCHAR) - 1; 1904 } 1905 } 1906 1907 EDIT_LockBuffer(hwnd, es); 1908 1909 if (es->buffer_size < size) { 1910 WARN("FAILED ! We now have %d+1\n", es->buffer_size); 1911 EDIT_NOTIFY_PARENT(hwnd, es, EN_ERRSPACE, "EN_ERRSPACE"); 1912 return FALSE; 1913 } else { 1914 TRACE("We now have %d+1\n", es->buffer_size); 1915 return TRUE; 1916 } 1917 } 1918 1919 1920 /********************************************************************* 1921 * 1922 * EDIT_MakeUndoFit 1923 * 1924 * Try to fit size + 1 bytes in the undo buffer. 1892 1925 * 1893 1926 */ 1894 1927 static BOOL EDIT_MakeUndoFit(EDITSTATE *es, UINT size) 1895 1928 { 1896 1897 1898 1899 1900 1901 1902 1903 1904 1929 UINT alloc_size; 1930 1931 if (size <= es->undo_buffer_size) 1932 return TRUE; 1933 1934 TRACE("trying to ReAlloc to %d+1\n", size); 1935 1936 alloc_size = ROUND_TO_GROW((size + 1) * sizeof(WCHAR)); 1937 if ((es->undo_text = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, es->undo_text, alloc_size))) { 1905 1938 #ifdef __WIN32OS2__ 1906 1939 es->undo_buffer_size = alloc_size/sizeof(WCHAR) - 1; 1907 1940 #else 1908 1941 es->undo_buffer_size = alloc_size/sizeof(WCHAR); 1909 1942 #endif 1910 1911 1912 1913 1914 1915 1916 1917 } 1918 1919 1920 /********************************************************************* 1921 * 1922 * 1943 return TRUE; 1944 } 1945 else 1946 { 1947 WARN("FAILED ! We now have %d+1\n", es->undo_buffer_size); 1948 return FALSE; 1949 } 1950 } 1951 1952 1953 /********************************************************************* 1954 * 1955 * EDIT_MoveBackward 1923 1956 * 1924 1957 */ 1925 1958 static void EDIT_MoveBackward(HWND hwnd, EDITSTATE *es, BOOL extend) 1926 1959 { 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 } 1941 1942 1943 /********************************************************************* 1944 * 1945 * 1946 * 1947 * 1948 * 1949 * 1960 INT e = es->selection_end; 1961 1962 if (e) { 1963 e--; 1964 if ((es->style & ES_MULTILINE) && e && 1965 (es->text[e - 1] == '\r') && (es->text[e] == '\n')) { 1966 e--; 1967 if (e && (es->text[e - 1] == '\r')) 1968 e--; 1969 } 1970 } 1971 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE); 1972 EDIT_EM_ScrollCaret(hwnd, es); 1973 } 1974 1975 1976 /********************************************************************* 1977 * 1978 * EDIT_MoveDown_ML 1979 * 1980 * Only for multi line controls 1981 * Move the caret one line down, on a column with the nearest 1982 * x coordinate on the screen (might be a different column). 1950 1983 * 1951 1984 */ 1952 1985 static void EDIT_MoveDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend) 1953 1986 { 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 } 1967 1968 1969 /********************************************************************* 1970 * 1971 * 1987 INT s = es->selection_start; 1988 INT e = es->selection_end; 1989 BOOL after_wrap = (es->flags & EF_AFTER_WRAP); 1990 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap); 1991 INT x = SLOWORD(pos); 1992 INT y = SHIWORD(pos); 1993 1994 e = EDIT_CharFromPos(hwnd, es, x, y + es->line_height, &after_wrap); 1995 if (!extend) 1996 s = e; 1997 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap); 1998 EDIT_EM_ScrollCaret(hwnd, es); 1999 } 2000 2001 2002 /********************************************************************* 2003 * 2004 * EDIT_MoveEnd 1972 2005 * 1973 2006 */ 1974 2007 static void EDIT_MoveEnd(HWND hwnd, EDITSTATE *es, BOOL extend) 1975 2008 { 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 } 1988 1989 1990 /********************************************************************* 1991 * 1992 * 2009 BOOL after_wrap = FALSE; 2010 INT e; 2011 2012 /* Pass a high value in x to make sure of receiving the end of the line */ 2013 if (es->style & ES_MULTILINE) 2014 e = EDIT_CharFromPos(hwnd, es, 0x3fffffff, 2015 HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap); 2016 else 2017 e = strlenW(es->text); 2018 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, after_wrap); 2019 EDIT_EM_ScrollCaret(hwnd, es); 2020 } 2021 2022 2023 /********************************************************************* 2024 * 2025 * EDIT_MoveForward 1993 2026 * 1994 2027 */ 1995 2028 static void EDIT_MoveForward(HWND hwnd, EDITSTATE *es, BOOL extend) 1996 2029 { 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 } 2011 2012 2013 /********************************************************************* 2014 * 2015 * 2016 * 2017 * 2030 INT e = es->selection_end; 2031 2032 if (es->text[e]) { 2033 e++; 2034 if ((es->style & ES_MULTILINE) && (es->text[e - 1] == '\r')) { 2035 if (es->text[e] == '\n') 2036 e++; 2037 else if ((es->text[e] == '\r') && (es->text[e + 1] == '\n')) 2038 e += 2; 2039 } 2040 } 2041 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE); 2042 EDIT_EM_ScrollCaret(hwnd, es); 2043 } 2044 2045 2046 /********************************************************************* 2047 * 2048 * EDIT_MoveHome 2049 * 2050 * Home key: move to beginning of line. 2018 2051 * 2019 2052 */ 2020 2053 static void EDIT_MoveHome(HWND hwnd, EDITSTATE *es, BOOL extend) 2021 2054 { 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 } 2033 2034 2035 /********************************************************************* 2036 * 2037 * 2038 * 2039 * 2040 * 2041 * 2055 INT e; 2056 2057 /* Pass the x_offset in x to make sure of receiving the first position of the line */ 2058 if (es->style & ES_MULTILINE) 2059 e = EDIT_CharFromPos(hwnd, es, -es->x_offset, 2060 HIWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL); 2061 else 2062 e = 0; 2063 EDIT_EM_SetSel(hwnd, es, extend ? es->selection_start : e, e, FALSE); 2064 EDIT_EM_ScrollCaret(hwnd, es); 2065 } 2066 2067 2068 /********************************************************************* 2069 * 2070 * EDIT_MovePageDown_ML 2071 * 2072 * Only for multi line controls 2073 * Move the caret one page down, on a column with the nearest 2074 * x coordinate on the screen (might be a different column). 2042 2075 * 2043 2076 */ 2044 2077 static void EDIT_MovePageDown_ML(HWND hwnd, EDITSTATE *es, BOOL extend) 2045 2078 { 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 } 2061 2062 2063 /********************************************************************* 2064 * 2065 * 2066 * 2067 * 2068 * 2069 * 2079 INT s = es->selection_start; 2080 INT e = es->selection_end; 2081 BOOL after_wrap = (es->flags & EF_AFTER_WRAP); 2082 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap); 2083 INT x = SLOWORD(pos); 2084 INT y = SHIWORD(pos); 2085 2086 e = EDIT_CharFromPos(hwnd, es, x, 2087 y + (es->format_rect.bottom - es->format_rect.top), 2088 &after_wrap); 2089 if (!extend) 2090 s = e; 2091 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap); 2092 EDIT_EM_ScrollCaret(hwnd, es); 2093 } 2094 2095 2096 /********************************************************************* 2097 * 2098 * EDIT_MovePageUp_ML 2099 * 2100 * Only for multi line controls 2101 * Move the caret one page up, on a column with the nearest 2102 * x coordinate on the screen (might be a different column). 2070 2103 * 2071 2104 */ 2072 2105 static void EDIT_MovePageUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend) 2073 2106 { 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 } 2089 2090 2091 /********************************************************************* 2092 * 2093 * 2094 * 2095 * 2096 * 2097 * 2107 INT s = es->selection_start; 2108 INT e = es->selection_end; 2109 BOOL after_wrap = (es->flags & EF_AFTER_WRAP); 2110 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap); 2111 INT x = SLOWORD(pos); 2112 INT y = SHIWORD(pos); 2113 2114 e = EDIT_CharFromPos(hwnd, es, x, 2115 y - (es->format_rect.bottom - es->format_rect.top), 2116 &after_wrap); 2117 if (!extend) 2118 s = e; 2119 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap); 2120 EDIT_EM_ScrollCaret(hwnd, es); 2121 } 2122 2123 2124 /********************************************************************* 2125 * 2126 * EDIT_MoveUp_ML 2127 * 2128 * Only for multi line controls 2129 * Move the caret one line up, on a column with the nearest 2130 * x coordinate on the screen (might be a different column). 2098 2131 * 2099 2132 */ 2100 2133 static void EDIT_MoveUp_ML(HWND hwnd, EDITSTATE *es, BOOL extend) 2101 2134 { 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 } 2115 2116 2117 /********************************************************************* 2118 * 2119 * 2135 INT s = es->selection_start; 2136 INT e = es->selection_end; 2137 BOOL after_wrap = (es->flags & EF_AFTER_WRAP); 2138 LRESULT pos = EDIT_EM_PosFromChar(hwnd, es, e, after_wrap); 2139 INT x = SLOWORD(pos); 2140 INT y = SHIWORD(pos); 2141 2142 e = EDIT_CharFromPos(hwnd, es, x, y - es->line_height, &after_wrap); 2143 if (!extend) 2144 s = e; 2145 EDIT_EM_SetSel(hwnd, es, s, e, after_wrap); 2146 EDIT_EM_ScrollCaret(hwnd, es); 2147 } 2148 2149 2150 /********************************************************************* 2151 * 2152 * EDIT_MoveWordBackward 2120 2153 * 2121 2154 */ 2122 2155 static void EDIT_MoveWordBackward(HWND hwnd, EDITSTATE *es, BOOL extend) 2123 2156 { 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 } 2147 2148 2149 /********************************************************************* 2150 * 2151 * 2157 INT s = es->selection_start; 2158 INT e = es->selection_end; 2159 INT l; 2160 INT ll; 2161 INT li; 2162 2163 l = EDIT_EM_LineFromChar(es, e); 2164 ll = EDIT_EM_LineLength(es, e); 2165 li = EDIT_EM_LineIndex(es, l); 2166 if (e - li == 0) { 2167 if (l) { 2168 li = EDIT_EM_LineIndex(es, l - 1); 2169 e = li + EDIT_EM_LineLength(es, li); 2170 } 2171 } else { 2172 e = li + (INT)EDIT_CallWordBreakProc(es, 2173 li, e - li, ll, WB_LEFT); 2174 } 2175 if (!extend) 2176 s = e; 2177 EDIT_EM_SetSel(hwnd, es, s, e, FALSE); 2178 EDIT_EM_ScrollCaret(hwnd, es); 2179 } 2180 2181 2182 /********************************************************************* 2183 * 2184 * EDIT_MoveWordForward 2152 2185 * 2153 2186 */ 2154 2187 static void EDIT_MoveWordForward(HWND hwnd, EDITSTATE *es, BOOL extend) 2155 2188 { 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 } 2177 2178 2179 /********************************************************************* 2180 * 2181 * 2189 INT s = es->selection_start; 2190 INT e = es->selection_end; 2191 INT l; 2192 INT ll; 2193 INT li; 2194 2195 l = EDIT_EM_LineFromChar(es, e); 2196 ll = EDIT_EM_LineLength(es, e); 2197 li = EDIT_EM_LineIndex(es, l); 2198 if (e - li == ll) { 2199 if ((es->style & ES_MULTILINE) && (l != es->line_count - 1)) 2200 e = EDIT_EM_LineIndex(es, l + 1); 2201 } else { 2202 e = li + EDIT_CallWordBreakProc(es, 2203 li, e - li + 1, ll, WB_RIGHT); 2204 } 2205 if (!extend) 2206 s = e; 2207 EDIT_EM_SetSel(hwnd, es, s, e, FALSE); 2208 EDIT_EM_ScrollCaret(hwnd, es); 2209 } 2210 2211 2212 /********************************************************************* 2213 * 2214 * EDIT_PaintLine 2182 2215 * 2183 2216 */ 2184 2217 static void EDIT_PaintLine(HWND hwnd, EDITSTATE *es, HDC dc, INT line, BOOL rev) 2185 2218 { 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 } 2221 2222 2223 /********************************************************************* 2224 * 2225 * 2219 INT s = es->selection_start; 2220 INT e = es->selection_end; 2221 INT li; 2222 INT ll; 2223 INT x; 2224 INT y; 2225 LRESULT pos; 2226 2227 if (es->style & ES_MULTILINE) { 2228 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 2229 if ((line < es->y_offset) || (line > es->y_offset + vlc) || (line >= es->line_count)) 2230 return; 2231 } else if (line) 2232 return; 2233 2234 TRACE("line=%d\n", line); 2235 2236 pos = EDIT_EM_PosFromChar(hwnd, es, EDIT_EM_LineIndex(es, line), FALSE); 2237 x = SLOWORD(pos); 2238 y = SHIWORD(pos); 2239 li = EDIT_EM_LineIndex(es, line); 2240 ll = EDIT_EM_LineLength(es, li); 2241 s = es->selection_start; 2242 e = es->selection_end; 2243 ORDER_INT(s, e); 2244 s = min(li + ll, max(li, s)); 2245 e = min(li + ll, max(li, e)); 2246 if (rev && (s != e) && 2247 ((es->flags & EF_FOCUSED) || (es->style & ES_NOHIDESEL))) { 2248 x += EDIT_PaintText(es, dc, x, y, line, 0, s - li, FALSE); 2249 x += EDIT_PaintText(es, dc, x, y, line, s - li, e - s, TRUE); 2250 x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE); 2251 } else 2252 x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE); 2253 } 2254 2255 2256 /********************************************************************* 2257 * 2258 * EDIT_PaintText 2226 2259 * 2227 2260 */ 2228 2261 static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col, INT count, BOOL rev) 2229 2262 { 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 } 2266 2267 2268 /********************************************************************* 2269 * 2270 * 2263 COLORREF BkColor; 2264 COLORREF TextColor; 2265 INT ret; 2266 INT li; 2267 INT BkMode; 2268 SIZE size; 2269 2270 if (!count) 2271 return 0; 2272 BkMode = GetBkMode(dc); 2273 BkColor = GetBkColor(dc); 2274 TextColor = GetTextColor(dc); 2275 if (rev) { 2276 SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT)); 2277 SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT)); 2278 SetBkMode( dc, OPAQUE); 2279 } 2280 li = EDIT_EM_LineIndex(es, line); 2281 if (es->style & ES_MULTILINE) { 2282 ret = (INT)LOWORD(TabbedTextOutW(dc, x, y, es->text + li + col, count, 2283 es->tabs_count, es->tabs, es->format_rect.left - es->x_offset)); 2284 } else { 2285 LPWSTR text = EDIT_GetPasswordPointer_SL(es); 2286 TextOutW(dc, x, y, text + li + col, count); 2287 GetTextExtentPoint32W(dc, text + li + col, count, &size); 2288 ret = size.cx; 2289 if (es->style & ES_PASSWORD) 2290 HeapFree(GetProcessHeap(), 0, text); 2291 } 2292 if (rev) { 2293 SetBkColor(dc, BkColor); 2294 SetTextColor(dc, TextColor); 2295 SetBkMode( dc, BkMode); 2296 } 2297 return ret; 2298 } 2299 2300 2301 /********************************************************************* 2302 * 2303 * EDIT_SetCaretPos 2271 2304 * 2272 2305 */ 2273 2306 static void EDIT_SetCaretPos(HWND hwnd, EDITSTATE *es, INT pos, 2274 2275 { 2276 2277 2278 } 2279 2280 2281 /********************************************************************* 2282 * 2283 * 2284 * 2285 * note:this is not (exactly) the handler called on EM_SETRECTNP2286 * 2307 BOOL after_wrap) 2308 { 2309 LRESULT res = EDIT_EM_PosFromChar(hwnd, es, pos, after_wrap); 2310 SetCaretPos(SLOWORD(res), SHIWORD(res)); 2311 } 2312 2313 2314 /********************************************************************* 2315 * 2316 * EDIT_SetRectNP 2317 * 2318 * note: this is not (exactly) the handler called on EM_SETRECTNP 2319 * it is also used to set the rect of a single line control 2287 2320 * 2288 2321 */ 2289 2322 static void EDIT_SetRectNP(HWND hwnd, EDITSTATE *es, LPRECT rc) 2290 2323 { 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 } 2334 2335 2336 /********************************************************************* 2337 * 2338 * 2324 CopyRect(&es->format_rect, rc); 2325 if (es->style & WS_BORDER) { 2326 INT bw = GetSystemMetrics(SM_CXBORDER) + 1; 2327 if(TWEAK_WineLook == WIN31_LOOK) 2328 bw += 2; 2329 es->format_rect.left += bw; 2330 es->format_rect.top += bw; 2331 es->format_rect.right -= bw; 2332 es->format_rect.bottom -= bw; 2333 } 2334 es->format_rect.left += es->left_margin; 2335 es->format_rect.right -= es->right_margin; 2336 es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width); 2337 if (es->style & ES_MULTILINE) 2338 { 2339 INT fw, vlc, max_x_offset, max_y_offset; 2340 2341 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 2342 es->format_rect.bottom = es->format_rect.top + max(1, vlc) * es->line_height; 2343 2344 /* correct es->x_offset */ 2345 fw = es->format_rect.right - es->format_rect.left; 2346 max_x_offset = es->text_width - fw; 2347 if(max_x_offset < 0) max_x_offset = 0; 2348 if(es->x_offset > max_x_offset) 2349 es->x_offset = max_x_offset; 2350 2351 /* correct es->y_offset */ 2352 max_y_offset = es->line_count - vlc; 2353 if(max_y_offset < 0) max_y_offset = 0; 2354 if(es->y_offset > max_y_offset) 2355 es->y_offset = max_y_offset; 2356 2357 /* force scroll info update */ 2358 EDIT_UpdateScrollInfo(hwnd, es); 2359 } 2360 else 2361 /* Windows doesn't care to fix text placement for SL controls */ 2362 es->format_rect.bottom = es->format_rect.top + es->line_height; 2363 2364 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) 2365 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0); 2366 } 2367 2368 2369 /********************************************************************* 2370 * 2371 * EDIT_UnlockBuffer 2339 2372 * 2340 2373 */ … … 2346 2379 if(!IsWindow(hwnd)) 2347 2380 { 2348 2349 2350 } 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 } 2438 2439 2440 /********************************************************************* 2441 * 2442 * 2381 WARN("edit hwnd %04x already destroyed\n", hwnd); 2382 return; 2383 } 2384 2385 if (!es) { 2386 ERR("no EDITSTATE ... please report\n"); 2387 return; 2388 } 2389 if (!es->lock_count) { 2390 ERR("lock_count == 0 ... please report\n"); 2391 return; 2392 } 2393 if (!es->text) { 2394 ERR("es->text == 0 ... please report\n"); 2395 return; 2396 } 2397 2398 if (force || (es->lock_count == 1)) { 2399 if (es->hloc32W) { 2400 CHAR *textA = NULL; 2401 BOOL _16bit = FALSE; 2402 UINT countA = 0; 2403 UINT countW = strlenW(es->text) + 1; 2404 2405 if(es->hloc32A) 2406 { 2407 UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL); 2408 TRACE("Synchronizing with 32-bit ANSI buffer\n"); 2409 TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new); 2410 countA = LocalSize(es->hloc32A); 2411 if(countA_new > countA) 2412 { 2413 HLOCAL hloc32A_new; 2414 UINT alloc_size = ROUND_TO_GROW(countA_new); 2415 TRACE("Resizing 32-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size); 2416 hloc32A_new = LocalReAlloc(es->hloc32A, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT); 2417 if(hloc32A_new) 2418 { 2419 es->hloc32A = hloc32A_new; 2420 countA = LocalSize(hloc32A_new); 2421 TRACE("Real new size %d bytes\n", countA); 2422 } 2423 else 2424 WARN("FAILED! Will synchronize partially\n"); 2425 } 2426 textA = LocalLock(es->hloc32A); 2427 } 2428 else if(es->hloc16) 2429 { 2430 UINT countA_new = WideCharToMultiByte(CP_ACP, 0, es->text, countW, NULL, 0, NULL, NULL); 2431 TRACE("Synchronizing with 16-bit ANSI buffer\n"); 2432 TRACE("%d WCHARs translated to %d bytes\n", countW, countA_new); 2433 countA = LOCAL_Size(hInstance, es->hloc16); 2434 if(countA_new > countA) 2435 { 2436 HLOCAL16 hloc16_new; 2437 UINT alloc_size = ROUND_TO_GROW(countA_new); 2438 TRACE("Resizing 16-bit ANSI buffer from %d to %d bytes\n", countA, alloc_size); 2439 hloc16_new = LOCAL_ReAlloc(hInstance, es->hloc16, alloc_size, LMEM_MOVEABLE | LMEM_ZEROINIT); 2440 if(hloc16_new) 2441 { 2442 es->hloc16 = hloc16_new; 2443 countA = LOCAL_Size(hInstance, hloc16_new); 2444 TRACE("Real new size %d bytes\n", countA); 2445 } 2446 else 2447 WARN("FAILED! Will synchronize partially\n"); 2448 } 2449 textA = LOCAL_Lock(hInstance, es->hloc16); 2450 _16bit = TRUE; 2451 } 2452 if(textA) 2453 { 2454 WideCharToMultiByte(CP_ACP, 0, es->text, countW, textA, countA, NULL, NULL); 2455 if(_16bit) 2456 LOCAL_Unlock(hInstance, es->hloc16); 2457 else 2458 LocalUnlock(es->hloc32A); 2459 } 2460 2461 LocalUnlock(es->hloc32W); 2462 es->text = NULL; 2463 } 2464 else { 2465 ERR("no buffer ... please report\n"); 2466 return; 2467 } 2468 } 2469 es->lock_count--; 2470 } 2471 2472 2473 /********************************************************************* 2474 * 2475 * EDIT_UpdateScrollInfo 2443 2476 * 2444 2477 */ … … 2447 2480 if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK)) 2448 2481 { 2449 2450 si.cbSize= sizeof(SCROLLINFO);2451 si.fMask= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;2452 si.nMin= 0;2453 si.nMax= es->line_count - 1;2454 si.nPage= (es->format_rect.bottom - es->format_rect.top) / es->line_height;2455 si.nPos= es->y_offset;2456 2457 2458 2482 SCROLLINFO si; 2483 si.cbSize = sizeof(SCROLLINFO); 2484 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; 2485 si.nMin = 0; 2486 si.nMax = es->line_count - 1; 2487 si.nPage = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 2488 si.nPos = es->y_offset; 2489 TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n", 2490 si.nMin, si.nMax, si.nPage, si.nPos); 2491 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 2459 2492 } 2460 2493 2461 2494 if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK)) 2462 2495 { 2463 2464 si.cbSize= sizeof(SCROLLINFO);2465 si.fMask= SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;2466 si.nMin= 0;2467 si.nMax= es->text_width - 1;2468 si.nPage= es->format_rect.right - es->format_rect.left;2469 si.nPos= es->x_offset;2470 2471 2472 2473 } 2474 } 2475 2476 /********************************************************************* 2477 * 2478 * 2479 * 2480 * 2481 * Note:unlike the specs for a WordBreakProc, this function only2482 * 2483 * 2484 * 2496 SCROLLINFO si; 2497 si.cbSize = sizeof(SCROLLINFO); 2498 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; 2499 si.nMin = 0; 2500 si.nMax = es->text_width - 1; 2501 si.nPage = es->format_rect.right - es->format_rect.left; 2502 si.nPos = es->x_offset; 2503 TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n", 2504 si.nMin, si.nMax, si.nPage, si.nPos); 2505 SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); 2506 } 2507 } 2508 2509 /********************************************************************* 2510 * 2511 * EDIT_WordBreakProc 2512 * 2513 * Find the beginning of words. 2514 * Note: unlike the specs for a WordBreakProc, this function only 2515 * allows to be called without linebreaks between s[0] upto 2516 * s[count - 1]. Remember it is only called 2517 * internally, so we can decide this for ourselves. 2485 2518 * 2486 2519 */ 2487 2520 static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action) 2488 2521 { 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 } 2541 2542 2543 /********************************************************************* 2544 * 2545 * 2522 INT ret = 0; 2523 2524 TRACE("s=%p, index=%d, count=%d, action=%d\n", s, index, count, action); 2525 2526 if(!s) return 0; 2527 2528 switch (action) { 2529 case WB_LEFT: 2530 if (!count) 2531 break; 2532 if (index) 2533 index--; 2534 if (s[index] == ' ') { 2535 while (index && (s[index] == ' ')) 2536 index--; 2537 if (index) { 2538 while (index && (s[index] != ' ')) 2539 index--; 2540 if (s[index] == ' ') 2541 index++; 2542 } 2543 } else { 2544 while (index && (s[index] != ' ')) 2545 index--; 2546 if (s[index] == ' ') 2547 index++; 2548 } 2549 ret = index; 2550 break; 2551 case WB_RIGHT: 2552 if (!count) 2553 break; 2554 if (index) 2555 index--; 2556 if (s[index] == ' ') 2557 while ((index < count) && (s[index] == ' ')) index++; 2558 else { 2559 while (s[index] && (s[index] != ' ') && (index < count)) 2560 index++; 2561 while ((s[index] == ' ') && (index < count)) index++; 2562 } 2563 ret = index; 2564 break; 2565 case WB_ISDELIMITER: 2566 ret = (s[index] == ' '); 2567 break; 2568 default: 2569 ERR("unknown action code, please report !\n"); 2570 break; 2571 } 2572 return ret; 2573 } 2574 2575 2576 /********************************************************************* 2577 * 2578 * EM_CHARFROMPOS 2546 2579 * 2547 2580 * returns line number (not index) in high-order word of result. 2548 2581 * NB : Q137805 is unclear about this. POINT * pointer in lParam apply 2549 2582 * to Richedit, not to the edit control. Original documentation is valid. 2550 * 2551 * 2583 * FIXME: do the specs mean to return -1 if outside client area or 2584 * if outside formatting rectangle ??? 2552 2585 * 2553 2586 */ 2554 2587 static LRESULT EDIT_EM_CharFromPos(HWND hwnd, EDITSTATE *es, INT x, INT y) 2555 2588 { 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 } 2569 2570 2571 /********************************************************************* 2572 * 2573 * 2589 POINT pt; 2590 RECT rc; 2591 INT index; 2592 2593 pt.x = x; 2594 pt.y = y; 2595 GetClientRect(hwnd, &rc); 2596 if (!PtInRect(&rc, pt)) 2597 return -1; 2598 2599 index = EDIT_CharFromPos(hwnd, es, x, y, NULL); 2600 return MAKELONG(index, EDIT_EM_LineFromChar(es, index)); 2601 } 2602 2603 2604 /********************************************************************* 2605 * 2606 * EM_FMTLINES 2574 2607 * 2575 2608 * Enable or disable soft breaks. … … 2577 2610 static BOOL EDIT_EM_FmtLines(EDITSTATE *es, BOOL add_eol) 2578 2611 { 2579 2580 2581 2582 2583 2584 2585 } 2586 2587 2588 /********************************************************************* 2589 * 2590 * 2591 * 2592 * 2593 * 2594 * 2595 * 2596 * 2612 es->flags &= ~EF_USE_SOFTBRK; 2613 if (add_eol) { 2614 es->flags |= EF_USE_SOFTBRK; 2615 FIXME("soft break enabled, not implemented\n"); 2616 } 2617 return add_eol; 2618 } 2619 2620 2621 /********************************************************************* 2622 * 2623 * EM_GETHANDLE 2624 * 2625 * Hopefully this won't fire back at us. 2626 * We always start with a fixed buffer in the local heap. 2627 * Despite of the documentation says that the local heap is used 2628 * only if DS_LOCALEDIT flag is set, NT and 2000 always allocate 2629 * buffer on the local heap. 2597 2630 * 2598 2631 */ 2599 2632 static HLOCAL EDIT_EM_GetHandle(EDITSTATE *es) 2600 2633 { 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2634 HLOCAL hLocal; 2635 2636 if (!(es->style & ES_MULTILINE)) 2637 return 0; 2638 2639 if(es->is_unicode) 2640 hLocal = es->hloc32W; 2641 else 2642 { 2643 if(!es->hloc32A) 2644 { 2645 CHAR *textA; 2646 UINT countA, alloc_size; 2647 TRACE("Allocating 32-bit ANSI alias buffer\n"); 2648 countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL); 2649 alloc_size = ROUND_TO_GROW(countA); 2650 if(!(es->hloc32A = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) 2651 { 2652 ERR("Could not allocate %d bytes for 32-bit ANSI alias buffer\n", alloc_size); 2653 return 0; 2654 } 2655 textA = LocalLock(es->hloc32A); 2656 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL); 2657 LocalUnlock(es->hloc32A); 2658 } 2659 hLocal = es->hloc32A; 2660 } 2661 2662 TRACE("Returning %04X, LocalSize() = %d\n", hLocal, LocalSize(hLocal)); 2663 return hLocal; 2631 2664 } 2632 2665 … … 2634 2667 /********************************************************************* 2635 2668 * 2636 * 2637 * 2638 * 2639 * 2640 * 2641 * 2642 * 2643 * 2644 * 2645 * 2646 * 2647 * 2669 * EM_GETHANDLE16 2670 * 2671 * Hopefully this won't fire back at us. 2672 * We always start with a buffer in 32 bit linear memory. 2673 * However, with this message a 16 bit application requests 2674 * a handle of 16 bit local heap memory, where it expects to find 2675 * the text. 2676 * It's a pitty that from this moment on we have to use this 2677 * local heap, because applications may rely on the handle 2678 * in the future. 2679 * 2680 * In this function we'll try to switch to local heap. 2648 2681 */ 2649 2682 static HLOCAL16 EDIT_EM_GetHandle16(HWND hwnd, EDITSTATE *es) 2650 2683 { 2651 2684 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE ); 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2685 CHAR *textA; 2686 UINT countA, alloc_size; 2687 2688 if (!(es->style & ES_MULTILINE)) 2689 return 0; 2690 2691 if (es->hloc16) 2692 return es->hloc16; 2693 2694 if (!LOCAL_HeapSize(hInstance)) { 2695 if (!LocalInit16(hInstance, 0, 2696 GlobalSize16(hInstance))) { 2697 ERR("could not initialize local heap\n"); 2698 return 0; 2699 } 2700 TRACE("local heap initialized\n"); 2701 } 2702 2703 countA = WideCharToMultiByte(CP_ACP, 0, es->text, -1, NULL, 0, NULL, NULL); 2704 alloc_size = ROUND_TO_GROW(countA); 2705 2706 TRACE("Allocating 16-bit ANSI alias buffer\n"); 2707 if (!(es->hloc16 = LOCAL_Alloc(hInstance, LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) { 2708 ERR("could not allocate new 16 bit buffer\n"); 2709 return 0; 2710 } 2711 2712 if (!(textA = (LPSTR)LOCAL_Lock(hInstance, es->hloc16))) { 2713 ERR("could not lock new 16 bit buffer\n"); 2714 LOCAL_Free(hInstance, es->hloc16); 2715 es->hloc16 = 0; 2716 return 0; 2717 } 2718 2719 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, countA, NULL, NULL); 2720 LOCAL_Unlock(hInstance, es->hloc16); 2721 2722 TRACE("Returning %04X, LocalSize() = %d\n", es->hloc16, LOCAL_Size(hInstance, es->hloc16)); 2723 return es->hloc16; 2691 2724 } 2692 2725 #endif … … 2694 2727 /********************************************************************* 2695 2728 * 2696 * 2729 * EM_GETLINE 2697 2730 * 2698 2731 */ 2699 2732 static INT EDIT_EM_GetLine(EDITSTATE *es, INT line, LPARAM lParam, BOOL unicode) 2700 2733 { 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 } 2741 2742 2743 /********************************************************************* 2744 * 2745 * 2734 LPWSTR src; 2735 INT line_len, dst_len; 2736 INT i; 2737 2738 if (es->style & ES_MULTILINE) { 2739 if (line >= es->line_count) 2740 return 0; 2741 } else 2742 line = 0; 2743 i = EDIT_EM_LineIndex(es, line); 2744 src = es->text + i; 2745 line_len = EDIT_EM_LineLength(es, i); 2746 dst_len = *(WORD *)lParam; 2747 if(unicode) 2748 { 2749 LPWSTR dst = (LPWSTR)lParam; 2750 if(dst_len <= line_len) 2751 { 2752 memcpy(dst, src, dst_len * sizeof(WCHAR)); 2753 return dst_len; 2754 } 2755 else /* Append 0 if enough space */ 2756 { 2757 memcpy(dst, src, line_len * sizeof(WCHAR)); 2758 dst[line_len] = 0; 2759 return line_len; 2760 } 2761 } 2762 else 2763 { 2764 LPSTR dst = (LPSTR)lParam; 2765 INT ret; 2766 ret = WideCharToMultiByte(CP_ACP, 0, src, line_len, dst, dst_len, NULL, NULL); 2767 if(!ret) /* Insufficient buffer size */ 2768 return dst_len; 2769 if(ret < dst_len) /* Append 0 if enough space */ 2770 dst[ret] = 0; 2771 return ret; 2772 } 2773 } 2774 2775 2776 /********************************************************************* 2777 * 2778 * EM_GETSEL 2746 2779 * 2747 2780 */ 2748 2781 static LRESULT EDIT_EM_GetSel(EDITSTATE *es, LPUINT start, LPUINT end) 2749 2782 { 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 } 2760 2761 2762 /********************************************************************* 2763 * 2764 * 2765 * 2766 * 2767 * 2768 * 2769 * 2783 UINT s = es->selection_start; 2784 UINT e = es->selection_end; 2785 2786 ORDER_UINT(s, e); 2787 if (start) 2788 *start = s; 2789 if (end) 2790 *end = e; 2791 return MAKELONG(s, e); 2792 } 2793 2794 2795 /********************************************************************* 2796 * 2797 * EM_GETTHUMB 2798 * 2799 * FIXME: is this right ? (or should it be only VSCROLL) 2800 * (and maybe only for edit controls that really have their 2801 * own scrollbars) (and maybe only for multiline controls ?) 2802 * All in all: very poorly documented 2770 2803 * 2771 2804 */ 2772 2805 static LRESULT EDIT_EM_GetThumb(HWND hwnd, EDITSTATE *es) 2773 2806 { 2774 2775 2776 } 2777 2778 2779 /********************************************************************* 2780 * 2781 * 2807 return MAKELONG(EDIT_WM_VScroll(hwnd, es, EM_GETTHUMB16, 0), 2808 EDIT_WM_HScroll(hwnd, es, EM_GETTHUMB16, 0)); 2809 } 2810 2811 2812 /********************************************************************* 2813 * 2814 * EM_LINEFROMCHAR 2782 2815 * 2783 2816 */ 2784 2817 static INT EDIT_EM_LineFromChar(EDITSTATE *es, INT index) 2785 2818 { 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 } 2806 2807 2808 /********************************************************************* 2809 * 2810 * 2819 INT line; 2820 LINEDEF *line_def; 2821 2822 if (!(es->style & ES_MULTILINE)) 2823 return 0; 2824 if (index > (INT)strlenW(es->text)) 2825 return es->line_count - 1; 2826 if (index == -1) 2827 index = min(es->selection_start, es->selection_end); 2828 2829 line = 0; 2830 line_def = es->first_line_def; 2831 index -= line_def->length; 2832 while ((index >= 0) && line_def->next) { 2833 line++; 2834 line_def = line_def->next; 2835 index -= line_def->length; 2836 } 2837 return line; 2838 } 2839 2840 2841 /********************************************************************* 2842 * 2843 * EM_LINEINDEX 2811 2844 * 2812 2845 */ 2813 2846 static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line) 2814 2847 { 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 } 2841 2842 2843 /********************************************************************* 2844 * 2845 * 2848 INT line_index; 2849 LINEDEF *line_def; 2850 2851 if (!(es->style & ES_MULTILINE)) 2852 return 0; 2853 if (line >= es->line_count) 2854 return -1; 2855 2856 line_index = 0; 2857 line_def = es->first_line_def; 2858 if (line == -1) { 2859 INT index = es->selection_end - line_def->length; 2860 while ((index >= 0) && line_def->next) { 2861 line_index += line_def->length; 2862 line_def = line_def->next; 2863 index -= line_def->length; 2864 } 2865 } else { 2866 while (line > 0) { 2867 line_index += line_def->length; 2868 line_def = line_def->next; 2869 line--; 2870 } 2871 } 2872 return line_index; 2873 } 2874 2875 2876 /********************************************************************* 2877 * 2878 * EM_LINELENGTH 2846 2879 * 2847 2880 */ 2848 2881 static INT EDIT_EM_LineLength(EDITSTATE *es, INT index) 2849 2882 { 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 } 2877 2878 2879 /********************************************************************* 2880 * 2881 * 2882 * 2883 * 2883 LINEDEF *line_def; 2884 2885 if (!(es->style & ES_MULTILINE)) 2886 return strlenW(es->text); 2887 2888 if (index == -1) { 2889 /* get the number of remaining non-selected chars of selected lines */ 2890 INT32 l; /* line number */ 2891 INT32 li; /* index of first char in line */ 2892 INT32 count; 2893 l = EDIT_EM_LineFromChar(es, es->selection_start); 2894 /* # chars before start of selection area */ 2895 count = es->selection_start - EDIT_EM_LineIndex(es, l); 2896 l = EDIT_EM_LineFromChar(es, es->selection_end); 2897 /* # chars after end of selection */ 2898 li = EDIT_EM_LineIndex(es, l); 2899 count += li + EDIT_EM_LineLength(es, li) - es->selection_end; 2900 return count; 2901 } 2902 line_def = es->first_line_def; 2903 index -= line_def->length; 2904 while ((index >= 0) && line_def->next) { 2905 line_def = line_def->next; 2906 index -= line_def->length; 2907 } 2908 return line_def->net_length; 2909 } 2910 2911 2912 /********************************************************************* 2913 * 2914 * EM_LINESCROLL 2915 * 2916 * NOTE: dx is in average character widths, dy - in lines; 2884 2917 * 2885 2918 */ 2886 2919 static BOOL EDIT_EM_LineScroll(HWND hwnd, EDITSTATE *es, INT dx, INT dy) 2887 2920 { 2888 2889 2890 2891 2892 2893 } 2894 2895 /********************************************************************* 2896 * 2897 * 2898 * 2899 * 2900 * 2901 * 2921 if (!(es->style & ES_MULTILINE)) 2922 return FALSE; 2923 2924 dx *= es->char_width; 2925 return EDIT_EM_LineScroll_internal(hwnd, es, dx, dy); 2926 } 2927 2928 /********************************************************************* 2929 * 2930 * EDIT_EM_LineScroll_internal 2931 * 2932 * Version of EDIT_EM_LineScroll for internal use. 2933 * It doesn't refuse if ES_MULTILINE is set and assumes that 2934 * dx is in pixels, dy - in lines. 2902 2935 * 2903 2936 */ 2904 2937 static BOOL EDIT_EM_LineScroll_internal(HWND hwnd, EDITSTATE *es, INT dx, INT dy) 2905 2938 { 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 } 2950 2951 2952 /********************************************************************* 2953 * 2954 * 2939 INT nyoff; 2940 INT x_offset_in_pixels; 2941 2942 if (es->style & ES_MULTILINE) 2943 { 2944 x_offset_in_pixels = es->x_offset; 2945 } 2946 else 2947 { 2948 dy = 0; 2949 x_offset_in_pixels = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->x_offset, FALSE)); 2950 } 2951 2952 if (-dx > x_offset_in_pixels) 2953 dx = -x_offset_in_pixels; 2954 if (dx > es->text_width - x_offset_in_pixels) 2955 dx = es->text_width - x_offset_in_pixels; 2956 nyoff = max(0, es->y_offset + dy); 2957 if (nyoff >= es->line_count) 2958 nyoff = es->line_count - 1; 2959 dy = (es->y_offset - nyoff) * es->line_height; 2960 if (dx || dy) { 2961 RECT rc1; 2962 RECT rc; 2963 2964 es->y_offset = nyoff; 2965 if(es->style & ES_MULTILINE) 2966 es->x_offset += dx; 2967 else 2968 es->x_offset += dx / es->char_width; 2969 2970 GetClientRect(hwnd, &rc1); 2971 IntersectRect(&rc, &rc1, &es->format_rect); 2972 ScrollWindowEx(hwnd, -dx, dy, 2973 NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE); 2974 /* force scroll info update */ 2975 EDIT_UpdateScrollInfo(hwnd, es); 2976 } 2977 if (dx && !(es->flags & EF_HSCROLL_TRACK)) 2978 EDIT_NOTIFY_PARENT(hwnd, es, EN_HSCROLL, "EN_HSCROLL"); 2979 if (dy && !(es->flags & EF_VSCROLL_TRACK)) 2980 EDIT_NOTIFY_PARENT(hwnd, es, EN_VSCROLL, "EN_VSCROLL"); 2981 return TRUE; 2982 } 2983 2984 2985 /********************************************************************* 2986 * 2987 * EM_POSFROMCHAR 2955 2988 * 2956 2989 */ 2957 2990 static LRESULT EDIT_EM_PosFromChar(HWND hwnd, EDITSTATE *es, INT index, BOOL after_wrap) 2958 2991 { 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 } 3013 3014 3015 /********************************************************************* 3016 * 3017 * 3018 * 3019 * 2992 INT len = strlenW(es->text); 2993 INT l; 2994 INT li; 2995 INT x; 2996 INT y = 0; 2997 HDC dc; 2998 HFONT old_font = 0; 2999 SIZE size; 3000 3001 index = min(index, len); 3002 dc = GetDC(hwnd); 3003 if (es->font) 3004 old_font = SelectObject(dc, es->font); 3005 if (es->style & ES_MULTILINE) { 3006 l = EDIT_EM_LineFromChar(es, index); 3007 y = (l - es->y_offset) * es->line_height; 3008 li = EDIT_EM_LineIndex(es, l); 3009 if (after_wrap && (li == index) && l) { 3010 INT l2 = l - 1; 3011 LINEDEF *line_def = es->first_line_def; 3012 while (l2) { 3013 line_def = line_def->next; 3014 l2--; 3015 } 3016 if (line_def->ending == END_WRAP) { 3017 l--; 3018 y -= es->line_height; 3019 li = EDIT_EM_LineIndex(es, l); 3020 } 3021 } 3022 x = LOWORD(GetTabbedTextExtentW(dc, es->text + li, index - li, 3023 es->tabs_count, es->tabs)) - es->x_offset; 3024 } else { 3025 LPWSTR text = EDIT_GetPasswordPointer_SL(es); 3026 if (index < es->x_offset) { 3027 GetTextExtentPoint32W(dc, text + index, 3028 es->x_offset - index, &size); 3029 x = -size.cx; 3030 } else { 3031 GetTextExtentPoint32W(dc, text + es->x_offset, 3032 index - es->x_offset, &size); 3033 x = size.cx; 3034 } 3035 y = 0; 3036 if (es->style & ES_PASSWORD) 3037 HeapFree(GetProcessHeap(), 0, text); 3038 } 3039 x += es->format_rect.left; 3040 y += es->format_rect.top; 3041 if (es->font) 3042 SelectObject(dc, old_font); 3043 ReleaseDC(hwnd, dc); 3044 return MAKELONG((INT16)x, (INT16)y); 3045 } 3046 3047 3048 /********************************************************************* 3049 * 3050 * EM_REPLACESEL 3051 * 3052 * FIXME: handle ES_NUMBER and ES_OEMCONVERT here 3020 3053 * 3021 3054 */ 3022 3055 static void EDIT_EM_ReplaceSel(HWND hwnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update) 3023 3056 { 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 } 3147 3148 3149 /********************************************************************* 3150 * 3151 * 3057 UINT strl = strlenW(lpsz_replace); 3058 UINT tl = strlenW(es->text); 3059 UINT utl; 3060 UINT s; 3061 UINT e; 3062 UINT i; 3063 LPWSTR p; 3064 HRGN hrgn = 0; 3065 3066 TRACE("%s, can_undo %d, send_update %d\n", 3067 debugstr_w(lpsz_replace), can_undo, send_update); 3068 3069 s = es->selection_start; 3070 e = es->selection_end; 3071 3072 if ((s == e) && !strl) 3073 return; 3074 3075 ORDER_UINT(s, e); 3076 3077 if (!EDIT_MakeFit(hwnd, es, tl - (e - s) + strl)) 3078 return; 3079 3080 if (e != s) { 3081 /* there is something to be deleted */ 3082 TRACE("deleting stuff.\n"); 3083 if (can_undo) { 3084 utl = strlenW(es->undo_text); 3085 if (!es->undo_insert_count && (*es->undo_text && (s == es->undo_position))) { 3086 /* undo-buffer is extended to the right */ 3087 EDIT_MakeUndoFit(es, utl + e - s); 3088 strncpyW(es->undo_text + utl, es->text + s, e - s + 1); 3089 (es->undo_text + utl)[e - s] = 0; /* ensure 0 termination */ 3090 } else if (!es->undo_insert_count && (*es->undo_text && (e == es->undo_position))) { 3091 /* undo-buffer is extended to the left */ 3092 EDIT_MakeUndoFit(es, utl + e - s); 3093 for (p = es->undo_text + utl ; p >= es->undo_text ; p--) 3094 p[e - s] = p[0]; 3095 for (i = 0 , p = es->undo_text ; i < e - s ; i++) 3096 p[i] = (es->text + s)[i]; 3097 es->undo_position = s; 3098 } else { 3099 /* new undo-buffer */ 3100 EDIT_MakeUndoFit(es, e - s); 3101 strncpyW(es->undo_text, es->text + s, e - s + 1); 3102 es->undo_text[e - s] = 0; /* ensure 0 termination */ 3103 es->undo_position = s; 3104 } 3105 /* any deletion makes the old insertion-undo invalid */ 3106 es->undo_insert_count = 0; 3107 } else 3108 EDIT_EM_EmptyUndoBuffer(es); 3109 3110 /* now delete */ 3111 strcpyW(es->text + s, es->text + e); 3112 } 3113 if (strl) { 3114 /* there is an insertion */ 3115 if (can_undo) { 3116 if ((s == es->undo_position) || 3117 ((es->undo_insert_count) && 3118 (s == es->undo_position + es->undo_insert_count))) 3119 /* 3120 * insertion is new and at delete position or 3121 * an extension to either left or right 3122 */ 3123 es->undo_insert_count += strl; 3124 else { 3125 /* new insertion undo */ 3126 es->undo_position = s; 3127 es->undo_insert_count = strl; 3128 /* new insertion makes old delete-buffer invalid */ 3129 *es->undo_text = '\0'; 3130 } 3131 } else 3132 EDIT_EM_EmptyUndoBuffer(es); 3133 3134 /* now insert */ 3135 tl = strlenW(es->text); 3136 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)); 3137 for (p = es->text + tl ; p >= es->text + s ; p--) 3138 p[strl] = p[0]; 3139 for (i = 0 , p = es->text + s ; i < strl ; i++) 3140 p[i] = lpsz_replace[i]; 3141 if(es->style & ES_UPPERCASE) 3142 CharUpperBuffW(p, strl); 3143 else if(es->style & ES_LOWERCASE) 3144 CharLowerBuffW(p, strl); 3145 s += strl; 3146 } 3147 if (es->style & ES_MULTILINE) 3148 { 3149 INT s = min(es->selection_start, es->selection_end); 3150 3151 hrgn = CreateRectRgn(0, 0, 0, 0); 3152 EDIT_BuildLineDefs_ML(hwnd, es, s, s + strl, 3153 strl - abs(es->selection_end - es->selection_start), hrgn); 3154 } 3155 else 3156 EDIT_CalcLineWidth_SL(hwnd, es); 3157 3158 EDIT_EM_SetSel(hwnd, es, s, s, FALSE); 3159 es->flags |= EF_MODIFIED; 3160 if (send_update) es->flags |= EF_UPDATE; 3161 EDIT_EM_ScrollCaret(hwnd, es); 3162 3163 /* force scroll info update */ 3164 EDIT_UpdateScrollInfo(hwnd, es); 3165 3166 if (hrgn) 3167 { 3168 EDIT_UpdateTextRegion(hwnd, es, hrgn, TRUE); 3169 DeleteObject(hrgn); 3170 } 3171 else 3172 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3173 3174 if(es->flags & EF_UPDATE) 3175 { 3176 es->flags &= ~EF_UPDATE; 3177 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE"); 3178 } 3179 } 3180 3181 3182 /********************************************************************* 3183 * 3184 * EM_SCROLL 3152 3185 * 3153 3186 */ 3154 3187 static LRESULT EDIT_EM_Scroll(HWND hwnd, EDITSTATE *es, INT action) 3155 3188 { 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 } 3195 3196 3197 /********************************************************************* 3198 * 3199 * 3189 INT dy; 3190 3191 if (!(es->style & ES_MULTILINE)) 3192 return (LRESULT)FALSE; 3193 3194 dy = 0; 3195 3196 switch (action) { 3197 case SB_LINEUP: 3198 if (es->y_offset) 3199 dy = -1; 3200 break; 3201 case SB_LINEDOWN: 3202 if (es->y_offset < es->line_count - 1) 3203 dy = 1; 3204 break; 3205 case SB_PAGEUP: 3206 if (es->y_offset) 3207 dy = -(es->format_rect.bottom - es->format_rect.top) / es->line_height; 3208 break; 3209 case SB_PAGEDOWN: 3210 if (es->y_offset < es->line_count - 1) 3211 dy = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 3212 break; 3213 default: 3214 return (LRESULT)FALSE; 3215 } 3216 if (dy) { 3217 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 3218 /* check if we are going to move too far */ 3219 if(es->y_offset + dy > es->line_count - vlc) 3220 dy = es->line_count - vlc - es->y_offset; 3221 3222 /* Notification is done in EDIT_EM_LineScroll */ 3223 if(dy) 3224 EDIT_EM_LineScroll(hwnd, es, 0, dy); 3225 } 3226 return MAKELONG((INT16)dy, (BOOL16)TRUE); 3227 } 3228 3229 3230 /********************************************************************* 3231 * 3232 * EM_SCROLLCARET 3200 3233 * 3201 3234 */ 3202 3235 static void EDIT_EM_ScrollCaret(HWND hwnd, EDITSTATE *es) 3203 3236 { 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3237 if (es->style & ES_MULTILINE) { 3238 INT l; 3239 INT li; 3240 INT vlc; 3241 INT ww; 3242 INT cw = es->char_width; 3243 INT x; 3244 INT dy = 0; 3245 INT dx = 0; 3246 3247 l = EDIT_EM_LineFromChar(es, es->selection_end); 3248 li = EDIT_EM_LineIndex(es, l); 3249 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP)); 3250 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 3251 if (l >= es->y_offset + vlc) 3252 dy = l - vlc + 1 - es->y_offset; 3253 if (l < es->y_offset) 3254 dy = l - es->y_offset; 3255 ww = es->format_rect.right - es->format_rect.left; 3256 if (x < es->format_rect.left) 3257 dx = x - es->format_rect.left - ww / HSCROLL_FRACTION / cw * cw; 3258 if (x > es->format_rect.right) 3259 dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw; 3260 if (dy || dx) 3261 { 3262 /* check if we are going to move too far */ 3263 if(es->x_offset + dx + ww > es->text_width) 3264 dx = es->text_width - ww - es->x_offset; 3265 if(dx || dy) 3266 EDIT_EM_LineScroll_internal(hwnd, es, dx, dy); 3267 } 3268 } else { 3269 INT x; 3270 INT goal; 3271 INT format_width; 3272 3273 if (!(es->style & ES_AUTOHSCROLL)) 3274 return; 3275 3276 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE)); 3277 format_width = es->format_rect.right - es->format_rect.left; 3278 if (x < es->format_rect.left) { 3279 goal = es->format_rect.left + format_width / HSCROLL_FRACTION; 3280 do { 3281 es->x_offset--; 3282 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE)); 3283 } while ((x < goal) && es->x_offset); 3284 /* FIXME: use ScrollWindow() somehow to improve performance */ 3285 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3286 } else if (x > es->format_rect.right) { 3287 INT x_last; 3288 INT len = strlenW(es->text); 3289 goal = es->format_rect.right - format_width / HSCROLL_FRACTION; 3290 do { 3291 es->x_offset++; 3292 x = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, es->selection_end, FALSE)); 3293 x_last = SLOWORD(EDIT_EM_PosFromChar(hwnd, es, len, FALSE)); 3294 } while ((x > goal) && (x_last > es->format_rect.right)); 3295 /* FIXME: use ScrollWindow() somehow to improve performance */ 3296 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3297 } 3298 } 3266 3299 3267 3300 if(es->flags & EF_FOCUSED) 3268 3269 } 3270 3271 3272 /********************************************************************* 3273 * 3274 * 3275 * 3276 * FIXME:ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???3301 EDIT_SetCaretPos(hwnd, es, es->selection_end, es->flags & EF_AFTER_WRAP); 3302 } 3303 3304 3305 /********************************************************************* 3306 * 3307 * EM_SETHANDLE 3308 * 3309 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ??? 3277 3310 * 3278 3311 */ … … 3281 3314 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE ); 3282 3315 3283 3284 3285 3286 3287 3288 3289 3290 3291 3316 if (!(es->style & ES_MULTILINE)) 3317 return; 3318 3319 if (!hloc) { 3320 WARN("called with NULL handle\n"); 3321 return; 3322 } 3323 3324 EDIT_UnlockBuffer(hwnd, es, TRUE); 3292 3325 3293 3326 #ifndef __WIN32OS2__ 3294 3295 3296 3297 3298 3327 if(es->hloc16) 3328 { 3329 LOCAL_Free(hInstance, es->hloc16); 3330 es->hloc16 = (HLOCAL16)NULL; 3331 } 3299 3332 #endif 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3333 if(es->is_unicode) 3334 { 3335 if(es->hloc32A) 3336 { 3337 LocalFree(es->hloc32A); 3338 es->hloc32A = (HLOCAL)NULL; 3339 } 3340 es->hloc32W = hloc; 3341 } 3342 else 3343 { 3344 INT countW, countA; 3345 HLOCAL hloc32W_new; 3346 WCHAR *textW; 3347 CHAR *textA; 3348 3349 countA = LocalSize(hloc); 3350 textA = LocalLock(hloc); 3351 countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0); 3352 if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR)))) 3353 { 3354 ERR("Could not allocate new unicode buffer\n"); 3355 return; 3356 } 3357 textW = LocalLock(hloc32W_new); 3358 MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW); 3359 LocalUnlock(hloc32W_new); 3360 LocalUnlock(hloc); 3361 3362 if(es->hloc32W) 3363 LocalFree(es->hloc32W); 3364 3365 es->hloc32W = hloc32W_new; 3366 es->hloc32A = hloc; 3367 } 3368 3369 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1; 3370 3371 EDIT_LockBuffer(hwnd, es); 3372 3373 es->x_offset = es->y_offset = 0; 3374 es->selection_start = es->selection_end = 0; 3375 EDIT_EM_EmptyUndoBuffer(es); 3376 es->flags &= ~EF_MODIFIED; 3377 es->flags &= ~EF_UPDATE; 3378 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0); 3379 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3380 EDIT_EM_ScrollCaret(hwnd, es); 3381 /* force scroll info update */ 3382 EDIT_UpdateScrollInfo(hwnd, es); 3350 3383 } 3351 3384 … … 3354 3387 /********************************************************************* 3355 3388 * 3356 * 3357 * 3358 * FIXME:ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ???3389 * EM_SETHANDLE16 3390 * 3391 * FIXME: ES_LOWERCASE, ES_UPPERCASE, ES_OEMCONVERT, ES_NUMBER ??? 3359 3392 * 3360 3393 */ … … 3362 3395 { 3363 3396 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE ); 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3397 INT countW, countA; 3398 HLOCAL hloc32W_new; 3399 WCHAR *textW; 3400 CHAR *textA; 3401 3402 if (!(es->style & ES_MULTILINE)) 3403 return; 3404 3405 if (!hloc) { 3406 WARN("called with NULL handle\n"); 3407 return; 3408 } 3409 3410 EDIT_UnlockBuffer(hwnd, es, TRUE); 3411 3412 if(es->hloc32A) 3413 { 3414 LocalFree(es->hloc32A); 3415 es->hloc32A = (HLOCAL)NULL; 3416 } 3417 3418 countA = LOCAL_Size(hInstance, hloc); 3419 textA = LOCAL_Lock(hInstance, hloc); 3420 countW = MultiByteToWideChar(CP_ACP, 0, textA, countA, NULL, 0); 3421 if(!(hloc32W_new = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, countW * sizeof(WCHAR)))) 3422 { 3423 ERR("Could not allocate new unicode buffer\n"); 3424 return; 3425 } 3426 textW = LocalLock(hloc32W_new); 3427 MultiByteToWideChar(CP_ACP, 0, textA, countA, textW, countW); 3428 LocalUnlock(hloc32W_new); 3429 LOCAL_Unlock(hInstance, hloc); 3430 3431 if(es->hloc32W) 3432 LocalFree(es->hloc32W); 3433 3434 es->hloc32W = hloc32W_new; 3435 es->hloc16 = hloc; 3436 3437 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1; 3438 3439 EDIT_LockBuffer(hwnd, es); 3440 3441 es->x_offset = es->y_offset = 0; 3442 es->selection_start = es->selection_end = 0; 3443 EDIT_EM_EmptyUndoBuffer(es); 3444 es->flags &= ~EF_MODIFIED; 3445 es->flags &= ~EF_UPDATE; 3446 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0); 3447 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3448 EDIT_EM_ScrollCaret(hwnd, es); 3449 /* force scroll info update */ 3450 EDIT_UpdateScrollInfo(hwnd, es); 3418 3451 } 3419 3452 #endif … … 3421 3454 /********************************************************************* 3422 3455 * 3423 * 3424 * 3425 * 3426 * 3456 * EM_SETLIMITTEXT 3457 * 3458 * FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF 3459 * However, the windows version is not complied to yet in all of edit.c 3427 3460 * 3428 3461 */ 3429 3462 static void EDIT_EM_SetLimitText(EDITSTATE *es, INT limit) 3430 3463 { 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 } 3443 3444 3445 /********************************************************************* 3446 * 3447 * 3464 if (es->style & ES_MULTILINE) { 3465 if (limit) 3466 es->buffer_limit = min(limit, BUFLIMIT_MULTI); 3467 else 3468 es->buffer_limit = BUFLIMIT_MULTI; 3469 } else { 3470 if (limit) 3471 es->buffer_limit = min(limit, BUFLIMIT_SINGLE); 3472 else 3473 es->buffer_limit = BUFLIMIT_SINGLE; 3474 } 3475 } 3476 3477 3478 /********************************************************************* 3479 * 3480 * EM_SETMARGINS 3448 3481 * 3449 3482 * EC_USEFONTINFO is used as a left or right value i.e. lParam and not as an … … 3453 3486 */ 3454 3487 static void EDIT_EM_SetMargins(EDITSTATE *es, INT action, 3455 3456 { 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 } 3472 3473 3474 /********************************************************************* 3475 * 3476 * 3488 INT left, INT right) 3489 { 3490 if (action & EC_LEFTMARGIN) { 3491 if (left != EC_USEFONTINFO) 3492 es->left_margin = left; 3493 else 3494 es->left_margin = es->char_width / 3; 3495 } 3496 3497 if (action & EC_RIGHTMARGIN) { 3498 if (right != EC_USEFONTINFO) 3499 es->right_margin = right; 3500 else 3501 es->right_margin = es->char_width / 3; 3502 } 3503 TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin); 3504 } 3505 3506 3507 /********************************************************************* 3508 * 3509 * EM_SETPASSWORDCHAR 3477 3510 * 3478 3511 */ … … 3481 3514 LONG style; 3482 3515 3483 3484 3485 3486 3487 3516 if (es->style & ES_MULTILINE) 3517 return; 3518 3519 if (es->password_char == c) 3520 return; 3488 3521 3489 3522 style = GetWindowLongA( hwnd, GWL_STYLE ); 3490 3491 3523 es->password_char = c; 3524 if (c) { 3492 3525 SetWindowLongA( hwnd, GWL_STYLE, style | ES_PASSWORD ); 3493 3526 es->style |= ES_PASSWORD; 3494 3527 } else { 3495 3528 SetWindowLongA( hwnd, GWL_STYLE, style & ~ES_PASSWORD ); 3496 3529 es->style &= ~ES_PASSWORD; 3497 3498 3499 } 3500 3501 3502 /********************************************************************* 3503 * 3504 * 3505 * 3506 * note:unlike the specs say: the order of start and end3507 * 3508 * 3530 } 3531 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3532 } 3533 3534 3535 /********************************************************************* 3536 * 3537 * EDIT_EM_SetSel 3538 * 3539 * note: unlike the specs say: the order of start and end 3540 * _is_ preserved in Windows. (i.e. start can be > end) 3541 * In other words: this handler is OK 3509 3542 * 3510 3543 */ 3511 3544 static void EDIT_EM_SetSel(HWND hwnd, EDITSTATE *es, UINT start, UINT end, BOOL after_wrap) 3512 3545 { 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3546 UINT old_start = es->selection_start; 3547 UINT old_end = es->selection_end; 3548 UINT len = strlenW(es->text); 3549 3550 if (start == (UINT)-1) { 3551 start = es->selection_end; 3552 end = es->selection_end; 3553 } else { 3554 start = min(start, len); 3555 end = min(end, len); 3556 } 3557 es->selection_start = start; 3558 es->selection_end = end; 3559 if (after_wrap) 3560 es->flags |= EF_AFTER_WRAP; 3561 else 3562 es->flags &= ~EF_AFTER_WRAP; 3530 3563 /* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */ 3531 3564 ORDER_UINT(start, end); … … 3533 3566 ORDER_UINT(start, old_start); 3534 3567 ORDER_UINT(old_start, old_end); 3535 3568 if (end != old_start) 3536 3569 { 3537 3570 /* … … 3552 3585 EDIT_InvalidateText(hwnd, es, end, old_end); 3553 3586 } 3554 3587 } 3555 3588 else EDIT_InvalidateText(hwnd, es, start, old_end); 3556 3589 } … … 3559 3592 /********************************************************************* 3560 3593 * 3561 * 3594 * EM_SETTABSTOPS 3562 3595 * 3563 3596 */ 3564 3597 static BOOL EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs) 3565 3598 { 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 } 3579 3580 3581 /********************************************************************* 3582 * 3583 * 3599 if (!(es->style & ES_MULTILINE)) 3600 return FALSE; 3601 if (es->tabs) 3602 HeapFree(GetProcessHeap(), 0, es->tabs); 3603 es->tabs_count = count; 3604 if (!count) 3605 es->tabs = NULL; 3606 else { 3607 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)); 3608 memcpy(es->tabs, tabs, count * sizeof(INT)); 3609 } 3610 return TRUE; 3611 } 3612 3613 3614 /********************************************************************* 3615 * 3616 * EM_SETTABSTOPS16 3584 3617 * 3585 3618 */ 3586 3619 static BOOL EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs) 3587 3620 { 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 } 3603 3604 3605 /********************************************************************* 3606 * 3607 * 3621 if (!(es->style & ES_MULTILINE)) 3622 return FALSE; 3623 if (es->tabs) 3624 HeapFree(GetProcessHeap(), 0, es->tabs); 3625 es->tabs_count = count; 3626 if (!count) 3627 es->tabs = NULL; 3628 else { 3629 INT i; 3630 es->tabs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)); 3631 for (i = 0 ; i < count ; i++) 3632 es->tabs[i] = *tabs++; 3633 } 3634 return TRUE; 3635 } 3636 3637 3638 /********************************************************************* 3639 * 3640 * EM_SETWORDBREAKPROC 3608 3641 * 3609 3642 */ 3610 3643 static void EDIT_EM_SetWordBreakProc(HWND hwnd, EDITSTATE *es, LPARAM lParam) 3611 3644 { 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3645 if (es->word_break_proc == (void *)lParam) 3646 return; 3647 3648 es->word_break_proc = (void *)lParam; 3649 es->word_break_proc16 = NULL; 3650 3651 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) { 3652 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0); 3653 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3654 } 3622 3655 } 3623 3656 … … 3626 3659 /********************************************************************* 3627 3660 * 3628 * 3661 * EM_SETWORDBREAKPROC16 3629 3662 * 3630 3663 */ 3631 3664 static void EDIT_EM_SetWordBreakProc16(HWND hwnd, EDITSTATE *es, EDITWORDBREAKPROC16 wbp) 3632 3665 { 3633 3634 3635 3636 3637 3638 3639 3640 3641 3666 if (es->word_break_proc16 == wbp) 3667 return; 3668 3669 es->word_break_proc = NULL; 3670 es->word_break_proc16 = wbp; 3671 if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL)) { 3672 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0); 3673 EDIT_UpdateText(hwnd, es, NULL, TRUE); 3674 } 3642 3675 } 3643 3676 #endif … … 3645 3678 /********************************************************************* 3646 3679 * 3647 * 3680 * EM_UNDO / WM_UNDO 3648 3681 * 3649 3682 */ 3650 3683 static BOOL EDIT_EM_Undo(HWND hwnd, EDITSTATE *es) 3651 3684 { 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3685 INT ulength; 3686 LPWSTR utext; 3687 3688 /* Protect read-only edit control from modification */ 3689 if(es->style & ES_READONLY) 3690 return FALSE; 3691 3692 ulength = strlenW(es->undo_text); 3693 utext = HeapAlloc(GetProcessHeap(), 0, (ulength + 1) * sizeof(WCHAR)); 3694 3695 strcpyW(utext, es->undo_text); 3696 3697 TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n", 3698 es->undo_insert_count, debugstr_w(utext)); 3699 3700 EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE); 3701 EDIT_EM_EmptyUndoBuffer(es); 3702 EDIT_EM_ReplaceSel(hwnd, es, TRUE, utext, FALSE); 3703 EDIT_EM_SetSel(hwnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE); 3671 3704 /* send the notification after the selection start and end are set */ 3672 3705 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE"); 3673 3674 3675 3676 3677 3678 3679 } 3680 3681 3682 /********************************************************************* 3683 * 3684 * 3706 EDIT_EM_ScrollCaret(hwnd, es); 3707 HeapFree(GetProcessHeap(), 0, utext); 3708 3709 TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n", 3710 es->undo_insert_count, debugstr_w(es->undo_text)); 3711 return TRUE; 3712 } 3713 3714 3715 /********************************************************************* 3716 * 3717 * WM_CHAR 3685 3718 * 3686 3719 */ … … 3689 3722 BOOL control; 3690 3723 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 } 3752 3753 3754 /********************************************************************* 3755 * 3756 * 3724 /* Protect read-only edit control from modification */ 3725 if(es->style & ES_READONLY) 3726 return; 3727 3728 control = GetKeyState(VK_CONTROL) & 0x8000; 3729 3730 switch (c) { 3731 case '\r': 3732 /* If the edit doesn't want the return and it's not a multiline edit, do nothing */ 3733 if(!(es->style & ES_MULTILINE) && !(es->style & ES_WANTRETURN)) 3734 break; 3735 case '\n': 3736 if (es->style & ES_MULTILINE) { 3737 if (es->style & ES_READONLY) { 3738 EDIT_MoveHome(hwnd, es, FALSE); 3739 EDIT_MoveDown_ML(hwnd, es, FALSE); 3740 } else { 3741 static const WCHAR cr_lfW[] = {'\r','\n',0}; 3742 EDIT_EM_ReplaceSel(hwnd, es, TRUE, cr_lfW, TRUE); 3743 } 3744 } 3745 break; 3746 case '\t': 3747 if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY)) 3748 { 3749 static const WCHAR tabW[] = {'\t',0}; 3750 EDIT_EM_ReplaceSel(hwnd, es, TRUE, tabW, TRUE); 3751 } 3752 break; 3753 case VK_BACK: 3754 if (!(es->style & ES_READONLY) && !control) { 3755 if (es->selection_start != es->selection_end) 3756 EDIT_WM_Clear(hwnd, es); 3757 else { 3758 /* delete character left of caret */ 3759 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE); 3760 EDIT_MoveBackward(hwnd, es, TRUE); 3761 EDIT_WM_Clear(hwnd, es); 3762 } 3763 } 3764 break; 3765 case 0x03: /* ^C */ 3766 SendMessageW(hwnd, WM_COPY, 0, 0); 3767 break; 3768 case 0x16: /* ^V */ 3769 SendMessageW(hwnd, WM_PASTE, 0, 0); 3770 break; 3771 case 0x18: /* ^X */ 3772 SendMessageW(hwnd, WM_CUT, 0, 0); 3773 break; 3774 3775 default: 3776 if (!(es->style & ES_READONLY) && (c >= ' ') && (c != 127)) { 3777 WCHAR str[2]; 3778 str[0] = c; 3779 str[1] = '\0'; 3780 EDIT_EM_ReplaceSel(hwnd, es, TRUE, str, TRUE); 3781 } 3782 break; 3783 } 3784 } 3785 3786 3787 /********************************************************************* 3788 * 3789 * WM_COMMAND 3757 3790 * 3758 3791 */ 3759 3792 static void EDIT_WM_Command(HWND hwnd, EDITSTATE *es, INT code, INT id, HWND control) 3760 3793 { 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 } 3789 3790 3791 /********************************************************************* 3792 * 3793 * 3794 * 3795 * 3796 * 3797 * 3798 * 3799 * 3800 * 3801 * 3802 * 3803 * 3804 * 3794 if (code || control) 3795 return; 3796 3797 switch (id) { 3798 case EM_UNDO: 3799 EDIT_EM_Undo(hwnd, es); 3800 break; 3801 case WM_CUT: 3802 EDIT_WM_Cut(hwnd, es); 3803 break; 3804 case WM_COPY: 3805 EDIT_WM_Copy(hwnd, es); 3806 break; 3807 case WM_PASTE: 3808 EDIT_WM_Paste(hwnd, es); 3809 break; 3810 case WM_CLEAR: 3811 EDIT_WM_Clear(hwnd, es); 3812 break; 3813 case EM_SETSEL: 3814 EDIT_EM_SetSel(hwnd, es, 0, (UINT)-1, FALSE); 3815 EDIT_EM_ScrollCaret(hwnd, es); 3816 break; 3817 default: 3818 ERR("unknown menu item, please report\n"); 3819 break; 3820 } 3821 } 3822 3823 3824 /********************************************************************* 3825 * 3826 * WM_CONTEXTMENU 3827 * 3828 * Note: the resource files resource/sysres_??.rc cannot define a 3829 * single popup menu. Hence we use a (dummy) menubar 3830 * containing the single popup menu as its first item. 3831 * 3832 * FIXME: the message identifiers have been chosen arbitrarily, 3833 * hence we use MF_BYPOSITION. 3834 * We might as well use the "real" values (anybody knows ?) 3835 * The menu definition is in resources/sysres_??.rc. 3836 * Once these are OK, we better use MF_BYCOMMAND here 3837 * (as we do in EDIT_WM_Command()). 3805 3838 * 3806 3839 */ 3807 3840 static void EDIT_WM_ContextMenu(HWND hwnd, EDITSTATE *es, INT x, INT y) 3808 3841 { 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 } 3832 3833 3834 /********************************************************************* 3835 * 3836 * 3842 HMENU menu = LoadMenuA(GetModuleHandleA("USER32"), "EDITMENU"); 3843 HMENU popup = GetSubMenu(menu, 0); 3844 UINT start = es->selection_start; 3845 UINT end = es->selection_end; 3846 3847 ORDER_UINT(start, end); 3848 3849 /* undo */ 3850 EnableMenuItem(popup, 0, MF_BYPOSITION | (EDIT_EM_CanUndo(es) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); 3851 /* cut */ 3852 EnableMenuItem(popup, 2, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); 3853 /* copy */ 3854 EnableMenuItem(popup, 3, MF_BYPOSITION | ((end - start) && !(es->style & ES_PASSWORD) ? MF_ENABLED : MF_GRAYED)); 3855 /* paste */ 3856 EnableMenuItem(popup, 4, MF_BYPOSITION | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); 3857 /* delete */ 3858 EnableMenuItem(popup, 5, MF_BYPOSITION | ((end - start) && !(es->style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); 3859 /* select all */ 3860 EnableMenuItem(popup, 7, MF_BYPOSITION | (start || (end != strlenW(es->text)) ? MF_ENABLED : MF_GRAYED)); 3861 3862 TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, hwnd, NULL); 3863 DestroyMenu(menu); 3864 } 3865 3866 3867 /********************************************************************* 3868 * 3869 * WM_COPY 3837 3870 * 3838 3871 */ 3839 3872 static void EDIT_WM_Copy(HWND hwnd, EDITSTATE *es) 3840 3873 { 3841 INT s = es->selection_start; 3842 INT e = es->selection_end; 3843 HGLOBAL hdst; 3844 LPWSTR dst; 3845 3846 if (e == s) 3847 return; 3848 ORDER_INT(s, e); 3849 hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)(e - s + 1) * sizeof(WCHAR)); 3850 dst = GlobalLock(hdst); 3851 strncpyW(dst, es->text + s, e - s); 3852 dst[e - s] = 0; /* ensure 0 termination */ 3853 TRACE("%s\n", debugstr_w(dst)); 3854 GlobalUnlock(hdst); 3855 OpenClipboard(hwnd); 3856 EmptyClipboard(); 3857 SetClipboardData(CF_UNICODETEXT, hdst); 3858 CloseClipboard(); 3859 } 3860 3861 3862 /********************************************************************* 3863 * 3864 * WM_CREATE 3874 INT s = es->selection_start; 3875 INT e = es->selection_end; 3876 HGLOBAL hdst; 3877 LPWSTR dst; 3878 3879 if (e == s) 3880 return; 3881 ORDER_INT(s, e); 3882 hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (DWORD)(e - s + 1) * sizeof(WCHAR)); 3883 dst = GlobalLock(hdst); 3884 strncpyW(dst, es->text + s, e - s); 3885 dst[e - s ] = 0; /* ensure 0 termination */ 3886 TRACE("%s\n", debugstr_w(dst)); 3887 3888 GlobalUnlock(hdst); 3889 OpenClipboard(hwnd); 3890 EmptyClipboard(); 3891 SetClipboardData(CF_UNICODETEXT, hdst); 3892 CloseClipboard(); 3893 } 3894 3895 3896 /********************************************************************* 3897 * 3898 * WM_CREATE 3865 3899 * 3866 3900 */ 3867 3901 static LRESULT EDIT_WM_Create(HWND hwnd, EDITSTATE *es, LPCWSTR name) 3868 3902 { 3869 3903 TRACE("%s\n", debugstr_w(name)); 3870 3904 /* 3871 * 3872 * 3873 * 3874 * 3905 * To initialize some final structure members, we call some helper 3906 * functions. However, since the EDITSTATE is not consistent (i.e. 3907 * not fully initialized), we should be very careful which 3908 * functions can be called, and in what order. 3875 3909 */ 3876 3910 EDIT_WM_SetFont(hwnd, es, 0, FALSE); … … 3878 3912 3879 3913 if (name && *name) { 3880 3881 3914 EDIT_EM_ReplaceSel(hwnd, es, FALSE, name, FALSE); 3915 /* if we insert text to the editline, the text scrolls out 3882 3916 * of the window, as the caret is placed after the insert 3883 3917 * pos normally; thus we reset es->selection... to 0 and 3884 3918 * update caret 3885 3919 */ 3886 3920 es->selection_start = es->selection_end = 0; 3887 3921 /* send the notification after the selection start and end are set */ 3888 3922 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE"); 3889 3923 EDIT_EM_ScrollCaret(hwnd, es); 3890 3924 } 3891 3925 /* force scroll info update */ … … 3897 3931 /********************************************************************* 3898 3932 * 3899 * 3933 * WM_DESTROY 3900 3934 * 3901 3935 */ … … 3903 3937 { 3904 3938 HINSTANCE hInstance = GetWindowLongA( hwnd, GWL_HINSTANCE ); 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3939 LINEDEF *pc, *pp; 3940 3941 if (es->hloc32W) { 3942 while (LocalUnlock(es->hloc32W)) ; 3943 LocalFree(es->hloc32W); 3944 } 3945 if (es->hloc32A) { 3946 while (LocalUnlock(es->hloc32A)) ; 3947 LocalFree(es->hloc32A); 3948 } 3915 3949 #ifndef __WIN32OS2__ 3916 3917 3918 3919 3950 if (es->hloc16) { 3951 while (LOCAL_Unlock(hInstance, es->hloc16)) ; 3952 LOCAL_Free(hInstance, es->hloc16); 3953 } 3920 3954 #endif 3921 3922 3923 3924 3925 3926 3927 3955 pc = es->first_line_def; 3956 while (pc) 3957 { 3958 pp = pc->next; 3959 HeapFree(GetProcessHeap(), 0, pc); 3960 pc = pp; 3961 } 3928 3962 3929 3963 SetWindowLongA( hwnd, 0, 0 ); 3930 3931 } 3932 3933 3934 /********************************************************************* 3935 * 3936 * 3964 HeapFree(GetProcessHeap(), 0, es); 3965 } 3966 3967 3968 /********************************************************************* 3969 * 3970 * WM_ERASEBKGND 3937 3971 * 3938 3972 */ 3939 3973 static LRESULT EDIT_WM_EraseBkGnd(HWND hwnd, EDITSTATE *es, HDC dc) 3940 3974 { 3941 3942 3975 HBRUSH brush; 3976 RECT rc; 3943 3977 3944 3978 if ( get_app_version() >= 0x40000 &&( … … 3951 3985 brush = (HBRUSH)GetStockObject(WHITE_BRUSH); 3952 3986 3953 3954 3955 3956 3957 * FIXME:specs say that we should UnrealizeObject() the brush,3958 *but the specs of UnrealizeObject() say that we shouldn't3959 *unrealize a stock object. The default brush that3960 *DefWndProc() returns is ... a stock object.3961 3962 3963 3964 } 3965 3966 3967 /********************************************************************* 3968 * 3969 * 3987 GetClientRect(hwnd, &rc); 3988 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); 3989 GetClipBox(dc, &rc); 3990 /* 3991 * FIXME: specs say that we should UnrealizeObject() the brush, 3992 * but the specs of UnrealizeObject() say that we shouldn't 3993 * unrealize a stock object. The default brush that 3994 * DefWndProc() returns is ... a stock object. 3995 */ 3996 FillRect(dc, &rc, brush); 3997 return -1; 3998 } 3999 4000 4001 /********************************************************************* 4002 * 4003 * WM_GETTEXT 3970 4004 * 3971 4005 */ … … 3976 4010 if(unicode) 3977 4011 { 3978 3979 3980 3981 4012 LPWSTR textW = (LPWSTR)lParam; 4013 strncpyW(textW, es->text, count); 4014 textW[count - 1] = 0; /* ensure 0 termination */ 4015 return strlenW(textW); 3982 4016 } 3983 4017 else 3984 4018 { 3985 LPSTR textA = (LPSTR)lParam; 3986 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL); 3987 textA[count - 1] = 0; /* ensure 0 termination */ 3988 return strlen(textA); 3989 } 3990 } 3991 3992 /********************************************************************* 3993 * 3994 * WM_HSCROLL 4019 LPSTR textA = (LPSTR)lParam; 4020 WideCharToMultiByte(CP_ACP, 0, es->text, -1, textA, count, NULL, NULL); 4021 #ifdef __WIN32OS2__ 4022 lstrtrunc( textA, count ); 4023 #else 4024 textA[count - 1] = 0; /* ensure 0 termination */ 4025 #endif 4026 return strlen(textA); 4027 } 4028 } 4029 4030 /********************************************************************* 4031 * 4032 * WM_HSCROLL 3995 4033 * 3996 4034 */ 3997 4035 static LRESULT EDIT_WM_HScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos) 3998 4036 { 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 *FIXME : the next two are undocumented !4083 *Are we doing the right thing ?4084 *At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,4085 *although it's also a regular control message.4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4037 INT dx; 4038 INT fw; 4039 4040 if (!(es->style & ES_MULTILINE)) 4041 return 0; 4042 4043 if (!(es->style & ES_AUTOHSCROLL)) 4044 return 0; 4045 4046 dx = 0; 4047 fw = es->format_rect.right - es->format_rect.left; 4048 switch (action) { 4049 case SB_LINELEFT: 4050 TRACE("SB_LINELEFT\n"); 4051 if (es->x_offset) 4052 dx = -es->char_width; 4053 break; 4054 case SB_LINERIGHT: 4055 TRACE("SB_LINERIGHT\n"); 4056 if (es->x_offset < es->text_width) 4057 dx = es->char_width; 4058 break; 4059 case SB_PAGELEFT: 4060 TRACE("SB_PAGELEFT\n"); 4061 if (es->x_offset) 4062 dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width; 4063 break; 4064 case SB_PAGERIGHT: 4065 TRACE("SB_PAGERIGHT\n"); 4066 if (es->x_offset < es->text_width) 4067 dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width; 4068 break; 4069 case SB_LEFT: 4070 TRACE("SB_LEFT\n"); 4071 if (es->x_offset) 4072 dx = -es->x_offset; 4073 break; 4074 case SB_RIGHT: 4075 TRACE("SB_RIGHT\n"); 4076 if (es->x_offset < es->text_width) 4077 dx = es->text_width - es->x_offset; 4078 break; 4079 case SB_THUMBTRACK: 4080 TRACE("SB_THUMBTRACK %d\n", pos); 4081 es->flags |= EF_HSCROLL_TRACK; 4082 if(es->style & WS_HSCROLL) 4083 dx = pos - es->x_offset; 4084 else 4085 { 4086 INT fw, new_x; 4087 /* Sanity check */ 4088 if(pos < 0 || pos > 100) return 0; 4089 /* Assume default scroll range 0-100 */ 4090 fw = es->format_rect.right - es->format_rect.left; 4091 new_x = pos * (es->text_width - fw) / 100; 4092 dx = es->text_width ? (new_x - es->x_offset) : 0; 4093 } 4094 break; 4095 case SB_THUMBPOSITION: 4096 TRACE("SB_THUMBPOSITION %d\n", pos); 4097 es->flags &= ~EF_HSCROLL_TRACK; 4098 if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_HSCROLL) 4099 dx = pos - es->x_offset; 4100 else 4101 { 4102 INT fw, new_x; 4103 /* Sanity check */ 4104 if(pos < 0 || pos > 100) return 0; 4105 /* Assume default scroll range 0-100 */ 4106 fw = es->format_rect.right - es->format_rect.left; 4107 new_x = pos * (es->text_width - fw) / 100; 4108 dx = es->text_width ? (new_x - es->x_offset) : 0; 4109 } 4110 if (!dx) { 4111 /* force scroll info update */ 4112 EDIT_UpdateScrollInfo(hwnd, es); 4113 EDIT_NOTIFY_PARENT(hwnd, es, EN_HSCROLL, "EN_HSCROLL"); 4114 } 4115 break; 4116 case SB_ENDSCROLL: 4117 TRACE("SB_ENDSCROLL\n"); 4118 break; 4119 /* 4120 * FIXME : the next two are undocumented ! 4121 * Are we doing the right thing ? 4122 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way, 4123 * although it's also a regular control message. 4124 */ 4125 case EM_GETTHUMB: /* this one is used by NT notepad */ 4126 case EM_GETTHUMB16: 4127 { 4128 LRESULT ret; 4129 if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_HSCROLL) 4130 ret = GetScrollPos(hwnd, SB_HORZ); 4131 else 4132 { 4133 /* Assume default scroll range 0-100 */ 4134 INT fw = es->format_rect.right - es->format_rect.left; 4135 ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0; 4136 } 4137 TRACE("EM_GETTHUMB: returning %ld\n", ret); 4138 return ret; 4139 } 4140 case EM_LINESCROLL16: 4141 TRACE("EM_LINESCROLL16\n"); 4142 dx = pos; 4143 break; 4144 4145 default: 4146 ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n", 4109 4147 action, action); 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 } 4123 4124 4125 /********************************************************************* 4126 * 4127 * 4148 return 0; 4149 } 4150 if (dx) 4151 { 4152 INT fw = es->format_rect.right - es->format_rect.left; 4153 /* check if we are going to move too far */ 4154 if(es->x_offset + dx + fw > es->text_width) 4155 dx = es->text_width - fw - es->x_offset; 4156 if(dx) 4157 EDIT_EM_LineScroll_internal(hwnd, es, dx, 0); 4158 } 4159 return 0; 4160 } 4161 4162 4163 /********************************************************************* 4164 * 4165 * EDIT_CheckCombo 4128 4166 * 4129 4167 */ … … 4143 4181 4144 4182 TRACE_(combo)("[%04x]: handling msg %04x (%04x)\n", 4145 4183 hwnd, (UINT16)msg, (UINT16)key); 4146 4184 4147 4185 if (key == VK_UP || key == VK_DOWN) … … 4185 4223 /********************************************************************* 4186 4224 * 4187 * 4188 * 4189 * 4190 * 4225 * WM_KEYDOWN 4226 * 4227 * Handling of special keys that don't produce a WM_CHAR 4228 * (i.e. non-printable keys) & Backspace & Delete 4191 4229 * 4192 4230 */ 4193 4231 static LRESULT EDIT_WM_KeyDown(HWND hwnd, EDITSTATE *es, INT key) 4194 4232 { 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 } 4301 4302 4303 /********************************************************************* 4304 * 4305 * 4233 BOOL shift; 4234 BOOL control; 4235 4236 if (GetKeyState(VK_MENU) & 0x8000) 4237 return 0; 4238 4239 shift = GetKeyState(VK_SHIFT) & 0x8000; 4240 control = GetKeyState(VK_CONTROL) & 0x8000; 4241 4242 switch (key) { 4243 case VK_F4: 4244 case VK_UP: 4245 if (EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key) || key == VK_F4) 4246 break; 4247 4248 /* fall through */ 4249 case VK_LEFT: 4250 if ((es->style & ES_MULTILINE) && (key == VK_UP)) 4251 EDIT_MoveUp_ML(hwnd, es, shift); 4252 else 4253 if (control) 4254 EDIT_MoveWordBackward(hwnd, es, shift); 4255 else 4256 EDIT_MoveBackward(hwnd, es, shift); 4257 break; 4258 case VK_DOWN: 4259 if (EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key)) 4260 break; 4261 /* fall through */ 4262 case VK_RIGHT: 4263 if ((es->style & ES_MULTILINE) && (key == VK_DOWN)) 4264 EDIT_MoveDown_ML(hwnd, es, shift); 4265 else if (control) 4266 EDIT_MoveWordForward(hwnd, es, shift); 4267 else 4268 EDIT_MoveForward(hwnd, es, shift); 4269 break; 4270 case VK_HOME: 4271 EDIT_MoveHome(hwnd, es, shift); 4272 break; 4273 case VK_END: 4274 EDIT_MoveEnd(hwnd, es, shift); 4275 break; 4276 case VK_PRIOR: 4277 if (es->style & ES_MULTILINE) 4278 EDIT_MovePageUp_ML(hwnd, es, shift); 4279 else 4280 EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key); 4281 break; 4282 case VK_NEXT: 4283 if (es->style & ES_MULTILINE) 4284 EDIT_MovePageDown_ML(hwnd, es, shift); 4285 else 4286 EDIT_CheckCombo(hwnd, es, WM_KEYDOWN, key); 4287 break; 4288 case VK_DELETE: 4289 if (!(es->style & ES_READONLY) && !(shift && control)) { 4290 if (es->selection_start != es->selection_end) { 4291 if (shift) 4292 EDIT_WM_Cut(hwnd, es); 4293 else 4294 EDIT_WM_Clear(hwnd, es); 4295 } else { 4296 if (shift) { 4297 /* delete character left of caret */ 4298 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE); 4299 EDIT_MoveBackward(hwnd, es, TRUE); 4300 EDIT_WM_Clear(hwnd, es); 4301 } else if (control) { 4302 /* delete to end of line */ 4303 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE); 4304 EDIT_MoveEnd(hwnd, es, TRUE); 4305 EDIT_WM_Clear(hwnd, es); 4306 } else { 4307 /* delete character right of caret */ 4308 EDIT_EM_SetSel(hwnd, es, (UINT)-1, 0, FALSE); 4309 EDIT_MoveForward(hwnd, es, TRUE); 4310 EDIT_WM_Clear(hwnd, es); 4311 } 4312 } 4313 } 4314 break; 4315 case VK_INSERT: 4316 if (shift) { 4317 if (!(es->style & ES_READONLY)) 4318 EDIT_WM_Paste(hwnd, es); 4319 } else if (control) 4320 EDIT_WM_Copy(hwnd, es); 4321 break; 4322 case VK_RETURN: 4323 /* If the edit doesn't want the return send a message to the default object */ 4324 if(!(es->style & ES_WANTRETURN)) 4325 { 4326 HWND hwndParent = GetParent(hwnd); 4327 DWORD dw = SendMessageW( hwndParent, DM_GETDEFID, 0, 0 ); 4328 if (HIWORD(dw) == DC_HASDEFID) 4329 { 4330 SendMessageW( hwndParent, WM_COMMAND, 4331 MAKEWPARAM( LOWORD(dw), BN_CLICKED ), 4332 (LPARAM)GetDlgItem( hwndParent, LOWORD(dw) ) ); 4333 } 4334 } 4335 break; 4336 } 4337 return 0; 4338 } 4339 4340 4341 /********************************************************************* 4342 * 4343 * WM_KILLFOCUS 4306 4344 * 4307 4345 */ 4308 4346 static LRESULT EDIT_WM_KillFocus(HWND hwnd, EDITSTATE *es) 4309 4347 { 4310 4311 4312 4313 4314 4315 4316 } 4317 4318 4319 /********************************************************************* 4320 * 4321 * 4322 * 4323 * 4348 es->flags &= ~EF_FOCUSED; 4349 DestroyCaret(); 4350 if(!(es->style & ES_NOHIDESEL)) 4351 EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end); 4352 EDIT_NOTIFY_PARENT(hwnd, es, EN_KILLFOCUS, "EN_KILLFOCUS"); 4353 return 0; 4354 } 4355 4356 4357 /********************************************************************* 4358 * 4359 * WM_LBUTTONDBLCLK 4360 * 4361 * The caret position has been set on the WM_LBUTTONDOWN message 4324 4362 * 4325 4363 */ 4326 4364 static LRESULT EDIT_WM_LButtonDblClk(HWND hwnd, EDITSTATE *es) 4327 4365 { 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 } 4346 4347 4348 /********************************************************************* 4349 * 4350 * 4366 INT s; 4367 INT e = es->selection_end; 4368 INT l; 4369 INT li; 4370 INT ll; 4371 4372 if (!(es->flags & EF_FOCUSED)) 4373 return 0; 4374 4375 l = EDIT_EM_LineFromChar(es, e); 4376 li = EDIT_EM_LineIndex(es, l); 4377 ll = EDIT_EM_LineLength(es, e); 4378 s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT); 4379 e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT); 4380 EDIT_EM_SetSel(hwnd, es, s, e, FALSE); 4381 EDIT_EM_ScrollCaret(hwnd, es); 4382 return 0; 4383 } 4384 4385 4386 /********************************************************************* 4387 * 4388 * WM_LBUTTONDOWN 4351 4389 * 4352 4390 */ 4353 4391 static LRESULT EDIT_WM_LButtonDown(HWND hwnd, EDITSTATE *es, DWORD keys, INT x, INT y) 4354 4392 { 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 } 4371 4372 4373 /********************************************************************* 4374 * 4375 * 4393 INT e; 4394 BOOL after_wrap; 4395 4396 if (!(es->flags & EF_FOCUSED)) 4397 return 0; 4398 4399 es->bCaptureState = TRUE; 4400 SetCapture(hwnd); 4401 EDIT_ConfinePoint(es, &x, &y); 4402 e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap); 4403 EDIT_EM_SetSel(hwnd, es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap); 4404 EDIT_EM_ScrollCaret(hwnd, es); 4405 es->region_posx = es->region_posy = 0; 4406 SetTimer(hwnd, 0, 100, NULL); 4407 return 0; 4408 } 4409 4410 4411 /********************************************************************* 4412 * 4413 * WM_LBUTTONUP 4376 4414 * 4377 4415 */ … … 4379 4417 { 4380 4418 #ifdef __WIN32OS2__ 4381 4382 4383 4384 4419 if (es->bCaptureState) { 4420 KillTimer(hwndSelf, 0); 4421 if(GetCapture() == hwndSelf) ReleaseCapture(); 4422 } 4385 4423 #else 4386 4387 4388 4389 4424 if (es->bCaptureState && GetCapture() == hwndSelf) { 4425 KillTimer(hwndSelf, 0); 4426 ReleaseCapture(); 4427 } 4390 4428 #endif 4391 4392 4393 } 4394 4395 4396 /********************************************************************* 4397 * 4398 * 4429 es->bCaptureState = FALSE; 4430 return 0; 4431 } 4432 4433 4434 /********************************************************************* 4435 * 4436 * WM_MBUTTONDOWN 4399 4437 * 4400 4438 */ … … 4408 4446 /********************************************************************* 4409 4447 * 4410 * 4448 * WM_MOUSEMOVE 4411 4449 * 4412 4450 */ 4413 4451 static LRESULT EDIT_WM_MouseMove(HWND hwnd, EDITSTATE *es, INT x, INT y) 4414 4452 { 4415 4416 4417 4418 4419 4420 4421 4422 4423 *FIXME: gotta do some scrolling if outside client4424 *area. Maybe reset the timer ?4425 4426 4427 4428 4429 4430 4431 4432 4433 } 4434 4435 4436 /********************************************************************* 4437 * 4438 * 4453 INT e; 4454 BOOL after_wrap; 4455 INT prex, prey; 4456 4457 if (GetCapture() != hwnd) 4458 return 0; 4459 4460 /* 4461 * FIXME: gotta do some scrolling if outside client 4462 * area. Maybe reset the timer ? 4463 */ 4464 prex = x; prey = y; 4465 EDIT_ConfinePoint(es, &x, &y); 4466 es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0); 4467 es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0); 4468 e = EDIT_CharFromPos(hwnd, es, x, y, &after_wrap); 4469 EDIT_EM_SetSel(hwnd, es, es->selection_start, e, after_wrap); 4470 return 0; 4471 } 4472 4473 4474 /********************************************************************* 4475 * 4476 * WM_NCCREATE 4439 4477 * 4440 4478 * See also EDIT_WM_StyleChanged … … 4442 4480 static LRESULT EDIT_WM_NCCreate(HWND hwnd, DWORD style, HWND hwndParent, BOOL unicode) 4443 4481 { 4444 4445 4446 4447 4448 4449 4450 4451 4482 EDITSTATE *es; 4483 UINT alloc_size; 4484 4485 TRACE("Creating %s edit control, style = %08lx\n", 4486 unicode ? "Unicode" : "ANSI", style); 4487 4488 if (!(es = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*es)))) 4489 return FALSE; 4452 4490 SetWindowLongA( hwnd, 0, (LONG)es ); 4453 4491 … … 4458 4496 */ 4459 4497 4460 4461 4498 es->is_unicode = unicode; 4499 es->style = style; 4462 4500 4463 4501 es->bEnableState = !(style & WS_DISABLED); 4464 4502 4465 4466 4467 4468 4469 4503 /* Save parent, which will be notified by EN_* messages */ 4504 es->hwndParent = hwndParent; 4505 4506 if (es->style & ES_COMBO) 4507 es->hwndListBox = GetDlgItem(hwndParent, ID_CB_LISTBOX); 4470 4508 4471 4509 /* Number overrides lowercase overrides uppercase (at least it … … 4478 4516 es->style &= ~ES_UPPERCASE; 4479 4517 } 4480 4481 4482 4483 4484 4485 4486 4487 4518 if (es->style & ES_MULTILINE) { 4519 es->buffer_limit = BUFLIMIT_MULTI; 4520 if (es->style & WS_VSCROLL) 4521 es->style |= ES_AUTOVSCROLL; 4522 if (es->style & WS_HSCROLL) 4523 es->style |= ES_AUTOHSCROLL; 4524 es->style &= ~ES_PASSWORD; 4525 if ((es->style & ES_CENTER) || (es->style & ES_RIGHT)) { 4488 4526 /* Confirmed - RIGHT overrides CENTER */ 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4527 if (es->style & ES_RIGHT) 4528 es->style &= ~ES_CENTER; 4529 es->style &= ~WS_HSCROLL; 4530 es->style &= ~ES_AUTOHSCROLL; 4531 } 4532 4533 /* FIXME: for now, all multi line controls are AUTOVSCROLL */ 4534 es->style |= ES_AUTOVSCROLL; 4535 } else { 4536 es->buffer_limit = BUFLIMIT_SINGLE; 4499 4537 if (WIN31_LOOK == TWEAK_WineLook || 4500 4538 WIN95_LOOK == TWEAK_WineLook) { 4501 4502 4539 es->style &= ~ES_CENTER; 4540 es->style &= ~ES_RIGHT; 4503 4541 } else { 4504 4505 4542 if (es->style & ES_RIGHT) 4543 es->style &= ~ES_CENTER; 4506 4544 } 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4545 es->style &= ~WS_HSCROLL; 4546 es->style &= ~WS_VSCROLL; 4547 es->style &= ~ES_AUTOVSCROLL; 4548 es->style &= ~ES_WANTRETURN; 4549 if (es->style & ES_PASSWORD) 4550 es->password_char = '*'; 4551 4552 /* FIXME: for now, all single line controls are AUTOHSCROLL */ 4553 es->style |= ES_AUTOHSCROLL; 4554 } 4555 4556 alloc_size = ROUND_TO_GROW((es->buffer_size + 1) * sizeof(WCHAR)); 4557 if(!(es->hloc32W = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, alloc_size))) 4558 return FALSE; 4559 es->buffer_size = LocalSize(es->hloc32W)/sizeof(WCHAR) - 1; 4560 4561 if (!(es->undo_text = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (es->buffer_size + 1) * sizeof(WCHAR)))) 4562 return FALSE; 4563 es->undo_buffer_size = es->buffer_size; 4564 4565 if (es->style & ES_MULTILINE) 4566 if (!(es->first_line_def = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINEDEF)))) 4567 return FALSE; 4568 es->line_count = 1; 4569 4570 /* 4571 * In Win95 look and feel, the WS_BORDER style is replaced by the 4572 * WS_EX_CLIENTEDGE style for the edit control. This gives the edit 4573 * control a non client area. Not always. This coordinates in some 4536 4574 * way with the window creation code in dialog.c When making 4537 4575 * modifications please ensure that the code still works for edit 4538 4576 * controls created directly with style 0x50800000, exStyle 0 ( 4539 4577 * which should have a single pixel border) 4540 4541 4542 4543 4544 4545 4546 4547 4578 */ 4579 if (TWEAK_WineLook != WIN31_LOOK) 4580 { 4581 es->style &= ~WS_BORDER; 4582 } 4583 else 4584 { 4585 if ((es->style & WS_BORDER) && !(es->style & WS_DLGFRAME)) 4548 4586 SetWindowLongA( hwnd, GWL_STYLE, 4549 4587 GetWindowLongA( hwnd, GWL_STYLE ) & ~WS_BORDER ); 4550 4551 4552 4553 } 4554 4555 /********************************************************************* 4556 * 4557 * 4588 } 4589 4590 return TRUE; 4591 } 4592 4593 /********************************************************************* 4594 * 4595 * WM_PAINT 4558 4596 * 4559 4597 */ 4560 4598 static void EDIT_WM_Paint(HWND hwnd, EDITSTATE *es, WPARAM wParam) 4561 4599 { 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4600 PAINTSTRUCT ps; 4601 INT i; 4602 HDC dc; 4603 HFONT old_font = 0; 4604 RECT rc; 4605 RECT rcLine; 4606 RECT rcRgn; 4607 BOOL rev = es->bEnableState && 4608 ((es->flags & EF_FOCUSED) || 4609 (es->style & ES_NOHIDESEL)); 4572 4610 if (!wParam) 4573 4611 dc = BeginPaint(hwnd, &ps); 4574 4612 else 4575 4613 dc = (HDC) wParam; 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4614 if(es->style & WS_BORDER) { 4615 GetClientRect(hwnd, &rc); 4616 if(es->style & ES_MULTILINE) { 4617 if(es->style & WS_HSCROLL) rc.bottom++; 4618 if(es->style & WS_VSCROLL) rc.right++; 4619 } 4620 Rectangle(dc, rc.left, rc.top, rc.right, rc.bottom); 4621 } 4622 IntersectClipRect(dc, es->format_rect.left, 4623 es->format_rect.top, 4624 es->format_rect.right, 4625 es->format_rect.bottom); 4626 if (es->style & ES_MULTILINE) { 4627 GetClientRect(hwnd, &rc); 4628 IntersectClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); 4629 } 4630 if (es->font) 4631 old_font = SelectObject(dc, es->font); 4594 4632 if ( get_app_version() >= 0x40000 &&( 4595 4633 !es->bEnableState || (es->style & ES_READONLY))) … … 4598 4636 EDIT_SEND_CTLCOLOR(hwnd, dc); 4599 4637 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4638 if (!es->bEnableState) 4639 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT)); 4640 GetClipBox(dc, &rcRgn); 4641 if (es->style & ES_MULTILINE) { 4642 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 4643 for (i = es->y_offset ; i <= min(es->y_offset + vlc, es->y_offset + es->line_count - 1) ; i++) { 4644 EDIT_GetLineRect(hwnd, es, i, 0, -1, &rcLine); 4645 if (IntersectRect(&rc, &rcRgn, &rcLine)) 4646 EDIT_PaintLine(hwnd, es, dc, i, rev); 4647 } 4648 } else { 4649 EDIT_GetLineRect(hwnd, es, 0, 0, -1, &rcLine); 4650 if (IntersectRect(&rc, &rcRgn, &rcLine)) 4651 EDIT_PaintLine(hwnd, es, dc, 0, rev); 4652 } 4653 if (es->font) 4654 SelectObject(dc, old_font); 4617 4655 4618 4656 if (!wParam) … … 4623 4661 /********************************************************************* 4624 4662 * 4625 * 4663 * WM_PASTE 4626 4664 * 4627 4665 */ 4628 4666 static void EDIT_WM_Paste(HWND hwnd, EDITSTATE *es) 4629 4667 { 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 } 4645 4646 4647 /********************************************************************* 4648 * 4649 * 4668 HGLOBAL hsrc; 4669 LPWSTR src; 4670 4671 /* Protect read-only edit control from modification */ 4672 if(es->style & ES_READONLY) 4673 return; 4674 4675 OpenClipboard(hwnd); 4676 if ((hsrc = GetClipboardData(CF_UNICODETEXT))) { 4677 src = (LPWSTR)GlobalLock(hsrc); 4678 EDIT_EM_ReplaceSel(hwnd, es, TRUE, src, TRUE); 4679 GlobalUnlock(hsrc); 4680 } 4681 CloseClipboard(); 4682 } 4683 4684 4685 /********************************************************************* 4686 * 4687 * WM_SETFOCUS 4650 4688 * 4651 4689 */ 4652 4690 static void EDIT_WM_SetFocus(HWND hwnd, EDITSTATE *es) 4653 4691 { 4654 4655 4656 4657 4658 4659 4660 4661 4662 } 4663 4664 4665 /********************************************************************* 4666 * 4667 * 4692 es->flags |= EF_FOCUSED; 4693 CreateCaret(hwnd, 0, 2, es->line_height); 4694 EDIT_SetCaretPos(hwnd, es, es->selection_end, 4695 es->flags & EF_AFTER_WRAP); 4696 if(!(es->style & ES_NOHIDESEL)) 4697 EDIT_InvalidateText(hwnd, es, es->selection_start, es->selection_end); 4698 ShowCaret(hwnd); 4699 EDIT_NOTIFY_PARENT(hwnd, es, EN_SETFOCUS, "EN_SETFOCUS"); 4700 } 4701 4702 4703 /********************************************************************* 4704 * 4705 * WM_SETFONT 4668 4706 * 4669 4707 * With Win95 look the margins are set to default font value unless … … 4674 4712 static void EDIT_WM_SetFont(HWND hwnd, EDITSTATE *es, HFONT font, BOOL redraw) 4675 4713 { 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 } 4714 4715 4716 /********************************************************************* 4717 * 4718 * 4714 TEXTMETRICW tm; 4715 HDC dc; 4716 HFONT old_font = 0; 4717 RECT r; 4718 4719 es->font = font; 4720 dc = GetDC(hwnd); 4721 if (font) 4722 old_font = SelectObject(dc, font); 4723 GetTextMetricsW(dc, &tm); 4724 es->line_height = tm.tmHeight; 4725 es->char_width = tm.tmAveCharWidth; 4726 if (font) 4727 SelectObject(dc, old_font); 4728 ReleaseDC(hwnd, dc); 4729 if (font && (TWEAK_WineLook > WIN31_LOOK)) 4730 EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN, 4731 EC_USEFONTINFO, EC_USEFONTINFO); 4732 4733 /* Force the recalculation of the format rect for each font change */ 4734 GetClientRect(hwnd, &r); 4735 EDIT_SetRectNP(hwnd, es, &r); 4736 4737 if (es->style & ES_MULTILINE) 4738 EDIT_BuildLineDefs_ML(hwnd, es, 0, strlenW(es->text), 0, (HRGN)0); 4739 else 4740 EDIT_CalcLineWidth_SL(hwnd, es); 4741 4742 if (redraw) 4743 EDIT_UpdateText(hwnd, es, NULL, TRUE); 4744 if (es->flags & EF_FOCUSED) { 4745 DestroyCaret(); 4746 CreateCaret(hwnd, 0, 2, es->line_height); 4747 EDIT_SetCaretPos(hwnd, es, es->selection_end, 4748 es->flags & EF_AFTER_WRAP); 4749 ShowCaret(hwnd); 4750 } 4751 } 4752 4753 4754 /********************************************************************* 4755 * 4756 * WM_SETTEXT 4719 4757 * 4720 4758 * NOTES … … 4731 4769 4732 4770 if(unicode) 4733 4771 text = (LPWSTR)lParam; 4734 4772 else if (lParam) 4735 4773 { 4736 4737 4738 4739 4740 } 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4774 LPCSTR textA = (LPCSTR)lParam; 4775 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0); 4776 if((text = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR)))) 4777 MultiByteToWideChar(CP_ACP, 0, textA, -1, text, countW); 4778 } 4779 4780 EDIT_EM_SetSel(hwnd, es, 0, (UINT)-1, FALSE); 4781 if (text) { 4782 TRACE("%s\n", debugstr_w(text)); 4783 EDIT_EM_ReplaceSel(hwnd, es, FALSE, text, FALSE); 4784 if(!unicode) 4785 HeapFree(GetProcessHeap(), 0, text); 4786 } else { 4787 static const WCHAR empty_stringW[] = {0}; 4788 TRACE("<NULL>\n"); 4789 EDIT_EM_ReplaceSel(hwnd, es, FALSE, empty_stringW, FALSE); 4790 } 4791 es->x_offset = 0; 4792 es->flags &= ~EF_MODIFIED; 4793 EDIT_EM_SetSel(hwnd, es, 0, 0, FALSE); 4756 4794 /* Send the notification after the selection start and end have been set 4757 4795 * edit control doesn't send notification on WM_SETTEXT 4758 4796 * if it is multiline, or it is part of combobox 4759 4797 */ 4760 4798 if( !((es->style & ES_MULTILINE) || es->hwndListBox)) 4761 4799 { 4762 4800 EDIT_NOTIFY_PARENT(hwnd, es, EN_CHANGE, "EN_CHANGE"); 4763 4801 EDIT_NOTIFY_PARENT(hwnd, es, EN_UPDATE, "EN_UPDATE"); 4764 4802 } 4765 4766 } 4767 4768 4769 /********************************************************************* 4770 * 4771 * 4803 EDIT_EM_ScrollCaret(hwnd, es); 4804 } 4805 4806 4807 /********************************************************************* 4808 * 4809 * WM_SIZE 4772 4810 * 4773 4811 */ 4774 4812 static void EDIT_WM_Size(HWND hwnd, EDITSTATE *es, UINT action, INT width, INT height) 4775 4813 { 4776 4777 4778 4779 4780 4781 4782 4783 } 4784 4785 4786 /********************************************************************* 4787 * 4788 * 4814 if ((action == SIZE_MAXIMIZED) || (action == SIZE_RESTORED)) { 4815 RECT rc; 4816 TRACE("width = %d, height = %d\n", width, height); 4817 SetRect(&rc, 0, 0, width, height); 4818 EDIT_SetRectNP(hwnd, es, &rc); 4819 EDIT_UpdateText(hwnd, es, NULL, TRUE); 4820 } 4821 } 4822 4823 4824 /********************************************************************* 4825 * 4826 * WM_STYLECHANGED 4789 4827 * 4790 4828 * This message is sent by SetWindowLong on having changed either the Style … … 4846 4884 /********************************************************************* 4847 4885 * 4848 * 4886 * WM_SYSKEYDOWN 4849 4887 * 4850 4888 */ 4851 4889 static LRESULT EDIT_WM_SysKeyDown(HWND hwnd, EDITSTATE *es, INT key, DWORD key_data) 4852 4890 { 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 } 4863 4864 4865 /********************************************************************* 4866 * 4867 * 4891 if ((key == VK_BACK) && (key_data & 0x2000)) { 4892 if (EDIT_EM_CanUndo(es)) 4893 EDIT_EM_Undo(hwnd, es); 4894 return 0; 4895 } else if (key == VK_UP || key == VK_DOWN) { 4896 if (EDIT_CheckCombo(hwnd, es, WM_SYSKEYDOWN, key)) 4897 return 0; 4898 } 4899 return DefWindowProcW(hwnd, WM_SYSKEYDOWN, (WPARAM)key, (LPARAM)key_data); 4900 } 4901 4902 4903 /********************************************************************* 4904 * 4905 * WM_TIMER 4868 4906 * 4869 4907 */ 4870 4908 static void EDIT_WM_Timer(HWND hwnd, EDITSTATE *es) 4871 4909 { 4872 4873 4874 4875 4876 4910 if (es->region_posx < 0) { 4911 EDIT_MoveBackward(hwnd, es, TRUE); 4912 } else if (es->region_posx > 0) { 4913 EDIT_MoveForward(hwnd, es, TRUE); 4914 } 4877 4915 /* 4878 * 4879 * 4880 */ 4881 } 4882 4883 /********************************************************************* 4884 * 4885 * 4916 * FIXME: gotta do some vertical scrolling here, like 4917 * EDIT_EM_LineScroll(hwnd, 0, 1); 4918 */ 4919 } 4920 4921 /********************************************************************* 4922 * 4923 * WM_VSCROLL 4886 4924 * 4887 4925 */ 4888 4926 static LRESULT EDIT_WM_VScroll(HWND hwnd, EDITSTATE *es, INT action, INT pos) 4889 4927 { 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 *FIXME : the next two are undocumented !4962 *Are we doing the right thing ?4963 *At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,4964 *although it's also a regular control message.4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4928 INT dy; 4929 4930 if (!(es->style & ES_MULTILINE)) 4931 return 0; 4932 4933 if (!(es->style & ES_AUTOVSCROLL)) 4934 return 0; 4935 4936 dy = 0; 4937 switch (action) { 4938 case SB_LINEUP: 4939 case SB_LINEDOWN: 4940 case SB_PAGEUP: 4941 case SB_PAGEDOWN: 4942 TRACE("action %d\n", action); 4943 EDIT_EM_Scroll(hwnd, es, action); 4944 return 0; 4945 case SB_TOP: 4946 TRACE("SB_TOP\n"); 4947 dy = -es->y_offset; 4948 break; 4949 case SB_BOTTOM: 4950 TRACE("SB_BOTTOM\n"); 4951 dy = es->line_count - 1 - es->y_offset; 4952 break; 4953 case SB_THUMBTRACK: 4954 TRACE("SB_THUMBTRACK %d\n", pos); 4955 es->flags |= EF_VSCROLL_TRACK; 4956 if(es->style & WS_VSCROLL) 4957 dy = pos - es->y_offset; 4958 else 4959 { 4960 /* Assume default scroll range 0-100 */ 4961 INT vlc, new_y; 4962 /* Sanity check */ 4963 if(pos < 0 || pos > 100) return 0; 4964 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 4965 new_y = pos * (es->line_count - vlc) / 100; 4966 dy = es->line_count ? (new_y - es->y_offset) : 0; 4967 TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n", 4968 es->line_count, es->y_offset, pos, dy); 4969 } 4970 break; 4971 case SB_THUMBPOSITION: 4972 TRACE("SB_THUMBPOSITION %d\n", pos); 4973 es->flags &= ~EF_VSCROLL_TRACK; 4974 if(es->style & WS_VSCROLL) 4975 dy = pos - es->y_offset; 4976 else 4977 { 4978 /* Assume default scroll range 0-100 */ 4979 INT vlc, new_y; 4980 /* Sanity check */ 4981 if(pos < 0 || pos > 100) return 0; 4982 vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 4983 new_y = pos * (es->line_count - vlc) / 100; 4984 dy = es->line_count ? (new_y - es->y_offset) : 0; 4985 TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n", 4986 es->line_count, es->y_offset, pos, dy); 4987 } 4988 if (!dy) 4989 { 4990 /* force scroll info update */ 4991 EDIT_UpdateScrollInfo(hwnd, es); 4992 EDIT_NOTIFY_PARENT(hwnd, es, EN_VSCROLL, "EN_VSCROLL"); 4993 } 4994 break; 4995 case SB_ENDSCROLL: 4996 TRACE("SB_ENDSCROLL\n"); 4997 break; 4998 /* 4999 * FIXME : the next two are undocumented ! 5000 * Are we doing the right thing ? 5001 * At least Win 3.1 Notepad makes use of EM_GETTHUMB this way, 5002 * although it's also a regular control message. 5003 */ 5004 case EM_GETTHUMB: /* this one is used by NT notepad */ 5005 case EM_GETTHUMB16: 5006 { 5007 LRESULT ret; 5008 if(GetWindowLongA( hwnd, GWL_STYLE ) & WS_VSCROLL) 5009 ret = GetScrollPos(hwnd, SB_VERT); 5010 else 5011 { 5012 /* Assume default scroll range 0-100 */ 5013 INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height; 5014 ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0; 5015 } 5016 TRACE("EM_GETTHUMB: returning %ld\n", ret); 5017 return ret; 5018 } 5019 case EM_LINESCROLL16: 5020 TRACE("EM_LINESCROLL16 %d\n", pos); 5021 dy = pos; 5022 break; 5023 5024 default: 5025 ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n", 4988 5026 action, action); 4989 4990 4991 4992 4993 4994 } 4995 4996 /********************************************************************* 4997 * 4998 * 5027 return 0; 5028 } 5029 if (dy) 5030 EDIT_EM_LineScroll(hwnd, es, 0, dy); 5031 return 0; 5032 } 5033 5034 /********************************************************************* 5035 * 5036 * EDIT_UpdateText 4999 5037 * 5000 5038 */ … … 5008 5046 /********************************************************************* 5009 5047 * 5010 * 5048 * EDIT_UpdateText 5011 5049 * 5012 5050 */
Note:
See TracChangeset
for help on using the changeset viewer.