comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/Text.d @ 0:6dd524f61e62

add dwt win and basic java stuff
author Frank Benoit <benoit@tionex.de>
date Mon, 02 Mar 2009 14:44:16 +0100
parents
children 2e09b0e6857a
comparison
equal deleted inserted replaced
-1:000000000000 0:6dd524f61e62
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module org.eclipse.swt.widgets.Text;
14
15
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.SWTException;
18 import org.eclipse.swt.events.ModifyListener;
19 import org.eclipse.swt.events.SelectionEvent;
20 import org.eclipse.swt.events.SelectionListener;
21 import org.eclipse.swt.events.VerifyListener;
22 import org.eclipse.swt.graphics.Font;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.graphics.Rectangle;
25 import org.eclipse.swt.internal.win32.OS;
26
27 import org.eclipse.swt.widgets.Scrollable;
28 import org.eclipse.swt.widgets.TypedListener;
29 import org.eclipse.swt.widgets.Event;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.swt.widgets.Control;
33
34 import java.lang.all;
35
36 /**
37 * Instances of this class are selectable user interface
38 * objects that allow the user to enter and modify text.
39 * Text controls can be either single or multi-line.
40 * When a text control is created with a border, the
41 * operating system includes a platform specific inset
42 * around the contents of the control. When created
43 * without a border, an effort is made to remove the
44 * inset such that the preferred size of the control
45 * is the same size as the contents.
46 * <p>
47 * <dl>
48 * <dt><b>Styles:</b></dt>
49 * <dd>CANCEL, CENTER, LEFT, MULTI, PASSWORD, SEARCH, SINGLE, RIGHT, READ_ONLY, WRAP</dd>
50 * <dt><b>Events:</b></dt>
51 * <dd>DefaultSelection, Modify, Verify</dd>
52 * </dl>
53 * <p>
54 * Note: Only one of the styles MULTI and SINGLE may be specified,
55 * and only one of the styles LEFT, CENTER, and RIGHT may be specified.
56 * </p><p>
57 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
58 * </p>
59 *
60 * @see <a href="http://www.eclipse.org/swt/snippets/#text">Text snippets</a>
61 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
62 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
63 */
64 public class Text : Scrollable {
65
66 alias Scrollable.computeSize computeSize;
67 alias Scrollable.dragDetect dragDetect;
68 alias Scrollable.sendKeyEvent sendKeyEvent;
69 alias Scrollable.setBounds setBounds;
70
71 int tabs, oldStart, oldEnd;
72 bool doubleClick, ignoreModify, ignoreVerify, ignoreCharacter;
73 String message;
74
75 /**
76 * The maximum number of characters that can be entered
77 * into a text widget.
78 * <p>
79 * Note that this value is platform dependent, based upon
80 * the native widget implementation.
81 * </p>
82 */
83 private static int LIMIT_;
84 public static int LIMIT(){
85 assert( static_this_completed );
86 return LIMIT_;
87 }
88
89 /**
90 * The delimiter used by multi-line text widgets. When text
91 * is queried and from the widget, it will be delimited using
92 * this delimiter.
93 */
94 public static const String DELIMITER = "\r\n";
95
96 /*
97 * This code is intentionally commented.
98 */
99 // static final char PASSWORD;
100
101 /*
102 * These values can be different on different platforms.
103 * Therefore they are not initialized in the declaration
104 * to stop the compiler from inlining.
105 */
106
107 private static /+const+/ WNDPROC EditProc;
108 static const TCHAR[] EditClass = "EDIT\0";
109
110 private static bool static_this_completed = false;
111 private static void static_this() {
112 if( static_this_completed ){
113 return;
114 }
115 synchronized {
116 if( static_this_completed ){
117 return;
118 }
119 LIMIT_ = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF;
120 WNDCLASS lpWndClass;
121 OS.GetClassInfo (null, EditClass.ptr, &lpWndClass);
122 EditProc = lpWndClass.lpfnWndProc;
123 /*
124 * This code is intentionally commented.
125 */
126 // int hwndText = OS.CreateWindowEx (0,
127 // EditClass,
128 // null,
129 // OS.WS_OVERLAPPED | OS.ES_PASSWORD,
130 // 0, 0, 0, 0,
131 // 0,
132 // 0,
133 // OS.GetModuleHandle (null),
134 // null);
135 // char echo = (char) OS.SendMessage (hwndText, OS.EM_GETPASSWORDCHAR, 0, 0);
136 // OS.DestroyWindow (hwndText);
137 // PASSWORD = echo !is 0 ? echo : '*';
138 static_this_completed = true;
139 }
140 }
141
142 /**
143 * Constructs a new instance of this class given its parent
144 * and a style value describing its behavior and appearance.
145 * <p>
146 * The style value is either one of the style constants defined in
147 * class <code>SWT</code> which is applicable to instances of this
148 * class, or must be built by <em>bitwise OR</em>'ing together
149 * (that is, using the <code>int</code> "|" operator) two or more
150 * of those <code>SWT</code> style constants. The class description
151 * lists the style constants that are applicable to the class.
152 * Style bits are also inherited from superclasses.
153 * </p>
154 *
155 * @param parent a composite control which will be the parent of the new instance (cannot be null)
156 * @param style the style of control to construct
157 *
158 * @exception IllegalArgumentException <ul>
159 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
160 * </ul>
161 * @exception SWTException <ul>
162 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
163 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
164 * </ul>
165 *
166 * @see SWT#SINGLE
167 * @see SWT#MULTI
168 * @see SWT#READ_ONLY
169 * @see SWT#WRAP
170 * @see Widget#checkSubclass
171 * @see Widget#getStyle
172 */
173 public this (Composite parent, int style) {
174 static_this();
175 super (parent, checkStyle (style));
176 }
177
178 override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) {
179 if (handle is null) return 0;
180 bool redraw = false;
181 switch (msg) {
182 case OS.WM_ERASEBKGND: {
183 if (findImageControl () !is null) return 0;
184 break;
185 }
186 case OS.WM_HSCROLL:
187 case OS.WM_VSCROLL: {
188 redraw = findImageControl () !is null && drawCount is 0 && OS.IsWindowVisible (handle);
189 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
190 break;
191 }
192 case OS.WM_PAINT: {
193 if (findImageControl () !is null) {
194 PAINTSTRUCT ps;
195 auto paintDC = OS.BeginPaint (handle, &ps);
196 int width = ps.rcPaint.right - ps.rcPaint.left;
197 int height = ps.rcPaint.bottom - ps.rcPaint.top;
198 if (width !is 0 && height !is 0) {
199 auto hDC = OS.CreateCompatibleDC (paintDC);
200 POINT lpPoint1, lpPoint2;
201 OS.SetWindowOrgEx (hDC, ps.rcPaint.left, ps.rcPaint.top, &lpPoint1);
202 OS.SetBrushOrgEx (hDC, ps.rcPaint.left, ps.rcPaint.top, &lpPoint2);
203 auto hBitmap = OS.CreateCompatibleBitmap (paintDC, width, height);
204 auto hOldBitmap = OS.SelectObject (hDC, hBitmap);
205 RECT rect;
206 OS.SetRect (&rect, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
207 drawBackground (hDC, &rect);
208 OS.CallWindowProc ( EditProc, hwnd, OS.WM_PAINT, cast(int)hDC, lParam);
209 OS.SetWindowOrgEx (hDC, lpPoint1.x, lpPoint1.y, null);
210 OS.SetBrushOrgEx (hDC, lpPoint2.x, lpPoint2.y, null);
211 OS.BitBlt (paintDC, ps.rcPaint.left, ps.rcPaint.top, width, height, hDC, 0, 0, OS.SRCCOPY);
212 OS.SelectObject (hDC, hOldBitmap);
213 OS.DeleteObject (hBitmap);
214 OS.DeleteObject (hDC);
215 }
216 OS.EndPaint (handle, &ps);
217 return 0;
218 }
219 break;
220 }
221 default:
222 }
223 int /*long*/ code = OS.CallWindowProc (EditProc, hwnd, msg, wParam, lParam);
224 switch (msg) {
225 case OS.WM_HSCROLL:
226 case OS.WM_VSCROLL: {
227 if (redraw) {
228 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
229 OS.InvalidateRect (handle, null, true);
230 }
231 break;
232 }
233 default:
234 }
235 return code;
236 }
237
238 override void createHandle () {
239 super.createHandle ();
240 OS.SendMessage (handle, OS.EM_LIMITTEXT, 0, 0);
241 if ((style & SWT.READ_ONLY) !is 0) {
242 if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) is 0) {
243 state |= THEME_BACKGROUND;
244 }
245 }
246 }
247
248 /**
249 * Adds the listener to the collection of listeners who will
250 * be notified when the receiver's text is modified, by sending
251 * it one of the messages defined in the <code>ModifyListener</code>
252 * interface.
253 *
254 * @param listener the listener which should be notified
255 *
256 * @exception IllegalArgumentException <ul>
257 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
258 * </ul>
259 * @exception SWTException <ul>
260 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
261 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
262 * </ul>
263 *
264 * @see ModifyListener
265 * @see #removeModifyListener
266 */
267 public void addModifyListener (ModifyListener listener) {
268 checkWidget ();
269 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
270 TypedListener typedListener = new TypedListener (listener);
271 addListener (SWT.Modify, typedListener);
272 }
273
274 /**
275 * Adds the listener to the collection of listeners who will
276 * be notified when the control is selected by the user, by sending
277 * it one of the messages defined in the <code>SelectionListener</code>
278 * interface.
279 * <p>
280 * <code>widgetSelected</code> is not called for texts.
281 * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed in a single-line text,
282 * or when ENTER is pressed in a search text. If the receiver has the <code>SWT.SEARCH | SWT.CANCEL</code> style
283 * and the user cancels the search, the event object detail field contains the value <code>SWT.CANCEL</code>.
284 * </p>
285 *
286 * @param listener the listener which should be notified when the control is selected by the user
287 *
288 * @exception IllegalArgumentException <ul>
289 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
290 * </ul>
291 * @exception SWTException <ul>
292 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
293 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
294 * </ul>
295 *
296 * @see SelectionListener
297 * @see #removeSelectionListener
298 * @see SelectionEvent
299 */
300 public void addSelectionListener (SelectionListener listener) {
301 checkWidget ();
302 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
303 TypedListener typedListener = new TypedListener (listener);
304 addListener (SWT.Selection,typedListener);
305 addListener (SWT.DefaultSelection,typedListener);
306 }
307
308 /**
309 * Adds the listener to the collection of listeners who will
310 * be notified when the receiver's text is verified, by sending
311 * it one of the messages defined in the <code>VerifyListener</code>
312 * interface.
313 *
314 * @param listener the listener which should be notified
315 *
316 * @exception IllegalArgumentException <ul>
317 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
318 * </ul>
319 * @exception SWTException <ul>
320 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
321 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
322 * </ul>
323 *
324 * @see VerifyListener
325 * @see #removeVerifyListener
326 */
327 public void addVerifyListener (VerifyListener listener) {
328 checkWidget ();
329 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
330 TypedListener typedListener = new TypedListener (listener);
331 addListener (SWT.Verify, typedListener);
332 }
333
334 /**
335 * Appends a string.
336 * <p>
337 * The new text is appended to the text at
338 * the end of the widget.
339 * </p>
340 *
341 * @param string the string to be appended
342 *
343 * @exception SWTException <ul>
344 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
345 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
346 * </ul>
347 */
348 public void append (String string) {
349 checkWidget ();
350 // SWT extension: allow null string
351 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
352 string = Display.withCrLf (string);
353 int length = OS.GetWindowTextLength (handle);
354 if (hooks (SWT.Verify) || filters (SWT.Verify)) {
355 string = verifyText (string, length, length, null);
356 if (string is null) return;
357 }
358 OS.SendMessage (handle, OS.EM_SETSEL, length, length);
359 TCHAR* buffer = StrToTCHARz (getCodePage (), string);
360 /*
361 * Feature in Windows. When an edit control with ES_MULTILINE
362 * style that does not have the WS_VSCROLL style is full (i.e.
363 * there is no space at the end to draw any more characters),
364 * EM_REPLACESEL sends a WM_CHAR with a backspace character
365 * to remove any further text that is added. This is an
366 * implementation detail of the edit control that is unexpected
367 * and can cause endless recursion when EM_REPLACESEL is sent
368 * from a WM_CHAR handler. The fix is to ignore calling the
369 * handler from WM_CHAR.
370 */
371 ignoreCharacter = true;
372 OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
373 ignoreCharacter = false;
374 OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
375 }
376
377 static int checkStyle (int style) {
378 if ((style & SWT.SEARCH) !is 0) {
379 style |= SWT.SINGLE | SWT.BORDER;
380 style &= ~SWT.PASSWORD;
381 }
382 if (OS.COMCTL32_MAJOR < 6) style &= ~SWT.SEARCH;
383 if ((style & SWT.SINGLE) !is 0 && (style & SWT.MULTI) !is 0) {
384 style &= ~SWT.MULTI;
385 }
386 style = checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
387 if ((style & SWT.SINGLE) !is 0) style &= ~(SWT.H_SCROLL | SWT.V_SCROLL | SWT.WRAP);
388 if ((style & SWT.WRAP) !is 0) {
389 style |= SWT.MULTI;
390 style &= ~SWT.H_SCROLL;
391 }
392 if ((style & SWT.MULTI) !is 0) style &= ~SWT.PASSWORD;
393 if ((style & (SWT.SINGLE | SWT.MULTI)) !is 0) return style;
394 if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) !is 0) return style | SWT.MULTI;
395 return style | SWT.SINGLE;
396 }
397
398 /**
399 * Clears the selection.
400 *
401 * @exception SWTException <ul>
402 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
403 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
404 * </ul>
405 */
406 public void clearSelection () {
407 checkWidget ();
408 static if (OS.IsWinCE) {
409 /*
410 * Bug in WinCE. Calling EM_SETSEL with -1 and 0 is equivalent
411 * to calling EM_SETSEL with 0 and -1. It causes the entire
412 * text to be selected instead of clearing the selection. The
413 * fix is to set the start of the selection to the end of the
414 * current selection.
415 */
416 int end;
417 OS.SendMessage (handle, OS.EM_GETSEL, null, &end);
418 OS.SendMessage (handle, OS.EM_SETSEL, end , end );
419 } else {
420 OS.SendMessage (handle, OS.EM_SETSEL, -1, 0);
421 }
422 }
423
424 override public Point computeSize (int wHint, int hHint, bool changed) {
425 checkWidget ();
426 int height = 0, width = 0;
427 if (wHint is SWT.DEFAULT || hHint is SWT.DEFAULT) {
428 HFONT newFont, oldFont;
429 auto hDC = OS.GetDC (handle);
430 newFont = cast(HFONT) OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
431 if (newFont !is null) oldFont = OS.SelectObject (hDC, newFont);
432 TEXTMETRIC tm;
433 OS.GetTextMetrics (hDC, &tm);
434 int count = (style & SWT.SINGLE) !is 0 ? 1 : OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
435 height = count * tm.tmHeight;
436 RECT rect;
437 int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_NOPREFIX;
438 bool wrap = (style & SWT.MULTI) !is 0 && (style & SWT.WRAP) !is 0;
439 if (wrap && wHint !is SWT.DEFAULT) {
440 flags |= OS.DT_WORDBREAK;
441 rect.right = wHint;
442 }
443 int length = OS.GetWindowTextLength (handle);
444 if (length !is 0) {
445 TCHAR[] buffer = NewTCHARs (getCodePage (), length + 1);
446 OS.GetWindowText (handle, buffer.ptr, length + 1);
447 OS.DrawText (hDC, buffer.ptr, length, &rect, flags);
448 width = rect.right - rect.left;
449 }
450 //This code is intentionally commented
451 // if (OS.COMCTL32_MAJOR >= 6) {
452 // if ((style & SWT.SEARCH) !is 0) {
453 // length = message.length ();
454 // if (length !is 0) {
455 // char [] buffer = new char [length + 1];
456 // message.getChars (0, length, buffer, 0);
457 // SIZE size = new SIZE ();
458 // OS.GetTextExtentPoint32W (hDC, buffer, length, size);
459 // width = Math.max (width, size.cx);
460 // }
461 // }
462 // }
463 if (wrap && hHint is SWT.DEFAULT) {
464 int newHeight = rect.bottom - rect.top;
465 if (newHeight !is 0) height = newHeight;
466 }
467 if (newFont !is null) OS.SelectObject (hDC, oldFont);
468 OS.ReleaseDC (handle, hDC);
469 }
470 if (width is 0) width = DEFAULT_WIDTH;
471 if (height is 0) height = DEFAULT_HEIGHT;
472 if (wHint !is SWT.DEFAULT) width = wHint;
473 if (hHint !is SWT.DEFAULT) height = hHint;
474 Rectangle trim = computeTrim (0, 0, width, height);
475 return new Point (trim.width, trim.height);
476 }
477
478 override public Rectangle computeTrim (int x, int y, int width, int height) {
479 checkWidget ();
480 Rectangle rect = super.computeTrim (x, y, width, height);
481 /*
482 * The preferred height of a single-line text widget
483 * has been hand-crafted to be the same height as
484 * the single-line text widget in an editable combo
485 * box.
486 */
487 int /*long*/ margins = OS.SendMessage(handle, OS.EM_GETMARGINS, 0, 0);
488 rect.x -= OS.LOWORD (margins);
489 rect.width += OS.LOWORD (margins) + OS.HIWORD (margins);
490 if ((style & SWT.H_SCROLL) !is 0) rect.width++;
491 if ((style & SWT.BORDER) !is 0) {
492 rect.x -= 1;
493 rect.y -= 1;
494 rect.width += 2;
495 rect.height += 2;
496 }
497 return rect;
498 }
499
500 /**
501 * Copies the selected text.
502 * <p>
503 * The current selection is copied to the clipboard.
504 * </p>
505 *
506 * @exception SWTException <ul>
507 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
508 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
509 * </ul>
510 */
511 public void copy () {
512 checkWidget ();
513 OS.SendMessage (handle, OS.WM_COPY, 0, 0);
514 }
515
516 override void createWidget () {
517 super.createWidget ();
518 message = "";
519 doubleClick = true;
520 setTabStops (tabs = 8);
521 fixAlignment ();
522 }
523
524 /**
525 * Cuts the selected text.
526 * <p>
527 * The current selection is first copied to the
528 * clipboard and then deleted from the widget.
529 * </p>
530 *
531 * @exception SWTException <ul>
532 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
533 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
534 * </ul>
535 */
536 public void cut () {
537 checkWidget ();
538 if ((style & SWT.READ_ONLY) !is 0) return;
539 OS.SendMessage (handle, OS.WM_CUT, 0, 0);
540 }
541
542 override int defaultBackground () {
543 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
544 return OS.GetSysColor ((bits & OS.ES_READONLY) !is 0 ? OS.COLOR_3DFACE : OS.COLOR_WINDOW);
545 }
546
547 override bool dragDetect (HWND hwnd, int x, int y, bool filter, bool [] detect, bool [] consume) {
548 if (filter) {
549 int start, end;
550 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
551 if (start !is end ) {
552 int /*long*/ lParam = OS.MAKELPARAM (x, y);
553 int position = OS.LOWORD (OS.SendMessage (handle, OS.EM_CHARFROMPOS, 0, lParam));
554 if (start <= position && position < end) {
555 if (super.dragDetect (hwnd, x, y, filter, detect, consume)) {
556 if (consume !is null) consume [0] = true;
557 return true;
558 }
559 }
560 }
561 return false;
562 }
563 return super.dragDetect (hwnd, x, y, filter, detect, consume);
564 }
565
566 void fixAlignment () {
567 /*
568 * Feature in Windows. When the edit control is not
569 * mirrored, it uses WS_EX_RIGHT, WS_EX_RTLREADING and
570 * WS_EX_LEFTSCROLLBAR to give the control a right to
571 * left appearance. This causes the control to be lead
572 * aligned no matter what alignment was specified by
573 * the programmer. For example, setting ES_RIGHT and
574 * WS_EX_LAYOUTRTL should cause the contents of the
575 * control to be left (trail) aligned in a mirrored world.
576 * When the orientation is changed by the user or
577 * specified by the programmer, WS_EX_RIGHT conflicts
578 * with the mirrored alignment. The fix is to clear
579 * or set WS_EX_RIGHT to achieve the correct alignment
580 * according to the orientation and mirroring.
581 */
582 if ((style & SWT.MIRRORED) !is 0) return;
583 int bits1 = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
584 int bits2 = OS.GetWindowLong (handle, OS.GWL_STYLE);
585 if ((style & SWT.LEFT_TO_RIGHT) !is 0) {
586 /*
587 * Bug in Windows 98. When the edit control is created
588 * with the style ES_RIGHT it automatically sets the
589 * WS_EX_LEFTSCROLLBAR bit. The fix is to clear the
590 * bit when the orientation of the control is left
591 * to right.
592 */
593 bits1 &= ~OS.WS_EX_LEFTSCROLLBAR;
594 if ((style & SWT.RIGHT) !is 0) {
595 bits1 |= OS.WS_EX_RIGHT;
596 bits2 |= OS.ES_RIGHT;
597 }
598 if ((style & SWT.LEFT) !is 0) {
599 bits1 &= ~OS.WS_EX_RIGHT;
600 bits2 &= ~OS.ES_RIGHT;
601 }
602 } else {
603 if ((style & SWT.RIGHT) !is 0) {
604 bits1 &= ~OS.WS_EX_RIGHT;
605 bits2 &= ~OS.ES_RIGHT;
606 }
607 if ((style & SWT.LEFT) !is 0) {
608 bits1 |= OS.WS_EX_RIGHT;
609 bits2 |= OS.ES_RIGHT;
610 }
611 }
612 if ((style & SWT.CENTER) !is 0) {
613 bits2 |= OS.ES_CENTER;
614 }
615 OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits1);
616 OS.SetWindowLong (handle, OS.GWL_STYLE, bits2);
617 }
618
619 override public int getBorderWidth () {
620 checkWidget ();
621 /*
622 * Feature in Windows 2000 and XP. Despite the fact that WS_BORDER
623 * is set when the edit control is created, the style bit is cleared.
624 * The fix is to avoid the check for WS_BORDER and use the SWT widget
625 * style bits instead.
626 */
627 // if ((style & SWT.BORDER) !is 0 && (style & SWT.FLAT) !is 0) {
628 // return OS.GetSystemMetrics (OS.SM_CXBORDER);
629 // }
630 return super.getBorderWidth ();
631 }
632
633 /**
634 * Returns the line number of the caret.
635 * <p>
636 * The line number of the caret is returned.
637 * </p>
638 *
639 * @return the line number
640 *
641 * @exception SWTException <ul>
642 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
643 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
644 * </ul>
645 */
646 public int getCaretLineNumber () {
647 checkWidget ();
648 return OS.SendMessage (handle, OS.EM_LINEFROMCHAR, -1, 0);
649 }
650
651 /**
652 * Returns a point describing the receiver's location relative
653 * to its parent (or its display if its parent is null).
654 * <p>
655 * The location of the caret is returned.
656 * </p>
657 *
658 * @return a point, the location of the caret
659 *
660 * @exception SWTException <ul>
661 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
662 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
663 * </ul>
664 */
665 public Point getCaretLocation () {
666 checkWidget ();
667 /*
668 * Bug in Windows. For some reason, Windows is unable
669 * to return the pixel coordinates of the last character
670 * in the widget. The fix is to temporarily insert a
671 * space, query the coordinates and delete the space.
672 * The selection is always an i-beam in this case because
673 * this is the only time the start of the selection can
674 * be equal to the last character position in the widget.
675 * If EM_POSFROMCHAR fails for any other reason, return
676 * pixel coordinates (0,0).
677 */
678 int position = getCaretPosition ();
679 int /*long*/ caretPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, position, 0);
680 if (caretPos is -1) {
681 caretPos = 0;
682 if (position >= OS.GetWindowTextLength (handle)) {
683 int cp = getCodePage ();
684 int start, end;
685 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
686 OS.SendMessage (handle, OS.EM_SETSEL, position, position);
687 /*
688 * Feature in Windows. When an edit control with ES_MULTILINE
689 * style that does not have the WS_VSCROLL style is full (i.e.
690 * there is no space at the end to draw any more characters),
691 * EM_REPLACESEL sends a WM_CHAR with a backspace character
692 * to remove any further text that is added. This is an
693 * implementation detail of the edit control that is unexpected
694 * and can cause endless recursion when EM_REPLACESEL is sent
695 * from a WM_CHAR handler. The fix is to ignore calling the
696 * handler from WM_CHAR.
697 */
698 ignoreCharacter = ignoreModify = true;
699 OS.SendMessage (handle, OS.EM_REPLACESEL, 0, StrToTCHARz (cp, " "));
700 caretPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, position, 0);
701 OS.SendMessage (handle, OS.EM_SETSEL, position, position + 1);
702 OS.SendMessage (handle, OS.EM_REPLACESEL, 0, StrToTCHARz (cp, ""));
703 ignoreCharacter = ignoreModify = false;
704 OS.SendMessage (handle, OS.EM_SETSEL, start , start );
705 OS.SendMessage (handle, OS.EM_SETSEL, start , end );
706 }
707 }
708 return new Point (OS.GET_X_LPARAM (caretPos), OS.GET_Y_LPARAM (caretPos));
709 }
710
711 /**
712 * Returns the character position of the caret.
713 * <p>
714 * Indexing is zero based.
715 * </p>
716 *
717 * @return the position of the caret
718 *
719 * @exception SWTException <ul>
720 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
721 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
722 * </ul>
723 */
724 public int getCaretPosition () {
725 checkWidget ();
726 int start, end;
727 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
728 /*
729 * In Windows, there is no API to get the position of the caret
730 * when the selection is not an i-beam. The best that can be done
731 * is to query the pixel position of the current caret and compare
732 * it to the pixel position of the start and end of the selection.
733 *
734 * NOTE: This does not work when the i-beam belongs to another
735 * control. In this case, guess that the i-beam is at the start
736 * of the selection.
737 */
738 int caret = start ;
739 if (start !is end ) {
740 int startLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, start, 0);
741 int endLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, end, 0);
742 if (startLine is endLine) {
743 static if (!OS.IsWinCE) {
744 int idThread = OS.GetWindowThreadProcessId (handle, null);
745 GUITHREADINFO lpgui;
746 lpgui.cbSize = GUITHREADINFO.sizeof;
747 if (OS.GetGUIThreadInfo (idThread, &lpgui)) {
748 if (lpgui.hwndCaret is handle || lpgui.hwndCaret is null) {
749 POINT ptCurrentPos;
750 if (OS.GetCaretPos (&ptCurrentPos)) {
751 int endPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, end, 0);
752 if (endPos is -1) {
753 int startPos = OS.SendMessage (handle, OS.EM_POSFROMCHAR, start, 0);
754 int startX = cast(short) (startPos & 0xFFFF);
755 if (ptCurrentPos.x > startX) caret = end;
756 } else {
757 int endX = cast(short) (endPos & 0xFFFF);
758 if (ptCurrentPos.x >= endX) caret = end;
759 }
760 }
761 }
762 }
763 }
764 } else {
765 int caretPos = OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0);
766 int caretLine = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, caretPos, 0);
767 if (caretLine is endLine) caret = end;
768 }
769 }
770 if (!OS.IsUnicode && OS.IsDBLocale) caret = mbcsToWcsPos (caret);
771 return caret;
772 }
773
774 /**
775 * Returns the number of characters.
776 *
777 * @return number of characters in the widget
778 *
779 * @exception SWTException <ul>
780 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
781 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
782 * </ul>
783 */
784 public int getCharCount () {
785 checkWidget ();
786 int length = OS.GetWindowTextLength (handle);
787 if (!OS.IsUnicode && OS.IsDBLocale) length = mbcsToWcsPos (length);
788 return length;
789 }
790
791 /**
792 * Returns the double click enabled flag.
793 * <p>
794 * The double click flag enables or disables the
795 * default action of the text widget when the user
796 * double clicks.
797 * </p>
798 *
799 * @return whether or not double click is enabled
800 *
801 * @exception SWTException <ul>
802 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
803 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
804 * </ul>
805 */
806 public bool getDoubleClickEnabled () {
807 checkWidget ();
808 return doubleClick;
809 }
810
811 /**
812 * Returns the echo character.
813 * <p>
814 * The echo character is the character that is
815 * displayed when the user enters text or the
816 * text is changed by the programmer.
817 * </p>
818 *
819 * @return the echo character
820 *
821 * @exception SWTException <ul>
822 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
823 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
824 * </ul>
825 *
826 * @see #setEchoChar
827 */
828 public char getEchoChar () {
829 checkWidget ();
830 wchar echo = cast(wchar) OS.SendMessage (handle, OS.EM_GETPASSWORDCHAR, 0, 0);
831 if (echo !is 0 && (echo = Display.mbcsToWcs (echo, getCodePage ())) is 0) echo = '*';
832 return echo;
833 }
834
835 /**
836 * Returns the editable state.
837 *
838 * @return whether or not the receiver is editable
839 *
840 * @exception SWTException <ul>
841 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
842 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
843 * </ul>
844 */
845 public bool getEditable () {
846 checkWidget ();
847 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
848 return (bits & OS.ES_READONLY) is 0;
849 }
850
851 /**
852 * Returns the number of lines.
853 *
854 * @return the number of lines in the widget
855 *
856 * @exception SWTException <ul>
857 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
858 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
859 * </ul>
860 */
861 public int getLineCount () {
862 checkWidget ();
863 return OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
864 }
865
866 /**
867 * Returns the line delimiter.
868 *
869 * @return a string that is the line delimiter
870 *
871 * @exception SWTException <ul>
872 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
873 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
874 * </ul>
875 *
876 * @see #DELIMITER
877 */
878 public String getLineDelimiter () {
879 checkWidget ();
880 return DELIMITER;
881 }
882
883 /**
884 * Returns the height of a line.
885 *
886 * @return the height of a row of text
887 *
888 * @exception SWTException <ul>
889 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
890 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
891 * </ul>
892 */
893 public int getLineHeight () {
894 checkWidget ();
895 HFONT newFont, oldFont;
896 auto hDC = OS.GetDC (handle);
897 newFont = cast(HFONT) OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
898 if (newFont !is null) oldFont = OS.SelectObject (hDC, newFont);
899 TEXTMETRIC tm;
900 OS.GetTextMetrics (hDC, &tm);
901 if (newFont !is null) OS.SelectObject (hDC, oldFont);
902 OS.ReleaseDC (handle, hDC);
903 return tm.tmHeight;
904 }
905
906 /**
907 * Returns the orientation of the receiver, which will be one of the
908 * constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
909 *
910 * @return the orientation style
911 *
912 * @exception SWTException <ul>
913 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
914 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
915 * </ul>
916 *
917 * @since 2.1.2
918 */
919 public int getOrientation () {
920 checkWidget();
921 return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
922 }
923
924 /**
925 * Returns the widget message. When the widget is created
926 * with the style <code>SWT.SEARCH</code>, the message text
927 * is displayed as a hint for the user, indicating the
928 * purpose of the field.
929 * <p>
930 * Note: This operation is a <em>HINT</em> and is not
931 * supported on platforms that do not have this concept.
932 * </p>
933 *
934 * @return the widget message
935 *
936 * @exception SWTException <ul>
937 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
938 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
939 * </ul>
940 *
941 * @since 3.3
942 */
943 public String getMessage () {
944 checkWidget ();
945 return message;
946 }
947
948 /**
949 * Returns the character position at the given point in the receiver
950 * or -1 if no such position exists. The point is in the coordinate
951 * system of the receiver.
952 * <p>
953 * Indexing is zero based.
954 * </p>
955 *
956 * @return the position of the caret
957 *
958 * @exception SWTException <ul>
959 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
960 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
961 * </ul>
962 *
963 * @since 3.3
964 */
965 //TODO - Javadoc
966 /*public*/ int getPosition (Point point) {
967 checkWidget();
968 if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
969 int /*long*/ lParam = OS.MAKELPARAM (point.x, point.y);
970 int position = OS.LOWORD (OS.SendMessage (handle, OS.EM_CHARFROMPOS, 0, lParam));
971 if (!OS.IsUnicode && OS.IsDBLocale) position = mbcsToWcsPos (position);
972 return position;
973 }
974
975 /**
976 * Returns a <code>Point</code> whose x coordinate is the
977 * character position representing the start of the selected
978 * text, and whose y coordinate is the character position
979 * representing the end of the selection. An "empty" selection
980 * is indicated by the x and y coordinates having the same value.
981 * <p>
982 * Indexing is zero based. The range of a selection is from
983 * 0..N where N is the number of characters in the widget.
984 * </p>
985 *
986 * @return a point representing the selection start and end
987 *
988 * @exception SWTException <ul>
989 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
990 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
991 * </ul>
992 */
993 public Point getSelection () {
994 checkWidget ();
995 int start, end;
996 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
997 if (!OS.IsUnicode && OS.IsDBLocale) {
998 start = mbcsToWcsPos (start);
999 end = mbcsToWcsPos (end);
1000 }
1001 return new Point (start, end);
1002 }
1003
1004 /**
1005 * Returns the number of selected characters.
1006 *
1007 * @return the number of selected characters.
1008 *
1009 * @exception SWTException <ul>
1010 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1011 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1012 * </ul>
1013 */
1014 public int getSelectionCount () {
1015 checkWidget ();
1016 Point selection = getSelection ();
1017 return selection.y - selection.x;
1018 }
1019
1020 /**
1021 * Gets the selected text, or an empty string if there is no current selection.
1022 *
1023 * @return the selected text
1024 *
1025 * @exception SWTException <ul>
1026 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1027 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1028 * </ul>
1029 */
1030 public String getSelectionText () {
1031 checkWidget ();
1032 int length = OS.GetWindowTextLength (handle);
1033 if (length is 0) return "";
1034 int start, end;
1035 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
1036 if (start is end ) return "";
1037 TCHAR[] buffer = NewTCHARs (getCodePage (), length + 1);
1038 OS.GetWindowText (handle, buffer.ptr, length + 1);
1039 return TCHARsToStr( buffer[ start .. end ] );
1040 }
1041
1042 /**
1043 * Returns the number of tabs.
1044 * <p>
1045 * Tab stop spacing is specified in terms of the
1046 * space (' ') character. The width of a single
1047 * tab stop is the pixel width of the spaces.
1048 * </p>
1049 *
1050 * @return the number of tab characters
1051 *
1052 * @exception SWTException <ul>
1053 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1054 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1055 * </ul>
1056 */
1057 public int getTabs () {
1058 checkWidget ();
1059 return tabs;
1060 }
1061
1062 int getTabWidth (int tabs) {
1063 HFONT oldFont;
1064 RECT rect;
1065 auto hDC = OS.GetDC (handle);
1066 HFONT newFont = cast(HFONT) OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1067 if (newFont !is null) oldFont = OS.SelectObject (hDC, newFont);
1068 int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1069 TCHAR[] SPACE = StrToTCHARs (getCodePage (), " ", false);
1070 OS.DrawText (hDC, SPACE.ptr, SPACE.length, &rect, flags);
1071 if (newFont !is null) OS.SelectObject (hDC, oldFont);
1072 OS.ReleaseDC (handle, hDC);
1073 return (rect.right - rect.left) * tabs;
1074 }
1075
1076 /**
1077 * Returns the widget text.
1078 * <p>
1079 * The text for a text widget is the characters in the widget, or
1080 * an empty string if this has never been set.
1081 * </p>
1082 *
1083 * @return the widget text
1084 *
1085 * @exception SWTException <ul>
1086 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1087 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1088 * </ul>
1089 */
1090 public String getText () {
1091 checkWidget ();
1092 int length_ = OS.GetWindowTextLength (handle);
1093 if (length_ is 0) return "";
1094 TCHAR[] buffer = NewTCHARs (getCodePage (), length_ + 1);
1095 OS.GetWindowText (handle, buffer.ptr, length_ + 1);
1096 return TCHARsToStr( buffer[0 .. length_] );
1097 }
1098
1099 /**
1100 * Returns a range of text. Returns an empty string if the
1101 * start of the range is greater than the end.
1102 * <p>
1103 * Indexing is zero based. The range of
1104 * a selection is from 0..N-1 where N is
1105 * the number of characters in the widget.
1106 * </p>
1107 *
1108 * @param start the start of the range
1109 * @param end the end of the range
1110 * @return the range of text
1111 *
1112 * @exception SWTException <ul>
1113 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1114 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1115 * </ul>
1116 */
1117 public String getText (int start, int end) {
1118 checkWidget ();
1119 if (!(start <= end && 0 <= end)) return "";
1120 int length = OS.GetWindowTextLength (handle);
1121 if (!OS.IsUnicode && OS.IsDBLocale) length = mbcsToWcsPos (length);
1122 start = Math.max (0, start);
1123 end = Math.min (end, length - 1);
1124 /*
1125 * NOTE: The current implementation uses substring ()
1126 * which can reference a potentially large character
1127 * array.
1128 */
1129 return getText ().substring (start, end + 1);
1130 }
1131
1132 /**
1133 * Returns the maximum number of characters that the receiver is capable of holding.
1134 * <p>
1135 * If this has not been changed by <code>setTextLimit()</code>,
1136 * it will be the constant <code>Text.LIMIT</code>.
1137 * </p>
1138 *
1139 * @return the text limit
1140 *
1141 * @exception SWTException <ul>
1142 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1143 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1144 * </ul>
1145 *
1146 * @see #LIMIT
1147 */
1148 public int getTextLimit () {
1149 checkWidget ();
1150 return OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
1151 }
1152
1153 /**
1154 * Returns the zero-relative index of the line which is currently
1155 * at the top of the receiver.
1156 * <p>
1157 * This index can change when lines are scrolled or new lines are added or removed.
1158 * </p>
1159 *
1160 * @return the index of the top line
1161 *
1162 * @exception SWTException <ul>
1163 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1164 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1165 * </ul>
1166 */
1167 public int getTopIndex () {
1168 checkWidget ();
1169 if ((style & SWT.SINGLE) !is 0) return 0;
1170 return OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0);
1171 }
1172
1173 /**
1174 * Returns the top pixel.
1175 * <p>
1176 * The top pixel is the pixel position of the line
1177 * that is currently at the top of the widget. On
1178 * some platforms, a text widget can be scrolled by
1179 * pixels instead of lines so that a partial line
1180 * is displayed at the top of the widget.
1181 * </p><p>
1182 * The top pixel changes when the widget is scrolled.
1183 * The top pixel does not include the widget trimming.
1184 * </p>
1185 *
1186 * @return the pixel position of the top line
1187 *
1188 * @exception SWTException <ul>
1189 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1190 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1191 * </ul>
1192 */
1193 public int getTopPixel () {
1194 checkWidget ();
1195 /*
1196 * Note, EM_GETSCROLLPOS is implemented in Rich Edit 3.0
1197 * and greater. The plain text widget and previous versions
1198 * of Rich Edit return zero.
1199 */
1200 int [2] buffer;
1201 int code = OS.SendMessage (handle, OS.EM_GETSCROLLPOS, 0, buffer.ptr);
1202 if (code is 1) return buffer [1];
1203 return getTopIndex () * getLineHeight ();
1204 }
1205
1206 /**
1207 * Inserts a string.
1208 * <p>
1209 * The old selection is replaced with the new text.
1210 * </p>
1211 *
1212 * @param string the string
1213 *
1214 * @exception SWTException <ul>
1215 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1216 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1217 * </ul>
1218 */
1219 public void insert (String string) {
1220 checkWidget ();
1221 // SWT extension: allow null string
1222 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
1223 string = Display.withCrLf (string);
1224 if (hooks (SWT.Verify) || filters (SWT.Verify)) {
1225 int start, end;
1226 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
1227 string = verifyText (string, start, end, null);
1228 if (string is null) return;
1229 }
1230 TCHAR* buffer = StrToTCHARz (getCodePage (), string );
1231 /*
1232 * Feature in Windows. When an edit control with ES_MULTILINE
1233 * style that does not have the WS_VSCROLL style is full (i.e.
1234 * there is no space at the end to draw any more characters),
1235 * EM_REPLACESEL sends a WM_CHAR with a backspace character
1236 * to remove any further text that is added. This is an
1237 * implementation detail of the edit control that is unexpected
1238 * and can cause endless recursion when EM_REPLACESEL is sent
1239 * from a WM_CHAR handler. The fix is to ignore calling the
1240 * handler from WM_CHAR.
1241 */
1242 ignoreCharacter = true;
1243 OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
1244 ignoreCharacter = false;
1245 }
1246
1247 int mbcsToWcsPos (int mbcsPos) {
1248 if (mbcsPos <= 0) return 0;
1249 if (OS.IsUnicode) return mbcsPos;
1250 int cp = getCodePage ();
1251 int wcsTotal = 0, mbcsTotal = 0;
1252 CHAR [] buffer = new CHAR [128];
1253 String delimiter = getLineDelimiter();
1254 int delimiterSize = delimiter.length;
1255 int count = OS.SendMessageA (handle, OS.EM_GETLINECOUNT, 0, 0);
1256 for (int line=0; line<count; line++) {
1257 int wcsSize = 0;
1258 int linePos = OS.SendMessageA (handle, OS.EM_LINEINDEX, line, 0);
1259 int mbcsSize = OS.SendMessageA (handle, OS.EM_LINELENGTH, linePos, 0);
1260 if (mbcsSize !is 0) {
1261 if (mbcsSize + delimiterSize > buffer.length) {
1262 buffer = new CHAR [mbcsSize + delimiterSize];
1263 }
1264 //ENDIAN
1265 buffer [0] = cast(char) (mbcsSize & 0xFF);
1266 buffer [1] = cast(char) (mbcsSize >> 8);
1267 mbcsSize = OS.SendMessageA (handle, OS.EM_GETLINE, line, buffer.ptr);
1268 wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer.ptr, mbcsSize, null, 0);
1269 }
1270 if (line - 1 !is count) {
1271 for (int i=0; i<delimiterSize; i++) {
1272 buffer [mbcsSize++] = cast(CHAR) delimiter.charAt (i);
1273 }
1274 wcsSize += delimiterSize;
1275 }
1276 if ((mbcsTotal + mbcsSize) >= mbcsPos) {
1277 int bufferSize = mbcsPos - mbcsTotal;
1278 wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer.ptr, bufferSize, null, 0);
1279 return wcsTotal + wcsSize;
1280 }
1281 wcsTotal += wcsSize;
1282 mbcsTotal += mbcsSize;
1283 }
1284 return wcsTotal;
1285 }
1286
1287 /**
1288 * Pastes text from clipboard.
1289 * <p>
1290 * The selected text is deleted from the widget
1291 * and new text inserted from the clipboard.
1292 * </p>
1293 *
1294 * @exception SWTException <ul>
1295 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1296 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1297 * </ul>
1298 */
1299 public void paste () {
1300 checkWidget ();
1301 if ((style & SWT.READ_ONLY) !is 0) return;
1302 OS.SendMessage (handle, OS.WM_PASTE, 0, 0);
1303 }
1304
1305 override void releaseWidget () {
1306 super.releaseWidget ();
1307 message = null;
1308 }
1309
1310 /**
1311 * Removes the listener from the collection of listeners who will
1312 * be notified when the receiver's text is modified.
1313 *
1314 * @param listener the listener which should no longer be notified
1315 *
1316 * @exception IllegalArgumentException <ul>
1317 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1318 * </ul>
1319 * @exception SWTException <ul>
1320 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1321 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1322 * </ul>
1323 *
1324 * @see ModifyListener
1325 * @see #addModifyListener
1326 */
1327 public void removeModifyListener (ModifyListener listener) {
1328 checkWidget ();
1329 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
1330 if (eventTable is null) return;
1331 eventTable.unhook (SWT.Modify, listener);
1332 }
1333
1334 /**
1335 * Removes the listener from the collection of listeners who will
1336 * be notified when the control is selected by the user.
1337 *
1338 * @param listener the listener which should no longer be notified
1339 *
1340 * @exception IllegalArgumentException <ul>
1341 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1342 * </ul>
1343 * @exception SWTException <ul>
1344 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1345 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1346 * </ul>
1347 *
1348 * @see SelectionListener
1349 * @see #addSelectionListener
1350 */
1351 public void removeSelectionListener (SelectionListener listener) {
1352 checkWidget ();
1353 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
1354 if (eventTable is null) return;
1355 eventTable.unhook (SWT.Selection, listener);
1356 eventTable.unhook (SWT.DefaultSelection,listener);
1357 }
1358
1359 /**
1360 * Removes the listener from the collection of listeners who will
1361 * be notified when the control is verified.
1362 *
1363 * @param listener the listener which should no longer be notified
1364 *
1365 * @exception IllegalArgumentException <ul>
1366 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1367 * </ul>
1368 * @exception SWTException <ul>
1369 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1370 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1371 * </ul>
1372 *
1373 * @see VerifyListener
1374 * @see #addVerifyListener
1375 */
1376 public void removeVerifyListener (VerifyListener listener) {
1377 checkWidget ();
1378 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
1379 if (eventTable is null) return;
1380 eventTable.unhook (SWT.Verify, listener);
1381 }
1382
1383 /**
1384 * Selects all the text in the receiver.
1385 *
1386 * @exception SWTException <ul>
1387 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1388 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1389 * </ul>
1390 */
1391 public void selectAll () {
1392 checkWidget ();
1393 OS.SendMessage (handle, OS.EM_SETSEL, 0, -1);
1394 }
1395
1396 override bool sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
1397 if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
1398 return false;
1399 }
1400 if ((style & SWT.READ_ONLY) !is 0) return true;
1401 if (ignoreVerify) return true;
1402 if (type !is SWT.KeyDown) return true;
1403 if (msg !is OS.WM_CHAR && msg !is OS.WM_KEYDOWN && msg !is OS.WM_IME_CHAR) {
1404 return true;
1405 }
1406 if (event.character is 0) return true;
1407 if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
1408 char key = event.character;
1409 int stateMask = event.stateMask;
1410
1411 /*
1412 * Disable all magic keys that could modify the text
1413 * and don't send events when Alt, Shift or Ctrl is
1414 * pressed.
1415 */
1416 switch (msg) {
1417 case OS.WM_CHAR:
1418 if (key !is 0x08 && key !is 0x7F && key !is '\r' && key !is '\t' && key !is '\n') break;
1419 // FALL THROUGH
1420 case OS.WM_KEYDOWN:
1421 if ((stateMask & (SWT.ALT | SWT.SHIFT | SWT.CONTROL)) !is 0) return false;
1422 break;
1423 default:
1424 }
1425
1426 /*
1427 * Feature in Windows. If the left button is down in
1428 * the text widget, it refuses the character. The fix
1429 * is to detect this case and avoid sending a verify
1430 * event.
1431 */
1432 if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
1433 if (handle is OS.GetCapture()) return true;
1434 }
1435
1436 /* Verify the character */
1437 String oldText = "";
1438 int start, end;
1439 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
1440 switch (key) {
1441 case 0x08: /* Bs */
1442 if (start is end ) {
1443 if (start is 0) return true;
1444 int lineStart = OS.SendMessage (handle, OS.EM_LINEINDEX, -1, 0);
1445 if (start is lineStart) {
1446 start = start - DELIMITER.length;
1447 } else {
1448 start = start - 1;
1449 if (!OS.IsUnicode && OS.IsDBLocale) {
1450 int newStart, newEnd;
1451 OS.SendMessage (handle, OS.EM_SETSEL, start, end);
1452 OS.SendMessage (handle, OS.EM_GETSEL, &newStart, &newEnd);
1453 if (start !is newStart) start = start - 1;
1454 }
1455 }
1456 start = Math.max (start, 0);
1457 }
1458 break;
1459 case 0x7F: /* Del */
1460 if (start is end) {
1461 int length = OS.GetWindowTextLength (handle);
1462 if (start is length) return true;
1463 int line = OS.SendMessage (handle, OS.EM_LINEFROMCHAR, end, 0);
1464 int lineStart = OS.SendMessage (handle, OS.EM_LINEINDEX, line + 1, 0);
1465 if (end is lineStart - DELIMITER.length) {
1466 end = end + DELIMITER.length;
1467 } else {
1468 end = end + 1;
1469 if (!OS.IsUnicode && OS.IsDBLocale) {
1470 int newStart, newEnd;
1471 OS.SendMessage (handle, OS.EM_SETSEL, start, end);
1472 OS.SendMessage (handle, OS.EM_GETSEL, &newStart, &newEnd);
1473 if (end !is newEnd) end = end + 1;
1474 }
1475 }
1476 end = Math.min (end, length);
1477 }
1478 break;
1479 case '\r': /* Return */
1480 if ((style & SWT.SINGLE) !is 0) return true;
1481 oldText = DELIMITER;
1482 break;
1483 default: /* Tab and other characters */
1484 if (key !is '\t' && key < 0x20) return true;
1485 oldText = [key];
1486 break;
1487 }
1488 String newText = verifyText (oldText, start, end, event);
1489 if (newText is null) return false;
1490 if (newText is oldText) return true;
1491 newText = Display.withCrLf (newText);
1492 TCHAR* buffer = StrToTCHARz (getCodePage (), newText);
1493 OS.SendMessage (handle, OS.EM_SETSEL, start, end);
1494 /*
1495 * Feature in Windows. When an edit control with ES_MULTILINE
1496 * style that does not have the WS_VSCROLL style is full (i.e.
1497 * there is no space at the end to draw any more characters),
1498 * EM_REPLACESEL sends a WM_CHAR with a backspace character
1499 * to remove any further text that is added. This is an
1500 * implementation detail of the edit control that is unexpected
1501 * and can cause endless recursion when EM_REPLACESEL is sent
1502 * from a WM_CHAR handler. The fix is to ignore calling the
1503 * handler from WM_CHAR.
1504 */
1505 ignoreCharacter = true;
1506 OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
1507 ignoreCharacter = false;
1508 return false;
1509 }
1510
1511 override void setBounds (int x, int y, int width, int height, int flags) {
1512 /*
1513 * Feature in Windows. When the caret is moved,
1514 * the text widget scrolls to show the new location.
1515 * This means that the text widget may be scrolled
1516 * to the right in order to show the caret when the
1517 * widget is not large enough to show both the caret
1518 * location and all the text. Unfortunately, when
1519 * the text widget is resized such that all the text
1520 * and the caret could be visible, Windows does not
1521 * scroll the widget back. The fix is to resize the
1522 * text widget, set the selection to the start of the
1523 * text and then restore the selection. This will
1524 * cause the text widget compute the correct scroll
1525 * position.
1526 */
1527 if ((flags & OS.SWP_NOSIZE) is 0 && width !is 0) {
1528 RECT rect;
1529 OS.GetWindowRect (handle, &rect);
1530 int /*long*/ margins = OS.SendMessage (handle, OS.EM_GETMARGINS, 0, 0);
1531 int marginWidth = OS.LOWORD (margins) + OS.HIWORD (margins);
1532 if (rect.right - rect.left <= marginWidth) {
1533 int start, end;
1534 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
1535 if (start !is 0 || end !is 0) {
1536 SetWindowPos (handle, null, x, y, width, height, flags);
1537 OS.SendMessage (handle, OS.EM_SETSEL, 0, 0);
1538 OS.SendMessage (handle, OS.EM_SETSEL, start, end);
1539 return;
1540 }
1541 }
1542 }
1543 super.setBounds (x, y, width, height, flags);
1544 }
1545
1546 override void setDefaultFont () {
1547 super.setDefaultFont ();
1548 setMargins ();
1549 }
1550
1551 /**
1552 * Sets the double click enabled flag.
1553 * <p>
1554 * The double click flag enables or disables the
1555 * default action of the text widget when the user
1556 * double clicks.
1557 * </p><p>
1558 * Note: This operation is a hint and is not supported on
1559 * platforms that do not have this concept.
1560 * </p>
1561 *
1562 * @param doubleClick the new double click flag
1563 *
1564 * @exception SWTException <ul>
1565 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1566 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1567 * </ul>
1568 */
1569 public void setDoubleClickEnabled (bool doubleClick) {
1570 checkWidget ();
1571 this.doubleClick = doubleClick;
1572 }
1573
1574 /**
1575 * Sets the echo character.
1576 * <p>
1577 * The echo character is the character that is
1578 * displayed when the user enters text or the
1579 * text is changed by the programmer. Setting
1580 * the echo character to '\0' clears the echo
1581 * character and redraws the original text.
1582 * If for any reason the echo character is invalid,
1583 * or if the platform does not allow modification
1584 * of the echo character, the default echo character
1585 * for the platform is used.
1586 * </p>
1587 *
1588 * @param echo the new echo character
1589 *
1590 * @exception SWTException <ul>
1591 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1592 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1593 * </ul>
1594 */
1595 public void setEchoChar (char echo) {
1596 checkWidget ();
1597 if ((style & SWT.MULTI) !is 0) return;
1598 if (echo !is 0) {
1599 if ((echo = cast(char) Display.wcsToMbcs (echo, getCodePage ())) is 0) echo = '*';
1600 }
1601 OS.SendMessage (handle, OS.EM_SETPASSWORDCHAR, echo, 0);
1602 /*
1603 * Bug in Windows. When the password character is changed,
1604 * Windows does not redraw to show the new password character.
1605 * The fix is to force a redraw when the character is set.
1606 */
1607 OS.InvalidateRect (handle, null, true);
1608 }
1609
1610 /**
1611 * Sets the editable state.
1612 *
1613 * @param editable the new editable state
1614 *
1615 * @exception SWTException <ul>
1616 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1617 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1618 * </ul>
1619 */
1620 public void setEditable (bool editable) {
1621 checkWidget ();
1622 style &= ~SWT.READ_ONLY;
1623 if (!editable) style |= SWT.READ_ONLY;
1624 OS.SendMessage (handle, OS.EM_SETREADONLY, editable ? 0 : 1, 0);
1625 }
1626
1627 override public void setFont (Font font) {
1628 checkWidget ();
1629 super.setFont (font);
1630 setTabStops (tabs);
1631 setMargins ();
1632 }
1633
1634 void setMargins () {
1635 /*
1636 * Bug in Windows. When EM_SETCUEBANNER is used to set the
1637 * banner text, the control does not take into account the
1638 * margins, causing the first character to be clipped. The
1639 * fix is to set the margins to zero.
1640 */
1641 if (OS.COMCTL32_MAJOR >= 6) {
1642 if ((style & SWT.SEARCH) !is 0) {
1643 OS.SendMessage (handle, OS.EM_SETMARGINS, OS.EC_LEFTMARGIN | OS.EC_RIGHTMARGIN, 0);
1644 }
1645 }
1646 }
1647
1648 /**
1649 * Sets the widget message. When the widget is created
1650 * with the style <code>SWT.SEARCH</code>, the message text
1651 * is displayed as a hint for the user, indicating the
1652 * purpose of the field.
1653 * <p>
1654 * Note: This operation is a <em>HINT</em> and is not
1655 * supported on platforms that do not have this concept.
1656 * </p>
1657 *
1658 * @param message the new message
1659 *
1660 * @exception SWTException <ul>
1661 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1662 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1663 * </ul>
1664 *
1665 * @since 3.3
1666 */
1667 public void setMessage (String message) {
1668 checkWidget ();
1669 // SWT extension: allow null string
1670 //if (message is null) error (SWT.ERROR_NULL_ARGUMENT);
1671 this.message = message;
1672 if (OS.COMCTL32_MAJOR >= 6) {
1673 if ((style & SWT.SEARCH) !is 0) {
1674 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1675 if ((bits & OS.ES_MULTILINE) is 0) {
1676 OS.SendMessage (handle, OS.EM_SETCUEBANNER, 0, StrToTCHARz( 0, message ));
1677 }
1678 }
1679 }
1680 }
1681
1682 /**
1683 * Sets the orientation of the receiver, which must be one
1684 * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
1685 * <p>
1686 * Note: This operation is a hint and is not supported on
1687 * platforms that do not have this concept.
1688 * </p>
1689 *
1690 * @param orientation new orientation style
1691 *
1692 * @exception SWTException <ul>
1693 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1694 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1695 * </ul>
1696 *
1697 * @since 2.1.2
1698 */
1699 public void setOrientation (int orientation) {
1700 checkWidget();
1701 static if (OS.IsWinCE) return;
1702 if (OS.WIN32_VERSION < OS.VERSION (4, 10)) return;
1703 int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
1704 if ((orientation & flags) is 0 || (orientation & flags) is flags) return;
1705 style &= ~flags;
1706 style |= orientation & flags;
1707 int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
1708 if ((style & SWT.RIGHT_TO_LEFT) !is 0) {
1709 bits |= OS.WS_EX_RTLREADING | OS.WS_EX_LEFTSCROLLBAR;
1710 } else {
1711 bits &= ~(OS.WS_EX_RTLREADING | OS.WS_EX_LEFTSCROLLBAR);
1712 }
1713 OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
1714 fixAlignment ();
1715 }
1716
1717 /**
1718 * Sets the selection.
1719 * <p>
1720 * Indexing is zero based. The range of
1721 * a selection is from 0..N where N is
1722 * the number of characters in the widget.
1723 * </p><p>
1724 * Text selections are specified in terms of
1725 * caret positions. In a text widget that
1726 * contains N characters, there are N+1 caret
1727 * positions, ranging from 0..N. This differs
1728 * from other functions that address character
1729 * position such as getText () that use the
1730 * regular array indexing rules.
1731 * </p>
1732 *
1733 * @param start new caret position
1734 *
1735 * @exception SWTException <ul>
1736 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1737 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1738 * </ul>
1739 */
1740 public void setSelection (int start) {
1741 checkWidget ();
1742 if (!OS.IsUnicode && OS.IsDBLocale) start = wcsToMbcsPos (start);
1743 OS.SendMessage (handle, OS.EM_SETSEL, start, start);
1744 OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
1745 }
1746
1747 /**
1748 * Sets the selection to the range specified
1749 * by the given start and end indices.
1750 * <p>
1751 * Indexing is zero based. The range of
1752 * a selection is from 0..N where N is
1753 * the number of characters in the widget.
1754 * </p><p>
1755 * Text selections are specified in terms of
1756 * caret positions. In a text widget that
1757 * contains N characters, there are N+1 caret
1758 * positions, ranging from 0..N. This differs
1759 * from other functions that address character
1760 * position such as getText () that use the
1761 * usual array indexing rules.
1762 * </p>
1763 *
1764 * @param start the start of the range
1765 * @param end the end of the range
1766 *
1767 * @exception SWTException <ul>
1768 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1769 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1770 * </ul>
1771 */
1772 public void setSelection (int start, int end) {
1773 checkWidget ();
1774 if (!OS.IsUnicode && OS.IsDBLocale) {
1775 start = wcsToMbcsPos (start);
1776 end = wcsToMbcsPos (end);
1777 }
1778 OS.SendMessage (handle, OS.EM_SETSEL, start, end);
1779 OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
1780 }
1781
1782 override public void setRedraw (bool redraw) {
1783 checkWidget ();
1784 super.setRedraw (redraw);
1785 /*
1786 * Feature in Windows. When WM_SETREDRAW is used to turn
1787 * redraw off, the edit control is not scrolled to show the
1788 * i-beam. The fix is to detect that the i-beam has moved
1789 * while redraw is turned off and force it to be visible
1790 * when redraw is restored.
1791 */
1792 if (drawCount !is 0) return;
1793 int start, end;
1794 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
1795 if (!redraw) {
1796 oldStart = start; oldEnd = end;
1797 } else {
1798 if (oldStart is start && oldEnd is end) return;
1799 OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
1800 }
1801 }
1802
1803 /**
1804 * Sets the selection to the range specified
1805 * by the given point, where the x coordinate
1806 * represents the start index and the y coordinate
1807 * represents the end index.
1808 * <p>
1809 * Indexing is zero based. The range of
1810 * a selection is from 0..N where N is
1811 * the number of characters in the widget.
1812 * </p><p>
1813 * Text selections are specified in terms of
1814 * caret positions. In a text widget that
1815 * contains N characters, there are N+1 caret
1816 * positions, ranging from 0..N. This differs
1817 * from other functions that address character
1818 * position such as getText () that use the
1819 * usual array indexing rules.
1820 * </p>
1821 *
1822 * @param selection the point
1823 *
1824 * @exception IllegalArgumentException <ul>
1825 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
1826 * </ul>
1827 * @exception SWTException <ul>
1828 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1829 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1830 * </ul>
1831 */
1832 public void setSelection (Point selection) {
1833 checkWidget ();
1834 if (selection is null) error (SWT.ERROR_NULL_ARGUMENT);
1835 setSelection (selection.x, selection.y);
1836 }
1837
1838 /**
1839 * Sets the number of tabs.
1840 * <p>
1841 * Tab stop spacing is specified in terms of the
1842 * space (' ') character. The width of a single
1843 * tab stop is the pixel width of the spaces.
1844 * </p>
1845 *
1846 * @param tabs the number of tabs
1847 *
1848 * </ul>
1849 * @exception SWTException <ul>
1850 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1851 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1852 * </ul>
1853 */
1854 public void setTabs (int tabs) {
1855 checkWidget ();
1856 if (tabs < 0) return;
1857 setTabStops (this.tabs = tabs);
1858 }
1859
1860 void setTabStops (int tabs) {
1861 /*
1862 * Feature in Windows. Windows expects the tab spacing in
1863 * dialog units so we must convert from space widths. Due
1864 * to round off error, the tab spacing may not be the exact
1865 * number of space widths, depending on the font.
1866 */
1867 int width = (getTabWidth (tabs) * 4) / OS.LOWORD (OS.GetDialogBaseUnits ());
1868 OS.SendMessage (handle, OS.EM_SETTABSTOPS, 1, &width);
1869 }
1870
1871 /**
1872 * Sets the contents of the receiver to the given string. If the receiver has style
1873 * SINGLE and the argument contains multiple lines of text, the result of this
1874 * operation is undefined and may vary from platform to platform.
1875 *
1876 * @param string the new text
1877 *
1878 * @exception SWTException <ul>
1879 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1880 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1881 * </ul>
1882 */
1883 public void setText (String string) {
1884 checkWidget ();
1885 // SWT extension: allow null string
1886 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
1887 string = Display.withCrLf (string);
1888 if (hooks (SWT.Verify) || filters (SWT.Verify)) {
1889 int length = OS.GetWindowTextLength (handle);
1890 string = verifyText (string, 0, length, null);
1891 if (string is null) return;
1892 }
1893 int limit = OS.SendMessage (handle, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
1894 if (string.length > limit) string = string.substring (0, limit);
1895 TCHAR* buffer = StrToTCHARz (getCodePage (), string);
1896 OS.SetWindowText (handle, buffer);
1897 /*
1898 * Bug in Windows. When the widget is multi line
1899 * text widget, it does not send a WM_COMMAND with
1900 * control code EN_CHANGE from SetWindowText () to
1901 * notify the application that the text has changed.
1902 * The fix is to send the event.
1903 */
1904 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1905 if ((bits & OS.ES_MULTILINE) !is 0) {
1906 sendEvent (SWT.Modify);
1907 // widget could be disposed at this point
1908 }
1909 }
1910
1911 /**
1912 * Sets the maximum number of characters that the receiver
1913 * is capable of holding to be the argument.
1914 * <p>
1915 * Instead of trying to set the text limit to zero, consider
1916 * creating a read-only text widget.
1917 * </p><p>
1918 * To reset this value to the default, use <code>setTextLimit(Text.LIMIT)</code>.
1919 * Specifying a limit value larger than <code>Text.LIMIT</code> sets the
1920 * receiver's limit to <code>Text.LIMIT</code>.
1921 * </p>
1922 *
1923 * @param limit new text limit
1924 *
1925 * @exception IllegalArgumentException <ul>
1926 * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
1927 * </ul>
1928 * @exception SWTException <ul>
1929 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1930 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1931 * </ul>
1932 *
1933 * @see #LIMIT
1934 */
1935 public void setTextLimit (int limit) {
1936 checkWidget ();
1937 if (limit is 0) error (SWT.ERROR_CANNOT_BE_ZERO);
1938 OS.SendMessage (handle, OS.EM_SETLIMITTEXT, limit, 0);
1939 }
1940
1941 /**
1942 * Sets the zero-relative index of the line which is currently
1943 * at the top of the receiver. This index can change when lines
1944 * are scrolled or new lines are added and removed.
1945 *
1946 * @param index the index of the top item
1947 *
1948 * @exception SWTException <ul>
1949 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1950 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1951 * </ul>
1952 */
1953 public void setTopIndex (int index) {
1954 checkWidget ();
1955 if ((style & SWT.SINGLE) !is 0) return;
1956 int count = OS.SendMessage (handle, OS.EM_GETLINECOUNT, 0, 0);
1957 index = Math.min (Math.max (index, 0), count - 1);
1958 int topIndex = OS.SendMessage (handle, OS.EM_GETFIRSTVISIBLELINE, 0, 0);
1959 OS.SendMessage (handle, OS.EM_LINESCROLL, 0, index - topIndex);
1960 }
1961
1962 /**
1963 * Shows the selection.
1964 * <p>
1965 * If the selection is already showing
1966 * in the receiver, this method simply returns. Otherwise,
1967 * lines are scrolled until the selection is visible.
1968 * </p>
1969 *
1970 * @exception SWTException <ul>
1971 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1972 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1973 * </ul>
1974 */
1975 public void showSelection () {
1976 checkWidget ();
1977 OS.SendMessage (handle, OS.EM_SCROLLCARET, 0, 0);
1978 }
1979
1980 String verifyText (String string, int start, int end, Event keyEvent) {
1981 if (ignoreVerify) return string;
1982 Event event = new Event ();
1983 event.text = string;
1984 event.start = start;
1985 event.end = end;
1986 if (keyEvent !is null) {
1987 event.character = keyEvent.character;
1988 event.keyCode = keyEvent.keyCode;
1989 event.stateMask = keyEvent.stateMask;
1990 }
1991 if (!OS.IsUnicode && OS.IsDBLocale) {
1992 event.start = mbcsToWcsPos (start);
1993 event.end = mbcsToWcsPos (end);
1994 }
1995 /*
1996 * It is possible (but unlikely), that application
1997 * code could have disposed the widget in the verify
1998 * event. If this happens, answer null to cancel
1999 * the operation.
2000 */
2001 sendEvent (SWT.Verify, event);
2002 if (!event.doit || isDisposed ()) return null;
2003 return event.text;
2004 }
2005
2006 int wcsToMbcsPos (int wcsPos) {
2007 if (wcsPos <= 0) return 0;
2008 if (OS.IsUnicode) return wcsPos;
2009 int cp = getCodePage ();
2010 int wcsTotal = 0, mbcsTotal = 0;
2011 CHAR [] buffer = new CHAR [128];
2012 String delimiter = getLineDelimiter ();
2013 int delimiterSize = delimiter.length;
2014 int count = OS.SendMessageA (handle, OS.EM_GETLINECOUNT, 0, 0);
2015 for (int line=0; line<count; line++) {
2016 int wcsSize = 0;
2017 int linePos = OS.SendMessageA (handle, OS.EM_LINEINDEX, line, 0);
2018 int mbcsSize = OS.SendMessageA (handle, OS.EM_LINELENGTH, linePos, 0);
2019 if (mbcsSize !is 0) {
2020 if (mbcsSize + delimiterSize > buffer.length) {
2021 buffer = new CHAR [mbcsSize + delimiterSize];
2022 }
2023 //ENDIAN
2024 buffer [0] = cast(char) (mbcsSize & 0xFF);
2025 buffer [1] = cast(char) (mbcsSize >> 8);
2026 mbcsSize = OS.SendMessageA (handle, OS.EM_GETLINE, line, buffer.ptr);
2027 wcsSize = OS.MultiByteToWideChar (cp, OS.MB_PRECOMPOSED, buffer.ptr, mbcsSize, null, 0);
2028 }
2029 if (line - 1 !is count) {
2030 for (int i=0; i<delimiterSize; i++) {
2031 buffer [mbcsSize++] = cast(byte) delimiter.charAt (i);
2032 }
2033 wcsSize += delimiterSize;
2034 }
2035 if ((wcsTotal + wcsSize) >= wcsPos) {
2036 wcsSize = 0;
2037 int index = 0;
2038 while (index < mbcsSize) {
2039 if ((wcsTotal + wcsSize) is wcsPos) {
2040 return mbcsTotal + index;
2041 }
2042 if (OS.IsDBCSLeadByte (buffer [index++])) index++;
2043 wcsSize++;
2044 }
2045 return mbcsTotal + mbcsSize;
2046 }
2047 wcsTotal += wcsSize;
2048 mbcsTotal += mbcsSize;
2049 }
2050 return mbcsTotal;
2051 }
2052
2053 override int widgetStyle () {
2054 int bits = super.widgetStyle () | OS.ES_AUTOHSCROLL;
2055 if ((style & SWT.PASSWORD) !is 0) bits |= OS.ES_PASSWORD;
2056 if ((style & SWT.CENTER) !is 0) bits |= OS.ES_CENTER;
2057 if ((style & SWT.RIGHT) !is 0) bits |= OS.ES_RIGHT;
2058 if ((style & SWT.READ_ONLY) !is 0) bits |= OS.ES_READONLY;
2059 if ((style & SWT.SINGLE) !is 0) {
2060 /*
2061 * Feature in Windows. When a text control is read-only,
2062 * uses COLOR_3DFACE for the background . If the text
2063 * controls single-line and is within a tab folder or
2064 * some other themed control, using WM_ERASEBKGND and
2065 * WM_CTRCOLOR to draw the theme background results in
2066 * pixel corruption. The fix is to use an ES_MULTILINE
2067 * text control instead.
2068 */
2069 if ((style & SWT.READ_ONLY) !is 0) {
2070 if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) is 0) {
2071 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
2072 bits |= OS.ES_MULTILINE;
2073 }
2074 }
2075 }
2076 return bits;
2077 }
2078 bits |= OS.ES_MULTILINE | OS.ES_NOHIDESEL | OS.ES_AUTOVSCROLL;
2079 if ((style & SWT.WRAP) !is 0) bits &= ~(OS.WS_HSCROLL | OS.ES_AUTOHSCROLL);
2080 return bits;
2081 }
2082
2083 override String windowClass () {
2084 return TCHARsToStr(EditClass);
2085 }
2086
2087 override int windowProc () {
2088 return cast(int)EditProc;
2089 }
2090
2091 override int windowProc (HWND hwnd, int msg, int wParam, int lParam) {
2092 if (msg is OS.EM_UNDO) {
2093 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2094 if ((bits & OS.ES_MULTILINE) is 0) {
2095 LRESULT result = wmClipboard (OS.EM_UNDO, wParam, lParam);
2096 if (result !is null) return result.value;
2097 return callWindowProc (hwnd, OS.EM_UNDO, wParam, lParam);
2098 }
2099 }
2100 if (msg is Display.SWT_RESTORECARET) {
2101 callWindowProc (hwnd, OS.WM_KILLFOCUS, 0, 0);
2102 callWindowProc (hwnd, OS.WM_SETFOCUS, 0, 0);
2103 return 1;
2104 }
2105 return super.windowProc (hwnd, msg, wParam, lParam);
2106 }
2107
2108 override LRESULT WM_CHAR (int wParam, int lParam) {
2109 if (ignoreCharacter) return null;
2110 LRESULT result = super.WM_CHAR (wParam, lParam);
2111 if (result !is null) return result;
2112
2113 /*
2114 * Bug in Windows. When the user types CTRL and BS
2115 * in an edit control, a DEL character is generated.
2116 * Rather than deleting the text, the DEL character
2117 * is inserted into the control. The fix is to detect
2118 * this case and not call the window proc.
2119 */
2120 switch (wParam) {
2121 case SWT.DEL:
2122 if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
2123 return LRESULT.ZERO;
2124 }
2125 default:
2126 }
2127
2128 /*
2129 * Feature in Windows. For some reason, when the
2130 * widget is a single line text widget, when the
2131 * user presses tab, return or escape, Windows beeps.
2132 * The fix is to look for these keys and not call
2133 * the window proc.
2134 */
2135 if ((style & SWT.SINGLE) !is 0) {
2136 switch (wParam) {
2137 case SWT.CR:
2138 postEvent (SWT.DefaultSelection);
2139 // FALL THROUGH
2140 case SWT.TAB:
2141 case SWT.ESC: return LRESULT.ZERO;
2142 default:
2143 }
2144 }
2145 return result;
2146 }
2147
2148 override LRESULT WM_CLEAR (int wParam, int lParam) {
2149 LRESULT result = super.WM_CLEAR (wParam, lParam);
2150 if (result !is null) return result;
2151 return wmClipboard (OS.WM_CLEAR, wParam, lParam);
2152 }
2153
2154 override LRESULT WM_CUT (int wParam, int lParam) {
2155 LRESULT result = super.WM_CUT (wParam, lParam);
2156 if (result !is null) return result;
2157 return wmClipboard (OS.WM_CUT, wParam, lParam);
2158 }
2159
2160 override LRESULT WM_ERASEBKGND (int wParam, int lParam) {
2161 LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
2162 if ((style & SWT.READ_ONLY) !is 0) {
2163 if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) is 0) {
2164 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2165 if ((bits & OS.ES_MULTILINE) !is 0) {
2166 Control control = findBackgroundControl ();
2167 if (control is null && background is -1) {
2168 if ((state & THEME_BACKGROUND) !is 0) {
2169 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
2170 control = findThemeControl ();
2171 if (control !is null) {
2172 RECT rect;
2173 OS.GetClientRect (handle, &rect);
2174 fillThemeBackground (cast(HANDLE)wParam, control, &rect);
2175 return LRESULT.ONE;
2176 }
2177 }
2178 }
2179 }
2180 }
2181 }
2182 }
2183 return result;
2184 }
2185
2186 override LRESULT WM_GETDLGCODE (int wParam, int lParam) {
2187 LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
2188 if (result !is null) return result;
2189
2190 /*
2191 * Bug in WinCE PPC. For some reason, sending WM_GETDLGCODE
2192 * to a multi-line edit control causes it to ignore return and
2193 * tab keys. The fix is to return the value which is normally
2194 * returned by the text window proc on other versions of Windows.
2195 */
2196 if (OS.IsPPC) {
2197 if ((style & SWT.MULTI) !is 0 && (style & SWT.READ_ONLY) is 0 && lParam is 0) {
2198 return new LRESULT (OS.DLGC_HASSETSEL | OS.DLGC_WANTALLKEYS | OS.DLGC_WANTCHARS);
2199 }
2200 }
2201
2202 /*
2203 * Feature in Windows. Despite the fact that the
2204 * edit control is read only, it still returns a
2205 * dialog code indicating that it wants all keys.
2206 * The fix is to detect this case and clear the bits.
2207 *
2208 * NOTE: A read only edit control processes arrow keys
2209 * so DLGC_WANTARROWS should not be cleared.
2210 */
2211 if ((style & SWT.READ_ONLY) !is 0) {
2212 int /*long*/ code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
2213 code &= ~(OS.DLGC_WANTALLKEYS | OS.DLGC_WANTTAB);
2214 return new LRESULT (code);
2215 }
2216 return null;
2217 }
2218
2219 override LRESULT WM_IME_CHAR (int wParam, int lParam) {
2220
2221 /* Process a DBCS character */
2222 Display display = this.display;
2223 display.lastKey = 0;
2224 display.lastAscii = wParam;
2225 display.lastVirtual = display.lastNull = display.lastDead = false;
2226 if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
2227 return LRESULT.ZERO;
2228 }
2229
2230 /*
2231 * Feature in Windows. The Windows text widget uses
2232 * two 2 WM_CHAR's to process a DBCS key instead of
2233 * using WM_IME_CHAR. The fix is to allow the text
2234 * widget to get the WM_CHAR's but ignore sending
2235 * them to the application.
2236 */
2237 ignoreCharacter = true;
2238 int /*long*/ result = callWindowProc (handle, OS.WM_IME_CHAR, wParam, lParam);
2239 MSG msg;
2240 int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
2241 while (OS.PeekMessage (&msg, handle, OS.WM_CHAR, OS.WM_CHAR, flags)) {
2242 OS.TranslateMessage (&msg);
2243 OS.DispatchMessage (&msg);
2244 }
2245 ignoreCharacter = false;
2246
2247 sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
2248 // widget could be disposed at this point
2249 display.lastKey = display.lastAscii = 0;
2250 return new LRESULT (result);
2251 }
2252
2253 override LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) {
2254 /*
2255 * Prevent Windows from processing WM_LBUTTONDBLCLK
2256 * when double clicking behavior is disabled by not
2257 * calling the window proc.
2258 */
2259 LRESULT result = null;
2260 sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam);
2261 if (!sendMouseEvent (SWT.MouseDoubleClick, 1, handle, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
2262 result = LRESULT.ZERO;
2263 }
2264 if (!display.captureChanged && !isDisposed ()) {
2265 if (OS.GetCapture () !is handle) OS.SetCapture (handle);
2266 }
2267 if (!doubleClick) return LRESULT.ZERO;
2268
2269 /*
2270 * Bug in Windows. When the last line of text in the
2271 * widget is double clicked and the line is empty, Windows
2272 * hides the i-beam then moves it to the first line in
2273 * the widget but does not scroll to show the user.
2274 * If the user types without clicking the mouse, invalid
2275 * characters are displayed at the end of each line of
2276 * text in the widget. The fix is to detect this case
2277 * and avoid calling the window proc.
2278 */
2279 int start, end;
2280 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
2281 if (start is end ) {
2282 int length = OS.GetWindowTextLength (handle);
2283 if (length is start) {
2284 int code = OS.SendMessage (handle, OS.EM_LINELENGTH, length, 0);
2285 if (code is 0) return LRESULT.ZERO;
2286 }
2287 }
2288 return result;
2289 }
2290
2291 override LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
2292 static if( OS.IsWinCE )
2293 if (OS.IsPPC) {
2294 LRESULT result = null;
2295 Display display = this.display;
2296 display.captureChanged = false;
2297 bool dispatch = sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam);
2298 /*
2299 * Note: On WinCE PPC, only attempt to recognize the gesture for
2300 * a context menu when the control contains a valid menu or there
2301 * are listeners for the MenuDetect event.
2302 *
2303 * Note: On WinCE PPC, the gesture that brings up a popup menu
2304 * on the text widget must keep the current text selection. As a
2305 * result, the window proc is only called if the menu is not shown.
2306 */
2307 bool hasMenu = menu !is null && !menu.isDisposed ();
2308 if (hasMenu || hooks (SWT.MenuDetect)) {
2309 int x = OS.GET_X_LPARAM (lParam);
2310 int y = OS.GET_Y_LPARAM (lParam);
2311 SHRGINFO shrg;
2312 shrg.cbSize = SHRGINFO.sizeof;
2313 shrg.hwndClient = handle;
2314 shrg.ptDown.x = x;
2315 shrg.ptDown.y = y;
2316 shrg.dwFlags = OS.SHRG_RETURNCMD;
2317 int type = OS.SHRecognizeGesture (&shrg);
2318 if (type is OS.GN_CONTEXTMENU) {
2319 showMenu (x, y);
2320 return LRESULT.ONE;
2321 }
2322 }
2323 if (dispatch) {
2324 result = new LRESULT (callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam));
2325 } else {
2326 result = LRESULT.ZERO;
2327 }
2328 if (!display.captureChanged && !isDisposed ()) {
2329 if (OS.GetCapture () !is handle) OS.SetCapture (handle);
2330 }
2331 return result;
2332 }
2333 return super.WM_LBUTTONDOWN (wParam, lParam);
2334 }
2335
2336 override LRESULT WM_PASTE (int wParam, int lParam) {
2337 LRESULT result = super.WM_PASTE (wParam, lParam);
2338 if (result !is null) return result;
2339 return wmClipboard (OS.WM_PASTE, wParam, lParam);
2340 }
2341
2342 override LRESULT WM_UNDO (int wParam, int lParam) {
2343 LRESULT result = super.WM_UNDO (wParam, lParam);
2344 if (result !is null) return result;
2345 return wmClipboard (OS.WM_UNDO, wParam, lParam);
2346 }
2347
2348 LRESULT wmClipboard (int msg, int /*long*/ wParam, int /*long*/ lParam) {
2349 if ((style & SWT.READ_ONLY) !is 0) return null;
2350 if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return null;
2351 bool call = false;
2352 int start, end;
2353 String newText = null;
2354 switch (msg) {
2355 case OS.WM_CLEAR:
2356 case OS.WM_CUT:
2357 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
2358 if (start !is end ) {
2359 newText = "";
2360 call = true;
2361 }
2362 break;
2363 case OS.WM_PASTE:
2364 OS.SendMessage (handle, OS.EM_GETSEL, start, end);
2365 newText = getClipboardText ();
2366 break;
2367 case OS.EM_UNDO:
2368 case OS.WM_UNDO:
2369 if (OS.SendMessage (handle, OS.EM_CANUNDO, 0, 0) !is 0) {
2370 ignoreModify = ignoreCharacter = true;
2371 OS.SendMessage (handle, OS.EM_GETSEL, &start, &end);
2372 callWindowProc (handle, msg, wParam, lParam);
2373 int length = OS.GetWindowTextLength (handle);
2374 int newStart, newEnd;
2375 OS.SendMessage (handle, OS.EM_GETSEL, &newStart, &newEnd);
2376 if (length !is 0 && newStart !is newEnd) {
2377 TCHAR[] buffer = NewTCHARs (getCodePage (), length + 1);
2378 OS.GetWindowText (handle, buffer.ptr, length + 1);
2379 newText = TCHARsToStr( buffer[ newStart .. newEnd ] );
2380 } else {
2381 newText = "";
2382 }
2383 callWindowProc (handle, msg, wParam, lParam);
2384 ignoreModify = ignoreCharacter = false;
2385 }
2386 break;
2387 default:
2388 }
2389 if (newText !is null) {
2390 String oldText = newText;
2391 newText = verifyText (newText, start, end, null);
2392 if (newText is null) return LRESULT.ZERO;
2393 if (newText !=/*eq*/oldText) {
2394 if (call) {
2395 callWindowProc (handle, msg, wParam, lParam);
2396 }
2397 newText = Display.withCrLf (newText);
2398 TCHAR* buffer = StrToTCHARz(getCodePage (), newText);
2399 /*
2400 * Feature in Windows. When an edit control with ES_MULTILINE
2401 * style that does not have the WS_VSCROLL style is full (i.e.
2402 * there is no space at the end to draw any more characters),
2403 * EM_REPLACESEL sends a WM_CHAR with a backspace character
2404 * to remove any further text that is added. This is an
2405 * implementation detail of the edit control that is unexpected
2406 * and can cause endless recursion when EM_REPLACESEL is sent
2407 * from a WM_CHAR handler. The fix is to ignore calling the
2408 * handler from WM_CHAR.
2409 */
2410 ignoreCharacter = true;
2411 OS.SendMessage (handle, OS.EM_REPLACESEL, 0, buffer);
2412 ignoreCharacter = false;
2413 return LRESULT.ZERO;
2414 }
2415 }
2416 if (msg is OS.WM_UNDO) {
2417 ignoreVerify = ignoreCharacter = true;
2418 callWindowProc (handle, OS.WM_UNDO, wParam, lParam);
2419 ignoreVerify = ignoreCharacter = false;
2420 return LRESULT.ONE;
2421 }
2422 return null;
2423 }
2424
2425 override LRESULT wmColorChild (int wParam, int lParam) {
2426 if ((style & SWT.READ_ONLY) !is 0) {
2427 if ((style & (SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL)) is 0) {
2428 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2429 if ((bits & OS.ES_MULTILINE) !is 0) {
2430 Control control = findBackgroundControl ();
2431 if (control is null && background is -1) {
2432 if ((state & THEME_BACKGROUND) !is 0) {
2433 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
2434 control = findThemeControl ();
2435 if (control !is null) {
2436 OS.SetTextColor (cast(HANDLE) wParam, getForegroundPixel ());
2437 OS.SetBkColor (cast(HANDLE) wParam, getBackgroundPixel ());
2438 OS.SetBkMode (cast(HANDLE) wParam, OS.TRANSPARENT);
2439 return new LRESULT ( cast(int) OS.GetStockObject (OS.NULL_BRUSH));
2440 }
2441 }
2442 }
2443 }
2444 }
2445 }
2446 }
2447 return super.wmColorChild (wParam, lParam);
2448 }
2449
2450 override LRESULT wmCommandChild (int wParam, int lParam) {
2451 int code = OS.HIWORD (wParam);
2452 switch (code) {
2453 case OS.EN_CHANGE:
2454 if (findImageControl () !is null) {
2455 OS.InvalidateRect (handle, null, true);
2456 }
2457 if (ignoreModify) break;
2458 /*
2459 * It is possible (but unlikely), that application
2460 * code could have disposed the widget in the modify
2461 * event. If this happens, end the processing of the
2462 * Windows message by returning zero as the result of
2463 * the window proc.
2464 */
2465 sendEvent (SWT.Modify);
2466 if (isDisposed ()) return LRESULT.ZERO;
2467 break;
2468 case OS.EN_ALIGN_LTR_EC:
2469 style &= ~SWT.RIGHT_TO_LEFT;
2470 style |= SWT.LEFT_TO_RIGHT;
2471 fixAlignment ();
2472 break;
2473 case OS.EN_ALIGN_RTL_EC:
2474 style &= ~SWT.LEFT_TO_RIGHT;
2475 style |= SWT.RIGHT_TO_LEFT;
2476 fixAlignment ();
2477 break;
2478 default:
2479 }
2480 return super.wmCommandChild (wParam, lParam);
2481 }
2482
2483 }
2484