API  1.0.0
CPCursor.j
Go to the documentation of this file.
1 /*
2 Cursor support by browser:
3  OS X 10.6/Chrome 8 : All
4  OS X 10.6/Safari 5 : All
5  OS X 10.6/Firefox 3 : All except disappearingItemCursor (no url() support)
6  OS X 10.6/Firefox 3.5 : All except disappearingItemCursor (no url() support)
7  OS X 10.6/Firefox 3.6 : All except disappearingItemCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
8  OS X 10.6/Firefox 4.0b10 : All
9  OS X/Opera 9 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
10  OS X/Opera 10 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
11  OS X/Opera 11 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
12  Win XP/Chrome 8 : All
13  Win XP/Safari 5 : All
14  Win XP/Firefox 3 : All
15  Win XP/Firefox 3.5 : All
16  Win XP/Firefox 3.6 : All
17  Win XP/Firefox 4.0b10 : All
18  Win XP/Opera 10 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
19  Win XP/Opera 11 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
20  Win XP/IE 7 : All
21  Win XP/IE 8 : All
22 */
23 
24 
25 @global CPApp
26 
27 var currentCursor = nil,
29  cursors = {},
31 
32 @typedef CPCursorPlatform
37 
38 @implementation CPCursor : CPObject
39 {
40  CPString _cssString;
41  CPString _hotSpot;
42  CPImage _image;
43  BOOL _isSetOnMouseEntered;
44  BOOL _isSetOnMouseExited;
45 }
46 
47 + (void)initialize
48 {
49  if (self !== CPCursor)
50  return;
51 
52  // IE < 9 does not support some CSS cursors, we map them to supported ones
53  ieCursorMap = {
54  "ew-resize": "e-resize",
55  "ns-resize": "n-resize",
56  "nesw-resize": "ne-resize",
57  "nwse-resize": "nw-resize"
58  };
59 }
60 
61 - (id)initWithCSSString:(CPString)aString
62 {
63  if (self = [super init])
64  _cssString = aString;
65 
66  return self;
67 }
68 
73 - (id)initWithImage:(CPImage)image hotSpot:(CGPoint)hotSpot
74 {
75  _hotSpot = hotSpot;
76  _image = image;
77  return [self initWithCSSString:"url(" + [_image filename] + ")" + hotSpot.x + " " + hotSpot.y + ", auto"];
78 }
79 
85 - (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CGPoint)aHotSpot
86 {
87  return [self initWithImage:image hotSpot:aHotSpot];
88 }
89 
90 + (void)hide
91 {
92  [self _setCursorCSS:@"none"]; // Not supported in IE < 9
93 }
94 
95 + (void)unhide
96 {
97  [self _setCursorCSS:[currentCursor _cssString]];
98 }
99 
100 + (void)setHiddenUntilMouseMoves:(BOOL)flag
101 {
102  if (flag)
103  [CPCursor hide];
104  else
105  [CPCursor unhide];
106 }
107 
108 - (void)pop
109 {
110  [CPCursor pop];
111 }
112 
113 + (void)pop
114 {
115  if (cursorStack.length > 1)
116  {
117  cursorStack.pop();
118  currentCursor = cursorStack[cursorStack.length - 1];
119  }
120 }
121 
122 - (void)push
123 {
124  cursorStack.push(self);
125  currentCursor = self;
126 }
127 
128 - (void)set
129 {
130  if (currentCursor === self)
131  return;
132 
133  currentCursor = self;
134 
135 #if PLATFORM(DOM)
136  [[self class] _setCursorCSS:_cssString];
137 #endif
138 }
139 
140 - (void)mouseEntered:(CPEvent)event
141 {
142 }
143 
144 - (void)mouseExited:(CPEvent)event
145 {
146 }
147 
149 {
150  return currentCursor;
151 }
152 
153 + (void)_setCursorCSS:(CPString)aString
154 {
155 #if PLATFORM(DOM)
156  var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
157 
158  for (var i = 0, count = [platformWindows count]; i < count; i++)
159  platformWindows[i]._DOMBodyElement.style.cursor = aString;
160 #endif
161 }
162 
163 // Internal method that is used to return the system cursors. Caches the system cursors for performance.
164 + (CPCursor)_nativeSystemCursorWithName:(CPString)cursorName cssString:(CPString)aString
165 {
166  var cursor = cursors[cursorName];
167 
168  if (typeof cursor === "undefined")
169  {
170  var cssString;
171 
172  // IE <= 8 does not support some cursors, map them to supported cursors
174 
175  if (ieLessThan9)
176  cssString = ieCursorMap[aString] || aString;
177  else
178  cssString = aString;
179 
180  cursors[cursorName] = cursor = [[CPCursor alloc] initWithCSSString:cssString];
181  }
182 
183  return cursor;
184 }
185 
186 + (CPCursor)_imageCursorWithName:(CPString)cursorName cssString:(CPString)aString
187 {
188  var cursor = cursors[cursorName];
189 
190  if (typeof cursor === "undefined")
191  {
192  var themeResourcePath = [[[CPApp themeBlend] bundle] resourcePath],
193  extension = CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) ? @"cur" : @"png";
194 
195  cssString = [CPString stringWithFormat:@"url(%@cursors/%@.%@), %@", themeResourcePath, cursorName, extension, aString];
196 
197  cursors[cursorName] = cursor = [[CPCursor alloc] initWithCSSString:cssString];
198  }
199 
200  return cursor;
201 }
202 
203 + (CPCursor)_tryUsingNativeSystemCursorWithName:(CPString)cursorName cssString:(CPString)cssName onPlatform:(CPCursorPlatform)shouldUseNativeCursorOn fallingBackWithImageAndCSSPointer:(CPString)aString
204 {
205  var useNativeSystemCursor = (((shouldUseNativeCursorOn == CPCursorPlatformBoth) ||
206  ((shouldUseNativeCursorOn == CPCursorPlatformMac) && CPBrowserIsOperatingSystem(CPMacOperatingSystem)) ||
208  && [CPCursor _nativeCursorExists:cssName]);
209 
210  if (useNativeSystemCursor)
211  return [CPCursor _nativeSystemCursorWithName:cursorName cssString:cssName];
212  else
213  return [CPCursor _imageCursorWithName:cursorName cssString:aString];
214 }
215 
216 + (BOOL)_nativeCursorExists:(CPString)cursorCSSName
217 {
218 #if PLATFORM(DOM)
219 
220  // FIXME: Trick until FF/Win & Chrome/Win correctly implement context-menu cursor
221  // They will answer that they implement it but they actually don't
222 
224  return NO;
225 
226  // Normal usage : try to set the cursor and check if resulting cursor is the one we tried to set.
227  // If yes, then the browser implements the cursor. If no (and usually we get "default"), then it doesn't.
228 
229  var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects],
230  count = [platformWindows count];
231 
232  if (count > 0)
233  {
234  var currentPlatformCursor = platformWindows[0]._DOMBodyElement.style.cursor;
235  platformWindows[0]._DOMBodyElement.style.cursor = cursorCSSName;
236  var doesExist = (platformWindows[0]._DOMBodyElement.style.cursor == cursorCSSName);
237  platformWindows[0]._DOMBodyElement.style.cursor = currentPlatformCursor;
238 
239  return doesExist;
240  }
241 #endif
242 
243  return NO;
244 }
245 
246 + (CPCursor)arrowCursor
247 {
248  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"default"];
249 }
250 
251 + (CPCursor)crosshairCursor
252 {
253  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"crosshair"];
254 }
255 
256 + (CPCursor)IBeamCursor
257 {
258  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"text"];
259 }
260 
261 + (CPCursor)pointingHandCursor
262 {
263  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer"];
264 }
265 
266 + (CPCursor)resizeNorthwestCursor
267 {
268  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nw-resize"];
269 }
270 
271 + (CPCursor)resizeNorthwestSoutheastCursor
272 {
273  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nwse-resize"];
274 }
275 
276 + (CPCursor)resizeNortheastCursor
277 {
278  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ne-resize"];
279 }
280 
281 + (CPCursor)resizeNortheastSouthwestCursor
282 {
283  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"nesw-resize"];
284 }
285 
286 + (CPCursor)resizeSouthwestCursor
287 {
288  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"sw-resize"];
289 }
290 
291 + (CPCursor)resizeSoutheastCursor
292 {
293  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"se-resize"];
294 }
295 
296 + (CPCursor)resizeDownCursor
297 {
298  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize"];
299 }
300 
301 + (CPCursor)resizeUpCursor
302 {
303  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"n-resize"];
304 }
305 
306 + (CPCursor)resizeLeftCursor
307 {
308  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"w-resize"];
309 }
310 
311 + (CPCursor)resizeRightCursor
312 {
313  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"e-resize"];
314 }
315 
316 + (CPCursor)resizeLeftRightCursor
317 {
318  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize"];
319 }
320 
321 + (CPCursor)resizeEastWestCursor
322 {
323  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ew-resize"];
324 }
325 
326 + (CPCursor)resizeUpDownCursor
327 {
328  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize"];
329 }
330 
331 + (CPCursor)resizeNorthSouthCursor
332 {
333  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"ns-resize"];
334 }
335 
336 + (CPCursor)operationNotAllowedCursor
337 {
338  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed"];
339 }
340 
341 + (CPCursor)dragCopyCursor
342 {
343  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"copy"];
344 }
345 
346 + (CPCursor)dragLinkCursor
347 {
348  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"alias"];
349 }
350 
351 + (CPCursor)contextualMenuCursor
352 {
353  return [CPCursor _tryUsingNativeSystemCursorWithName:CPStringFromSelector(_cmd)
354  cssString:@"context-menu"
355  onPlatform:CPCursorPlatformBoth
356  fallingBackWithImageAndCSSPointer:@"default"];
357 }
358 
359 + (CPCursor)openHandCursor
360 {
361  return [CPCursor _tryUsingNativeSystemCursorWithName:CPStringFromSelector(_cmd)
362  cssString:@"grab"
363  onPlatform:CPCursorPlatformMac
364  fallingBackWithImageAndCSSPointer:@"default"];
365 }
366 
367 + (CPCursor)closedHandCursor
368 {
369  return [CPCursor _tryUsingNativeSystemCursorWithName:CPStringFromSelector(_cmd)
370  cssString:@"grabbing"
371  onPlatform:CPCursorPlatformMac
372  fallingBackWithImageAndCSSPointer:@"default"];
373 }
374 
375 + (CPCursor)disappearingItemCursor
376 {
377  return [CPCursor _imageCursorWithName:CPStringFromSelector(_cmd) cssString:@"default"];
378 }
379 
380 + (CPCursor)IBeamCursorForVerticalLayout
381 {
382  return [CPCursor _nativeSystemCursorWithName:CPStringFromSelector(_cmd) cssString:@"vertical-text"];
383 }
384 
385 @end
386 
387 @implementation CPCursor(CPCoding)
388 
389 - (id)initWithCoder:(CPCoder)coder
390 {
391  if (self = [super init])
392  _cssString = [coder decodeObjectForKey:@"CPCursorNameKey"];
393 
394  return self;
395 }
396 
397 - (void)encodeWithCoder:(CPCoder)coder
398 {
399  [coder encodeObject:_cssString forKey:@"CPCursorNameKey"];
400 }
401 
402 @end
403 
405 
409 - (CPString)_cssString
410 {
411  return _cssString;
412 }
413 
417 - (void)set_cssString:(CPString)aValue
418 {
419  _cssString = aValue;
420 }
421 
425 - (CPString)hotSpot
426 {
427  return _hotSpot;
428 }
429 
433 - (CPImage)image
434 {
435  return _image;
436 }
437 
441 - (BOOL)isSetOnMouseEntered
442 {
443  return _isSetOnMouseEntered;
444 }
445 
449 - (void)setOnMouseEntered:(BOOL)aValue
450 {
451  _isSetOnMouseEntered = aValue;
452 }
453 
457 - (BOOL)isSetOnMouseExited
458 {
459  return _isSetOnMouseExited;
460 }
461 
465 - (void)setOnMouseExited:(BOOL)aValue
466 {
467  _isSetOnMouseExited = aValue;
468 }
469 
470 @end
id init()
Definition: CALayer.j:126
void hide()
Definition: CPCursor.j:90
CPCursorPlatformWindows
Definition: CPCursor.j:35
void unhide()
Definition: CPCursor.j:95
void pop()
Definition: CPCursor.j:108
CPCursorPlatform CPCursorPlatformNone
Definition: CPCursor.j:33
CPSet visiblePlatformWindows()
An immutable string (collection of characters).
Definition: CPString.h:2
CPInternetExplorerBrowserEngine
Definition: CPImage.h:2
function CPFeatureIsCompatible(aFeature)
CPWindowsOperatingSystem
CPEdgeBrowserEngine
CPCursorPlatformMac
Definition: CPCursor.j:34
CPHTMLCanvasFeature
function CPBrowserIsOperatingSystem(anOperatingSystem)
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
global CPApp var cursorStack
Definition: CPCursor.j:28
id initWithCSSString:(CPString aString)
Definition: CPCursor.j:61
CPMacOperatingSystem
global CPApp var ieCursorMap
Definition: CPCursor.j:30
CPCursor currentCursor()
Definition: CPCursor.j:148
Definition: CPEvent.h:2
Class class()
Definition: CPObject.j:179
function CPBrowserIsEngine(anEngine)
CPCursorPlatformBoth
Definition: CPCursor.j:36
global CPApp var currentCursor
Definition: CPCursor.j:27
id alloc()
Definition: CPObject.j:130
global CPApp var cursors
Definition: CPCursor.j:29
id stringWithFormat:(CPString format, [,] ...)
Definition: CPString.j:166
id initWithImage:hotSpot:(CPImage image, [hotSpot] CGPoint hotSpot)
Definition: CPCursor.j:73