1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxCursor class
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
15 #include "wx/cursor.h"
18 #include "wx/xpmdecod.h"
20 #include "wx/mac/private.h"
22 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxBitmap
)
24 const short kwxCursorBullseye
= 10 ;
25 const short kwxCursorBlank
= 11 ;
26 const short kwxCursorPencil
= 12 ;
27 const short kwxCursorMagnifier
= 13 ;
28 const short kwxCursorNoEntry
= 14 ;
29 const short kwxCursorPaintBrush
= 15 ;
30 const short kwxCursorPointRight
= 16 ;
31 const short kwxCursorPointLeft
= 17 ;
32 const short kwxCursorQuestionArrow
= 18 ;
33 const short kwxCursorRightArrow
= 19 ;
34 const short kwxCursorSizeNS
= 20 ;
35 const short kwxCursorSize
= 21 ;
36 const short kwxCursorSizeNESW
= 22 ;
37 const short kwxCursorSizeNWSE
= 23 ;
38 const short kwxCursorRoller
= 24 ;
40 wxCursor gMacCurrentCursor
;
42 wxCursorRefData::wxCursorRefData()
47 m_disposeHandle
= false ;
48 m_releaseHandle
= false ;
49 m_isColorCursor
= false ;
53 wxCursorRefData::~wxCursorRefData()
55 if ( m_isColorCursor
)
57 ::DisposeCCursor( (CCrsrHandle
) m_hCursor
) ;
59 else if ( m_disposeHandle
)
61 ::DisposeHandle( (Handle
) m_hCursor
) ;
63 else if ( m_releaseHandle
)
65 // we don't release the resource since it may already
75 wxCursor::wxCursor(const char WXUNUSED(bits
)[], int WXUNUSED(width
), int WXUNUSED(height
),
76 int WXUNUSED(hotSpotX
), int WXUNUSED(hotSpotY
), const char WXUNUSED(maskBits
)[])
80 wxCursor::wxCursor( const wxImage
&image
)
82 CreateFromImage( image
) ;
85 wxCursor::wxCursor(const char **bits
)
87 (void) CreateFromXpm(bits
);
90 wxCursor::wxCursor(char **bits
)
92 (void) CreateFromXpm((const char **)bits
);
95 bool wxCursor::CreateFromXpm(const char **bits
)
97 wxCHECK_MSG( bits
!= NULL
, FALSE
, wxT("invalid cursor data") );
99 wxImage img
= decoder
.ReadData(bits
);
100 wxCHECK_MSG( img
.Ok(), FALSE
, wxT("invalid cursor data") );
101 CreateFromImage( img
) ;
105 short GetCTabIndex( CTabHandle colors
, RGBColor
*col
)
108 unsigned long bestdiff
= 0xFFFF ;
109 for ( int i
= 0 ; i
< (**colors
).ctSize
; ++i
)
111 unsigned long diff
= abs(col
->red
- (**colors
).ctTable
[i
].rgb
.red
) +
112 abs(col
->green
- (**colors
).ctTable
[i
].rgb
.green
) +
113 abs(col
->blue
- (**colors
).ctTable
[i
].rgb
.blue
) ;
114 if ( diff
< bestdiff
)
117 retval
= (**colors
).ctTable
[i
].value
;
123 void wxCursor::CreateFromImage(const wxImage
& image
)
125 m_refData
= new wxCursorRefData
;
130 int hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
131 int hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
132 int image_w
= image
.GetWidth();
133 int image_h
= image
.GetHeight();
135 wxASSERT_MSG( hotSpotX
>= 0 && hotSpotX
< image_w
&&
136 hotSpotY
>= 0 && hotSpotY
< image_h
,
137 _T("invalid cursor hot spot coordinates") );
139 wxImage
image16(image
); // final image of correct size
141 // if image is too small then place it in the center, resize it if too big
142 if ((w
> image_w
) && (h
> image_h
))
144 wxPoint
offset((w
- image_w
)/2, (h
- image_h
)/2);
145 hotSpotX
= hotSpotX
+ offset
.x
;
146 hotSpotY
= hotSpotY
+ offset
.y
;
148 image16
= image
.Size(wxSize(w
, h
), offset
);
150 else if ((w
!= image_w
) || (h
!= image_h
))
152 hotSpotX
= int(hotSpotX
* double(w
) / double(image_w
));
153 hotSpotY
= int(hotSpotY
* double(h
) / double(image_h
));
155 image16
= image
.Scale(w
, h
);
158 unsigned char * rgbBits
= image16
.GetData();
159 bool bHasMask
= image16
.HasMask() ;
162 // monochrome implementation
163 M_CURSORDATA
->m_hCursor
= NewHandle( sizeof( Cursor
) ) ;
164 M_CURSORDATA
->m_disposeHandle
= true ;
165 HLock( (Handle
) M_CURSORDATA
->m_hCursor
) ;
166 CursPtr cp
= *(CursHandle
)M_CURSORDATA
->m_hCursor
;
167 memset( cp
->data
, 0 , sizeof( Bits16
) ) ;
168 memset( cp
->mask
, 0 , sizeof( Bits16
) ) ;
170 unsigned char mr
= image16
.GetMaskRed() ;
171 unsigned char mg
= image16
.GetMaskGreen() ;
172 unsigned char mb
= image16
.GetMaskBlue() ;
173 for ( int y
= 0 ; y
< h
; ++y
)
178 for ( int x
= 0 ; x
< w
; ++x
)
180 long pos
= (y
* w
+ x
) * 3;
182 unsigned char r
= rgbBits
[pos
] ;
183 unsigned char g
= rgbBits
[pos
+1] ;
184 unsigned char b
= rgbBits
[pos
+2] ;
185 if ( bHasMask
&& r
==mr
&& g
==mg
&& b
==mb
)
187 // masked area, does not appear anywhere
191 if ( (int)r
+ (int)g
+ (int)b
< 0x0200 )
193 rowbits
|= ( 1 << (15-x
) ) ;
195 maskbits
|= ( 1 << (15-x
) ) ;
198 cp
->data
[y
] = rowbits
;
199 cp
->mask
[y
] = maskbits
;
203 memcpy( cp
->mask
, cp
->data
, sizeof( Bits16
) ) ;
205 cp
->hotSpot
.h
= hotSpotX
;
206 cp
->hotSpot
.v
= hotSpotY
;
207 HUnlock( (Handle
) M_CURSORDATA
->m_hCursor
) ;
209 PixMapHandle pm
= (PixMapHandle
) NewHandleClear( sizeof (PixMap
)) ;
211 short bytesPerPixel
= 1 ;
213 Rect bounds
= { 0 , 0 , extent
, extent
} ;
214 CCrsrHandle ch
= (CCrsrHandle
) NewHandleClear ( sizeof( CCrsr
) ) ;
215 CTabHandle newColors
= GetCTable( 8 ) ;
216 HandToHand((Handle
*) &newColors
);
217 // set the values to the indices
218 for ( int i
= 0 ; i
< (**newColors
).ctSize
; ++i
)
220 (**newColors
).ctTable
[i
].value
= i
;
222 HLock( (Handle
) ch
) ;
223 (**ch
).crsrType
= 0x8001 ; // color cursors
224 (**ch
).crsrMap
= pm
;
225 short bytesPerRow
= bytesPerPixel
* extent
;
228 (**pm
).rowBytes
= bytesPerRow
| 0x8000;
229 (**pm
).bounds
= bounds
;
230 (**pm
).pmVersion
= 0;
233 (**pm
).hRes
= 0x00480000; /* 72 DPI default res */
234 (**pm
).vRes
= 0x00480000; /* 72 DPI default res */
235 (**pm
).pixelSize
= depth
;
236 (**pm
).pixelType
= 0;
238 (**pm
).cmpSize
= depth
;
239 (**pm
).pmTable
= newColors
;
241 (**ch
).crsrData
= NewHandleClear( extent
* bytesPerRow
) ;
242 (**ch
).crsrXData
= NULL
;
243 (**ch
).crsrXValid
= 0;
244 (**ch
).crsrXHandle
= NULL
;
246 (**ch
).crsrHotSpot
.h
= hotSpotX
;
247 (**ch
).crsrHotSpot
.v
= hotSpotY
;
248 (**ch
).crsrXTable
= NULL
;
249 (**ch
).crsrID
= GetCTSeed() ;
251 memset( (**ch
).crsr1Data
, 0 , sizeof( Bits16
) ) ;
252 memset( (**ch
).crsrMask
, 0 , sizeof( Bits16
) ) ;
254 unsigned char mr
= image16
.GetMaskRed() ;
255 unsigned char mg
= image16
.GetMaskGreen() ;
256 unsigned char mb
= image16
.GetMaskBlue() ;
257 for ( int y
= 0 ; y
< h
; ++y
)
262 for ( int x
= 0 ; x
< w
; ++x
)
264 long pos
= (y
* w
+ x
) * 3;
266 unsigned char r
= rgbBits
[pos
] ;
267 unsigned char g
= rgbBits
[pos
+1] ;
268 unsigned char b
= rgbBits
[pos
+2] ;
269 RGBColor col
= { 0xFFFF ,0xFFFF, 0xFFFF } ;
271 if ( bHasMask
&& r
==mr
&& g
==mg
&& b
==mb
)
273 // masked area, does not appear anywhere
277 if ( (int)r
+ (int)g
+ (int)b
< 0x0200 )
279 rowbits
|= ( 1 << (15-x
) ) ;
281 maskbits
|= ( 1 << (15-x
) ) ;
283 col
= *((RGBColor
*) wxColor( r
, g
, b
).GetPixel()) ;
285 *((*(**ch
).crsrData
) + y
* bytesPerRow
+ x
) =
286 GetCTabIndex( newColors
, &col
) ;
288 (**ch
).crsr1Data
[y
] = rowbits
;
289 (**ch
).crsrMask
[y
] = maskbits
;
293 memcpy( (**ch
).crsrMask
, (**ch
).crsr1Data
, sizeof( Bits16
) ) ;
296 HUnlock((Handle
) ch
) ;
297 M_CURSORDATA
->m_hCursor
= ch
;
298 M_CURSORDATA
->m_isColorCursor
= true ;
302 wxCursor::wxCursor(const wxString
& cursor_file
, long flags
, int hotSpotX
, int hotSpotY
)
304 m_refData
= new wxCursorRefData
;
305 if ( flags
== wxBITMAP_TYPE_MACCURSOR_RESOURCE
)
308 wxMacStringToPascal( cursor_file
, theName
) ;
310 wxStAppResource resload
;
311 Handle resHandle
= ::GetNamedResource( 'crsr' , theName
) ;
316 GetResInfo( resHandle
, &theId
, &theType
, theName
) ;
317 ReleaseResource( resHandle
) ;
318 M_CURSORDATA
->m_hCursor
= GetCCursor( theId
) ;
319 if ( M_CURSORDATA
->m_hCursor
)
320 M_CURSORDATA
->m_isColorCursor
= true ;
324 Handle resHandle
= ::GetNamedResource( 'CURS' , theName
) ;
329 GetResInfo( resHandle
, &theId
, &theType
, theName
) ;
330 ReleaseResource( resHandle
) ;
331 M_CURSORDATA
->m_hCursor
= GetCursor( theId
) ;
332 if ( M_CURSORDATA
->m_hCursor
)
333 M_CURSORDATA
->m_releaseHandle
= true ;
340 image
.LoadFile( cursor_file
, flags
) ;
343 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
,hotSpotX
) ;
344 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
,hotSpotY
) ;
346 CreateFromImage(image
) ;
351 // Cursors by stock number
352 wxCursor::wxCursor(int cursor_type
)
354 m_refData
= new wxCursorRefData
;
358 case wxCURSOR_COPY_ARROW
:
359 M_CURSORDATA
->m_themeCursor
= kThemeCopyArrowCursor
;
362 M_CURSORDATA
->m_themeCursor
= kThemeWatchCursor
;
365 M_CURSORDATA
->m_themeCursor
= kThemeIBeamCursor
;
368 M_CURSORDATA
->m_themeCursor
= kThemeCrossCursor
;
370 case wxCURSOR_SIZENWSE
:
372 wxStAppResource resload
;
373 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNWSE
);
376 case wxCURSOR_SIZENESW
:
378 wxStAppResource resload
;
379 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNESW
);
382 case wxCURSOR_SIZEWE
:
384 M_CURSORDATA
->m_themeCursor
= kThemeResizeLeftRightCursor
;
387 case wxCURSOR_SIZENS
:
389 wxStAppResource resload
;
390 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNS
);
393 case wxCURSOR_SIZING
:
395 wxStAppResource resload
;
396 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSize
);
401 M_CURSORDATA
->m_themeCursor
= kThemePointingHandCursor
;
404 case wxCURSOR_BULLSEYE
:
406 wxStAppResource resload
;
407 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorBullseye
);
410 case wxCURSOR_PENCIL
:
412 wxStAppResource resload
;
413 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPencil
);
416 case wxCURSOR_MAGNIFIER
:
418 wxStAppResource resload
;
419 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorMagnifier
);
422 case wxCURSOR_NO_ENTRY
:
424 wxStAppResource resload
;
425 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorNoEntry
);
430 M_CURSORDATA
->m_themeCursor
= kThemeWatchCursor
;
433 case wxCURSOR_PAINT_BRUSH
:
435 wxStAppResource resload
;
436 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPaintBrush
);
439 case wxCURSOR_POINT_LEFT
:
441 wxStAppResource resload
;
442 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPointLeft
);
445 case wxCURSOR_POINT_RIGHT
:
447 wxStAppResource resload
;
448 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPointRight
);
451 case wxCURSOR_QUESTION_ARROW
:
453 wxStAppResource resload
;
454 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorQuestionArrow
);
459 wxStAppResource resload
;
460 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorBlank
);
463 case wxCURSOR_RIGHT_ARROW
:
465 wxStAppResource resload
;
466 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorRightArrow
);
469 case wxCURSOR_SPRAYCAN
:
471 wxStAppResource resload
;
472 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorRoller
);
477 case wxCURSOR_LEFT_BUTTON
:
478 case wxCURSOR_RIGHT_BUTTON
:
479 case wxCURSOR_MIDDLE_BUTTON
:
481 M_CURSORDATA
->m_themeCursor
= kThemeArrowCursor
;
484 if ( M_CURSORDATA
->m_themeCursor
== -1 )
485 M_CURSORDATA
->m_releaseHandle
= true ;
488 void wxCursor::MacInstall() const
490 gMacCurrentCursor
= *this ;
491 if ( m_refData
&& M_CURSORDATA
->m_themeCursor
!= -1 )
493 SetThemeCursor( M_CURSORDATA
->m_themeCursor
) ;
495 else if ( m_refData
&& M_CURSORDATA
->m_hCursor
)
497 if ( M_CURSORDATA
->m_isColorCursor
)
498 ::SetCCursor( (CCrsrHandle
) M_CURSORDATA
->m_hCursor
) ;
500 ::SetCursor( * (CursHandle
) M_CURSORDATA
->m_hCursor
) ;
504 SetThemeCursor( kThemeArrowCursor
) ;
508 wxCursor::~wxCursor()
512 // Global cursor setting
513 void wxSetCursor(const wxCursor
& cursor
)
515 cursor
.MacInstall() ;