]> git.saurik.com Git - wxWidgets.git/blame - src/mac/cursor.cpp
made wxFFile a bit more safe: don't crash when Tell() and Length() are called on...
[wxWidgets.git] / src / mac / cursor.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: cursor.cpp
3// Purpose: wxCursor class
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
e40298d5 9// Licence: wxWindows licence
e9576ca5
SC
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "cursor.h"
14#endif
15
0e13e965
GD
16#include "wx/defs.h"
17
18#include "wx/app.h"
e9576ca5
SC
19#include "wx/cursor.h"
20#include "wx/icon.h"
c6a071d2 21#include "wx/image.h"
c5e59178
SC
22#include "wx/xpmdecod.h"
23
76a5e5d2 24#include "wx/mac/private.h"
e9576ca5 25
2f1ae414 26#if !USE_SHARED_LIBRARIES
e9576ca5 27IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap)
2f1ae414 28#endif
e9576ca5 29
c6a071d2
SC
30const short kwxCursorBullseye = 10 ;
31const short kwxCursorBlank = 11 ;
32const short kwxCursorPencil = 12 ;
33const short kwxCursorMagnifier = 13 ;
34const short kwxCursorNoEntry = 14 ;
35const short kwxCursorPaintBrush = 15 ;
36const short kwxCursorPointRight = 16 ;
37const short kwxCursorPointLeft = 17 ;
38const short kwxCursorQuestionArrow = 18 ;
39const short kwxCursorRightArrow = 19 ;
40const short kwxCursorSizeNS = 20 ;
41const short kwxCursorSize = 21 ;
42const short kwxCursorSizeNESW = 22 ;
43const short kwxCursorSizeNWSE = 23 ;
44const short kwxCursorRoller = 24 ;
45
e40298d5 46wxCursor gMacCurrentCursor ;
519cb848 47
e9576ca5
SC
48wxCursorRefData::wxCursorRefData()
49{
c6a071d2
SC
50 m_width = 16;
51 m_height = 16;
519cb848 52 m_hCursor = NULL ;
c6a071d2
SC
53 m_disposeHandle = false ;
54 m_releaseHandle = false ;
55 m_isColorCursor = false ;
56 m_themeCursor = -1 ;
e9576ca5
SC
57}
58
59wxCursorRefData::~wxCursorRefData()
60{
c6a071d2
SC
61 if ( m_isColorCursor )
62 {
63 ::DisposeCCursor( (CCrsrHandle) m_hCursor ) ;
64 }
e40298d5
JS
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 }
e9576ca5
SC
74}
75
76// Cursors
77wxCursor::wxCursor()
78{
79}
80
81wxCursor::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
c6a071d2
SC
86wxCursor::wxCursor( const wxImage &image )
87{
ce72eadb 88 CreateFromImage( image ) ;
c6a071d2
SC
89}
90
c5e59178
SC
91wxCursor::wxCursor(const char **bits)
92{
93 (void) CreateFromXpm(bits);
94}
95
96wxCursor::wxCursor(char **bits)
97{
98 (void) CreateFromXpm((const char **)bits);
99}
100
101bool 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
111short 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
ce72eadb 129void wxCursor::CreateFromImage(const wxImage & image)
c6a071d2
SC
130{
131 m_refData = new wxCursorRefData;
132
133 wxImage image16 = image.Scale(16,16) ;
e40298d5 134 unsigned char * rgbBits = image16.GetData();
c6a071d2 135
e40298d5 136
c6a071d2
SC
137 int w = image16.GetWidth() ;
138 int h = image16.GetHeight() ;
139 bool bHasMask = image16.HasMask() ;
140
1a81dc12
MB
141 int hotSpotX = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
142 int hotSpotY = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
c6a071d2
SC
143 if (hotSpotX < 0 || hotSpotX >= w)
144 hotSpotX = 0;
145 if (hotSpotY < 0 || hotSpotY >= h)
146 hotSpotY = 0;
147
c5e59178
SC
148#if 0
149 // monochrome implementation
c6a071d2
SC
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
e40298d5
JS
157 unsigned char mr = image16.GetMaskRed() ;
158 unsigned char mg = image16.GetMaskGreen() ;
159 unsigned char mb = image16.GetMaskBlue() ;
c6a071d2
SC
160 for ( int y = 0 ; y < h ; ++y )
161 {
e40298d5
JS
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;
c6a071d2 168
e40298d5
JS
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 {
c5e59178 178 if ( (int)r + (int)g + (int)b < 0x0200 )
e40298d5
JS
179 {
180 rowbits |= ( 1 << (15-x) ) ;
181 }
182 maskbits |= ( 1 << (15-x) ) ;
183 }
184 }
185 cp->data[y] = rowbits ;
186 cp->mask[y] = maskbits ;
c6a071d2
SC
187 }
188 if ( !bHasMask )
189 {
e40298d5 190 memcpy( cp->mask , cp->data , sizeof( Bits16) ) ;
c6a071d2 191 }
c6a071d2
SC
192 cp->hotSpot.h = hotSpotX ;
193 cp->hotSpot.v = hotSpotY ;
194 HUnlock( (Handle) M_CURSORDATA->m_hCursor ) ;
c5e59178
SC
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
c6a071d2
SC
287}
288
e9576ca5
SC
289wxCursor::wxCursor(const wxString& cursor_file, long flags, int hotSpotX, int hotSpotY)
290{
291 m_refData = new wxCursorRefData;
c6a071d2
SC
292 if ( flags == wxBITMAP_TYPE_MACCURSOR_RESOURCE )
293 {
e40298d5 294 Str255 theName ;
427ff662 295 wxMacStringToPascal( cursor_file , theName ) ;
e40298d5 296
c6a071d2 297 wxStAppResource resload ;
e40298d5
JS
298 Handle resHandle = ::GetNamedResource( 'crsr' , theName ) ;
299 if ( resHandle )
300 {
301 short theId = -1 ;
302 OSType theType ;
303 GetResInfo( resHandle , &theId , &theType , theName ) ;
304 ReleaseResource( resHandle ) ;
305 M_CURSORDATA->m_hCursor = GetCCursor( theId ) ;
306 if ( M_CURSORDATA->m_hCursor )
307 M_CURSORDATA->m_isColorCursor = true ;
308 }
309 else
310 {
311 Handle resHandle = ::GetNamedResource( 'CURS' , theName ) ;
312 if ( resHandle )
313 {
314 short theId = -1 ;
315 OSType theType ;
316 GetResInfo( resHandle , &theId , &theType , theName ) ;
317 ReleaseResource( resHandle ) ;
318 M_CURSORDATA->m_hCursor = GetCursor( theId ) ;
319 if ( M_CURSORDATA->m_hCursor )
320 M_CURSORDATA->m_releaseHandle = true ;
321 }
c6a071d2
SC
322 }
323 }
324 else
325 {
326 wxImage image ;
327 image.LoadFile( cursor_file , flags ) ;
328 if( image.Ok() )
329 {
1a81dc12
MB
330 image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,hotSpotX ) ;
331 image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,hotSpotY ) ;
c6a071d2 332 delete m_refData ;
ce72eadb 333 CreateFromImage(image) ;
c6a071d2
SC
334 }
335 }
e9576ca5
SC
336}
337
338// Cursors by stock number
339wxCursor::wxCursor(int cursor_type)
340{
e40298d5
JS
341 m_refData = new wxCursorRefData;
342
343 switch (cursor_type)
344 {
c5e59178
SC
345 case wxCURSOR_COPY_ARROW:
346 M_CURSORDATA->m_themeCursor = kThemeCopyArrowCursor ;
347 break;
e9576ca5 348 case wxCURSOR_WAIT:
e40298d5
JS
349 M_CURSORDATA->m_themeCursor = kThemeWatchCursor ;
350 break;
e9576ca5 351 case wxCURSOR_IBEAM:
e40298d5
JS
352 M_CURSORDATA->m_themeCursor = kThemeIBeamCursor ;
353 break;
e9576ca5 354 case wxCURSOR_CROSS:
e40298d5
JS
355 M_CURSORDATA->m_themeCursor = kThemeCrossCursor;
356 break;
e9576ca5 357 case wxCURSOR_SIZENWSE:
e40298d5
JS
358 {
359 wxStAppResource resload ;
360 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNWSE);
361 }
362 break;
e9576ca5 363 case wxCURSOR_SIZENESW:
e40298d5
JS
364 {
365 wxStAppResource resload ;
366 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNESW);
367 }
368 break;
e9576ca5 369 case wxCURSOR_SIZEWE:
e40298d5
JS
370 {
371 M_CURSORDATA->m_themeCursor = kThemeResizeLeftRightCursor;
372 }
373 break;
e9576ca5 374 case wxCURSOR_SIZENS:
e40298d5
JS
375 {
376 wxStAppResource resload ;
377 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNS);
378 }
379 break;
380 case wxCURSOR_SIZING:
381 {
382 wxStAppResource resload ;
383 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSize);
384 }
385 break;
e9576ca5 386 case wxCURSOR_HAND:
e40298d5
JS
387 {
388 M_CURSORDATA->m_themeCursor = kThemePointingHandCursor;
389 }
390 break;
e9576ca5 391 case wxCURSOR_BULLSEYE:
fe3fcb05 392 {
e40298d5
JS
393 wxStAppResource resload ;
394 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorBullseye);
fe3fcb05
SC
395 }
396 break;
e9576ca5 397 case wxCURSOR_PENCIL:
fe3fcb05 398 {
e40298d5
JS
399 wxStAppResource resload ;
400 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPencil);
fe3fcb05
SC
401 }
402 break;
e9576ca5 403 case wxCURSOR_MAGNIFIER:
fe3fcb05 404 {
e40298d5
JS
405 wxStAppResource resload ;
406 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorMagnifier);
fe3fcb05
SC
407 }
408 break;
e9576ca5 409 case wxCURSOR_NO_ENTRY:
fe3fcb05 410 {
e40298d5
JS
411 wxStAppResource resload ;
412 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorNoEntry);
fe3fcb05
SC
413 }
414 break;
e9576ca5 415 case wxCURSOR_WATCH:
e40298d5
JS
416 {
417 M_CURSORDATA->m_themeCursor = kThemeWatchCursor;
418 break;
419 }
e9576ca5 420 case wxCURSOR_PAINT_BRUSH:
e40298d5
JS
421 {
422 wxStAppResource resload ;
423 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPaintBrush);
424 break;
425 }
e9576ca5 426 case wxCURSOR_POINT_LEFT:
e40298d5
JS
427 {
428 wxStAppResource resload ;
429 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPointLeft);
430 break;
431 }
e9576ca5 432 case wxCURSOR_POINT_RIGHT:
e40298d5
JS
433 {
434 wxStAppResource resload ;
435 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPointRight);
436 break;
437 }
e9576ca5 438 case wxCURSOR_QUESTION_ARROW:
e40298d5
JS
439 {
440 wxStAppResource resload ;
441 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorQuestionArrow);
442 break;
443 }
e9576ca5 444 case wxCURSOR_BLANK:
e40298d5
JS
445 {
446 wxStAppResource resload ;
447 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorBlank);
448 break;
449 }
c6a071d2 450 case wxCURSOR_RIGHT_ARROW:
e40298d5
JS
451 {
452 wxStAppResource resload ;
453 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorRightArrow);
454 break;
455 }
c6a071d2 456 case wxCURSOR_SPRAYCAN:
e40298d5
JS
457 {
458 wxStAppResource resload ;
459 M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorRoller);
460 break;
461 }
c6a071d2 462 case wxCURSOR_CHAR:
e9576ca5 463 case wxCURSOR_ARROW:
c6a071d2
SC
464 case wxCURSOR_LEFT_BUTTON:
465 case wxCURSOR_RIGHT_BUTTON:
466 case wxCURSOR_MIDDLE_BUTTON:
e40298d5
JS
467 default:
468 M_CURSORDATA->m_themeCursor = kThemeArrowCursor ;
469 break;
470 }
471 if ( M_CURSORDATA->m_themeCursor == -1 )
472 M_CURSORDATA->m_releaseHandle = true ;
519cb848 473}
e9576ca5 474
519cb848
SC
475void wxCursor::MacInstall() const
476{
e40298d5
JS
477 gMacCurrentCursor = *this ;
478 if ( m_refData && M_CURSORDATA->m_themeCursor != -1 )
479 {
480 SetThemeCursor( M_CURSORDATA->m_themeCursor ) ;
481 }
482 else if ( m_refData && M_CURSORDATA->m_hCursor )
483 {
484 if ( M_CURSORDATA->m_isColorCursor )
485 ::SetCCursor( (CCrsrHandle) M_CURSORDATA->m_hCursor ) ;
486 else
487 ::SetCursor( * (CursHandle) M_CURSORDATA->m_hCursor ) ;
488 }
489 else
490 {
491 SetThemeCursor( kThemeArrowCursor ) ;
492 }
e9576ca5
SC
493}
494
495wxCursor::~wxCursor()
496{
497}
498
499// Global cursor setting
500void wxSetCursor(const wxCursor& cursor)
501{
e40298d5 502 cursor.MacInstall() ;
e9576ca5
SC
503}
504
505