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