Mercurial > projects > dwt-mac
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 } |