Mercurial > projects > dwt2
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 |