comparison dwt/graphics/Cursor.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 649b8e223d5a
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 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 *******************************************************************************/
11 module dwt.graphics.Cursor;
12
13 import dwt.dwthelper.utils;
14
15
16 import dwt.DWT;
17 import dwt.DWTError;
18 import dwt.internal.cocoa.NSBitmapImageRep;
19 import dwt.internal.cocoa.NSCursor;
20 import dwt.internal.cocoa.NSImage;
21 import dwt.internal.cocoa.NSPoint;
22 import dwt.internal.cocoa.NSSize;
23 import dwt.internal.cocoa.NSString;
24 import dwt.internal.cocoa.OS;
25
26 /**
27 * Instances of this class manage operating system resources that
28 * specify the appearance of the on-screen pointer. To create a
29 * cursor you specify the device and either a simple cursor style
30 * describing one of the standard operating system provided cursors
31 * or the image and mask data for the desired appearance.
32 * <p>
33 * Application code must explicitly invoke the <code>Cursor.dispose()</code>
34 * method to release the operating system resources managed by each instance
35 * when those instances are no longer required.
36 * </p>
37 * <dl>
38 * <dt><b>Styles:</b></dt>
39 * <dd>
40 * CURSOR_ARROW, CURSOR_WAIT, CURSOR_CROSS, CURSOR_APPSTARTING, CURSOR_HELP,
41 * CURSOR_SIZEALL, CURSOR_SIZENESW, CURSOR_SIZENS, CURSOR_SIZENWSE, CURSOR_SIZEWE,
42 * CURSOR_SIZEN, CURSOR_SIZES, CURSOR_SIZEE, CURSOR_SIZEW, CURSOR_SIZENE, CURSOR_SIZESE,
43 * CURSOR_SIZESW, CURSOR_SIZENW, CURSOR_UPARROW, CURSOR_IBEAM, CURSOR_NO, CURSOR_HAND
44 * </dd>
45 * </dl>
46 * <p>
47 * Note: Only one of the above styles may be specified.
48 * </p>
49 */
50
51 public final class Cursor extends Resource {
52
53 /**
54 * the handle to the OS cursor resource
55 * (Warning: This field is platform dependent)
56 * <p>
57 * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
58 * public API. It is marked public only so that it can be shared
59 * within the packages provided by DWT. It is not available on all
60 * platforms and should never be accessed from application code.
61 * </p>
62 */
63 public NSCursor handle;
64
65 /**
66 * Prevents uninitialized instances from being created outside the package.
67 */
68 Cursor(Device device) {
69 super(device);
70 }
71
72 /**
73 * Constructs a new cursor given a device and a style
74 * constant describing the desired cursor appearance.
75 * <p>
76 * You must dispose the cursor when it is no longer required.
77 * </p>
78 *
79 * @param device the device on which to allocate the cursor
80 * @param style the style of cursor to allocate
81 *
82 * @exception IllegalArgumentException <ul>
83 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
84 * <li>ERROR_INVALID_ARGUMENT - when an unknown style is specified</li>
85 * </ul>
86 * @exception DWTError <ul>
87 * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
88 * </ul>
89 *
90 * @see DWT#CURSOR_ARROW
91 * @see DWT#CURSOR_WAIT
92 * @see DWT#CURSOR_CROSS
93 * @see DWT#CURSOR_APPSTARTING
94 * @see DWT#CURSOR_HELP
95 * @see DWT#CURSOR_SIZEALL
96 * @see DWT#CURSOR_SIZENESW
97 * @see DWT#CURSOR_SIZENS
98 * @see DWT#CURSOR_SIZENWSE
99 * @see DWT#CURSOR_SIZEWE
100 * @see DWT#CURSOR_SIZEN
101 * @see DWT#CURSOR_SIZES
102 * @see DWT#CURSOR_SIZEE
103 * @see DWT#CURSOR_SIZEW
104 * @see DWT#CURSOR_SIZENE
105 * @see DWT#CURSOR_SIZESE
106 * @see DWT#CURSOR_SIZESW
107 * @see DWT#CURSOR_SIZENW
108 * @see DWT#CURSOR_UPARROW
109 * @see DWT#CURSOR_IBEAM
110 * @see DWT#CURSOR_NO
111 * @see DWT#CURSOR_HAND
112 */
113 public Cursor(Device device, int style) {
114 super(device);
115 switch (style) {
116 case DWT.CURSOR_HAND: handle = NSCursor.pointingHandCursor(); break;
117 case DWT.CURSOR_ARROW: handle = NSCursor.arrowCursor(); break;
118 case DWT.CURSOR_WAIT: handle = NSCursor.crosshairCursor(); break;
119 case DWT.CURSOR_CROSS: handle = NSCursor.crosshairCursor(); break;
120 case DWT.CURSOR_APPSTARTING: handle = NSCursor.arrowCursor(); break;
121 case DWT.CURSOR_HELP: handle = NSCursor.crosshairCursor(); break;
122 case DWT.CURSOR_SIZEALL: handle = NSCursor.crosshairCursor(); break;
123 case DWT.CURSOR_SIZENESW: handle = NSCursor.crosshairCursor(); break;
124 case DWT.CURSOR_SIZENS: handle = NSCursor.resizeUpDownCursor(); break;
125 case DWT.CURSOR_SIZENWSE: handle = NSCursor.crosshairCursor(); break;
126 case DWT.CURSOR_SIZEWE: handle = NSCursor.resizeLeftRightCursor(); break;
127 case DWT.CURSOR_SIZEN: handle = NSCursor.resizeUpCursor(); break;
128 case DWT.CURSOR_SIZES: handle = NSCursor.resizeDownCursor(); break;
129 case DWT.CURSOR_SIZEE: handle = NSCursor.resizeRightCursor(); break;
130 case DWT.CURSOR_SIZEW: handle = NSCursor.resizeLeftCursor(); break;
131 case DWT.CURSOR_SIZENE: handle = NSCursor.crosshairCursor(); break;
132 case DWT.CURSOR_SIZESE: handle = NSCursor.crosshairCursor(); break;
133 case DWT.CURSOR_SIZESW: handle = NSCursor.crosshairCursor(); break;
134 case DWT.CURSOR_SIZENW: handle = NSCursor.crosshairCursor(); break;
135 case DWT.CURSOR_UPARROW: handle = NSCursor.crosshairCursor(); break;
136 case DWT.CURSOR_IBEAM: handle = NSCursor.IBeamCursor(); break;
137 case DWT.CURSOR_NO: handle = NSCursor.crosshairCursor(); break;
138 default:
139 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
140 }
141 handle.retain();
142 handle.setOnMouseEntered(true);
143 init();
144 }
145
146 /**
147 * Constructs a new cursor given a device, image and mask
148 * data describing the desired cursor appearance, and the x
149 * and y coordinates of the <em>hotspot</em> (that is, the point
150 * within the area covered by the cursor which is considered
151 * to be where the on-screen pointer is "pointing").
152 * <p>
153 * The mask data is allowed to be null, but in this case the source
154 * must be an ImageData representing an icon that specifies both
155 * color data and mask data.
156 * <p>
157 * You must dispose the cursor when it is no longer required.
158 * </p>
159 *
160 * @param device the device on which to allocate the cursor
161 * @param source the color data for the cursor
162 * @param mask the mask data for the cursor (or null)
163 * @param hotspotX the x coordinate of the cursor's hotspot
164 * @param hotspotY the y coordinate of the cursor's hotspot
165 *
166 * @exception IllegalArgumentException <ul>
167 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
168 * <li>ERROR_NULL_ARGUMENT - if the source is null</li>
169 * <li>ERROR_NULL_ARGUMENT - if the mask is null and the source does not have a mask</li>
170 * <li>ERROR_INVALID_ARGUMENT - if the source and the mask are not the same
171 * size, or if the hotspot is outside the bounds of the image</li>
172 * </ul>
173 * @exception DWTError <ul>
174 * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
175 * </ul>
176 */
177 public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
178 super(device);
179 if (source is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
180 if (mask is null) {
181 if (source.getTransparencyType() !is DWT.TRANSPARENCY_MASK) {
182 DWT.error(DWT.ERROR_NULL_ARGUMENT);
183 }
184 mask = source.getTransparencyMask();
185 }
186 /* Check the bounds. Mask must be the same size as source */
187 if (mask.width !is source.width || mask.height !is source.height) {
188 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
189 }
190 /* Check the hotspots */
191 if (hotspotX >= source.width || hotspotX < 0 ||
192 hotspotY >= source.height || hotspotY < 0) {
193 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
194 }
195 byte[] data = new byte[source.width * source.height * 4];
196 for (int y = 0; y < source.height; y++) {
197 int offset = y * source.width * 4;
198 for (int x = 0; x < source.width; x++) {
199 int pixel = source.getPixel(x, y);
200 int maskPixel = mask.getPixel(x, y);
201 if (pixel is 0 && maskPixel is 0) {
202 // BLACK
203 data[offset] = (byte)0xFF;
204 } else if (pixel is 0 && maskPixel is 1) {
205 // WHITE - cursor color
206 data[offset] = data[offset + 1] = data[offset + 2] = data[offset + 3] = (byte)0xFF;
207 } else if (pixel is 1 && maskPixel is 0) {
208 // SCREEN
209 } else {
210 /*
211 * Feature in the Macintosh. It is not possible to have
212 * the reverse screen case using NSCursor.
213 * Reverse screen will be the same as screen.
214 */
215 // REVERSE SCREEN -> SCREEN
216 }
217 offset += 4;
218 }
219 }
220 createNSCursor(hotspotX, hotspotY, data, source.width, source.height);
221 init();
222 }
223
224 void createNSCursor(int hotspotX, int hotspotY, byte[] buffer, int width, int height) {
225 NSImage nsImage = (NSImage)new NSImage().alloc();
226 NSBitmapImageRep nsImageRep = (NSBitmapImageRep)new NSBitmapImageRep().alloc();
227 handle = (NSCursor)new NSCursor().alloc();
228 NSSize size = new NSSize();
229 size.width = width;
230 size.height = height;
231 nsImage = nsImage.initWithSize(size);
232 nsImageRep = nsImageRep.initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel_(0, width, height,
233 8, 4, true, false, new NSString(OS.NSDeviceRGBColorSpace()),
234 OS.NSAlphaFirstBitmapFormat | OS.NSAlphaNonpremultipliedBitmapFormat, width * 4, 32);
235 OS.memmove(nsImageRep.bitmapData(), buffer, buffer.length);
236 nsImage.addRepresentation(nsImageRep);
237 NSPoint point = new NSPoint();
238 point.x = hotspotX;
239 point.y = hotspotY;
240 handle = handle.initWithImage_hotSpot_(nsImage, point);
241 nsImageRep.release();
242 nsImage.release();
243 }
244
245 /**
246 * Constructs a new cursor given a device, image data describing
247 * the desired cursor appearance, and the x and y coordinates of
248 * the <em>hotspot</em> (that is, the point within the area
249 * covered by the cursor which is considered to be where the
250 * on-screen pointer is "pointing").
251 * <p>
252 * You must dispose the cursor when it is no longer required.
253 * </p>
254 *
255 * @param device the device on which to allocate the cursor
256 * @param source the image data for the cursor
257 * @param hotspotX the x coordinate of the cursor's hotspot
258 * @param hotspotY the y coordinate of the cursor's hotspot
259 *
260 * @exception IllegalArgumentException <ul>
261 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
262 * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
263 * <li>ERROR_INVALID_ARGUMENT - if the hotspot is outside the bounds of the
264 * image</li>
265 * </ul>
266 * @exception DWTError <ul>
267 * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
268 * </ul>
269 *
270 * @since 3.0
271 */
272 public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
273 super(device);
274 if (source is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
275 if (hotspotX >= source.width || hotspotX < 0 ||
276 hotspotY >= source.height || hotspotY < 0) {
277 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
278 }
279 byte[] data = new byte[source.width * source.height * 4];
280 PaletteData palette = source.palette;
281 if (palette.isDirect) {
282 ImageData.blit(ImageData.BLIT_SRC,
283 source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, palette.redMask, palette.greenMask, palette.blueMask,
284 ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
285 data, 32, source.width * 4, ImageData.MSB_FIRST, 0, 0, source.width, source.height, 0xFF0000, 0xFF00, 0xFF,
286 false, false);
287 } else {
288 RGB[] rgbs = palette.getRGBs();
289 int length = rgbs.length;
290 byte[] srcReds = new byte[length];
291 byte[] srcGreens = new byte[length];
292 byte[] srcBlues = new byte[length];
293 for (int i = 0; i < rgbs.length; i++) {
294 RGB rgb = rgbs[i];
295 if (rgb is null) continue;
296 srcReds[i] = (byte)rgb.red;
297 srcGreens[i] = (byte)rgb.green;
298 srcBlues[i] = (byte)rgb.blue;
299 }
300 ImageData.blit(ImageData.BLIT_SRC,
301 source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, srcReds, srcGreens, srcBlues,
302 ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
303 data, 32, source.width * 4, ImageData.MSB_FIRST, 0, 0, source.width, source.height, 0xFF0000, 0xFF00, 0xFF,
304 false, false);
305 }
306 if (source.maskData !is null || source.transparentPixel !is -1) {
307 ImageData mask = source.getTransparencyMask();
308 byte[] maskData = mask.data;
309 int maskBpl = mask.bytesPerLine;
310 int offset = 0, maskOffset = 0;
311 for (int y = 0; y<source.height; y++) {
312 for (int x = 0; x<source.width; x++) {
313 data[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) !is 0 ? (byte)0xff : 0;
314 offset += 4;
315 }
316 maskOffset += maskBpl;
317 }
318 } else if (source.alpha !is -1) {
319 byte alpha = (byte)source.alpha;
320 for (int i=0; i<data.length; i+=4) {
321 data[i] = alpha;
322 }
323 } else if (source.alphaData !is null) {
324 byte[] alphaData = source.alphaData;
325 for (int i=0; i<data.length; i+=4) {
326 data[i] = alphaData[i/4];
327 }
328 }
329 createNSCursor(hotspotX, hotspotY, data, source.width, source.height);
330 init();
331 }
332
333 void destroy() {
334 handle.release();
335 handle = null;
336 }
337
338 /**
339 * Compares the argument to the receiver, and returns true
340 * if they represent the <em>same</em> object using a class
341 * specific comparison.
342 *
343 * @param object the object to compare with this object
344 * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
345 *
346 * @see #hashCode
347 */
348 public bool equals (Object object) {
349 if (object is this) return true;
350 if (!(object instanceof Cursor)) return false;
351 Cursor cursor = (Cursor) object;
352 return device is cursor.device && handle is cursor.handle;
353 }
354
355 /**
356 * Returns an integer hash code for the receiver. Any two
357 * objects that return <code>true</code> when passed to
358 * <code>equals</code> must return the same value for this
359 * method.
360 *
361 * @return the receiver's hash
362 *
363 * @see #equals
364 */
365 public int hashCode () {
366 return handle !is null ? handle.id : 0;
367 }
368
369 /**
370 * Returns <code>true</code> if the cursor has been disposed,
371 * and <code>false</code> otherwise.
372 * <p>
373 * This method gets the dispose state for the cursor.
374 * When a cursor has been disposed, it is an error to
375 * invoke any other method using the cursor.
376 *
377 * @return <code>true</code> when the cursor is disposed and <code>false</code> otherwise
378 */
379 public bool isDisposed() {
380 return handle is null;
381 }
382
383 /**
384 * Returns a string containing a concise, human-readable
385 * description of the receiver.
386 *
387 * @return a string representation of the receiver
388 */
389 public String toString () {
390 if (isDisposed()) return "Cursor {*DISPOSED*}";
391 return "Cursor {" + handle + "}";
392 }
393
394 /**
395 * Invokes platform specific functionality to allocate a new cursor.
396 * <p>
397 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
398 * API for <code>Cursor</code>. It is marked public only so that it
399 * can be shared within the packages provided by DWT. It is not
400 * available on all platforms, and should never be called from
401 * application code.
402 * </p>
403 *
404 * @param device the device on which to allocate the color
405 * @param handle the handle for the cursor
406 *
407 * @private
408 */
409 public static Cursor cocoa_new(Device device, NSCursor handle) {
410 Cursor cursor = new Cursor(device);
411 cursor.handle = handle;
412 return cursor;
413 }
414
415 }