comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/Spinner.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 4c0057e71936
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.Spinner;
14
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.SWTException;
17 import org.eclipse.swt.events.ModifyListener;
18 import org.eclipse.swt.events.SelectionEvent;
19 import org.eclipse.swt.events.SelectionListener;
20 import org.eclipse.swt.events.VerifyListener;
21 import org.eclipse.swt.graphics.Point;
22 import org.eclipse.swt.graphics.Rectangle;
23 import org.eclipse.swt.internal.win32.OS;
24
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.TypedListener;
27 import org.eclipse.swt.widgets.Event;
28 import org.eclipse.swt.widgets.Shell;
29
30
31 import java.lang.all;
32 import tango.text.convert.Integer : toString;
33 static import tango.text.Text;
34 alias tango.text.Text.Text!(char) StringBuffer;
35 import tango.util.Convert;
36
37 /**
38 * Instances of this class are selectable user interface
39 * objects that allow the user to enter and modify numeric
40 * values.
41 * <p>
42 * Note that although this class is a subclass of <code>Composite</code>,
43 * it does not make sense to add children to it, or set a layout on it.
44 * </p><p>
45 * <dl>
46 * <dt><b>Styles:</b></dt>
47 * <dd>READ_ONLY, WRAP</dd>
48 * <dt><b>Events:</b></dt>
49 * <dd>Selection, Modify, Verify</dd>
50 * </dl>
51 * </p><p>
52 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
53 * </p>
54 *
55 * @see <a href="http://www.eclipse.org/swt/snippets/#spinner">Spinner snippets</a>
56 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
57 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
58 *
59 * @since 3.1
60 */
61 public class Spinner : Composite {
62
63 alias Composite.computeSize computeSize;
64 alias Composite.sendKeyEvent sendKeyEvent;
65 alias Composite.setBackgroundImage setBackgroundImage;
66 alias Composite.setToolTipText setToolTipText;
67 alias Composite.windowProc windowProc;
68
69 HWND hwndText, hwndUpDown;
70 bool ignoreModify;
71 int pageIncrement, digits;
72 static /+const+/ WNDPROC EditProc;
73 static const TCHAR[] EditClass = "EDIT";
74 static /+const+/ WNDPROC UpDownProc;
75 static const TCHAR[] UpDownClass = OS.UPDOWN_CLASS;
76
77 private static bool static_this_completed = false;
78 private static void static_this() {
79 if( static_this_completed ){
80 return;
81 }
82 synchronized {
83 if( static_this_completed ){
84 return;
85 }
86 WNDCLASS lpWndClass;
87 OS.GetClassInfo (null, EditClass.ptr, &lpWndClass);
88 EditProc = lpWndClass.lpfnWndProc;
89 OS.GetClassInfo (null, UpDownClass.ptr, &lpWndClass);
90 UpDownProc = lpWndClass.lpfnWndProc;
91 static_this_completed = true;
92 }
93 }
94 /**
95 * the operating system limit for the number of characters
96 * that the text field in an instance of this class can hold
97 *
98 * @since 3.4
99 */
100 public static int LIMIT;
101
102 /*
103 * These values can be different on different platforms.
104 * Therefore they are not initialized in the declaration
105 * to stop the compiler from inlining.
106 */
107 static this() {
108 LIMIT = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF;
109 }
110
111 /**
112 * Constructs a new instance of this class given its parent
113 * and a style value describing its behavior and appearance.
114 * <p>
115 * The style value is either one of the style constants defined in
116 * class <code>SWT</code> which is applicable to instances of this
117 * class, or must be built by <em>bitwise OR</em>'ing together
118 * (that is, using the <code>int</code> "|" operator) two or more
119 * of those <code>SWT</code> style constants. The class description
120 * lists the style constants that are applicable to the class.
121 * Style bits are also inherited from superclasses.
122 * </p>
123 *
124 * @param parent a composite control which will be the parent of the new instance (cannot be null)
125 * @param style the style of control to construct
126 *
127 * @exception IllegalArgumentException <ul>
128 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
129 * </ul>
130 * @exception SWTException <ul>
131 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
132 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
133 * </ul>
134 *
135 * @see SWT#READ_ONLY
136 * @see SWT#WRAP
137 * @see Widget#checkSubclass
138 * @see Widget#getStyle
139 */
140 public this (Composite parent, int style) {
141 static_this();
142 super (parent, checkStyle (style));
143 }
144
145 override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) {
146 if (handle is null) return 0;
147 if (hwnd is hwndText) {
148 return OS.CallWindowProc (EditProc, hwnd, msg, wParam, lParam);
149 }
150 if (hwnd is hwndUpDown) {
151 return OS.CallWindowProc (UpDownProc, hwnd, msg, wParam, lParam);
152 }
153 return OS.DefWindowProc (handle, msg, wParam, lParam);
154 }
155
156 static int checkStyle (int style) {
157 /*
158 * Even though it is legal to create this widget
159 * with scroll bars, they serve no useful purpose
160 * because they do not automatically scroll the
161 * widget's client area. The fix is to clear
162 * the SWT style.
163 */
164 return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
165 }
166
167 override bool checkHandle (HWND hwnd) {
168 return hwnd is handle || hwnd is hwndText || hwnd is hwndUpDown;
169 }
170
171 override protected void checkSubclass () {
172 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
173 }
174
175 override void createHandle () {
176 super.createHandle ();
177 state &= ~(CANVAS | THEME_BACKGROUND);
178 auto hInstance = OS.GetModuleHandle (null);
179 int textExStyle = (style & SWT.BORDER) !is 0 ? OS.WS_EX_CLIENTEDGE : 0;
180 int textStyle = OS.WS_CHILD | OS.WS_VISIBLE | OS.ES_AUTOHSCROLL | OS.WS_CLIPSIBLINGS;
181 if ((style & SWT.READ_ONLY) !is 0) textStyle |= OS.ES_READONLY;
182 if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
183 if ((style & SWT.RIGHT_TO_LEFT) !is 0) textExStyle |= OS.WS_EX_LAYOUTRTL;
184 }
185 hwndText = OS.CreateWindowEx (
186 textExStyle,
187 EditClass.ptr,
188 null,
189 textStyle,
190 0, 0, 0, 0,
191 handle,
192 null,
193 hInstance,
194 null);
195 if (hwndText is null) error (SWT.ERROR_NO_HANDLES);
196 OS.SetWindowLongPtr (hwndText, OS.GWLP_ID, cast(LONG_PTR)hwndText);
197 int upDownStyle = OS.WS_CHILD | OS.WS_VISIBLE | OS.UDS_AUTOBUDDY;
198 if ((style & SWT.WRAP) !is 0) upDownStyle |= OS.UDS_WRAP;
199 if ((style & SWT.BORDER) !is 0) {
200 if ((style & SWT.RIGHT_TO_LEFT) !is 0) {
201 upDownStyle |= OS.UDS_ALIGNLEFT;
202 } else {
203 upDownStyle |= OS.UDS_ALIGNRIGHT;
204 }
205 }
206 hwndUpDown = OS.CreateWindowEx (
207 0,
208 UpDownClass.ptr,
209 null,
210 upDownStyle,
211 0, 0, 0, 0,
212 handle,
213 null,
214 hInstance,
215 null);
216 if (hwndUpDown is null) error (SWT.ERROR_NO_HANDLES);
217 int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
218 SetWindowPos (hwndText, hwndUpDown, 0, 0, 0, 0, flags);
219 OS.SetWindowLongPtr (hwndUpDown, OS.GWLP_ID, cast(LONG_PTR)hwndUpDown);
220 if (OS.IsDBLocale) {
221 auto hIMC = OS.ImmGetContext (handle);
222 OS.ImmAssociateContext (hwndText, hIMC);
223 OS.ImmAssociateContext (hwndUpDown, hIMC);
224 OS.ImmReleaseContext (handle, hIMC);
225 }
226 OS.SendMessage (hwndUpDown, OS.UDM_SETRANGE32, 0, 100);
227 OS.SendMessage (hwndUpDown, OS.IsWinCE ? OS.UDM_SETPOS : OS.UDM_SETPOS32, 0, 0);
228 pageIncrement = 10;
229 digits = 0;
230 TCHAR* buffer = StrToTCHARz (getCodePage (), "0");
231 OS.SetWindowText (hwndText, buffer);
232 }
233
234 /**
235 * Adds the listener to the collection of listeners who will
236 * be notified when the receiver's text is modified, by sending
237 * it one of the messages defined in the <code>ModifyListener</code>
238 * interface.
239 *
240 * @param listener the listener which should be notified
241 *
242 * @exception IllegalArgumentException <ul>
243 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
244 * </ul>
245 * @exception SWTException <ul>
246 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
247 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
248 * </ul>
249 *
250 * @see ModifyListener
251 * @see #removeModifyListener
252 */
253 public void addModifyListener (ModifyListener listener) {
254 checkWidget ();
255 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
256 TypedListener typedListener = new TypedListener (listener);
257 addListener (SWT.Modify, typedListener);
258 }
259
260 /**
261 * Adds the listener to the collection of listeners who will
262 * be notified when the control is selected by the user, by sending
263 * it one of the messages defined in the <code>SelectionListener</code>
264 * interface.
265 * <p>
266 * <code>widgetSelected</code> is not called for texts.
267 * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed in a single-line text.
268 * </p>
269 *
270 * @param listener the listener which should be notified when the control is selected by the user
271 *
272 * @exception IllegalArgumentException <ul>
273 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
274 * </ul>
275 * @exception SWTException <ul>
276 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
277 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
278 * </ul>
279 *
280 * @see SelectionListener
281 * @see #removeSelectionListener
282 * @see SelectionEvent
283 */
284 public void addSelectionListener(SelectionListener listener) {
285 checkWidget ();
286 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
287 TypedListener typedListener = new TypedListener (listener);
288 addListener (SWT.Selection,typedListener);
289 addListener (SWT.DefaultSelection,typedListener);
290 }
291
292 /**
293 * Adds the listener to the collection of listeners who will
294 * be notified when the receiver's text is verified, by sending
295 * it one of the messages defined in the <code>VerifyListener</code>
296 * interface.
297 *
298 * @param listener the listener which should be notified
299 *
300 * @exception IllegalArgumentException <ul>
301 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
302 * </ul>
303 * @exception SWTException <ul>
304 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
305 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
306 * </ul>
307 *
308 * @see VerifyListener
309 * @see #removeVerifyListener
310 */
311 void addVerifyListener (VerifyListener listener) {
312 checkWidget();
313 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
314 TypedListener typedListener = new TypedListener (listener);
315 addListener (SWT.Verify, typedListener);
316 }
317
318 override HWND borderHandle () {
319 return hwndText;
320 }
321
322 override public Point computeSize (int wHint, int hHint, bool changed) {
323 checkWidget ();
324 int width = 0, height = 0;
325 if (wHint is SWT.DEFAULT || hHint is SWT.DEFAULT) {
326 HFONT newFont, oldFont;
327 auto hDC = OS.GetDC (hwndText);
328 newFont = cast(HFONT) OS.SendMessage (hwndText, OS.WM_GETFONT, 0, 0);
329 if (newFont !is null) oldFont = OS.SelectObject (hDC, newFont);
330 TEXTMETRIC tm;
331 OS.GetTextMetrics (hDC, &tm);
332 height = tm.tmHeight;
333 RECT rect;
334 int max;
335 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, null, &max);
336 String string = .toString( max );
337 if (digits > 0) {
338 StringBuffer buffer = new StringBuffer ();
339 buffer.append (string);
340 buffer.append (getDecimalSeparator ());
341 int count = digits - string.length;
342 while (count >= 0) {
343 buffer.append ("0");
344 count--;
345 }
346 string = buffer.toString ();
347 }
348 TCHAR[] buffer = StrToTCHARs (getCodePage (), string, false);
349 int flags = OS.DT_CALCRECT | OS.DT_EDITCONTROL | OS.DT_NOPREFIX;
350 OS.DrawText (hDC, buffer.ptr, buffer.length, &rect, flags);
351 width = rect.right - rect.left;
352 if (newFont !is null ) OS.SelectObject (hDC, oldFont);
353 OS.ReleaseDC (hwndText, hDC);
354 }
355 if (width is 0) width = DEFAULT_WIDTH;
356 if (height is 0) height = DEFAULT_HEIGHT;
357 if (wHint !is SWT.DEFAULT) width = wHint;
358 if (hHint !is SWT.DEFAULT) height = hHint;
359 Rectangle trim = computeTrim (0, 0, width, height);
360 if (hHint is SWT.DEFAULT) {
361 int upDownHeight = OS.GetSystemMetrics (OS.SM_CYVSCROLL) + 2 * getBorderWidth ();
362 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
363 upDownHeight += (style & SWT.BORDER) !is 0 ? 1 : 3;
364 }
365 trim.height = Math.max (trim.height, upDownHeight);
366 }
367 return new Point (trim.width, trim.height);
368 }
369
370 override public Rectangle computeTrim (int x, int y, int width, int height) {
371 checkWidget ();
372
373 /* Get the trim of the text control */
374 RECT rect;
375 OS.SetRect (&rect, x, y, x + width, y + height);
376 int bits0 = OS.GetWindowLong (hwndText, OS.GWL_STYLE);
377 int bits1 = OS.GetWindowLong (hwndText, OS.GWL_EXSTYLE);
378 OS.AdjustWindowRectEx (&rect, bits0, false, bits1);
379 width = rect.right - rect.left;
380 height = rect.bottom - rect.top;
381
382 /*
383 * The preferred height of a single-line text widget
384 * has been hand-crafted to be the same height as
385 * the single-line text widget in an editable combo
386 * box.
387 */
388 int /*long*/ margins = OS.SendMessage (hwndText, OS.EM_GETMARGINS, 0, 0);
389 x -= OS.LOWORD (margins);
390 width += OS.LOWORD (margins) + OS.HIWORD (margins);
391 if ((style & SWT.BORDER) !is 0) {
392 x -= 1;
393 y -= 1;
394 width += 2;
395 height += 2;
396 }
397 width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
398 return new Rectangle (x, y, width, height);
399 }
400
401 /**
402 * Copies the selected text.
403 * <p>
404 * The current selection is copied to the clipboard.
405 * </p>
406 *
407 * @exception SWTException <ul>
408 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
409 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
410 * </ul>
411 */
412 public void copy () {
413 checkWidget ();
414 OS.SendMessage (hwndText, OS.WM_COPY, 0, 0);
415 }
416
417 /**
418 * Cuts the selected text.
419 * <p>
420 * The current selection is first copied to the
421 * clipboard and then deleted from the widget.
422 * </p>
423 *
424 * @exception SWTException <ul>
425 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
426 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
427 * </ul>
428 */
429 public void cut () {
430 checkWidget ();
431 if ((style & SWT.READ_ONLY) !is 0) return;
432 OS.SendMessage (hwndText, OS.WM_CUT, 0, 0);
433 }
434
435 override int defaultBackground () {
436 return OS.GetSysColor (OS.COLOR_WINDOW);
437 }
438
439 override void enableWidget (bool enabled) {
440 super.enableWidget (enabled);
441 OS.EnableWindow (hwndText, enabled);
442 OS.EnableWindow (hwndUpDown, enabled);
443 }
444
445 override void deregister () {
446 super.deregister ();
447 display.removeControl (hwndText);
448 display.removeControl (hwndUpDown);
449 }
450
451 override bool hasFocus () {
452 auto hwndFocus = OS.GetFocus ();
453 if (hwndFocus is handle) return true;
454 if (hwndFocus is hwndText) return true;
455 if (hwndFocus is hwndUpDown) return true;
456 return false;
457 }
458
459 /**
460 * Returns the number of decimal places used by the receiver.
461 *
462 * @return the digits
463 *
464 * @exception SWTException <ul>
465 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
466 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
467 * </ul>
468 */
469 public int getDigits () {
470 checkWidget ();
471 return digits;
472 }
473
474 String getDecimalSeparator () {
475 TCHAR[] tchar = NewTCHARs (getCodePage (), 4);
476 int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_SDECIMAL, tchar.ptr, 4);
477 return size !is 0 ? TCHARsToStr( tchar[0 .. size-1] ) : ".";
478 }
479
480 /**
481 * Returns the amount that the receiver's value will be
482 * modified by when the up/down arrows are pressed.
483 *
484 * @return the increment
485 *
486 * @exception SWTException <ul>
487 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
488 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
489 * </ul>
490 */
491 public int getIncrement () {
492 checkWidget ();
493 UDACCEL udaccel;
494 OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, 1, &udaccel);
495 return udaccel.nInc;
496 }
497
498 /**
499 * Returns the maximum value which the receiver will allow.
500 *
501 * @return the maximum
502 *
503 * @exception SWTException <ul>
504 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
505 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
506 * </ul>
507 */
508 public int getMaximum () {
509 checkWidget ();
510 int max;
511 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, null, &max);
512 return max;
513 }
514
515 /**
516 * Returns the minimum value which the receiver will allow.
517 *
518 * @return the minimum
519 *
520 * @exception SWTException <ul>
521 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
522 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
523 * </ul>
524 */
525 public int getMinimum () {
526 checkWidget ();
527 int min;
528 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, null);
529 return min;
530 }
531
532 /**
533 * Returns the amount that the receiver's position will be
534 * modified by when the page up/down keys are pressed.
535 *
536 * @return the page increment
537 *
538 * @exception SWTException <ul>
539 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
540 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
541 * </ul>
542 */
543 public int getPageIncrement () {
544 checkWidget ();
545 return pageIncrement;
546 }
547
548 /**
549 * Returns the <em>selection</em>, which is the receiver's position.
550 *
551 * @return the selection
552 *
553 * @exception SWTException <ul>
554 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
555 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
556 * </ul>
557 */
558 public int getSelection () {
559 checkWidget ();
560 static if (OS.IsWinCE) {
561 return OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
562 } else {
563 return OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
564 }
565 }
566
567 int getSelectionText (bool [] parseFail) {
568 int length_ = OS.GetWindowTextLength (hwndText);
569 TCHAR[] buffer = NewTCHARs (getCodePage (), length_ + 1);
570 OS.GetWindowText (hwndText, buffer.ptr, length_ + 1);
571 String string = TCHARsToStr( buffer[ 0 .. length_] );
572 try {
573 int value;
574 if (digits > 0) {
575 String decimalSeparator = getDecimalSeparator ();
576 int index = string.indexOf (decimalSeparator);
577 if (index !is -1) {
578 int startIndex = string.startsWith ("+") || string.startsWith ("-") ? 1 : 0;
579 String wholePart = startIndex !is index ? string.substring (startIndex, index) : "0";
580 String decimalPart = string.substring (index + 1);
581 if (decimalPart.length > digits) {
582 decimalPart = decimalPart.substring (0, digits);
583 } else {
584 int i = digits - decimalPart.length;
585 for (int j = 0; j < i; j++) {
586 decimalPart = decimalPart ~ "0";
587 }
588 }
589 int wholeValue = Integer.parseInt (wholePart);
590 int decimalValue = Integer.parseInt (decimalPart);
591 for (int i = 0; i < digits; i++) wholeValue *= 10;
592 value = wholeValue + decimalValue;
593 if (string.startsWith ("-")) value = -value;
594 } else {
595 value = Integer.parseInt (string);
596 for (int i = 0; i < digits; i++) value *= 10;
597 }
598 } else {
599 value = Integer.parseInt (string);
600 }
601 int max, min;
602 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, &max);
603 if (min <= value && value <= max) return value;
604 } catch (NumberFormatException e) {
605 }
606 parseFail [0] = true;
607 return -1;
608 }
609
610 /**
611 * Returns a string containing a copy of the contents of the
612 * receiver's text field, or an empty string if there are no
613 * contents.
614 *
615 * @return the receiver's text
616 *
617 * @exception SWTException <ul>
618 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
619 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
620 * </ul>
621 *
622 * @since 3.4
623 */
624 public String getText () {
625 checkWidget ();
626 int length_ = OS.GetWindowTextLength (hwndText);
627 if (length_ is 0) return "";
628 TCHAR[] buffer = NewTCHARs (getCodePage (), length_ + 1);
629 OS.GetWindowText (hwndText, buffer.ptr, length_ + 1);
630 return TCHARsToStr( buffer[0 .. length_] );
631 }
632
633 /**
634 * Returns the maximum number of characters that the receiver's
635 * text field is capable of holding. If this has not been changed
636 * by <code>setTextLimit()</code>, it will be the constant
637 * <code>Spinner.LIMIT</code>.
638 *
639 * @return the text limit
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 * @see #LIMIT
647 *
648 * @since 3.4
649 */
650 public int getTextLimit () {
651 checkWidget ();
652 return OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
653 }
654
655 int mbcsToWcsPos (int mbcsPos) {
656 if (mbcsPos <= 0) return 0;
657 if (OS.IsUnicode) return mbcsPos;
658 int mbcsSize = OS.GetWindowTextLengthA (hwndText);
659 if (mbcsSize is 0) return 0;
660 if (mbcsPos >= mbcsSize) return mbcsSize;
661 CHAR [] buffer = new CHAR [mbcsSize + 1];
662 OS.GetWindowTextA (hwndText, buffer.ptr, mbcsSize + 1);
663 return OS.MultiByteToWideChar (getCodePage (), OS.MB_PRECOMPOSED, buffer.ptr, mbcsPos, null, 0);
664 }
665
666 /**
667 * Pastes text from clipboard.
668 * <p>
669 * The selected text is deleted from the widget
670 * and new text inserted from the clipboard.
671 * </p>
672 *
673 * @exception SWTException <ul>
674 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
675 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
676 * </ul>
677 */
678 public void paste () {
679 checkWidget ();
680 if ((style & SWT.READ_ONLY) !is 0) return;
681 OS.SendMessage (hwndText, OS.WM_PASTE, 0, 0);
682 }
683
684 override void register () {
685 super.register ();
686 display.addControl (hwndText, this);
687 display.addControl (hwndUpDown, this);
688 }
689
690 override void releaseHandle () {
691 super.releaseHandle ();
692 hwndText = hwndUpDown = null;
693 }
694
695 /**
696 * Removes the listener from the collection of listeners who will
697 * be notified when the receiver's text is modified.
698 *
699 * @param listener the listener which should no longer be notified
700 *
701 * @exception IllegalArgumentException <ul>
702 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
703 * </ul>
704 * @exception SWTException <ul>
705 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
706 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
707 * </ul>
708 *
709 * @see ModifyListener
710 * @see #addModifyListener
711 */
712 public void removeModifyListener (ModifyListener listener) {
713 checkWidget ();
714 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
715 if (eventTable is null) return;
716 eventTable.unhook (SWT.Modify, listener);
717 }
718
719 /**
720 * Removes the listener from the collection of listeners who will
721 * be notified when the control is selected by the user.
722 *
723 * @param listener the listener which should no longer be notified
724 *
725 * @exception IllegalArgumentException <ul>
726 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
727 * </ul>
728 * @exception SWTException <ul>
729 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
730 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
731 * </ul>
732 *
733 * @see SelectionListener
734 * @see #addSelectionListener
735 */
736 public void removeSelectionListener(SelectionListener listener) {
737 checkWidget ();
738 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
739 if (eventTable is null) return;
740 eventTable.unhook (SWT.Selection, listener);
741 eventTable.unhook (SWT.DefaultSelection,listener);
742 }
743
744 /**
745 * Removes the listener from the collection of listeners who will
746 * be notified when the control is verified.
747 *
748 * @param listener the listener which should no longer be notified
749 *
750 * @exception IllegalArgumentException <ul>
751 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
752 * </ul>
753 * @exception SWTException <ul>
754 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
755 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
756 * </ul>
757 *
758 * @see VerifyListener
759 * @see #addVerifyListener
760 */
761 void removeVerifyListener (VerifyListener listener) {
762 checkWidget ();
763 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
764 if (eventTable is null) return;
765 eventTable.unhook (SWT.Verify, listener);
766 }
767
768 override bool sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
769 if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
770 return false;
771 }
772 if ((style & SWT.READ_ONLY) !is 0) return true;
773 if (type !is SWT.KeyDown) return true;
774 if (msg !is OS.WM_CHAR && msg !is OS.WM_KEYDOWN && msg !is OS.WM_IME_CHAR) {
775 return true;
776 }
777 if (event.character is 0) return true;
778 // if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
779 char key = event.character;
780 int stateMask = event.stateMask;
781
782 /*
783 * Disable all magic keys that could modify the text
784 * and don't send events when Alt, Shift or Ctrl is
785 * pressed.
786 */
787 switch (msg) {
788 case OS.WM_CHAR:
789 if (key !is 0x08 && key !is 0x7F && key !is '\r' && key !is '\t' && key !is '\n') break;
790 // FALL THROUGH
791 case OS.WM_KEYDOWN:
792 if ((stateMask & (SWT.ALT | SWT.SHIFT | SWT.CONTROL)) !is 0) return false;
793 break;
794 default:
795 }
796
797 /*
798 * If the left button is down, the text widget refuses the character.
799 */
800 if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
801 return true;
802 }
803
804 /* Verify the character */
805 String oldText = "";
806 int start, end;
807 OS.SendMessage (hwndText, OS.EM_GETSEL, &start, &end);
808 switch (key) {
809 case 0x08: /* Bs */
810 if (start is end) {
811 if (start is 0) return true;
812 start = start - 1;
813 if (!OS.IsUnicode && OS.IsDBLocale) {
814 int newStart, newEnd;
815 OS.SendMessage (hwndText, OS.EM_SETSEL, start, end);
816 OS.SendMessage (hwndText, OS.EM_GETSEL, &newStart, &newEnd);
817 if (start !is newStart) start = start - 1;
818 }
819 start = Math.max (start, 0);
820 }
821 break;
822 case 0x7F: /* Del */
823 if (start is end) {
824 int length_ = OS.GetWindowTextLength (hwndText);
825 if (start is length_) return true;
826 end = end + 1;
827 if (!OS.IsUnicode && OS.IsDBLocale) {
828 int newStart, newEnd;
829 OS.SendMessage (hwndText, OS.EM_SETSEL, start, end);
830 OS.SendMessage (hwndText, OS.EM_GETSEL, &newStart, &newEnd);
831 if (end !is newEnd) end = end + 1;
832 }
833 end = Math.min (end, length_);
834 }
835 break;
836 case '\r': /* Return */
837 return true;
838 default: /* Tab and other characters */
839 if (key !is '\t' && key < 0x20) return true;
840 oldText = [key];
841 break;
842 }
843 String newText = verifyText (oldText, start, end, event);
844 if (newText is null) return false;
845 if (newText is oldText) return true;
846 TCHAR* buffer = StrToTCHARz (getCodePage (), newText);
847 OS.SendMessage (hwndText, OS.EM_SETSEL, start, end);
848 OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
849 return false;
850 }
851
852 override void setBackgroundImage (HBITMAP hBitmap) {
853 super.setBackgroundImage (hBitmap);
854 OS.InvalidateRect (hwndText, null, true);
855 }
856
857 override void setBackgroundPixel (int pixel) {
858 super.setBackgroundPixel (pixel);
859 OS.InvalidateRect (hwndText, null, true);
860 }
861
862 /**
863 * Sets the number of decimal places used by the receiver.
864 * <p>
865 * The digit setting is used to allow for floating point values in the receiver.
866 * For example, to set the selection to a floating point value of 1.37 call setDigits() with
867 * a value of 2 and setSelection() with a value of 137. Similarly, if getDigits() has a value
868 * of 2 and getSelection() returns 137 this should be interpreted as 1.37. This applies to all
869 * numeric APIs.
870 * </p>
871 *
872 * @param value the new digits (must be greater than or equal to zero)
873 *
874 * @exception IllegalArgumentException <ul>
875 * <li>ERROR_INVALID_ARGUMENT - if the value is less than zero</li>
876 * </ul>
877 * @exception SWTException <ul>
878 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
879 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
880 * </ul>
881 */
882 public void setDigits (int value) {
883 checkWidget ();
884 if (value < 0) error (SWT.ERROR_INVALID_ARGUMENT);
885 if (value is this.digits) return;
886 this.digits = value;
887 int pos;
888 static if (OS.IsWinCE) {
889 pos = OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
890 } else {
891 pos = OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
892 }
893 setSelection (pos, false, true, false);
894 }
895
896 override void setForegroundPixel (int pixel) {
897 super.setForegroundPixel (pixel);
898 OS.InvalidateRect (hwndText, null, true);
899 }
900
901 /**
902 * Sets the amount that the receiver's value will be
903 * modified by when the up/down arrows are pressed to
904 * the argument, which must be at least one.
905 *
906 * @param value the new increment (must be greater than zero)
907 *
908 * @exception SWTException <ul>
909 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
910 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
911 * </ul>
912 */
913 public void setIncrement (int value) {
914 checkWidget ();
915 if (value < 1) return;
916 auto hHeap = OS.GetProcessHeap ();
917 int count = OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, 0, cast(UDACCEL*)null);
918 auto udaccels = cast(UDACCEL*) OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, UDACCEL.sizeof * count);
919 OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, count, udaccels);
920 int first = -1;
921 UDACCEL udaccel;
922 for (int i = 0; i < count; i++) {
923 void* offset = udaccels + i;
924 OS.MoveMemory (&udaccel, offset, UDACCEL.sizeof);
925 if (first is -1) first = udaccel.nInc;
926 udaccel.nInc = udaccel.nInc * value / first;
927 OS.MoveMemory (offset, &udaccel, UDACCEL.sizeof);
928 }
929 OS.SendMessage (hwndUpDown, OS.UDM_SETACCEL, count, udaccels);
930 OS.HeapFree (hHeap, 0, udaccels);
931 }
932
933 /**
934 * Sets the maximum value that the receiver will allow. This new
935 * value will be ignored if it is not greater than the receiver's current
936 * minimum value. If the new maximum is applied then the receiver's
937 * selection value will be adjusted if necessary to fall within its new range.
938 *
939 * @param value the new maximum, which must be greater than the current minimum
940 *
941 * @exception SWTException <ul>
942 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
943 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
944 * </ul>
945 */
946 public void setMaximum (int value) {
947 checkWidget ();
948 int min;
949 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, null);
950 if (value <= min) return;
951 int pos;
952 static if (OS.IsWinCE) {
953 pos = OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
954 } else {
955 pos = OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
956 }
957 OS.SendMessage (hwndUpDown , OS.UDM_SETRANGE32, min, value);
958 if (pos > value) setSelection (value, true, true, false);
959 }
960
961 /**
962 * Sets the minimum value that the receiver will allow. This new
963 * value will be ignored if it is not less than the receiver's
964 * current maximum value. If the new minimum is applied then the receiver's
965 * selection value will be adjusted if necessary to fall within its new range.
966 *
967 * @param value the new minimum, which must be less than the current maximum
968 *
969 * @exception SWTException <ul>
970 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
971 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
972 * </ul>
973 */
974 public void setMinimum (int value) {
975 checkWidget ();
976 int max;
977 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, null, &max);
978 if (value >= max) return;
979 int pos;
980 static if (OS.IsWinCE) {
981 pos = OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
982 } else {
983 pos = OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
984 }
985 OS.SendMessage (hwndUpDown , OS.UDM_SETRANGE32, value, max);
986 if (pos < value) setSelection (value, true, true, false);
987 }
988
989 /**
990 * Sets the amount that the receiver's position will be
991 * modified by when the page up/down keys are pressed
992 * to the argument, which must be at least one.
993 *
994 * @param value the page increment (must be greater than zero)
995 *
996 * @exception SWTException <ul>
997 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
998 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
999 * </ul>
1000 */
1001 public void setPageIncrement (int value) {
1002 checkWidget ();
1003 if (value < 1) return;
1004 pageIncrement = value;
1005 }
1006
1007 /**
1008 * Sets the <em>selection</em>, which is the receiver's
1009 * position, to the argument. If the argument is not within
1010 * the range specified by minimum and maximum, it will be
1011 * adjusted to fall within this range.
1012 *
1013 * @param value the new selection (must be zero or greater)
1014 *
1015 * @exception SWTException <ul>
1016 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1017 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1018 * </ul>
1019 */
1020 public void setSelection (int value) {
1021 checkWidget ();
1022 int max, min;
1023 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, &max);
1024 value = Math.min (Math.max (min, value), max );
1025 setSelection (value, true, true, false);
1026 }
1027
1028 void setSelection (int value, bool setPos, bool setText, bool notify) {
1029 if (setPos) {
1030 OS.SendMessage (hwndUpDown , OS.IsWinCE ? OS.UDM_SETPOS : OS.UDM_SETPOS32, 0, value);
1031 }
1032 if (setText) {
1033 String string;
1034 if (digits is 0) {
1035 string = .toString (value);
1036 } else {
1037 string = to!(String)(Math.abs (value));
1038 String decimalSeparator = getDecimalSeparator ();
1039 int index = string.length - digits;
1040 StringBuffer buffer = new StringBuffer ();
1041 if (value < 0) buffer.append ("-");
1042 if (index > 0) {
1043 buffer.append (string.substring (0, index));
1044 buffer.append (decimalSeparator);
1045 buffer.append (string.substring (index));
1046 } else {
1047 buffer.append ("0");
1048 buffer.append (decimalSeparator);
1049 while (index++ < 0) buffer.append ("0");
1050 buffer.append (string);
1051 }
1052 string = buffer.toString ();
1053 }
1054 if (hooks (SWT.Verify) || filters (SWT.Verify)) {
1055 int length_ = OS.GetWindowTextLength (hwndText);
1056 string = verifyText (string, 0, length_, null);
1057 if (string is null) return;
1058 }
1059 TCHAR* buffer = StrToTCHARz (getCodePage (), string);
1060 OS.SetWindowText (hwndText, buffer);
1061 OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
1062 if (!OS.IsWinCE) {
1063 OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, hwndText, OS.OBJID_CLIENT, 0);
1064 }
1065 }
1066 if (notify) postEvent (SWT.Selection);
1067 }
1068
1069 /**
1070 * Sets the maximum number of characters that the receiver's
1071 * text field is capable of holding to be the argument.
1072 * <p>
1073 * To reset this value to the default, use <code>setTextLimit(Spinner.LIMIT)</code>.
1074 * Specifying a limit value larger than <code>Spinner.LIMIT</code> sets the
1075 * receiver's limit to <code>Spinner.LIMIT</code>.
1076 * </p>
1077 * @param limit new text limit
1078 *
1079 * @exception IllegalArgumentException <ul>
1080 * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
1081 * </ul>
1082 * @exception SWTException <ul>
1083 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1084 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1085 * </ul>
1086 *
1087 * @see #LIMIT
1088 *
1089 * @since 3.4
1090 */
1091 public void setTextLimit (int limit) {
1092 checkWidget ();
1093 if (limit is 0) error (SWT.ERROR_CANNOT_BE_ZERO);
1094 OS.SendMessage (hwndText, OS.EM_SETLIMITTEXT, limit, 0);
1095 }
1096
1097 override void setToolTipText (Shell shell, String string) {
1098 shell.setToolTipText (hwndText, string);
1099 shell.setToolTipText (hwndUpDown, string);
1100 }
1101
1102 /**
1103 * Sets the receiver's selection, minimum value, maximum
1104 * value, digits, increment and page increment all at once.
1105 * <p>
1106 * Note: This is similar to setting the values individually
1107 * using the appropriate methods, but may be implemented in a
1108 * more efficient fashion on some platforms.
1109 * </p>
1110 *
1111 * @param selection the new selection value
1112 * @param minimum the new minimum value
1113 * @param maximum the new maximum value
1114 * @param digits the new digits value
1115 * @param increment the new increment value
1116 * @param pageIncrement the new pageIncrement value
1117 *
1118 * @exception SWTException <ul>
1119 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1120 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1121 * </ul>
1122 *
1123 * @since 3.2
1124 */
1125 public void setValues (int selection, int minimum, int maximum, int digits, int increment, int pageIncrement) {
1126 checkWidget ();
1127 if (maximum <= minimum) return;
1128 if (digits < 0) return;
1129 if (increment < 1) return;
1130 if (pageIncrement < 1) return;
1131 selection = Math.min (Math.max (minimum, selection), maximum);
1132 setIncrement (increment);
1133 this.pageIncrement = pageIncrement;
1134 this.digits = digits;
1135 OS.SendMessage (hwndUpDown , OS.UDM_SETRANGE32, minimum, maximum);
1136 setSelection (selection, true, true, false);
1137 }
1138
1139 override void subclass () {
1140 super.subclass ();
1141 int /*long*/ newProc = display.windowProc;
1142 OS.SetWindowLongPtr (hwndText, OS.GWLP_WNDPROC, newProc);
1143 OS.SetWindowLongPtr (hwndUpDown, OS.GWLP_WNDPROC, newProc);
1144 }
1145
1146 override void unsubclass () {
1147 super.unsubclass ();
1148 OS.SetWindowLongPtr (hwndText, OS.GWLP_WNDPROC, cast(LONG_PTR)EditProc);
1149 OS.SetWindowLongPtr (hwndUpDown, OS.GWLP_WNDPROC, cast(LONG_PTR)UpDownProc);
1150 }
1151
1152 String verifyText (String string, int start, int end, Event keyEvent) {
1153 Event event = new Event ();
1154 event.text = string;
1155 event.start = start;
1156 event.end = end;
1157 if (keyEvent !is null) {
1158 event.character = keyEvent.character;
1159 event.keyCode = keyEvent.keyCode;
1160 event.stateMask = keyEvent.stateMask;
1161 }
1162 int index = 0;
1163 if (digits > 0) {
1164 String decimalSeparator = getDecimalSeparator ();
1165 index = string.indexOf (decimalSeparator);
1166 if (index !is -1) {
1167 string = string.substring (0, index) ~ string.substring (index + 1);
1168 }
1169 index = 0;
1170 }
1171 if (string.length > 0) {
1172 int min;
1173 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, null);
1174 if (min < 0 && string.charAt (0) is '-') index++;
1175 }
1176 while (index < string.length ) {
1177 if (!CharacterIsDigit (string.charAt (index))) break;
1178 index++;
1179 }
1180 event.doit = index is string.length ;
1181 if (!OS.IsUnicode && OS.IsDBLocale) {
1182 event.start = mbcsToWcsPos (start);
1183 event.end = mbcsToWcsPos (end);
1184 }
1185 sendEvent (SWT.Verify, event);
1186 if (!event.doit || isDisposed ()) return null;
1187 return event.text;
1188 }
1189
1190 override int widgetExtStyle () {
1191 return super.widgetExtStyle () & ~OS.WS_EX_CLIENTEDGE;
1192 }
1193
1194 override int windowProc (HWND hwnd, int msg, int wParam, int lParam) {
1195 if (hwnd is hwndText || hwnd is hwndUpDown) {
1196 LRESULT result = null;
1197 switch (msg) {
1198 /* Keyboard messages */
1199 case OS.WM_CHAR: result = wmChar (hwnd, wParam, lParam); break;
1200 case OS.WM_IME_CHAR: result = wmIMEChar (hwnd, wParam, lParam); break;
1201 case OS.WM_KEYDOWN: result = wmKeyDown (hwnd, wParam, lParam); break;
1202 case OS.WM_KEYUP: result = wmKeyUp (hwnd, wParam, lParam); break;
1203 case OS.WM_SYSCHAR: result = wmSysChar (hwnd, wParam, lParam); break;
1204 case OS.WM_SYSKEYDOWN: result = wmSysKeyDown (hwnd, wParam, lParam); break;
1205 case OS.WM_SYSKEYUP: result = wmSysKeyUp (hwnd, wParam, lParam); break;
1206
1207 /* Mouse Messages */
1208 case OS.WM_CAPTURECHANGED: result = wmCaptureChanged (hwnd, wParam, lParam); break;
1209 case OS.WM_LBUTTONDBLCLK: result = wmLButtonDblClk (hwnd, wParam, lParam); break;
1210 case OS.WM_LBUTTONDOWN: result = wmLButtonDown (hwnd, wParam, lParam); break;
1211 case OS.WM_LBUTTONUP: result = wmLButtonUp (hwnd, wParam, lParam); break;
1212 case OS.WM_MBUTTONDBLCLK: result = wmMButtonDblClk (hwnd, wParam, lParam); break;
1213 case OS.WM_MBUTTONDOWN: result = wmMButtonDown (hwnd, wParam, lParam); break;
1214 case OS.WM_MBUTTONUP: result = wmMButtonUp (hwnd, wParam, lParam); break;
1215 case OS.WM_MOUSEHOVER: result = wmMouseHover (hwnd, wParam, lParam); break;
1216 case OS.WM_MOUSELEAVE: result = wmMouseLeave (hwnd, wParam, lParam); break;
1217 case OS.WM_MOUSEMOVE: result = wmMouseMove (hwnd, wParam, lParam); break;
1218 // case OS.WM_MOUSEWHEEL: result = wmMouseWheel (hwnd, wParam, lParam); break;
1219 case OS.WM_RBUTTONDBLCLK: result = wmRButtonDblClk (hwnd, wParam, lParam); break;
1220 case OS.WM_RBUTTONDOWN: result = wmRButtonDown (hwnd, wParam, lParam); break;
1221 case OS.WM_RBUTTONUP: result = wmRButtonUp (hwnd, wParam, lParam); break;
1222 case OS.WM_XBUTTONDBLCLK: result = wmXButtonDblClk (hwnd, wParam, lParam); break;
1223 case OS.WM_XBUTTONDOWN: result = wmXButtonDown (hwnd, wParam, lParam); break;
1224 case OS.WM_XBUTTONUP: result = wmXButtonUp (hwnd, wParam, lParam); break;
1225
1226 /* Focus Messages */
1227 case OS.WM_SETFOCUS: result = wmSetFocus (hwnd, wParam, lParam); break;
1228 case OS.WM_KILLFOCUS: result = wmKillFocus (hwnd, wParam, lParam); break;
1229
1230 /* Paint messages */
1231 case OS.WM_PAINT: result = wmPaint (hwnd, wParam, lParam); break;
1232 case OS.WM_PRINT: result = wmPrint (hwnd, wParam, lParam); break;
1233
1234 /* Menu messages */
1235 case OS.WM_CONTEXTMENU: result = wmContextMenu (hwnd, wParam, lParam); break;
1236
1237 /* Clipboard messages */
1238 case OS.WM_CLEAR:
1239 case OS.WM_CUT:
1240 case OS.WM_PASTE:
1241 case OS.WM_UNDO:
1242 case OS.EM_UNDO:
1243 if (hwnd is hwndText) {
1244 result = wmClipboard (hwnd, msg, wParam, lParam);
1245 }
1246 break;
1247 default:
1248 }
1249 if (result !is null) return result.value;
1250 return callWindowProc (hwnd, msg, wParam, lParam);
1251 }
1252 return super.windowProc (hwnd, msg, wParam, lParam);
1253 }
1254
1255 override LRESULT WM_ERASEBKGND (int wParam, int lParam) {
1256 super.WM_ERASEBKGND (wParam, lParam);
1257 drawBackground (cast(HANDLE)wParam);
1258 return LRESULT.ONE;
1259 }
1260
1261 override LRESULT WM_KILLFOCUS (int wParam, int lParam) {
1262 return null;
1263 }
1264
1265 override LRESULT WM_SETFOCUS (int wParam, int lParam) {
1266 OS.SetFocus (hwndText);
1267 OS.SendMessage (hwndText, OS.EM_SETSEL, 0, -1);
1268 return null;
1269 }
1270
1271 override LRESULT WM_SETFONT (int wParam, int lParam) {
1272 LRESULT result = super.WM_SETFONT (wParam, lParam);
1273 if (result !is null) return result;
1274 OS.SendMessage (hwndText, OS.WM_SETFONT, wParam, lParam);
1275 return result;
1276 }
1277
1278 override LRESULT WM_SIZE (int wParam, int lParam) {
1279 LRESULT result = super.WM_SIZE (wParam, lParam);
1280 if (isDisposed ()) return result;
1281 int width = OS.LOWORD (lParam), height = OS.HIWORD (lParam);
1282 int upDownWidth = OS.GetSystemMetrics (OS.SM_CXVSCROLL);
1283 int textWidth = width - upDownWidth;
1284 int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
1285 int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
1286 SetWindowPos (hwndText, null, 0, 0, textWidth + border, height, flags);
1287 SetWindowPos (hwndUpDown, null, textWidth, 0, upDownWidth, height, flags);
1288 return result;
1289 }
1290
1291 override LRESULT wmChar (HWND hwnd, int wParam, int lParam) {
1292 LRESULT result = super.wmChar (hwnd, wParam, lParam);
1293 if (result !is null) return result;
1294 /*
1295 * Feature in Windows. For some reason, when the
1296 * widget is a single line text widget, when the
1297 * user presses tab, return or escape, Windows beeps.
1298 * The fix is to look for these keys and not call
1299 * the window proc.
1300 */
1301 switch (wParam) {
1302 case SWT.CR:
1303 postEvent (SWT.DefaultSelection);
1304 // FALL THROUGH
1305 case SWT.TAB:
1306 case SWT.ESC: return LRESULT.ZERO;
1307 default:
1308 }
1309 return result;
1310 }
1311
1312 LRESULT wmClipboard (HWND hwndText, int msg, int wParam, int lParam) {
1313 if ((style & SWT.READ_ONLY) !is 0) return null;
1314 // if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return null;
1315 bool call = false;
1316 int start, end;
1317 String newText = null;
1318 switch (msg) {
1319 case OS.WM_CLEAR:
1320 case OS.WM_CUT:
1321 OS.SendMessage (hwndText, OS.EM_GETSEL, &start, &end);
1322 if (start !is end) {
1323 newText = "";
1324 call = true;
1325 }
1326 break;
1327 case OS.WM_PASTE:
1328 OS.SendMessage (hwndText, OS.EM_GETSEL, &start, &end);
1329 newText = getClipboardText ();
1330 break;
1331 case OS.EM_UNDO:
1332 case OS.WM_UNDO:
1333 if (OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0) !is 0) {
1334 ignoreModify = true;
1335 OS.SendMessage (hwndText, OS.EM_GETSEL, &start, &end);
1336 OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
1337 int length_ = OS.GetWindowTextLength (hwndText);
1338 int newStart, newEnd;
1339 OS.SendMessage (hwndText, OS.EM_GETSEL, &newStart, &newEnd);
1340 if (length_ !is 0 && newStart !is newEnd ) {
1341 TCHAR[] buffer = NewTCHARs (getCodePage (), length_ + 1);
1342 OS.GetWindowText (hwndText, buffer.ptr, length_ + 1);
1343 newText = TCHARsToStr( buffer[ newStart .. newEnd ] );
1344 } else {
1345 newText = "";
1346 }
1347 OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
1348 ignoreModify = false;
1349 }
1350 break;
1351 default:
1352 }
1353 if (newText !is null) {
1354 String oldText = newText;
1355 newText = verifyText (newText, start, end, null);
1356 if (newText is null) return LRESULT.ZERO;
1357 if ( newText !=/*eq*/ oldText ) {
1358 if (call) {
1359 OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
1360 }
1361 TCHAR[] buffer = StrToTCHARs (getCodePage (), newText, true);
1362 if (msg is OS.WM_SETTEXT) {
1363 auto hHeap = OS.GetProcessHeap ();
1364 int byteCount = buffer.length * TCHAR.sizeof;
1365 auto pszText = cast(TCHAR*) OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
1366 OS.MoveMemory (pszText, buffer.ptr, byteCount);
1367 int code = OS.CallWindowProc (EditProc, hwndText, msg, wParam, cast(int) pszText);
1368 OS.HeapFree (hHeap, 0, pszText);
1369 return new LRESULT (code);
1370 } else {
1371 OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer.ptr);
1372 return LRESULT.ZERO;
1373 }
1374 }
1375 }
1376 return null;
1377 }
1378
1379 override LRESULT wmCommandChild (int wParam, int lParam) {
1380 int code = OS.HIWORD (wParam);
1381 switch (code) {
1382 case OS.EN_CHANGE:
1383 if (ignoreModify) break;
1384 bool [] parseFail = new bool [1];
1385 int value = getSelectionText (parseFail);
1386 if (!parseFail [0]) {
1387 int pos;
1388 static if (OS.IsWinCE) {
1389 pos = OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
1390 } else {
1391 pos = OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
1392 }
1393 if (pos !is value) setSelection (value, true, false, true);
1394 }
1395 sendEvent (SWT.Modify);
1396 if (isDisposed ()) return LRESULT.ZERO;
1397 break;
1398 default:
1399 }
1400 return super.wmCommandChild (wParam, lParam);
1401 }
1402
1403 override LRESULT wmKeyDown (HWND hwnd, int wParam, int lParam) {
1404 LRESULT result = super.wmKeyDown (hwnd, wParam, lParam);
1405 if (result !is null) return result;
1406
1407 /* Increment the value */
1408 UDACCEL udaccel;
1409 OS.SendMessage (hwndUpDown, OS.UDM_GETACCEL, 1, &udaccel);
1410 int delta = 0;
1411 switch (wParam) {
1412 case OS.VK_UP: delta = udaccel.nInc; break;
1413 case OS.VK_DOWN: delta = -udaccel.nInc; break;
1414 case OS.VK_PRIOR: delta = pageIncrement; break;
1415 case OS.VK_NEXT: delta = -pageIncrement; break;
1416 default:
1417 }
1418 if (delta !is 0) {
1419 bool [1] parseFail;
1420 int value = getSelectionText (parseFail);
1421 if (parseFail [0]) {
1422 static if (OS.IsWinCE) {
1423 value = OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
1424 } else {
1425 value = OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
1426 }
1427 }
1428 int newValue = value + delta;
1429 int max, min;
1430 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, &max);
1431 if ((style & SWT.WRAP) !is 0) {
1432 if (newValue < min ) newValue = max;
1433 if (newValue > max ) newValue = min;
1434 }
1435 newValue = Math.min (Math.max (min , newValue), max );
1436 if (value !is newValue) setSelection (newValue, true, true, true);
1437 }
1438
1439 /* Stop the edit control from moving the caret */
1440 switch (wParam) {
1441 case OS.VK_UP:
1442 case OS.VK_DOWN:
1443 return LRESULT.ZERO;
1444 default:
1445 }
1446 return result;
1447 }
1448
1449 override LRESULT wmKillFocus (HWND hwnd, int wParam, int lParam) {
1450 bool [1] parseFail;
1451 int value = getSelectionText (parseFail);
1452 if (parseFail [0]) {
1453 static if (OS.IsWinCE) {
1454 value = OS.LOWORD (OS.SendMessage (hwndUpDown, OS.UDM_GETPOS, 0, 0));
1455 } else {
1456 value = OS.SendMessage (hwndUpDown, OS.UDM_GETPOS32, 0, 0);
1457 }
1458 setSelection (value, false, true, false);
1459 }
1460 return super.wmKillFocus (hwnd, wParam, lParam);
1461 }
1462
1463 override LRESULT wmNotifyChild (NMHDR* hdr, int wParam, int lParam) {
1464 switch (hdr.code) {
1465 case OS.UDN_DELTAPOS:
1466 NMUPDOWN* lpnmud = cast(NMUPDOWN*)lParam;
1467 //OS.MoveMemory (lpnmud, lParam, NMUPDOWN.sizeof);
1468 int value = lpnmud.iPos + lpnmud.iDelta;
1469 int max, min;
1470 OS.SendMessage (hwndUpDown , OS.UDM_GETRANGE32, &min, &max);
1471 if ((style & SWT.WRAP) !is 0) {
1472 if (value < min ) value = max ;
1473 if (value > max ) value = min ;
1474 }
1475 /*
1476 * The SWT.Modify event is sent after the widget has been
1477 * updated with the new state. Rather than allowing
1478 * the default updown window proc to set the value
1479 * when the user clicks on the updown control, set
1480 * the value explicitly and stop the window proc
1481 * from running.
1482 */
1483 value = Math.min (Math.max (min , value), max );
1484 if (value !is lpnmud.iPos) {
1485 setSelection (value, true, true, true);
1486 }
1487 return LRESULT.ONE;
1488 default:
1489 }
1490 return super.wmNotifyChild (hdr, wParam, lParam);
1491 }
1492
1493 override LRESULT wmScrollChild (int wParam, int lParam) {
1494 int code = OS.LOWORD (wParam);
1495 switch (code) {
1496 case OS.SB_THUMBPOSITION:
1497 postEvent (SWT.Selection);
1498 break;
1499 default:
1500 }
1501 return super.wmScrollChild (wParam, lParam);
1502 }
1503
1504 }
1505