1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/classic/cursor.cpp
3 // Purpose: wxCursor class
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
18 #include "wx/cursor.h"
26 #include "wx/xpmdecod.h"
28 #include "wx/mac/private.h"
30 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxBitmap
)
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 ;
48 wxCursor gMacCurrentCursor
;
50 wxCursorRefData::wxCursorRefData()
55 m_disposeHandle
= false ;
56 m_releaseHandle
= false ;
57 m_isColorCursor
= false ;
61 wxCursorRefData::~wxCursorRefData()
63 if ( m_isColorCursor
)
65 ::DisposeCCursor( (CCrsrHandle
) m_hCursor
) ;
67 else if ( m_disposeHandle
)
69 ::DisposeHandle( (Handle
) m_hCursor
) ;
71 else if ( m_releaseHandle
)
73 // we don't release the resource since it may already
83 wxCursor::wxCursor(const char WXUNUSED(bits
)[], int WXUNUSED(width
), int WXUNUSED(height
),
84 int WXUNUSED(hotSpotX
), int WXUNUSED(hotSpotY
), const char WXUNUSED(maskBits
)[])
88 wxCursor::wxCursor( const wxImage
&image
)
90 CreateFromImage( image
) ;
93 wxCursor::wxCursor(const char **bits
)
95 (void) CreateFromXpm(bits
);
98 wxCursor::wxCursor(char **bits
)
100 (void) CreateFromXpm((const char **)bits
);
103 bool wxCursor::CreateFromXpm(const char **bits
)
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
) ;
113 short GetCTabIndex( CTabHandle colors
, RGBColor
*col
)
116 unsigned long bestdiff
= 0xFFFF ;
117 for ( int i
= 0 ; i
< (**colors
).ctSize
; ++i
)
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
)
125 retval
= (**colors
).ctTable
[i
].value
;
131 void wxCursor::CreateFromImage(const wxImage
& image
)
133 m_refData
= new wxCursorRefData
;
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();
143 wxASSERT_MSG( hotSpotX
>= 0 && hotSpotX
< image_w
&&
144 hotSpotY
>= 0 && hotSpotY
< image_h
,
145 _T("invalid cursor hot spot coordinates") );
147 wxImage
image16(image
); // final image of correct size
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
))
152 wxPoint
offset((w
- image_w
)/2, (h
- image_h
)/2);
153 hotSpotX
= hotSpotX
+ offset
.x
;
154 hotSpotY
= hotSpotY
+ offset
.y
;
156 image16
= image
.Size(wxSize(w
, h
), offset
);
158 else if ((w
!= image_w
) || (h
!= image_h
))
160 hotSpotX
= int(hotSpotX
* double(w
) / double(image_w
));
161 hotSpotY
= int(hotSpotY
* double(h
) / double(image_h
));
163 image16
= image
.Scale(w
, h
);
166 unsigned char * rgbBits
= image16
.GetData();
167 bool bHasMask
= image16
.HasMask() ;
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
) ) ;
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
)
186 for ( int x
= 0 ; x
< w
; ++x
)
188 long pos
= (y
* w
+ x
) * 3;
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
)
195 // masked area, does not appear anywhere
199 if ( (int)r
+ (int)g
+ (int)b
< 0x0200 )
201 rowbits
|= ( 1 << (15-x
) ) ;
203 maskbits
|= ( 1 << (15-x
) ) ;
206 cp
->data
[y
] = rowbits
;
207 cp
->mask
[y
] = maskbits
;
211 memcpy( cp
->mask
, cp
->data
, sizeof( Bits16
) ) ;
213 cp
->hotSpot
.h
= hotSpotX
;
214 cp
->hotSpot
.v
= hotSpotY
;
215 HUnlock( (Handle
) M_CURSORDATA
->m_hCursor
) ;
217 PixMapHandle pm
= (PixMapHandle
) NewHandleClear( sizeof (PixMap
)) ;
219 short bytesPerPixel
= 1 ;
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
)
228 (**newColors
).ctTable
[i
].value
= i
;
230 HLock( (Handle
) ch
) ;
231 (**ch
).crsrType
= 0x8001 ; // color cursors
232 (**ch
).crsrMap
= pm
;
233 short bytesPerRow
= bytesPerPixel
* extent
;
236 (**pm
).rowBytes
= bytesPerRow
| 0x8000;
237 (**pm
).bounds
= bounds
;
238 (**pm
).pmVersion
= 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;
246 (**pm
).cmpSize
= depth
;
247 (**pm
).pmTable
= newColors
;
249 (**ch
).crsrData
= NewHandleClear( extent
* bytesPerRow
) ;
250 (**ch
).crsrXData
= NULL
;
251 (**ch
).crsrXValid
= 0;
252 (**ch
).crsrXHandle
= NULL
;
254 (**ch
).crsrHotSpot
.h
= hotSpotX
;
255 (**ch
).crsrHotSpot
.v
= hotSpotY
;
256 (**ch
).crsrXTable
= NULL
;
257 (**ch
).crsrID
= GetCTSeed() ;
259 memset( (**ch
).crsr1Data
, 0 , sizeof( Bits16
) ) ;
260 memset( (**ch
).crsrMask
, 0 , sizeof( Bits16
) ) ;
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
)
270 for ( int x
= 0 ; x
< w
; ++x
)
272 long pos
= (y
* w
+ x
) * 3;
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 } ;
279 if ( bHasMask
&& r
==mr
&& g
==mg
&& b
==mb
)
281 // masked area, does not appear anywhere
285 if ( (int)r
+ (int)g
+ (int)b
< 0x0200 )
287 rowbits
|= ( 1 << (15-x
) ) ;
289 maskbits
|= ( 1 << (15-x
) ) ;
291 col
= *((RGBColor
*) wxColor( r
, g
, b
).GetPixel()) ;
293 *((*(**ch
).crsrData
) + y
* bytesPerRow
+ x
) =
294 GetCTabIndex( newColors
, &col
) ;
296 (**ch
).crsr1Data
[y
] = rowbits
;
297 (**ch
).crsrMask
[y
] = maskbits
;
301 memcpy( (**ch
).crsrMask
, (**ch
).crsr1Data
, sizeof( Bits16
) ) ;
304 HUnlock((Handle
) ch
) ;
305 M_CURSORDATA
->m_hCursor
= ch
;
306 M_CURSORDATA
->m_isColorCursor
= true ;
310 wxCursor::wxCursor(const wxString
& cursor_file
, long flags
, int hotSpotX
, int hotSpotY
)
312 m_refData
= new wxCursorRefData
;
313 if ( flags
== wxBITMAP_TYPE_MACCURSOR_RESOURCE
)
316 wxMacStringToPascal( cursor_file
, theName
) ;
318 wxStAppResource resload
;
319 Handle resHandle
= ::GetNamedResource( 'crsr' , theName
) ;
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 ;
332 Handle resHandle
= ::GetNamedResource( 'CURS' , theName
) ;
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 ;
348 image
.LoadFile( cursor_file
, flags
) ;
351 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
,hotSpotX
) ;
352 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
,hotSpotY
) ;
354 CreateFromImage(image
) ;
359 // Cursors by stock number
360 wxCursor::wxCursor(int cursor_type
)
362 m_refData
= new wxCursorRefData
;
366 case wxCURSOR_COPY_ARROW
:
367 M_CURSORDATA
->m_themeCursor
= kThemeCopyArrowCursor
;
370 M_CURSORDATA
->m_themeCursor
= kThemeWatchCursor
;
373 M_CURSORDATA
->m_themeCursor
= kThemeIBeamCursor
;
376 M_CURSORDATA
->m_themeCursor
= kThemeCrossCursor
;
378 case wxCURSOR_SIZENWSE
:
380 wxStAppResource resload
;
381 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNWSE
);
384 case wxCURSOR_SIZENESW
:
386 wxStAppResource resload
;
387 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNESW
);
390 case wxCURSOR_SIZEWE
:
392 M_CURSORDATA
->m_themeCursor
= kThemeResizeLeftRightCursor
;
395 case wxCURSOR_SIZENS
:
397 wxStAppResource resload
;
398 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNS
);
401 case wxCURSOR_SIZING
:
403 wxStAppResource resload
;
404 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSize
);
409 M_CURSORDATA
->m_themeCursor
= kThemePointingHandCursor
;
412 case wxCURSOR_BULLSEYE
:
414 wxStAppResource resload
;
415 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorBullseye
);
418 case wxCURSOR_PENCIL
:
420 wxStAppResource resload
;
421 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPencil
);
424 case wxCURSOR_MAGNIFIER
:
426 wxStAppResource resload
;
427 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorMagnifier
);
430 case wxCURSOR_NO_ENTRY
:
432 wxStAppResource resload
;
433 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorNoEntry
);
438 M_CURSORDATA
->m_themeCursor
= kThemeWatchCursor
;
441 case wxCURSOR_PAINT_BRUSH
:
443 wxStAppResource resload
;
444 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPaintBrush
);
447 case wxCURSOR_POINT_LEFT
:
449 wxStAppResource resload
;
450 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPointLeft
);
453 case wxCURSOR_POINT_RIGHT
:
455 wxStAppResource resload
;
456 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPointRight
);
459 case wxCURSOR_QUESTION_ARROW
:
461 wxStAppResource resload
;
462 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorQuestionArrow
);
467 wxStAppResource resload
;
468 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorBlank
);
471 case wxCURSOR_RIGHT_ARROW
:
473 wxStAppResource resload
;
474 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorRightArrow
);
477 case wxCURSOR_SPRAYCAN
:
479 wxStAppResource resload
;
480 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorRoller
);
485 case wxCURSOR_LEFT_BUTTON
:
486 case wxCURSOR_RIGHT_BUTTON
:
487 case wxCURSOR_MIDDLE_BUTTON
:
489 M_CURSORDATA
->m_themeCursor
= kThemeArrowCursor
;
492 if ( M_CURSORDATA
->m_themeCursor
== -1 )
493 M_CURSORDATA
->m_releaseHandle
= true ;
496 void wxCursor::MacInstall() const
498 gMacCurrentCursor
= *this ;
499 if ( m_refData
&& M_CURSORDATA
->m_themeCursor
!= -1 )
501 SetThemeCursor( M_CURSORDATA
->m_themeCursor
) ;
503 else if ( m_refData
&& M_CURSORDATA
->m_hCursor
)
505 if ( M_CURSORDATA
->m_isColorCursor
)
506 ::SetCCursor( (CCrsrHandle
) M_CURSORDATA
->m_hCursor
) ;
508 ::SetCursor( * (CursHandle
) M_CURSORDATA
->m_hCursor
) ;
512 SetThemeCursor( kThemeArrowCursor
) ;
516 wxCursor::~wxCursor()
520 // Global cursor setting
521 void wxSetCursor(const wxCursor
& cursor
)
523 cursor
.MacInstall() ;