comparison dwt/widgets/ToolTip.d @ 123:63a09873578e

Fixed compile errors
author Jacob Carlborg <doob@me.com>
date Thu, 15 Jan 2009 23:08:54 +0100
parents 62202ce0039f
children 07399639c0c8
comparison
equal deleted inserted replaced
122:2e671fa40eec 123:63a09873578e
81 static final int INSET = 4; 81 static final int INSET = 4;
82 static final int TIP_HEIGHT = 20; 82 static final int TIP_HEIGHT = 20;
83 static final int IMAGE_SIZE = 16; 83 static final int IMAGE_SIZE = 16;
84 static final int DELAY = 10000; 84 static final int DELAY = 10000;
85 85
86 /** 86 /**
87 * Constructs a new instance of this class given its parent 87 * Constructs a new instance of this class given its parent
88 * and a style value describing its behavior and appearance. 88 * and a style value describing its behavior and appearance.
89 * <p> 89 * <p>
90 * The style value is either one of the style constants defined in 90 * The style value is either one of the style constants defined in
91 * class <code>DWT</code> which is applicable to instances of this 91 * class <code>DWT</code> which is applicable to instances of this
92 * class, or must be built by <em>bitwise OR</em>'ing together 92 * class, or must be built by <em>bitwise OR</em>'ing together
93 * (that is, using the <code>int</code> "|" operator) two or more 93 * (that is, using the <code>int</code> "|" operator) two or more
94 * of those <code>DWT</code> style constants. The class description 94 * of those <code>DWT</code> style constants. The class description
95 * lists the style constants that are applicable to the class. 95 * lists the style constants that are applicable to the class.
96 * Style bits are also inherited from superclasses. 96 * Style bits are also inherited from superclasses.
97 * </p> 97 * </p>
98 * 98 *
99 * @param parent a composite control which will be the parent of the new instance (cannot be null) 99 * @param parent a composite control which will be the parent of the new instance (cannot be null)
100 * @param style the style of control to construct 100 * @param style the style of control to construct
101 * 101 *
102 * @exception IllegalArgumentException <ul> 102 * @exception IllegalArgumentException <ul>
103 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 103 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
104 * </ul> 104 * </ul>
105 * @exception DWTException <ul> 105 * @exception DWTException <ul>
106 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> 106 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
107 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> 107 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
108 * </ul> 108 * </ul>
109 * 109 *
110 * @see DWT#ICON_ERROR 110 * @see DWT#ICON_ERROR
111 * @see DWT#ICON_INFORMATION 111 * @see DWT#ICON_INFORMATION
112 * @see DWT#ICON_WARNING 112 * @see DWT#ICON_WARNING
113 * @see Widget#checkSubclass 113 * @see Widget#checkSubclass
114 * @see Widget#getStyle 114 * @see Widget#getStyle
115 */ 115 */
116 public this (Shell parent, int style) { 116 public this (Shell parent, int style) {
117 super (parent, checkStyle (style)); 117 super (parent, checkStyle (style));
118 this.parent = parent; 118 this.parent = parent;
119 this.autohide = true; 119 this.autohide = true;
120 x = y = -1; 120 x = y = -1;
121 Display display = getDisplay ();
122 tip = new Shell (parent, DWT.ON_TOP | DWT.NO_TRIM);
123 Color background = display.getSystemColor (DWT.COLOR_INFO_BACKGROUND);
124 tip.setBackground (background);
125 listener = new class Listener {
126 public void handleEvent (Event event) {
127 switch (event.type) {
128 case DWT.Dispose: onDispose (event); break;
129 case DWT.Paint: onPaint (event); break;
130 case DWT.MouseDown: onMouseDown (event); break;
131 default:
132 assert(false);
133 }
134 }
135 };
136 addListener (DWT.Dispose, listener);
137 tip.addListener (DWT.Paint, listener);
138 tip.addListener (DWT.MouseDown, listener);
139 }
140
141 static int checkStyle (int style) {
142 int mask = DWT.ICON_ERROR | DWT.ICON_INFORMATION | DWT.ICON_WARNING;
143 if ((style & mask) is 0) return style;
144 return checkBits (style, DWT.ICON_INFORMATION, DWT.ICON_WARNING, DWT.ICON_ERROR, 0, 0, 0);
145 }
146
147 /**
148 * Adds the listener to the collection of listeners who will
149 * be notified when the receiver is selected by the user, by sending
150 * it one of the messages defined in the <code>SelectionListener</code>
151 * interface.
152 * <p>
153 * <code>widgetSelected</code> is called when the receiver is selected.
154 * <code>widgetDefaultSelected</code> is not called.
155 * </p>
156 *
157 * @param listener the listener which should be notified when the receiver is selected by the user
158 *
159 * @exception IllegalArgumentException <ul>
160 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
161 * </ul>
162 * @exception DWTException <ul>
163 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
164 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
165 * </ul>
166 *
167 * @see SelectionListener
168 * @see #removeSelectionListener
169 * @see SelectionEvent
170 */
171 public void addSelectionListener (SelectionListener listener) {
172 checkWidget ();
173 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
174 TypedListener typedListener = new TypedListener (listener);
175 addListener (DWT.Selection,typedListener);
176 addListener (DWT.DefaultSelection,typedListener);
177 }
178
179 void configure () {
180 Display display = parent.getDisplay ();
181 int x = this.x;
182 int y = this.y;
183 if (x is -1 || y is -1) {
184 Point point;
185 if (item !is null) {
186 point = item.getLocation ();
187 } else {
188 point = display.getCursorLocation ();
189 }
190 x = point.x;
191 y = point.y;
192 }
193 dwt.widgets.Monitor.Monitor monitor = parent.getMonitor ();
194 Rectangle dest = monitor.getBounds ();
195 Point size = getSize (dest.width / 4);
196 int w = size.x;
197 int h = size.y;
198 int t = (style & DWT.BALLOON) !is 0 ? TIP_HEIGHT : 0;
199 int i = (style & DWT.BALLOON) !is 0 ? 16 : 0;
200 tip.setSize (w, h + t);
201 int [] polyline;
202 spikeAbove = dest.height >= y + size.y + t;
203 if (dest.width >= x + size.x) {
204 if (dest.height >= y + size.y + t) {
205 polyline = [
206 0, 5+t, 1, 5+t, 1, 3+t, 3, 1+t, 5, 1+t, 5, t,
207 16, t, 16, 0, 35, t,
208 w-5, t, w-5, 1+t, w-3, 1+t, w-1, 3+t, w-1, 5+t, w, 5+t,
209 w, h-5+t, w-1, h-5+t, w-1, h-3+t, w-2, h-3+t, w-2, h-2+t, w-3, h-2+t, w-3, h-1+t, w-5, h-1+t, w-5, h+t,
210 5, h+t, 5, h-1+t, 3, h-1+t, 3, h-2+t, 2, h-2+t, 2, h-3+t, 1, h-3+t, 1, h-5+t, 0, h-5+t,
211 0, 5+t];
212 borderPolygon = [
213 0, 5+t, 1, 4+t, 1, 3+t, 3, 1+t, 4, 1+t, 5, t,
214 16, t, 16, 1, 35, t,
215 w-6, 0+t, w-5, 1+t, w-4, 1+t, w-2, 3+t, w-2, 4+t, w-1, 5+t,
216 w-1, h-6+t, w-2, h-5+t, w-2, h-4+t, w-4, h-2+t, w-5, h-2+t, w-6, h-1+t,
217 5, h-1+t, 4, h-2+t, 3, h-2+t, 1, h-4+t, 1, h-5+t, 0, h-6+t,
218 0, 5+t];
219 tip.setLocation (Math.max (0, x - i), y);
220 } else {
221 polyline = [
222 0, 5, 1, 5, 1, 3, 3, 1, 5, 1, 5, 0,
223 w-5, 0, w-5, 1, w-3, 1, w-1, 3, w-1, 5, w, 5,
224 w, h-5, w-1, h-5, w-1, h-3, w-2, h-3, w-2, h-2, w-3, h-2, w-3, h-1, w-5, h-1, w-5, h,
225 35, h, 16, h+t, 16, h,
226 5, h, 5, h-1, 3, h-1, 3, h-2, 2, h-2, 2, h-3, 1, h-3, 1, h-5, 0, h-5,
227 0, 5];
228 borderPolygon = [
229 0, 5, 1, 4, 1, 3, 3, 1, 4, 1, 5, 0,
230 w-6, 0, w-5, 1, w-4, 1, w-2, 3, w-2, 4, w-1, 5,
231 w-1, h-6, w-2, h-5, w-2, h-4, w-4, h-2, w-5, h-2, w-6, h-1,
232 36, h-1, 16, h+t-1, 16, h-1,
233 5, h-1, 4, h-2, 3, h-2, 1, h-4, 1, h-5, 0, h-6,
234 0, 5];
235 tip.setLocation (Math.max (0, x - i), y - size.y - t);
236 }
237 } else {
238 if (dest.height >= y + size.y + t) {
239 polyline = [
240 0, 5+t, 1, 5+t, 1, 3+t, 3, 1+t, 5, 1+t, 5, t,
241 w-35, t, w-16, 0, w-16, t,
242 w-5, t, w-5, 1+t, w-3, 1+t, w-1, 3+t, w-1, 5+t, w, 5+t,
243 w, h-5+t, w-1, h-5+t, w-1, h-3+t, w-2, h-3+t, w-2, h-2+t, w-3, h-2+t, w-3, h-1+t, w-5, h-1+t, w-5, h+t,
244 5, h+t, 5, h-1+t, 3, h-1+t, 3, h-2+t, 2, h-2+t, 2, h-3+t, 1, h-3+t, 1, h-5+t, 0, h-5+t,
245 0, 5+t];
246 borderPolygon = [
247 0, 5+t, 1, 4+t, 1, 3+t, 3, 1+t, 4, 1+t, 5, t,
248 w-35, t, w-17, 2, w-17, t,
249 w-6, t, w-5, 1+t, w-4, 1+t, w-2, 3+t, w-2, 4+t, w-1, 5+t,
250 w-1, h-6+t, w-2, h-5+t, w-2, h-4+t, w-4, h-2+t, w-5, h-2+t, w-6, h-1+t,
251 5, h-1+t, 4, h-2+t, 3, h-2+t, 1, h-4+t, 1, h-5+t, 0, h-6+t,
252 0, 5+t];
253 tip.setLocation (Math.min (dest.width - size.x, x - size.x + i), y);
254 } else {
255 polyline = [
256 0, 5, 1, 5, 1, 3, 3, 1, 5, 1, 5, 0,
257 w-5, 0, w-5, 1, w-3, 1, w-1, 3, w-1, 5, w, 5,
258 w, h-5, w-1, h-5, w-1, h-3, w-2, h-3, w-2, h-2, w-3, h-2, w-3, h-1, w-5, h-1, w-5, h,
259 w-16, h, w-16, h+t, w-35, h,
260 5, h, 5, h-1, 3, h-1, 3, h-2, 2, h-2, 2, h-3, 1, h-3, 1, h-5, 0, h-5,
261 0, 5];
262 borderPolygon = [
263 0, 5, 1, 4, 1, 3, 3, 1, 4, 1, 5, 0,
264 w-6, 0, w-5, 1, w-4, 1, w-2, 3, w-2, 4, w-1, 5,
265 w-1, h-6, w-2, h-5, w-2, h-4, w-4, h-2, w-5, h-2, w-6, h-1,
266 w-17, h-1, w-17, h+t-2, w-36, h-1,
267 5, h-1, 4, h-2, 3, h-2, 1, h-4, 1, h-5, 0, h-6,
268 0, 5];
269 tip.setLocation (Math.min (dest.width - size.x, x - size.x + i), y - size.y - t);
270 }
271 }
272 if ((style & DWT.BALLOON) !is 0) {
273 if (region !is null) region.dispose ();
274 region = new Region (display);
275 region.add (polyline);
276 tip.setRegion (region);
277 }
278 }
279
280 /**
281 * Returns <code>true</code> if the receiver is automatically
282 * hidden by the platform, and <code>false</code> otherwise.
283 *
284 * @return the receiver's auto hide state
285 *
286 * @exception DWTException <ul>
287 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
288 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
289 * </ul>
290 *
291 */
292 public bool getAutoHide () {
293 checkWidget ();
294 return autohide;
295 }
296
297 Point getSize (int maxWidth) {
298 int textWidth = 0, messageWidth = 0;
299 if (layoutText !is null) {
300 layoutText.setWidth (-1);
301 textWidth = layoutText.getBounds ().width;
302 }
303 if (layoutMessage !is null) {
304 layoutMessage.setWidth (-1);
305 messageWidth = layoutMessage.getBounds ().width;
306 }
307 int messageTrim = 2 * INSET + 2 * BORDER + 2 * PADDING;
308 bool hasImage = layoutText !is null && (style & DWT.BALLOON) !is 0 && (style & (DWT.ICON_ERROR | DWT.ICON_INFORMATION | DWT.ICON_WARNING)) !is 0;
309 int textTrim = messageTrim + (hasImage ? IMAGE_SIZE : 0);
310 int width = Math.min (maxWidth, Math.max (textWidth + textTrim, messageWidth + messageTrim));
311 int textHeight = 0, messageHeight = 0;
312 if (layoutText !is null) {
313 layoutText.setWidth (maxWidth - textTrim);
314 textHeight = layoutText.getBounds ().height;
315 }
316 if (layoutMessage !is null) {
317 layoutMessage.setWidth (maxWidth - messageTrim);
318 messageHeight = layoutMessage.getBounds ().height;
319 }
320 int height = 2 * BORDER + 2 * PADDING + messageHeight;
321 if (layoutText !is null) height += Math.max (IMAGE_SIZE, textHeight) + 2 * PADDING;
322 return new Point (width, height);
323 }
324
325 /**
326 * Returns the receiver's message, which will be an empty
327 * string if it has never been set.
328 *
329 * @return the receiver's message
330 *
331 * @exception DWTException <ul>
332 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
333 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
334 * </ul>
335 */
336 public String getMessage () {
337 checkWidget ();
338 return layoutMessage !is null ? layoutMessage.getText() : "";
339 }
340
341 /**
342 * Returns the receiver's parent, which must be a <code>Shell</code>.
343 *
344 * @return the receiver's parent
345 *
346 * @exception DWTException <ul>
347 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
348 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
349 * </ul>
350 */
351 public Shell getParent () {
352 checkWidget ();
353 return parent;
354 }
355
356 /**
357 * Returns the receiver's text, which will be an empty
358 * string if it has never been set.
359 *
360 * @return the receiver's text
361 *
362 * @exception DWTException <ul>
363 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
364 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
365 * </ul>
366 */
367 public String getText () {
368 checkWidget ();
369 return layoutText !is null ? layoutText.getText() : "";
370 }
371
372 /**
373 * Returns <code>true</code> if the receiver is visible, and
374 * <code>false</code> otherwise.
375 * <p>
376 * If one of the receiver's ancestors is not visible or some
377 * other condition makes the receiver not visible, this method
378 * may still indicate that it is considered visible even though
379 * it may not actually be showing.
380 * </p>
381 *
382 * @return the receiver's visibility state
383 *
384 * @exception DWTException <ul>
385 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
386 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
387 * </ul>
388 */
389 public bool getVisible () {
390 checkWidget ();
391 return tip.getVisible ();
392 }
393
394 /**
395 * Returns <code>true</code> if the receiver is visible and all
396 * of the receiver's ancestors are visible and <code>false</code>
397 * otherwise.
398 *
399 * @return the receiver's visibility state
400 *
401 * @exception DWTException <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 * @see #getVisible
407 */
408 public bool isVisible () {
409 checkWidget ();
410 return getVisible ();
411 }
412
413 void onDispose (Event event) {
414 removeListener (DWT.Dispose, listener);
415 notifyListeners (DWT.Dispose, event);
416 event.type = DWT.None;
417
418 if (runnable !is null) {
121 Display display = getDisplay (); 419 Display display = getDisplay ();
122 tip = new Shell (parent, DWT.ON_TOP | DWT.NO_TRIM); 420 display.timerExec (-1, runnable);
123 Color background = display.getSystemColor (DWT.COLOR_INFO_BACKGROUND); 421 }
124 tip.setBackground (background); 422 runnable = null;
125 listener = new class Listener { 423 tip.dispose ();
126 public void handleEvent (Event event) { 424 tip = null;
127 switch (event.type) { 425 if (region !is null) region.dispose ();
128 case DWT.Dispose: onDispose (event); break; 426 region = null;
129 case DWT.Paint: onPaint (event); break; 427 if (layoutText !is null) layoutText.dispose ();
130 case DWT.MouseDown: onMouseDown (event); break; 428 layoutText = null;
131 default: 429 if (layoutMessage !is null) layoutMessage.dispose ();
132 assert(false); 430 layoutMessage = null;
133 } 431 if (boldFont !is null) boldFont.dispose ();
432 boldFont = null;
433 borderPolygon = null;
434 }
435
436 void onMouseDown (Event event) {
437 notifyListeners (DWT.Selection, new Event ());
438 setVisible (false);
439 }
440
441 void onPaint (Event event) {
442 GC gc = event.gc;
443 int x = BORDER + PADDING;
444 int y = BORDER + PADDING;
445 if ((style & DWT.BALLOON) !is 0) {
446 if (spikeAbove) y += TIP_HEIGHT;
447 gc.drawPolygon (borderPolygon);
448 } else {
449 Rectangle rect = tip.getClientArea ();
450 gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height -1);
451 }
452 if (layoutText !is null) {
453 int id = style & (DWT.ICON_ERROR | DWT.ICON_INFORMATION | DWT.ICON_WARNING);
454 if ((style & DWT.BALLOON) !is 0 && id !is 0) {
455 Display display = getDisplay ();
456 Image image = display.getSystemImage (id);
457 Rectangle rect = image.getBounds ();
458 gc.drawImage (image, 0, 0, rect.width, rect.height, x, y, IMAGE_SIZE, IMAGE_SIZE);
459 x += IMAGE_SIZE;
460 }
461 x += INSET;
462 layoutText.draw (gc, x, y);
463 y += 2 * PADDING + Math.max (IMAGE_SIZE, layoutText.getBounds ().height);
464 }
465 if (layoutMessage !is null) {
466 x = BORDER + PADDING + INSET;
467 layoutMessage.draw (gc, x, y);
468 }
469 }
470
471 /**
472 * Removes the listener from the collection of listeners who will
473 * be notified when the receiver is selected by the user.
474 *
475 * @param listener the listener which should no longer be notified
476 *
477 * @exception IllegalArgumentException <ul>
478 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
479 * </ul>
480 * @exception DWTException <ul>
481 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
482 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
483 * </ul>
484 *
485 * @see SelectionListener
486 * @see #addSelectionListener
487 */
488 public void removeSelectionListener (SelectionListener listener) {
489 checkWidget();
490 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
491 if (eventTable is null) return;
492 eventTable.unhook (DWT.Selection, listener);
493 eventTable.unhook (DWT.DefaultSelection,listener);
494 }
495
496 /**
497 * Makes the receiver hide automatically when <code>true</code>,
498 * and remain visible when <code>false</code>.
499 *
500 * @param autoHide the auto hide state
501 *
502 * @exception DWTException <ul>
503 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
504 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
505 * </ul>
506 *
507 * @see #getVisible
508 * @see #setVisible
509 */
510 public void setAutoHide (bool autohide) {
511 checkWidget ();
512 this.autohide = autohide;
513 //TODO - update when visible
514 }
515
516 /**
517 * Sets the location of the receiver, which must be a tooltip,
518 * to the point specified by the arguments which are relative
519 * to the display.
520 * <p>
521 * Note that this is different from most widgets where the
522 * location of the widget is relative to the parent.
523 * </p>
524 *
525 * @param x the new x coordinate for the receiver
526 * @param y the new y coordinate for the receiver
527 *
528 * @exception DWTException <ul>
529 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
530 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
531 * </ul>
532 */
533 public void setLocation (int x, int y) {
534 checkWidget ();
535 if (this.x is x && this.y is y) return;
536 this.x = x;
537 this.y = y;
538 if (tip.getVisible ()) configure ();
539 }
540
541 /**
542 * Sets the location of the receiver, which must be a tooltip,
543 * to the point specified by the argument which is relative
544 * to the display.
545 * <p>
546 * Note that this is different from most widgets where the
547 * location of the widget is relative to the parent.
548 * </p><p>
549 * Note that the platform window manager ultimately has control
550 * over the location of tooltips.
551 * </p>
552 *
553 * @param location the new location for the receiver
554 *
555 * @exception IllegalArgumentException <ul>
556 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
557 * </ul>
558 * @exception DWTException <ul>
559 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
560 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
561 * </ul>
562 */
563 public void setLocation (Point location) {
564 checkWidget ();
565 if (location is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
566 setLocation (location.x, location.y);
567 }
568
569 /**
570 * Sets the receiver's message.
571 *
572 * @param string the new message
573 *
574 * @exception IllegalArgumentException <ul>
575 * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
576 * </ul>
577 * @exception DWTException <ul>
578 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
579 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
580 * </ul>
581 */
582 public void setMessage (String string) {
583 checkWidget ();
584 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
585 if (layoutMessage !is null) layoutMessage.dispose();
586 layoutMessage = null;
587 if (string.length () !is 0) {
588 Display display = getDisplay ();
589 layoutMessage = new TextLayout (display);
590 layoutMessage.setText (string);
591 }
592 if (tip.getVisible ()) configure ();
593 }
594
595 /**
596 * Sets the receiver's text.
597 *
598 * @param string the new text
599 *
600 * @exception IllegalArgumentException <ul>
601 * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
602 * </ul>
603 * @exception DWTException <ul>
604 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
605 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
606 * </ul>
607 */
608 public void setText (String string) {
609 checkWidget ();
610 //if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
611 if (layoutText !is null) layoutText.dispose ();
612 layoutText = null;
613 if (boldFont !is null) boldFont.dispose ();
614 boldFont = null;
615 if (string.length () !is 0) {
616 Display display = getDisplay ();
617 layoutText = new TextLayout (display);
618 layoutText.setText (string);
619 Font font = display.getSystemFont ();
620 FontData data = font.getFontData () [0];
621 boldFont = new Font (cast(Device) display, data.getName (), data.getHeight (), DWT.BOLD);
622 TextStyle style = new TextStyle (boldFont, null, null);
623 layoutText.setStyle (style, 0, string.length ());
624 }
625 if (tip.getVisible ()) configure ();
626 }
627
628 /**
629 * Marks the receiver as visible if the argument is <code>true</code>,
630 * and marks it invisible otherwise.
631 * <p>
632 * If one of the receiver's ancestors is not visible or some
633 * other condition makes the receiver not visible, marking
634 * it visible may not actually cause it to be displayed.
635 * </p>
636 *
637 * @param visible the new visibility state
638 *
639 * @exception DWTException <ul>
640 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
641 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
642 * </ul>
643 */
644 public void setVisible (bool visible) {
645 if (visible) configure ();
646 tip.setVisible (visible);
647 Display display = getDisplay ();
648 if (runnable !is null) display.timerExec (-1, runnable);
649 runnable = null;
650 if (autohide && visible) {
651 runnable = new class Runnable {
652 public void run () {
653 if (!isDisposed ()) setVisible (false);
134 } 654 }
135 }; 655 };
136 addListener (DWT.Dispose, listener); 656 display.timerExec(DELAY, runnable);
137 tip.addListener (DWT.Paint, listener); 657 }
138 tip.addListener (DWT.MouseDown, listener); 658 }
139 } 659
140 660 }
141 static int checkStyle (int style) {
142 int mask = DWT.ICON_ERROR | DWT.ICON_INFORMATION | DWT.ICON_WARNING;
143 if ((style & mask) is 0) return style;
144 return checkBits (style, DWT.ICON_INFORMATION, DWT.ICON_WARNING, DWT.ICON_ERROR, 0, 0, 0);
145 }
146
147 /**
148 * Adds the listener to the collection of listeners who will
149 * be notified when the receiver is selected by the user, by sending
150 * it one of the messages defined in the <code>SelectionListener</code>
151 * interface.
152 * <p>
153 * <code>widgetSelected</code> is called when the receiver is selected.
154 * <code>widgetDefaultSelected</code> is not called.
155 * </p>
156 *
157 * @param listener the listener which should be notified when the receiver is selected by the user
158 *
159 * @exception IllegalArgumentException <ul>
160 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
161 * </ul>
162 * @exception DWTException <ul>
163 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
164 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
165 * </ul>
166 *
167 * @see SelectionListener
168 * @see #removeSelectionListener
169 * @see SelectionEvent
170 */
171 public void addSelectionListener (SelectionListener listener) {
172 checkWidget ();
173 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
174 TypedListener typedListener = new TypedListener (listener);
175 addListener (DWT.Selection,typedListener);
176 addListener (DWT.DefaultSelection,typedListener);
177 }
178
179 void configure () {
180 Display display = parent.getDisplay ();
181 int x = this.x;
182 int y = this.y;
183 if (x is -1 || y is -1) {
184 Point point;
185 if (item !is null) {
186 point = item.getLocation ();
187 } else {
188 point = display.getCursorLocation ();
189 }
190 x = point.x;
191 y = point.y;
192 }
193 dwt.widgets.Monitor.Monitor monitor = parent.getMonitor ();
194 Rectangle dest = monitor.getBounds ();
195 Point size = getSize (dest.width / 4);
196 int w = size.x;
197 int h = size.y;
198 int t = (style & DWT.BALLOON) !is 0 ? TIP_HEIGHT : 0;
199 int i = (style & DWT.BALLOON) !is 0 ? 16 : 0;
200 tip.setSize (w, h + t);
201 int [] polyline;
202 spikeAbove = dest.height >= y + size.y + t;
203 if (dest.width >= x + size.x) {
204 if (dest.height >= y + size.y + t) {
205 polyline = [
206 0, 5+t, 1, 5+t, 1, 3+t, 3, 1+t, 5, 1+t, 5, t,
207 16, t, 16, 0, 35, t,
208 w-5, t, w-5, 1+t, w-3, 1+t, w-1, 3+t, w-1, 5+t, w, 5+t,
209 w, h-5+t, w-1, h-5+t, w-1, h-3+t, w-2, h-3+t, w-2, h-2+t, w-3, h-2+t, w-3, h-1+t, w-5, h-1+t, w-5, h+t,
210 5, h+t, 5, h-1+t, 3, h-1+t, 3, h-2+t, 2, h-2+t, 2, h-3+t, 1, h-3+t, 1, h-5+t, 0, h-5+t,
211 0, 5+t];
212 borderPolygon = [
213 0, 5+t, 1, 4+t, 1, 3+t, 3, 1+t, 4, 1+t, 5, t,
214 16, t, 16, 1, 35, t,
215 w-6, 0+t, w-5, 1+t, w-4, 1+t, w-2, 3+t, w-2, 4+t, w-1, 5+t,
216 w-1, h-6+t, w-2, h-5+t, w-2, h-4+t, w-4, h-2+t, w-5, h-2+t, w-6, h-1+t,
217 5, h-1+t, 4, h-2+t, 3, h-2+t, 1, h-4+t, 1, h-5+t, 0, h-6+t,
218 0, 5+t];
219 tip.setLocation (Math.max (0, x - i), y);
220 } else {
221 polyline = [
222 0, 5, 1, 5, 1, 3, 3, 1, 5, 1, 5, 0,
223 w-5, 0, w-5, 1, w-3, 1, w-1, 3, w-1, 5, w, 5,
224 w, h-5, w-1, h-5, w-1, h-3, w-2, h-3, w-2, h-2, w-3, h-2, w-3, h-1, w-5, h-1, w-5, h,
225 35, h, 16, h+t, 16, h,
226 5, h, 5, h-1, 3, h-1, 3, h-2, 2, h-2, 2, h-3, 1, h-3, 1, h-5, 0, h-5,
227 0, 5];
228 borderPolygon = [
229 0, 5, 1, 4, 1, 3, 3, 1, 4, 1, 5, 0,
230 w-6, 0, w-5, 1, w-4, 1, w-2, 3, w-2, 4, w-1, 5,
231 w-1, h-6, w-2, h-5, w-2, h-4, w-4, h-2, w-5, h-2, w-6, h-1,
232 36, h-1, 16, h+t-1, 16, h-1,
233 5, h-1, 4, h-2, 3, h-2, 1, h-4, 1, h-5, 0, h-6,
234 0, 5];
235 tip.setLocation (Math.max (0, x - i), y - size.y - t);
236 }
237 } else {
238 if (dest.height >= y + size.y + t) {
239 polyline = [
240 0, 5+t, 1, 5+t, 1, 3+t, 3, 1+t, 5, 1+t, 5, t,
241 w-35, t, w-16, 0, w-16, t,
242 w-5, t, w-5, 1+t, w-3, 1+t, w-1, 3+t, w-1, 5+t, w, 5+t,
243 w, h-5+t, w-1, h-5+t, w-1, h-3+t, w-2, h-3+t, w-2, h-2+t, w-3, h-2+t, w-3, h-1+t, w-5, h-1+t, w-5, h+t,
244 5, h+t, 5, h-1+t, 3, h-1+t, 3, h-2+t, 2, h-2+t, 2, h-3+t, 1, h-3+t, 1, h-5+t, 0, h-5+t,
245 0, 5+t];
246 borderPolygon = [
247 0, 5+t, 1, 4+t, 1, 3+t, 3, 1+t, 4, 1+t, 5, t,
248 w-35, t, w-17, 2, w-17, t,
249 w-6, t, w-5, 1+t, w-4, 1+t, w-2, 3+t, w-2, 4+t, w-1, 5+t,
250 w-1, h-6+t, w-2, h-5+t, w-2, h-4+t, w-4, h-2+t, w-5, h-2+t, w-6, h-1+t,
251 5, h-1+t, 4, h-2+t, 3, h-2+t, 1, h-4+t, 1, h-5+t, 0, h-6+t,
252 0, 5+t];
253 tip.setLocation (Math.min (dest.width - size.x, x - size.x + i), y);
254 } else {
255 polyline = [
256 0, 5, 1, 5, 1, 3, 3, 1, 5, 1, 5, 0,
257 w-5, 0, w-5, 1, w-3, 1, w-1, 3, w-1, 5, w, 5,
258 w, h-5, w-1, h-5, w-1, h-3, w-2, h-3, w-2, h-2, w-3, h-2, w-3, h-1, w-5, h-1, w-5, h,
259 w-16, h, w-16, h+t, w-35, h,
260 5, h, 5, h-1, 3, h-1, 3, h-2, 2, h-2, 2, h-3, 1, h-3, 1, h-5, 0, h-5,
261 0, 5];
262 borderPolygon = [
263 0, 5, 1, 4, 1, 3, 3, 1, 4, 1, 5, 0,
264 w-6, 0, w-5, 1, w-4, 1, w-2, 3, w-2, 4, w-1, 5,
265 w-1, h-6, w-2, h-5, w-2, h-4, w-4, h-2, w-5, h-2, w-6, h-1,
266 w-17, h-1, w-17, h+t-2, w-36, h-1,
267 5, h-1, 4, h-2, 3, h-2, 1, h-4, 1, h-5, 0, h-6,
268 0, 5];
269 tip.setLocation (Math.min (dest.width - size.x, x - size.x + i), y - size.y - t);
270 }
271 }
272 if ((style & DWT.BALLOON) !is 0) {
273 if (region !is null) region.dispose ();
274 region = new Region (display);
275 region.add (polyline);
276 tip.setRegion (region);
277 }
278 }
279
280 /**
281 * Returns <code>true</code> if the receiver is automatically
282 * hidden by the platform, and <code>false</code> otherwise.
283 *
284 * @return the receiver's auto hide state
285 *
286 * @exception DWTException <ul>
287 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
288 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
289 * </ul>
290 *
291 */
292 public bool getAutoHide () {
293 checkWidget ();
294 return autohide;
295 }
296
297 Point getSize (int maxWidth) {
298 int textWidth = 0, messageWidth = 0;
299 if (layoutText !is null) {
300 layoutText.setWidth (-1);
301 textWidth = layoutText.getBounds ().width;
302 }
303 if (layoutMessage !is null) {
304 layoutMessage.setWidth (-1);
305 messageWidth = layoutMessage.getBounds ().width;
306 }
307 int messageTrim = 2 * INSET + 2 * BORDER + 2 * PADDING;
308 bool hasImage = layoutText !is null && (style & DWT.BALLOON) !is 0 && (style & (DWT.ICON_ERROR | DWT.ICON_INFORMATION | DWT.ICON_WARNING)) !is 0;
309 int textTrim = messageTrim + (hasImage ? IMAGE_SIZE : 0);
310 int width = Math.min (maxWidth, Math.max (textWidth + textTrim, messageWidth + messageTrim));
311 int textHeight = 0, messageHeight = 0;
312 if (layoutText !is null) {
313 layoutText.setWidth (maxWidth - textTrim);
314 textHeight = layoutText.getBounds ().height;
315 }
316 if (layoutMessage !is null) {
317 layoutMessage.setWidth (maxWidth - messageTrim);
318 messageHeight = layoutMessage.getBounds ().height;
319 }
320 int height = 2 * BORDER + 2 * PADDING + messageHeight;
321 if (layoutText !is null) height += Math.max (IMAGE_SIZE, textHeight) + 2 * PADDING;
322 return new Point (width, height);
323 }
324
325 /**
326 * Returns the receiver's message, which will be an empty
327 * string if it has never been set.
328 *
329 * @return the receiver's message
330 *
331 * @exception DWTException <ul>
332 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
333 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
334 * </ul>
335 */
336 public String getMessage () {
337 checkWidget ();
338 return layoutMessage !is null ? layoutMessage.getText() : "";
339 }
340
341 /**
342 * Returns the receiver's parent, which must be a <code>Shell</code>.
343 *
344 * @return the receiver's parent
345 *
346 * @exception DWTException <ul>
347 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
348 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
349 * </ul>
350 */
351 public Shell getParent () {
352 checkWidget ();
353 return parent;
354 }
355
356 /**
357 * Returns the receiver's text, which will be an empty
358 * string if it has never been set.
359 *
360 * @return the receiver's text
361 *
362 * @exception DWTException <ul>
363 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
364 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
365 * </ul>
366 */
367 public String getText () {
368 checkWidget ();
369 return layoutText !is null ? layoutText.getText() : "";
370 }
371
372 /**
373 * Returns <code>true</code> if the receiver is visible, and
374 * <code>false</code> otherwise.
375 * <p>
376 * If one of the receiver's ancestors is not visible or some
377 * other condition makes the receiver not visible, this method
378 * may still indicate that it is considered visible even though
379 * it may not actually be showing.
380 * </p>
381 *
382 * @return the receiver's visibility state
383 *
384 * @exception DWTException <ul>
385 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
386 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
387 * </ul>
388 */
389 public bool getVisible () {
390 checkWidget ();
391 return tip.getVisible ();
392 }
393
394 /**
395 * Returns <code>true</code> if the receiver is visible and all
396 * of the receiver's ancestors are visible and <code>false</code>
397 * otherwise.
398 *
399 * @return the receiver's visibility state
400 *
401 * @exception DWTException <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 * @see #getVisible
407 */
408 public bool isVisible () {
409 checkWidget ();
410 return getVisible ();
411 }
412
413 void onDispose (Event event) {
414 removeListener (DWT.Dispose, listener);
415 notifyListeners (DWT.Dispose, event);
416 event.type = DWT.None;
417
418 if (runnable !is null) {
419 Display display = getDisplay ();
420 display.timerExec (-1, runnable);
421 }
422 runnable = null;
423 tip.dispose ();
424 tip = null;
425 if (region !is null) region.dispose ();
426 region = null;
427 if (layoutText !is null) layoutText.dispose ();
428 layoutText = null;
429 if (layoutMessage !is null) layoutMessage.dispose ();
430 layoutMessage = null;
431 if (boldFont !is null) boldFont.dispose ();
432 boldFont = null;
433 borderPolygon = null;
434 }
435
436 void onMouseDown (Event event) {
437 notifyListeners (DWT.Selection, new Event ());
438 setVisible (false);
439 }
440
441 void onPaint (Event event) {
442 GC gc = event.gc;
443 int x = BORDER + PADDING;
444 int y = BORDER + PADDING;
445 if ((style & DWT.BALLOON) !is 0) {
446 if (spikeAbove) y += TIP_HEIGHT;
447 gc.drawPolygon (borderPolygon);
448 } else {
449 Rectangle rect = tip.getClientArea ();
450 gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height -1);
451 }
452 if (layoutText !is null) {
453 int id = style & (DWT.ICON_ERROR | DWT.ICON_INFORMATION | DWT.ICON_WARNING);
454 if ((style & DWT.BALLOON) !is 0 && id !is 0) {
455 Display display = getDisplay ();
456 Image image = display.getSystemImage (id);
457 Rectangle rect = image.getBounds ();
458 gc.drawImage (image, 0, 0, rect.width, rect.height, x, y, IMAGE_SIZE, IMAGE_SIZE);
459 x += IMAGE_SIZE;
460 }
461 x += INSET;
462 layoutText.draw (gc, x, y);
463 y += 2 * PADDING + Math.max (IMAGE_SIZE, layoutText.getBounds ().height);
464 }
465 if (layoutMessage !is null) {
466 x = BORDER + PADDING + INSET;
467 layoutMessage.draw (gc, x, y);
468 }
469 }
470
471 /**
472 * Removes the listener from the collection of listeners who will
473 * be notified when the receiver is selected by the user.
474 *
475 * @param listener the listener which should no longer be notified
476 *
477 * @exception IllegalArgumentException <ul>
478 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
479 * </ul>
480 * @exception DWTException <ul>
481 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
482 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
483 * </ul>
484 *
485 * @see SelectionListener
486 * @see #addSelectionListener
487 */
488 public void removeSelectionListener (SelectionListener listener) {
489 checkWidget();
490 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
491 if (eventTable is null) return;
492 eventTable.unhook (DWT.Selection, listener);
493 eventTable.unhook (DWT.DefaultSelection,listener);
494 }
495
496 /**
497 * Makes the receiver hide automatically when <code>true</code>,
498 * and remain visible when <code>false</code>.
499 *
500 * @param autoHide the auto hide state
501 *
502 * @exception DWTException <ul>
503 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
504 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
505 * </ul>
506 *
507 * @see #getVisible
508 * @see #setVisible
509 */
510 public void setAutoHide (bool autohide) {
511 checkWidget ();
512 this.autohide = autohide;
513 //TODO - update when visible
514 }
515
516 /**
517 * Sets the location of the receiver, which must be a tooltip,
518 * to the point specified by the arguments which are relative
519 * to the display.
520 * <p>
521 * Note that this is different from most widgets where the
522 * location of the widget is relative to the parent.
523 * </p>
524 *
525 * @param x the new x coordinate for the receiver
526 * @param y the new y coordinate for the receiver
527 *
528 * @exception DWTException <ul>
529 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
530 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
531 * </ul>
532 */
533 public void setLocation (int x, int y) {
534 checkWidget ();
535 if (this.x is x && this.y is y) return;
536 this.x = x;
537 this.y = y;
538 if (tip.getVisible ()) configure ();
539 }
540
541 /**
542 * Sets the location of the receiver, which must be a tooltip,
543 * to the point specified by the argument which is relative
544 * to the display.
545 * <p>
546 * Note that this is different from most widgets where the
547 * location of the widget is relative to the parent.
548 * </p><p>
549 * Note that the platform window manager ultimately has control
550 * over the location of tooltips.
551 * </p>
552 *
553 * @param location the new location for the receiver
554 *
555 * @exception IllegalArgumentException <ul>
556 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
557 * </ul>
558 * @exception DWTException <ul>
559 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
560 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
561 * </ul>
562 */
563 public void setLocation (Point location) {
564 checkWidget ();
565 if (location is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
566 setLocation (location.x, location.y);
567 }
568
569 /**
570 * Sets the receiver's message.
571 *
572 * @param string the new message
573 *
574 * @exception IllegalArgumentException <ul>
575 * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
576 * </ul>
577 * @exception DWTException <ul>
578 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
579 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
580 * </ul>
581 */
582 public void setMessage (String string) {
583 checkWidget ();
584 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
585 if (layoutMessage !is null) layoutMessage.dispose();
586 layoutMessage = null;
587 if (string.length () !is 0) {
588 Display display = getDisplay ();
589 layoutMessage = new TextLayout (display);
590 layoutMessage.setText (string);
591 }
592 if (tip.getVisible ()) configure ();
593 }
594
595 /**
596 * Sets the receiver's text.
597 *
598 * @param string the new text
599 *
600 * @exception IllegalArgumentException <ul>
601 * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
602 * </ul>
603 * @exception DWTException <ul>
604 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
605 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
606 * </ul>
607 */
608 public void setText (String string) {
609 checkWidget ();
610 //if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
611 if (layoutText !is null) layoutText.dispose ();
612 layoutText = null;
613 if (boldFont !is null) boldFont.dispose ();
614 boldFont = null;
615 if (string.length () !is 0) {
616 Display display = getDisplay ();
617 layoutText = new TextLayout (display);
618 layoutText.setText (string);
619 Font font = display.getSystemFont ();
620 FontData data = font.getFontData () [0];
621 boldFont = new Font (cast(Device) display, data.getName (), data.getHeight (), DWT.BOLD);
622 TextStyle style = new TextStyle (boldFont, null, null);
623 layoutText.setStyle (style, 0, string.length ());
624 }
625 if (tip.getVisible ()) configure ();
626 }
627
628 /**
629 * Marks the receiver as visible if the argument is <code>true</code>,
630 * and marks it invisible otherwise.
631 * <p>
632 * If one of the receiver's ancestors is not visible or some
633 * other condition makes the receiver not visible, marking
634 * it visible may not actually cause it to be displayed.
635 * </p>
636 *
637 * @param visible the new visibility state
638 *
639 * @exception DWTException <ul>
640 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
641 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
642 * </ul>
643 */
644 public void setVisible (bool visible) {
645 if (visible) configure ();
646 tip.setVisible (visible);
647 Display display = getDisplay ();
648 if (runnable !is null) display.timerExec (-1, runnable);
649 runnable = null;
650 if (autohide && visible) {
651 runnable = new class Runnable {
652 public void run () {
653 if (!isDisposed ()) setVisible (false);
654 }
655 };
656 display.timerExec(DELAY, runnable);
657 }
658 }
659
660 }