1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxCursor class
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "cursor.h"
19 #include "wx/cursor.h"
22 #include "wx/xpmdecod.h"
24 #include "wx/mac/private.h"
26 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxBitmap
)
28 const short kwxCursorBullseye
= 10 ;
29 const short kwxCursorBlank
= 11 ;
30 const short kwxCursorPencil
= 12 ;
31 const short kwxCursorMagnifier
= 13 ;
32 const short kwxCursorNoEntry
= 14 ;
33 const short kwxCursorPaintBrush
= 15 ;
34 const short kwxCursorPointRight
= 16 ;
35 const short kwxCursorPointLeft
= 17 ;
36 const short kwxCursorQuestionArrow
= 18 ;
37 const short kwxCursorRightArrow
= 19 ;
38 const short kwxCursorSizeNS
= 20 ;
39 const short kwxCursorSize
= 21 ;
40 const short kwxCursorSizeNESW
= 22 ;
41 const short kwxCursorSizeNWSE
= 23 ;
42 const short kwxCursorRoller
= 24 ;
44 wxCursor gMacCurrentCursor
;
46 wxCursorRefData::wxCursorRefData()
51 m_disposeHandle
= false ;
52 m_releaseHandle
= false ;
53 m_isColorCursor
= false ;
57 wxCursorRefData::~wxCursorRefData()
59 if ( m_isColorCursor
)
61 ::DisposeCCursor( (CCrsrHandle
) m_hCursor
) ;
63 else if ( m_disposeHandle
)
65 ::DisposeHandle( (Handle
) m_hCursor
) ;
67 else if ( m_releaseHandle
)
69 // we don't release the resource since it may already
79 wxCursor::wxCursor(const char WXUNUSED(bits
)[], int WXUNUSED(width
), int WXUNUSED(height
),
80 int WXUNUSED(hotSpotX
), int WXUNUSED(hotSpotY
), const char WXUNUSED(maskBits
)[])
84 wxCursor::wxCursor( const wxImage
&image
)
86 CreateFromImage( image
) ;
89 wxCursor::wxCursor(const char **bits
)
91 (void) CreateFromXpm(bits
);
94 wxCursor::wxCursor(char **bits
)
96 (void) CreateFromXpm((const char **)bits
);
99 bool wxCursor::CreateFromXpm(const char **bits
)
101 wxCHECK_MSG( bits
!= NULL
, FALSE
, wxT("invalid cursor data") )
102 wxXPMDecoder decoder
;
103 wxImage img
= decoder
.ReadData(bits
);
104 wxCHECK_MSG( img
.Ok(), FALSE
, wxT("invalid cursor data") )
105 CreateFromImage( img
) ;
109 short GetCTabIndex( CTabHandle colors
, RGBColor
*col
)
112 unsigned long bestdiff
= 0xFFFF ;
113 for ( int i
= 0 ; i
< (**colors
).ctSize
; ++i
)
115 unsigned long diff
= abs(col
->red
- (**colors
).ctTable
[i
].rgb
.red
) +
116 abs(col
->green
- (**colors
).ctTable
[i
].rgb
.green
) +
117 abs(col
->blue
- (**colors
).ctTable
[i
].rgb
.blue
) ;
118 if ( diff
< bestdiff
)
121 retval
= (**colors
).ctTable
[i
].value
;
127 void wxCursor::CreateFromImage(const wxImage
& image
)
129 m_refData
= new wxCursorRefData
;
134 int hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
135 int hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
136 int image_w
= image
.GetWidth();
137 int image_h
= image
.GetHeight();
139 wxASSERT_MSG( hotSpotX
>= 0 && hotSpotX
< image_w
&&
140 hotSpotY
>= 0 && hotSpotY
< image_h
,
141 _T("invalid cursor hot spot coordinates") );
143 wxImage
image16(image
); // final image of correct size
145 // if image is too small then place it in the center, resize it if too big
146 if ((w
> image_w
) && (h
> image_h
))
148 wxPoint
offset((w
- image_w
)/2, (h
- image_h
)/2);
149 hotSpotX
= hotSpotX
+ offset
.x
;
150 hotSpotY
= hotSpotY
+ offset
.y
;
152 image16
= image
.Size(wxSize(w
, h
), offset
);
154 else if ((w
!= image_w
) || (h
!= image_h
))
156 hotSpotX
= int(hotSpotX
* double(w
) / double(image_w
));
157 hotSpotY
= int(hotSpotY
* double(h
) / double(image_h
));
159 image16
= image
.Scale(w
, h
);
162 unsigned char * rgbBits
= image16
.GetData();
163 bool bHasMask
= image16
.HasMask() ;
166 // monochrome implementation
167 M_CURSORDATA
->m_hCursor
= NewHandle( sizeof( Cursor
) ) ;
168 M_CURSORDATA
->m_disposeHandle
= true ;
169 HLock( (Handle
) M_CURSORDATA
->m_hCursor
) ;
170 CursPtr cp
= *(CursHandle
)M_CURSORDATA
->m_hCursor
;
171 memset( cp
->data
, 0 , sizeof( Bits16
) ) ;
172 memset( cp
->mask
, 0 , sizeof( Bits16
) ) ;
174 unsigned char mr
= image16
.GetMaskRed() ;
175 unsigned char mg
= image16
.GetMaskGreen() ;
176 unsigned char mb
= image16
.GetMaskBlue() ;
177 for ( int y
= 0 ; y
< h
; ++y
)
182 for ( int x
= 0 ; x
< w
; ++x
)
184 long pos
= (y
* w
+ x
) * 3;
186 unsigned char r
= rgbBits
[pos
] ;
187 unsigned char g
= rgbBits
[pos
+1] ;
188 unsigned char b
= rgbBits
[pos
+2] ;
189 if ( bHasMask
&& r
==mr
&& g
==mg
&& b
==mb
)
191 // masked area, does not appear anywhere
195 if ( (int)r
+ (int)g
+ (int)b
< 0x0200 )
197 rowbits
|= ( 1 << (15-x
) ) ;
199 maskbits
|= ( 1 << (15-x
) ) ;
202 cp
->data
[y
] = rowbits
;
203 cp
->mask
[y
] = maskbits
;
207 memcpy( cp
->mask
, cp
->data
, sizeof( Bits16
) ) ;
209 cp
->hotSpot
.h
= hotSpotX
;
210 cp
->hotSpot
.v
= hotSpotY
;
211 HUnlock( (Handle
) M_CURSORDATA
->m_hCursor
) ;
213 PixMapHandle pm
= (PixMapHandle
) NewHandleClear( sizeof (PixMap
)) ;
215 short bytesPerPixel
= 1 ;
217 Rect bounds
= { 0 , 0 , extent
, extent
} ;
218 CCrsrHandle ch
= (CCrsrHandle
) NewHandleClear ( sizeof( CCrsr
) ) ;
219 CTabHandle newColors
= GetCTable( 8 ) ;
220 HandToHand((Handle
*) &newColors
);
221 // set the values to the indices
222 for ( int i
= 0 ; i
< (**newColors
).ctSize
; ++i
)
224 (**newColors
).ctTable
[i
].value
= i
;
226 HLock( (Handle
) ch
) ;
227 (**ch
).crsrType
= 0x8001 ; // color cursors
228 (**ch
).crsrMap
= pm
;
229 short bytesPerRow
= bytesPerPixel
* extent
;
232 (**pm
).rowBytes
= bytesPerRow
| 0x8000;
233 (**pm
).bounds
= bounds
;
234 (**pm
).pmVersion
= 0;
237 (**pm
).hRes
= 0x00480000; /* 72 DPI default res */
238 (**pm
).vRes
= 0x00480000; /* 72 DPI default res */
239 (**pm
).pixelSize
= depth
;
240 (**pm
).pixelType
= 0;
242 (**pm
).cmpSize
= depth
;
243 (**pm
).pmTable
= newColors
;
245 (**ch
).crsrData
= NewHandleClear( extent
* bytesPerRow
) ;
246 (**ch
).crsrXData
= NULL
;
247 (**ch
).crsrXValid
= 0;
248 (**ch
).crsrXHandle
= NULL
;
250 (**ch
).crsrHotSpot
.h
= hotSpotX
;
251 (**ch
).crsrHotSpot
.v
= hotSpotY
;
252 (**ch
).crsrXTable
= NULL
;
253 (**ch
).crsrID
= GetCTSeed() ;
255 memset( (**ch
).crsr1Data
, 0 , sizeof( Bits16
) ) ;
256 memset( (**ch
).crsrMask
, 0 , sizeof( Bits16
) ) ;
258 unsigned char mr
= image16
.GetMaskRed() ;
259 unsigned char mg
= image16
.GetMaskGreen() ;
260 unsigned char mb
= image16
.GetMaskBlue() ;
261 for ( int y
= 0 ; y
< h
; ++y
)
266 for ( int x
= 0 ; x
< w
; ++x
)
268 long pos
= (y
* w
+ x
) * 3;
270 unsigned char r
= rgbBits
[pos
] ;
271 unsigned char g
= rgbBits
[pos
+1] ;
272 unsigned char b
= rgbBits
[pos
+2] ;
273 RGBColor col
= { 0xFFFF ,0xFFFF, 0xFFFF } ;
275 if ( bHasMask
&& r
==mr
&& g
==mg
&& b
==mb
)
277 // masked area, does not appear anywhere
281 if ( (int)r
+ (int)g
+ (int)b
< 0x0200 )
283 rowbits
|= ( 1 << (15-x
) ) ;
285 maskbits
|= ( 1 << (15-x
) ) ;
287 col
= *((RGBColor
*) wxColor( r
, g
, b
).GetPixel()) ;
289 *((*(**ch
).crsrData
) + y
* bytesPerRow
+ x
) =
290 GetCTabIndex( newColors
, &col
) ;
292 (**ch
).crsr1Data
[y
] = rowbits
;
293 (**ch
).crsrMask
[y
] = maskbits
;
297 memcpy( (**ch
).crsrMask
, (**ch
).crsr1Data
, sizeof( Bits16
) ) ;
300 HUnlock((Handle
) ch
) ;
301 M_CURSORDATA
->m_hCursor
= ch
;
302 M_CURSORDATA
->m_isColorCursor
= true ;
306 wxCursor::wxCursor(const wxString
& cursor_file
, long flags
, int hotSpotX
, int hotSpotY
)
308 m_refData
= new wxCursorRefData
;
309 if ( flags
== wxBITMAP_TYPE_MACCURSOR_RESOURCE
)
312 wxMacStringToPascal( cursor_file
, theName
) ;
314 wxStAppResource resload
;
315 Handle resHandle
= ::GetNamedResource( 'crsr' , theName
) ;
320 GetResInfo( resHandle
, &theId
, &theType
, theName
) ;
321 ReleaseResource( resHandle
) ;
322 M_CURSORDATA
->m_hCursor
= GetCCursor( theId
) ;
323 if ( M_CURSORDATA
->m_hCursor
)
324 M_CURSORDATA
->m_isColorCursor
= true ;
328 Handle resHandle
= ::GetNamedResource( 'CURS' , theName
) ;
333 GetResInfo( resHandle
, &theId
, &theType
, theName
) ;
334 ReleaseResource( resHandle
) ;
335 M_CURSORDATA
->m_hCursor
= GetCursor( theId
) ;
336 if ( M_CURSORDATA
->m_hCursor
)
337 M_CURSORDATA
->m_releaseHandle
= true ;
344 image
.LoadFile( cursor_file
, flags
) ;
347 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
,hotSpotX
) ;
348 image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
,hotSpotY
) ;
350 CreateFromImage(image
) ;
355 // Cursors by stock number
356 wxCursor::wxCursor(int cursor_type
)
358 m_refData
= new wxCursorRefData
;
362 case wxCURSOR_COPY_ARROW
:
363 M_CURSORDATA
->m_themeCursor
= kThemeCopyArrowCursor
;
366 M_CURSORDATA
->m_themeCursor
= kThemeWatchCursor
;
369 M_CURSORDATA
->m_themeCursor
= kThemeIBeamCursor
;
372 M_CURSORDATA
->m_themeCursor
= kThemeCrossCursor
;
374 case wxCURSOR_SIZENWSE
:
376 wxStAppResource resload
;
377 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNWSE
);
380 case wxCURSOR_SIZENESW
:
382 wxStAppResource resload
;
383 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNESW
);
386 case wxCURSOR_SIZEWE
:
388 M_CURSORDATA
->m_themeCursor
= kThemeResizeLeftRightCursor
;
391 case wxCURSOR_SIZENS
:
393 wxStAppResource resload
;
394 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSizeNS
);
397 case wxCURSOR_SIZING
:
399 wxStAppResource resload
;
400 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorSize
);
405 M_CURSORDATA
->m_themeCursor
= kThemePointingHandCursor
;
408 case wxCURSOR_BULLSEYE
:
410 wxStAppResource resload
;
411 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorBullseye
);
414 case wxCURSOR_PENCIL
:
416 wxStAppResource resload
;
417 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPencil
);
420 case wxCURSOR_MAGNIFIER
:
422 wxStAppResource resload
;
423 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorMagnifier
);
426 case wxCURSOR_NO_ENTRY
:
428 wxStAppResource resload
;
429 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorNoEntry
);
434 M_CURSORDATA
->m_themeCursor
= kThemeWatchCursor
;
437 case wxCURSOR_PAINT_BRUSH
:
439 wxStAppResource resload
;
440 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPaintBrush
);
443 case wxCURSOR_POINT_LEFT
:
445 wxStAppResource resload
;
446 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPointLeft
);
449 case wxCURSOR_POINT_RIGHT
:
451 wxStAppResource resload
;
452 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorPointRight
);
455 case wxCURSOR_QUESTION_ARROW
:
457 wxStAppResource resload
;
458 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorQuestionArrow
);
463 wxStAppResource resload
;
464 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorBlank
);
467 case wxCURSOR_RIGHT_ARROW
:
469 wxStAppResource resload
;
470 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorRightArrow
);
473 case wxCURSOR_SPRAYCAN
:
475 wxStAppResource resload
;
476 M_CURSORDATA
->m_hCursor
= ::GetCursor(kwxCursorRoller
);
481 case wxCURSOR_LEFT_BUTTON
:
482 case wxCURSOR_RIGHT_BUTTON
:
483 case wxCURSOR_MIDDLE_BUTTON
:
485 M_CURSORDATA
->m_themeCursor
= kThemeArrowCursor
;
488 if ( M_CURSORDATA
->m_themeCursor
== -1 )
489 M_CURSORDATA
->m_releaseHandle
= true ;
492 void wxCursor::MacInstall() const
494 gMacCurrentCursor
= *this ;
495 if ( m_refData
&& M_CURSORDATA
->m_themeCursor
!= -1 )
497 SetThemeCursor( M_CURSORDATA
->m_themeCursor
) ;
499 else if ( m_refData
&& M_CURSORDATA
->m_hCursor
)
501 if ( M_CURSORDATA
->m_isColorCursor
)
502 ::SetCCursor( (CCrsrHandle
) M_CURSORDATA
->m_hCursor
) ;
504 ::SetCursor( * (CursHandle
) M_CURSORDATA
->m_hCursor
) ;
508 SetThemeCursor( kThemeArrowCursor
) ;
512 wxCursor::~wxCursor()
516 // Global cursor setting
517 void wxSetCursor(const wxCursor
& cursor
)
519 cursor
.MacInstall() ;