]> git.saurik.com Git - wxWidgets.git/blob - src/mac/classic/cursor.cpp
Restore a use case that was lost with the last set of updates, using a
[wxWidgets.git] / src / mac / classic / cursor.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/classic/cursor.cpp
3 // Purpose: wxCursor class
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #include "wx/cursor.h"
19
20 #ifndef WX_PRECOMP
21 #include "wx/app.h"
22 #include "wx/icon.h"
23 #include "wx/image.h"
24 #endif // WX_PRECOMP
25
26 #include "wx/xpmdecod.h"
27
28 #include "wx/mac/private.h"
29
30 IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap)
31
32 const short kwxCursorBullseye = 10 ;
33 const short kwxCursorBlank = 11 ;
34 const short kwxCursorPencil = 12 ;
35 const short kwxCursorMagnifier = 13 ;
36 const short kwxCursorNoEntry = 14 ;
37 const short kwxCursorPaintBrush = 15 ;
38 const short kwxCursorPointRight = 16 ;
39 const short kwxCursorPointLeft = 17 ;
40 const short kwxCursorQuestionArrow = 18 ;
41 const short kwxCursorRightArrow = 19 ;
42 const short kwxCursorSizeNS = 20 ;
43 const short kwxCursorSize = 21 ;
44 const short kwxCursorSizeNESW = 22 ;
45 const short kwxCursorSizeNWSE = 23 ;
46 const short kwxCursorRoller = 24 ;
47
48 wxCursor gMacCurrentCursor ;
49
50 wxCursorRefData::wxCursorRefData()
51 {
52 m_width = 16;
53 m_height = 16;
54 m_hCursor = NULL ;
55 m_disposeHandle = false ;
56 m_releaseHandle = false ;
57 m_isColorCursor = false ;
58 m_themeCursor = -1 ;
59 }
60
61 wxCursorRefData::~wxCursorRefData()
62 {
63 if ( m_isColorCursor )
64 {
65 ::DisposeCCursor( (CCrsrHandle) m_hCursor ) ;
66 }
67 else if ( m_disposeHandle )
68 {
69 ::DisposeHandle( (Handle ) m_hCursor ) ;
70 }
71 else if ( m_releaseHandle )
72 {
73 // we don't release the resource since it may already
74 // be in use again
75 }
76 }
77
78 // Cursors
79 wxCursor::wxCursor()
80 {
81 }
82
83 wxCursor::wxCursor(const char WXUNUSED(bits)[], int WXUNUSED(width), int WXUNUSED(height),
84 int WXUNUSED(hotSpotX), int WXUNUSED(hotSpotY), const char WXUNUSED(maskBits)[])
85 {
86 }
87
88 wxCursor::wxCursor( const wxImage &image )
89 {
90 CreateFromImage( image ) ;
91 }
92
93 wxCursor::wxCursor(const char **bits)
94 {
95 (void) CreateFromXpm(bits);
96 }
97
98 wxCursor::wxCursor(char **bits)
99 {
100 (void) CreateFromXpm((const char **)bits);
101 }
102
103 bool wxCursor::CreateFromXpm(const char **bits)
104 {
105 wxCHECK_MSG( bits != NULL, false, wxT("invalid cursor data") );
106 wxXPMDecoder decoder;
107 wxImage img = decoder.ReadData(bits);
108 wxCHECK_MSG( img.Ok(), false, wxT("invalid cursor data") );
109 CreateFromImage( img ) ;
110 return true;
111 }
112
113 short GetCTabIndex( CTabHandle colors , RGBColor *col )
114 {
115 short retval = 0 ;
116 unsigned long bestdiff = 0xFFFF ;
117 for ( int i = 0 ; i < (**colors).ctSize ; ++i )
118 {
119 unsigned long diff = abs(col->red - (**colors).ctTable[i].rgb.red ) +
120 abs(col->green - (**colors).ctTable[i].rgb.green ) +
121 abs(col->blue - (**colors).ctTable[i].rgb.blue ) ;
122 if ( diff < bestdiff )
123 {
124 bestdiff = diff ;
125 retval = (**colors).ctTable[i].value ;
126 }
127 }
128 return retval ;
129 }
130
131 void wxCursor::CreateFromImage(const wxImage & image)
132 {
133 m_refData = new wxCursorRefData;
134
135 int w = 16;
136 int h = 16;
137
138 int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
139 int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
140 int image_w = image.GetWidth();
141 int image_h = image.GetHeight();
142
143 wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < image_w &&
144 hotSpotY >= 0 && hotSpotY < image_h,
145 _T("invalid cursor hot spot coordinates") );
146
147 wxImage image16(image); // final image of correct size
148
149 // if image is too small then place it in the center, resize it if too big
150 if ((w > image_w) && (h > image_h))
151 {
152 wxPoint offset((w - image_w)/2, (h - image_h)/2);
153 hotSpotX = hotSpotX + offset.x;
154 hotSpotY = hotSpotY + offset.y;
155
156 image16 = image.Size(wxSize(w, h), offset);
157 }
158 else if ((w != image_w) || (h != image_h))
159 {
160 hotSpotX = int(hotSpotX * double(w) / double(image_w));
161 hotSpotY = int(hotSpotY * double(h) / double(image_h));
162
163 image16 = image.Scale(w, h);
164 }
165
166 unsigned char * rgbBits = image16.GetData();
167 bool bHasMask = image16.HasMask() ;
168
169 #if 0
170 // monochrome implementation
171 M_CURSORDATA->m_hCursor = NewHandle( sizeof( Cursor ) ) ;
172 M_CURSORDATA->m_disposeHandle = true ;
173 HLock( (Handle) M_CURSORDATA->m_hCursor ) ;
174 CursPtr cp = *(CursHandle)M_CURSORDATA->m_hCursor ;
175 memset( cp->data , 0 , sizeof( Bits16 ) ) ;
176 memset( cp->mask , 0 , sizeof( Bits16 ) ) ;
177
178 unsigned char mr = image16.GetMaskRed() ;
179 unsigned char mg = image16.GetMaskGreen() ;
180 unsigned char mb = image16.GetMaskBlue() ;
181 for ( int y = 0 ; y < h ; ++y )
182 {
183 short rowbits = 0 ;
184 short maskbits = 0 ;
185
186 for ( int x = 0 ; x < w ; ++x )
187 {
188 long pos = (y * w + x) * 3;
189
190 unsigned char r = rgbBits[pos] ;
191 unsigned char g = rgbBits[pos+1] ;
192 unsigned char b = rgbBits[pos+2] ;
193 if ( bHasMask && r==mr && g==mg && b==mb )
194 {
195 // masked area, does not appear anywhere
196 }
197 else
198 {
199 if ( (int)r + (int)g + (int)b < 0x0200 )
200 {
201 rowbits |= ( 1 << (15-x) ) ;
202 }
203 maskbits |= ( 1 << (15-x) ) ;
204 }
205 }
206 cp->data[y] = rowbits ;
207 cp->mask[y] = maskbits ;
208 }
209 if ( !bHasMask )
210 {
211 memcpy( cp->mask , cp->data , sizeof( Bits16) ) ;
212 }
213 cp->hotSpot.h = hotSpotX ;
214 cp->hotSpot.v = hotSpotY ;
215 HUnlock( (Handle) M_CURSORDATA->m_hCursor ) ;
216 #else
217 PixMapHandle pm = (PixMapHandle) NewHandleClear( sizeof (PixMap)) ;
218 short extent = 16 ;
219 short bytesPerPixel = 1 ;
220 short depth = 8 ;
221 Rect bounds = { 0 , 0 , extent , extent } ;
222 CCrsrHandle ch = (CCrsrHandle) NewHandleClear ( sizeof( CCrsr ) ) ;
223 CTabHandle newColors = GetCTable( 8 ) ;
224 HandToHand((Handle *) &newColors);
225 // set the values to the indices
226 for ( int i = 0 ; i < (**newColors).ctSize ; ++i )
227 {
228 (**newColors).ctTable[i].value = i ;
229 }
230 HLock( (Handle) ch) ;
231 (**ch).crsrType = 0x8001 ; // color cursors
232 (**ch).crsrMap = pm ;
233 short bytesPerRow = bytesPerPixel * extent ;
234
235 (**pm).baseAddr = 0;
236 (**pm).rowBytes = bytesPerRow | 0x8000;
237 (**pm).bounds = bounds;
238 (**pm).pmVersion = 0;
239 (**pm).packType = 0;
240 (**pm).packSize = 0;
241 (**pm).hRes = 0x00480000; /* 72 DPI default res */
242 (**pm).vRes = 0x00480000; /* 72 DPI default res */
243 (**pm).pixelSize = depth;
244 (**pm).pixelType = 0;
245 (**pm).cmpCount = 1;
246 (**pm).cmpSize = depth;
247 (**pm).pmTable = newColors;
248
249 (**ch).crsrData = NewHandleClear( extent * bytesPerRow ) ;
250 (**ch).crsrXData = NULL ;
251 (**ch).crsrXValid = 0;
252 (**ch).crsrXHandle = NULL;
253
254 (**ch).crsrHotSpot.h = hotSpotX ;
255 (**ch).crsrHotSpot.v = hotSpotY ;
256 (**ch).crsrXTable = NULL ;
257 (**ch).crsrID = GetCTSeed() ;
258
259 memset( (**ch).crsr1Data , 0 , sizeof( Bits16 ) ) ;
260 memset( (**ch).crsrMask , 0 , sizeof( Bits16 ) ) ;
261
262 unsigned char mr = image16.GetMaskRed() ;
263 unsigned char mg = image16.GetMaskGreen() ;
264 unsigned char mb = image16.GetMaskBlue() ;
265 for ( int y = 0 ; y < h ; ++y )
266 {
267 short rowbits = 0 ;
268 short maskbits = 0 ;
269
270 for ( int x = 0 ; x < w ; ++x )
271 {
272 long pos = (y * w + x) * 3;
273
274 unsigned char r = rgbBits[pos] ;
275 unsigned char g = rgbBits[pos+1] ;
276 unsigned char b = rgbBits[pos+2] ;
277 RGBColor col = { 0xFFFF ,0xFFFF, 0xFFFF } ;
278
279 if ( bHasMask && r==mr && g==mg && b==mb )
280 {
281 // masked area, does not appear anywhere
282 }
283 else
284 {
285 if ( (int)r + (int)g + (int)b < 0x0200 )
286 {
287 rowbits |= ( 1 << (15-x) ) ;
288 }
289 maskbits |= ( 1 << (15-x) ) ;
290
291 col = *((RGBColor*) wxColor( r , g , b ).GetPixel()) ;
292 }
293 *((*(**ch).crsrData) + y * bytesPerRow + x) =
294 GetCTabIndex( newColors , &col) ;
295 }
296 (**ch).crsr1Data[y] = rowbits ;
297 (**ch).crsrMask[y] = maskbits ;
298 }
299 if ( !bHasMask )
300 {
301 memcpy( (**ch).crsrMask , (**ch).crsr1Data , sizeof( Bits16) ) ;
302 }
303
304 HUnlock((Handle) ch) ;
305 M_CURSORDATA->m_hCursor = ch ;
306 M_CURSORDATA->m_isColorCursor = true ;
307 #endif
308 }
309
310 wxCursor::wxCursor(const wxString& cursor_file, long flags, int hotSpotX, int hotSpotY)
311 {
312 m_refData = new wxCursorRefData;
313 if ( flags == wxBITMAP_TYPE_MACCURSOR_RESOURCE )
314 {
315 Str255 theName ;
316 wxMacStringToPascal( cursor_file , theName ) ;
317
318 wxStAppResource resload ;
319 Handle resHandle = ::GetNamedResource( 'crsr' , theName ) ;
320 if ( resHandle )
321 {
322 short theId = -1 ;
323 OSType theType ;
324 GetResInfo( resHandle , &theId , &theType , theName ) ;
325 ReleaseResource( resHandle ) ;
326 M_CURSORDATA->m_hCursor = GetCCursor( theId ) ;
327 if ( M_CURSORDATA->m_hCursor )
328 M_CURSORDATA->m_isColorCursor = true ;
329 }
330 else
331 {
332 Handle resHandle = ::GetNamedResource( 'CURS' , theName ) ;
333 if ( resHandle )
334 {
335 short theId = -1 ;
336 OSType theType ;
337 GetResInfo( resHandle , &theId , &theType , theName ) ;
338 ReleaseResource( resHandle ) ;
339 M_CURSORDATA->m_hCursor = GetCursor( theId ) ;
340 if ( M_CURSORDATA->m_hCursor )
341 M_CURSORDATA->m_releaseHandle = true ;
342 }
343 }
344 }
345 else
346 {
347 wxImage image ;
348 image.LoadFile( cursor_file , flags ) ;
349 if( image.Ok() )
350 {
351 image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,hotSpotX ) ;
352 image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,hotSpotY ) ;
353 delete m_refData ;
354 CreateFromImage(image) ;
355 }
356 }
357 }
358
359 // Cursors by stock number
360 wxCursor::wxCursor(int cursor_type)
361 {
362 m_refData = new wxCursorRefData;
363
364 switch (cursor_type)
365 {
366 case wxCURSOR_COPY_ARROW:
367 M_CURSORDATA->m_themeCursor = kThemeCopyArrowCursor ;
368 break;
369 case wxCURSOR_WAIT:
370 M_CURSORDATA->m_themeCursor = kThemeWatchCursor ;
371 break;
372 case wxCURSOR_IBEAM:
373 M_CURSORDATA->m_themeCursor = kThemeIBeamCursor ;
374 break;
375 case wxCURSOR_CROSS:
376 M_CURSORDATA->m_themeCursor = kThemeCrossCursor;
377 break;
378 case wxCURSOR_SIZENWSE:
379 {
380 wxStAppResource resload ;
381 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNWSE);
382 }
383 break;
384 case wxCURSOR_SIZENESW:
385 {
386 wxStAppResource resload ;
387 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNESW);
388 }
389 break;
390 case wxCURSOR_SIZEWE:
391 {
392 M_CURSORDATA->m_themeCursor = kThemeResizeLeftRightCursor;
393 }
394 break;
395 case wxCURSOR_SIZENS:
396 {
397 wxStAppResource resload ;
398 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNS);
399 }
400 break;
401 case wxCURSOR_SIZING:
402 {
403 wxStAppResource resload ;
404 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSize);
405 }
406 break;
407 case wxCURSOR_HAND:
408 {
409 M_CURSORDATA->m_themeCursor = kThemePointingHandCursor;
410 }
411 break;
412 case wxCURSOR_BULLSEYE:
413 {
414 wxStAppResource resload ;
415 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorBullseye);
416 }
417 break;
418 case wxCURSOR_PENCIL:
419 {
420 wxStAppResource resload ;
421 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPencil);
422 }
423 break;
424 case wxCURSOR_MAGNIFIER:
425 {
426 wxStAppResource resload ;
427 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorMagnifier);
428 }
429 break;
430 case wxCURSOR_NO_ENTRY:
431 {
432 wxStAppResource resload ;
433 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorNoEntry);
434 }
435 break;
436 case wxCURSOR_WATCH:
437 {
438 M_CURSORDATA->m_themeCursor = kThemeWatchCursor;
439 break;
440 }
441 case wxCURSOR_PAINT_BRUSH:
442 {
443 wxStAppResource resload ;
444 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPaintBrush);
445 break;
446 }
447 case wxCURSOR_POINT_LEFT:
448 {
449 wxStAppResource resload ;
450 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPointLeft);
451 break;
452 }
453 case wxCURSOR_POINT_RIGHT:
454 {
455 wxStAppResource resload ;
456 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPointRight);
457 break;
458 }
459 case wxCURSOR_QUESTION_ARROW:
460 {
461 wxStAppResource resload ;
462 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorQuestionArrow);
463 break;
464 }
465 case wxCURSOR_BLANK:
466 {
467 wxStAppResource resload ;
468 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorBlank);
469 break;
470 }
471 case wxCURSOR_RIGHT_ARROW:
472 {
473 wxStAppResource resload ;
474 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorRightArrow);
475 break;
476 }
477 case wxCURSOR_SPRAYCAN:
478 {
479 wxStAppResource resload ;
480 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorRoller);
481 break;
482 }
483 case wxCURSOR_CHAR:
484 case wxCURSOR_ARROW:
485 case wxCURSOR_LEFT_BUTTON:
486 case wxCURSOR_RIGHT_BUTTON:
487 case wxCURSOR_MIDDLE_BUTTON:
488 default:
489 M_CURSORDATA->m_themeCursor = kThemeArrowCursor ;
490 break;
491 }
492 if ( M_CURSORDATA->m_themeCursor == -1 )
493 M_CURSORDATA->m_releaseHandle = true ;
494 }
495
496 void wxCursor::MacInstall() const
497 {
498 gMacCurrentCursor = *this ;
499 if ( m_refData && M_CURSORDATA->m_themeCursor != -1 )
500 {
501 SetThemeCursor( M_CURSORDATA->m_themeCursor ) ;
502 }
503 else if ( m_refData && M_CURSORDATA->m_hCursor )
504 {
505 if ( M_CURSORDATA->m_isColorCursor )
506 ::SetCCursor( (CCrsrHandle) M_CURSORDATA->m_hCursor ) ;
507 else
508 ::SetCursor( * (CursHandle) M_CURSORDATA->m_hCursor ) ;
509 }
510 else
511 {
512 SetThemeCursor( kThemeArrowCursor ) ;
513 }
514 }
515
516 wxCursor::~wxCursor()
517 {
518 }
519
520 // Global cursor setting
521 void wxSetCursor(const wxCursor& cursor)
522 {
523 cursor.MacInstall() ;
524 }