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.Caret;
14 
15 import java.lang.all;
16 
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.internal.gtk.OS;
19 import org.eclipse.swt.graphics.Image;
20 import org.eclipse.swt.graphics.Font;
21 import org.eclipse.swt.graphics.Point;
22 import org.eclipse.swt.graphics.Rectangle;
23 import org.eclipse.swt.widgets.Widget;
24 import org.eclipse.swt.widgets.Canvas;
25 
26 /**
27  * Instances of this class provide an i-beam that is typically used
28  * as the insertion point for text.
29  * <dl>
30  * <dt><b>Styles:</b></dt>
31  * <dd>(none)</dd>
32  * <dt><b>Events:</b></dt>
33  * <dd>(none)</dd>
34  * </dl>
35  * <p>
36  * IMPORTANT: This class is intended to be subclassed <em>only</em>
37  * within the SWT implementation.
38  * </p>
39  * 
40  * @see <a href="http://www.eclipse.org/swt/snippets/#caret">Caret snippets</a>
41  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Canvas tab</a>
42  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
43  */
44 public class Caret : Widget {
45     Canvas parent;
46     int x, y, width, height;
47     bool isVisible_, isShowing;
48     int blinkRate;
49     Image image;
50     Font font;
51 
52     static const int DEFAULT_WIDTH = 1;
53 
54 /**
55  * Constructs a new instance of this class given its parent
56  * and a style value describing its behavior and appearance.
57  * <p>
58  * The style value is either one of the style constants defined in
59  * class <code>SWT</code> which is applicable to instances of this
60  * class, or must be built by <em>bitwise OR</em>'ing together
61  * (that is, using the <code>int</code> "|" operator) two or more
62  * of those <code>SWT</code> style constants. The class description
63  * lists the style constants that are applicable to the class.
64  * Style bits are also inherited from superclasses.
65  * </p>
66  *
67  * @param parent a composite control which will be the parent of the new instance (cannot be null)
68  * @param style the style of control to construct
69  *
70  * @exception IllegalArgumentException <ul>
71  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
72  * </ul>
73  * @exception SWTException <ul>
74  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
75  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
76  * </ul>
77  *
78  * @see SWT
79  * @see Widget#checkSubclass
80  * @see Widget#getStyle
81  */
82 public this (Canvas parent, int style) {
83     super (parent, style);
84     this.parent = parent;
85     createWidget (0);
86 }
87 
88 bool blinkCaret () {
89     if (!isVisible_) return true;
90     if (!isShowing) return showCaret ();
91     if (blinkRate is 0) return true;
92     return hideCaret ();
93 }
94 
95 override void createWidget (int index) {
96     super.createWidget (index);
97     blinkRate = display.getCaretBlinkTime ();
98     isVisible_ = true;
99     if (parent.getCaret () is null) {
100         parent.setCaret (this);
101     }
102 }
103 
104 bool drawCaret () {
105     if (parent is null) return false;
106     if (parent.isDisposed ()) return false;
107     auto window = parent.paintWindow ();
108     auto gc = OS.gdk_gc_new (window);
109     GdkColor* color = new GdkColor ();
110     color.red = 0xffff;
111     color.green = 0xffff;
112     color.blue = 0xffff;
113     auto colormap = OS.gdk_colormap_get_system ();
114     OS.gdk_colormap_alloc_color (colormap, color, true, true);
115     OS.gdk_gc_set_foreground (gc, color);
116     OS.gdk_gc_set_function (gc, OS.GDK_XOR);
117     if (image !is null && !image.isDisposed() && image.mask is null) {
118         int width; int height;
119         OS.gdk_drawable_get_size(image.pixmap, &width, &height);
120         int nX = x;
121         if ((parent.style & SWT.MIRRORED) !is 0) nX = parent.getClientWidth () - width - nX;
122         OS.gdk_draw_drawable(window, gc, image.pixmap, 0, 0, x, y, width, height);
123     } else {
124         int nWidth = width, nHeight = height;
125         if (nWidth <= 0) nWidth = DEFAULT_WIDTH;
126         int nX = x;
127         if ((parent.style & SWT.MIRRORED) !is 0) nX = parent.getClientWidth () - nWidth - nX;
128         OS.gdk_draw_rectangle (window, gc, 1, nX, y, nWidth, nHeight);
129     }
130     OS.g_object_unref (gc);
131     OS.gdk_colormap_free_colors (colormap, color, 1);
132     return true;
133 }
134 
135 /**
136  * Returns a rectangle describing the receiver's size and location
137  * relative to its parent (or its display if its parent is null).
138  *
139  * @return the receiver's bounding rectangle
140  *
141  * @exception SWTException <ul>
142  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
143  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
144  * </ul>
145  */
146 public Rectangle getBounds () {
147     checkWidget();
148     if (image !is null) {
149         Rectangle rect = image.getBounds ();
150         return new Rectangle (x, y, rect.width, rect.height);
151     } else {
152         if (width is 0) {
153             return new Rectangle (x, y, DEFAULT_WIDTH, height);
154         }
155     }
156     return new Rectangle (x, y, width, height);
157 }
158 
159 /**
160  * Returns the font that the receiver will use to paint textual information.
161  *
162  * @return the receiver's font
163  *
164  * @exception SWTException <ul>
165  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
166  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
167  * </ul>
168  */
169 public Font getFont () {
170     checkWidget();
171     if (font !is null) return font;
172     return parent.getFont ();
173 }
174 
175 /**
176  * Returns the image that the receiver will use to paint the caret.
177  *
178  * @return the receiver's image
179  *
180  * @exception SWTException <ul>
181  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
182  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
183  * </ul>
184  */
185 public Image getImage () {
186     checkWidget();
187     return image;
188 }
189 
190 /**
191  * Returns a point describing the receiver's location relative
192  * to its parent (or its display if its parent is null).
193  *
194  * @return the receiver's location
195  *
196  * @exception SWTException <ul>
197  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
198  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
199  * </ul>
200  */
201 public Point getLocation () {
202     checkWidget();
203     return new Point (x, y);
204 }
205 
206 /**
207  * Returns the receiver's parent, which must be a <code>Canvas</code>.
208  *
209  * @return the receiver's parent
210  *
211  * @exception SWTException <ul>
212  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
213  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
214  * </ul>
215  */
216 public Canvas getParent () {
217     checkWidget();
218     return parent;
219 }
220 
221 /**
222  * Returns a point describing the receiver's size.
223  *
224  * @return the receiver's size
225  *
226  * @exception SWTException <ul>
227  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
228  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
229  * </ul>
230  */
231 public Point getSize () {
232     checkWidget();
233     if (image !is null) {
234         Rectangle rect = image.getBounds ();
235         return new Point (rect.width, rect.height);
236     } else {
237         if (width is 0) {
238             return new Point (DEFAULT_WIDTH, height);
239         }
240     }
241     return new Point (width, height);
242 }
243 
244 /**
245  * Returns <code>true</code> if the receiver is visible, and
246  * <code>false</code> otherwise.
247  * <p>
248  * If one of the receiver's ancestors is not visible or some
249  * other condition makes the receiver not visible, this method
250  * may still indicate that it is considered visible even though
251  * it may not actually be showing.
252  * </p>
253  *
254  * @return the receiver's visibility state
255  *
256  * @exception SWTException <ul>
257  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
258  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
259  * </ul>
260  */
261 public bool getVisible () {
262     checkWidget();
263     return isVisible_;
264 }
265 
266 bool hideCaret () {
267     if (!isShowing) return true;
268     isShowing = false;
269     return drawCaret ();
270 }
271 
272 /**
273  * Returns <code>true</code> if the receiver is visible and all
274  * of the receiver's ancestors are visible and <code>false</code>
275  * otherwise.
276  *
277  * @return the receiver's visibility state
278  *
279  * @exception SWTException <ul>
280  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
281  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
282  * </ul>
283  *
284  * @see #getVisible
285  */
286 public bool isVisible () {
287     checkWidget();
288     return isVisible_ && parent.isVisible () && parent.hasFocus ();
289 }
290 
291 bool isFocusCaret () {
292     return this is display.currentCaret;
293 }
294 
295 void killFocus () {
296     if (display.currentCaret !is this) return;
297     display.setCurrentCaret (null);
298     if (isVisible_) hideCaret ();
299 }
300 
301 override void releaseParent () {
302     super.releaseParent ();
303     if (this is parent.getCaret ()) parent.setCaret (null);
304 }
305 
306 override void releaseWidget () {
307     super.releaseWidget ();
308     if (display.currentCaret is this) {
309         hideCaret ();
310         display.setCurrentCaret (null);
311     }
312     parent = null;
313     image = null;
314 }
315 
316 /**
317  * Sets the receiver's size and location to the rectangular
318  * area specified by the arguments. The <code>x</code> and
319  * <code>y</code> arguments are relative to the receiver's
320  * parent (or its display if its parent is null).
321  *
322  * @param x the new x coordinate for the receiver
323  * @param y the new y coordinate for the receiver
324  * @param width the new width for the receiver
325  * @param height the new height for the receiver
326  *
327  * @exception SWTException <ul>
328  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
329  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
330  * </ul>
331  */
332 public void setBounds (int x, int y, int width, int height) {
333     checkWidget();
334     if (this.x is x && this.y is y && this.width is width && this.height is height) return;
335     bool isFocus = isFocusCaret ();
336     if (isFocus && isVisible_) hideCaret ();
337     this.x = x; this.y = y;
338     this.width = width; this.height = height;
339     parent.updateCaret ();
340     if (isFocus && isVisible_) showCaret ();
341 }
342 
343 /**
344  * Sets the receiver's size and location to the rectangular
345  * area specified by the argument. The <code>x</code> and
346  * <code>y</code> fields of the rectangle are relative to
347  * the receiver's parent (or its display if its parent is null).
348  *
349  * @param rect the new bounds for the receiver
350  *
351  * @exception SWTException <ul>
352  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
353  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
354  * </ul>
355  */
356 public void setBounds (Rectangle rect) {
357     checkWidget();
358     if (rect is null) error (SWT.ERROR_NULL_ARGUMENT);
359     setBounds (rect.x, rect.y, rect.width, rect.height);
360 }
361 
362 void setFocus () {
363     if (display.currentCaret is this) return;
364     display.setCurrentCaret (this);
365     if (isVisible_) showCaret ();
366 }
367 
368 /**
369  * Sets the font that the receiver will use to paint textual information
370  * to the font specified by the argument, or to the default font for that
371  * kind of control if the argument is null.
372  *
373  * @param font the new font (or null)
374  *
375  * @exception IllegalArgumentException <ul>
376  *    <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
377  * </ul>
378  * @exception SWTException <ul>
379  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
380  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
381  * </ul>
382  */
383 public void setFont (Font font) {
384     checkWidget();
385     if (font !is null && font.isDisposed ()) {
386         error (SWT.ERROR_INVALID_ARGUMENT);
387     }
388     this.font = font;
389 }
390 
391 /**
392  * Sets the image that the receiver will use to paint the caret
393  * to the image specified by the argument, or to the default
394  * which is a filled rectangle if the argument is null
395  *
396  * @param image the new image (or null)
397  *
398  * @exception IllegalArgumentException <ul>
399  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
400  * </ul>
401  * @exception SWTException <ul>
402  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
403  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
404  * </ul>
405  */
406 public void setImage (Image image) {
407     checkWidget();
408     if (image !is null && image.isDisposed ()) {
409         error (SWT.ERROR_INVALID_ARGUMENT);
410     }
411     bool isFocus = isFocusCaret ();
412     if (isFocus && isVisible_) hideCaret ();
413     this.image = image;
414     if (isFocus && isVisible_) showCaret ();
415 }
416 
417 /**
418  * Sets the receiver's location to the point specified by
419  * the arguments which are relative to the receiver's
420  * parent (or its display if its parent is null).
421  *
422  * @param x the new x coordinate for the receiver
423  * @param y the new y coordinate for the receiver
424  *
425  * @exception SWTException <ul>
426  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
427  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
428  * </ul>
429  */
430 public void setLocation (int x, int y) {
431     checkWidget();
432     setBounds (x, y, width, height);
433 }
434 
435 /**
436  * Sets the receiver's location to the point specified by
437  * the argument which is relative to the receiver's
438  * parent (or its display if its parent is null).
439  *
440  * @param location the new location for the receiver
441  *
442  * @exception SWTException <ul>
443  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
444  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
445  * </ul>
446  */
447 public void setLocation (Point location) {
448     checkWidget();
449     if (location is null) error (SWT.ERROR_NULL_ARGUMENT);
450     setLocation (location.x, location.y);
451 }
452 
453 /**
454  * Sets the receiver's size to the point specified by the arguments.
455  *
456  * @param width the new width for the receiver
457  * @param height the new height for the receiver
458  *
459  * @exception SWTException <ul>
460  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
461  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
462  * </ul>
463  */
464 public void setSize (int width, int height) {
465     checkWidget();
466     setBounds (x, y, width, height);
467 }
468 
469 /**
470  * Sets the receiver's size to the point specified by the argument.
471  *
472  * @param size the new extent for the receiver
473  *
474  * @exception IllegalArgumentException <ul>
475  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
476  * </ul>
477  * @exception SWTException <ul>
478  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
479  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
480  * </ul>
481  */
482 public void setSize (Point size) {
483     checkWidget();
484     if (size is null) error (SWT.ERROR_NULL_ARGUMENT);
485     setSize (size.x, size.y);
486 }
487 
488 /**
489  * Marks the receiver as visible if the argument is <code>true</code>,
490  * and marks it invisible otherwise.
491  * <p>
492  * If one of the receiver's ancestors is not visible or some
493  * other condition makes the receiver not visible, marking
494  * it visible may not actually cause it to be displayed.
495  * </p>
496  *
497  * @param visible the new visibility state
498  *
499  * @exception SWTException <ul>
500  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
501  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
502  * </ul>
503  */
504 public void setVisible (bool visible) {
505     checkWidget();
506     if (visible is isVisible_) return;
507     isVisible_ = visible;
508     if (!isFocusCaret ()) return;
509     if (isVisible_) {
510         showCaret ();
511     } else {
512         hideCaret ();
513     }
514 }
515 
516 bool showCaret () {
517     if (isShowing) return true;
518     isShowing = true;
519     return drawCaret ();
520 }
521 
522 }