]> git.saurik.com Git - wxWidgets.git/blob - src/msw/cursor.cpp
Removed some superflous #defines already added by plaform.h, simplified a bit
[wxWidgets.git] / src / msw / cursor.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/cursor.cpp
3 // Purpose: wxCursor class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997-2003 Julian Smart and Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "cursor.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/list.h"
33 #include "wx/utils.h"
34 #include "wx/app.h"
35 #include "wx/bitmap.h"
36 #include "wx/icon.h"
37 #include "wx/cursor.h"
38 #include "wx/settings.h"
39 #endif
40
41 #include "wx/ptr_scpd.h"
42
43 #include "wx/module.h"
44 #include "wx/image.h"
45 #include "wx/msw/private.h"
46
47 #ifndef __WXMICROWIN__
48 #include "wx/msw/dib.h"
49 #endif
50
51 #if wxUSE_RESOURCE_LOADING_IN_MSW
52 #include "wx/msw/curico.h"
53 #include "wx/msw/curicop.h"
54 #endif
55
56 // define functions missing in MicroWin
57 #ifdef __WXMICROWIN__
58 static inline void DestroyCursor(HCURSOR) { }
59 static inline void SetCursor(HCURSOR) { }
60 #endif // __WXMICROWIN__
61
62 // ----------------------------------------------------------------------------
63 // private classes
64 // ----------------------------------------------------------------------------
65
66 class WXDLLEXPORT wxCursorRefData : public wxGDIImageRefData
67 {
68 public:
69 // the second parameter is used to tell us to delete the cursor when we're
70 // done with it (normally we shouldn't call DestroyCursor() this is why it
71 // doesn't happen by default)
72 wxCursorRefData(HCURSOR hcursor = 0, bool takeOwnership = false);
73
74 virtual ~wxCursorRefData() { Free(); }
75
76 virtual void Free();
77
78
79 // return the size of the standard cursor: notice that the system only
80 // supports the cursors of this size
81 static wxCoord GetStandardWidth();
82 static wxCoord GetStandardHeight();
83
84 private:
85 bool m_destroyCursor;
86
87 // standard cursor size, computed on first use
88 static wxSize ms_sizeStd;
89 };
90
91 // ----------------------------------------------------------------------------
92 // wxWin macros
93 // ----------------------------------------------------------------------------
94
95 IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxGDIObject)
96
97 // ----------------------------------------------------------------------------
98 // globals
99 // ----------------------------------------------------------------------------
100
101 // Current cursor, in order to hang on to cursor handle when setting the cursor
102 // globally
103 static wxCursor *gs_globalCursor = NULL;
104
105 // ----------------------------------------------------------------------------
106 // private classes
107 // ----------------------------------------------------------------------------
108
109 class wxCursorModule : public wxModule
110 {
111 public:
112 virtual bool OnInit()
113 {
114 gs_globalCursor = new wxCursor;
115
116 return TRUE;
117 }
118
119 virtual void OnExit()
120 {
121 delete gs_globalCursor;
122 gs_globalCursor = (wxCursor *)NULL;
123 }
124 };
125
126 // ----------------------------------------------------------------------------
127 // other types
128 // ----------------------------------------------------------------------------
129
130 wxDECLARE_SCOPED_ARRAY(unsigned char, ByteArray);
131 wxDEFINE_SCOPED_ARRAY(unsigned char, ByteArray);
132
133 // ============================================================================
134 // implementation
135 // ============================================================================
136
137 // ----------------------------------------------------------------------------
138 // wxCursorRefData
139 // ----------------------------------------------------------------------------
140
141 wxSize wxCursorRefData::ms_sizeStd;
142
143 wxCoord wxCursorRefData::GetStandardWidth()
144 {
145 if ( !ms_sizeStd.x )
146 ms_sizeStd.x = wxSystemSettings::GetMetric(wxSYS_CURSOR_X);
147
148 return ms_sizeStd.x;
149 }
150
151 wxCoord wxCursorRefData::GetStandardHeight()
152 {
153 if ( !ms_sizeStd.y )
154 ms_sizeStd.y = wxSystemSettings::GetMetric(wxSYS_CURSOR_Y);
155
156 return ms_sizeStd.y;
157 }
158
159 wxCursorRefData::wxCursorRefData(HCURSOR hcursor, bool destroy)
160 {
161 m_hCursor = (WXHCURSOR)hcursor;
162
163 if ( m_hCursor )
164 {
165 m_width = GetStandardWidth();
166 m_height = GetStandardHeight();
167 }
168
169 m_destroyCursor = destroy;
170 }
171
172 void wxCursorRefData::Free()
173 {
174 if ( m_hCursor )
175 {
176 if ( m_destroyCursor )
177 ::DestroyCursor((HCURSOR)m_hCursor);
178
179 m_hCursor = 0;
180 }
181 }
182
183 // ----------------------------------------------------------------------------
184 // Cursors
185 // ----------------------------------------------------------------------------
186
187 wxCursor::wxCursor()
188 {
189 }
190
191 wxCursor::wxCursor(const wxImage& image)
192 {
193 // image has to be of the standard cursor size, otherwise we won't be able
194 // to create it
195 const int w = wxCursorRefData::GetStandardWidth();
196 const int h = wxCursorRefData::GetStandardHeight();
197
198 wxImage image32 = image.Scale(w, h);
199
200 const int imagebitcount = (w*h)/8;
201
202 ByteArray bits(new unsigned char [imagebitcount]),
203 maskBits(new unsigned char [imagebitcount]);
204
205 int i, j, i8;
206 unsigned char c, cMask;
207
208 const unsigned char * const rgbBits = image32.GetData();
209
210 // first create the XOR mask
211 for ( i = 0; i < imagebitcount; i++ )
212 {
213 bits[i] = 0;
214 i8 = i * 8;
215 // unlike gtk, the pixels go in the opposite order in the bytes
216 cMask = 128;
217 for ( j = 0; j < 8; j++ )
218 {
219 // possible overflow if we do the summation first ?
220 c = rgbBits[(i8+j)*3]/3 +
221 rgbBits[(i8+j)*3+1]/3 +
222 rgbBits[(i8+j)*3+2]/3;
223
224 // if average value is > mid grey
225 if ( c > 127 )
226 bits[i] = bits[i] | cMask;
227 cMask = cMask / 2;
228 }
229 }
230
231 // now the AND one
232 if ( image32.HasMask() )
233 {
234 unsigned char r = image32.GetMaskRed(),
235 g = image32.GetMaskGreen(),
236 b = image32.GetMaskBlue();
237
238 for ( i = 0; i < imagebitcount; i++ )
239 {
240 maskBits[i] = 0x0;
241 i8 = i * 8;
242
243 cMask = 128;
244 for ( j = 0; j < 8; j++ )
245 {
246 if ( rgbBits[(i8+j)*3] == r &&
247 rgbBits[(i8+j)*3+1] == g &&
248 rgbBits[(i8+j)*3+2] == b )
249 {
250 maskBits[i] = maskBits[i] | cMask;
251 }
252
253 cMask = cMask / 2;
254 }
255 }
256 }
257 else // no mask in the image
258 {
259 memset(maskBits.get(), 0, sizeof(unsigned char)*imagebitcount);
260 }
261
262 // determine where should the cursors hot spot be
263 int hotSpotX = image32.GetOptionInt(wxCUR_HOTSPOT_X);
264 int hotSpotY = image32.GetOptionInt(wxCUR_HOTSPOT_Y);
265 if (hotSpotX < 0 || hotSpotX >= w)
266 hotSpotX = 0;
267 if (hotSpotY < 0 || hotSpotY >= h)
268 hotSpotY = 0;
269
270 // do create cursor now
271 HCURSOR hcursor = ::CreateCursor
272 (
273 wxGetInstance(),
274 hotSpotX, hotSpotY,
275 w, h,
276 /* AND */ maskBits.get(),
277 /* XOR */ bits.get()
278 );
279
280 if ( !hcursor )
281 {
282 wxLogLastError(_T("CreateCursor"));
283 }
284 else
285 {
286 m_refData = new wxCursorRefData(hcursor, true /* delete it */);
287 }
288 }
289
290 wxCursor::wxCursor(const char WXUNUSED(bits)[],
291 int WXUNUSED(width),
292 int WXUNUSED(height),
293 int WXUNUSED(hotSpotX), int WXUNUSED(hotSpotY),
294 const char WXUNUSED(maskBits)[])
295 {
296 }
297
298 // MicroWin doesn't have support needed for the other ctors
299 #ifdef __WXMICROWIN__
300
301 wxCursor::wxCursor(const wxString& WXUNUSED(filename),
302 long WXUNUSED(kind),
303 int WXUNUSED(hotSpotX),
304 int WXUNUSED(hotSpotY))
305 {
306 }
307
308 wxCursor::wxCursor(int WXUNUSED(cursor_type))
309 {
310 }
311
312 #else // !__WXMICROWIN__
313
314 wxCursor::wxCursor(const wxString& filename,
315 long kind,
316 int hotSpotX,
317 int hotSpotY)
318 {
319 HCURSOR hcursor;
320 switch ( kind )
321 {
322 case wxBITMAP_TYPE_CUR_RESOURCE:
323 hcursor = ::LoadCursor(wxGetInstance(), filename);
324 break;
325
326 case wxBITMAP_TYPE_CUR:
327 hcursor = ::LoadCursorFromFile(filename);
328 break;
329
330 #if wxUSE_RESOURCE_LOADING_IN_MSW
331 case wxBITMAP_TYPE_ICO:
332 hcursor = IconToCursor((wxChar *)filename.c_str(),
333 wxGetInstance(),
334 hotSpotX, hotSpotY,
335 NULL, NULL);
336 break;
337
338 case wxBITMAP_TYPE_BMP:
339 {
340 HBITMAP hBitmap = 0;
341 HPALETTE hPalette = 0;
342 if ( wxReadDIB((wxChar *)filename.c_str(), &hBitmap, &hPalette) )
343 {
344 if (hPalette)
345 DeleteObject(hPalette);
346
347 POINT pt;
348 pt.x = hotSpotX;
349 pt.y = hotSpotY;
350 hcursor = MakeCursorFromBitmap(wxGetInstance(), hBitmap, &pt);
351 DeleteObject(hBitmap);
352 }
353 else
354 {
355 hcursor = NULL;
356 }
357 }
358 break;
359 #endif // wxUSE_RESOURCE_LOADING_IN_MSW
360
361 default:
362 wxFAIL_MSG( _T("unknown cursor resource type") );
363
364 hcursor = NULL;
365 }
366
367 if ( hcursor )
368 {
369 m_refData = new wxCursorRefData(hcursor, true /* delete it later */);
370
371 #if WXWIN_COMPATIBILITY_2
372 ((wxCursorRefData *)m_refData)->SetOk();
373 #endif // WXWIN_COMPATIBILITY_2
374 }
375 }
376
377 // Cursors by stock number
378 wxCursor::wxCursor(int idCursor)
379 {
380 // all wxWindows standard cursors
381 static const struct StdCursor
382 {
383 // is this a standard Windows cursor?
384 bool isStd;
385
386 // the cursor name or id
387 LPCTSTR name;
388 } stdCursors[] =
389 {
390 { true, NULL }, // wxCURSOR_NONE
391 { true, IDC_ARROW }, // wxCURSOR_ARROW
392 { false, _T("wxCURSOR_RIGHT_ARROW") }, // wxCURSOR_RIGHT_ARROW
393 { false, _T("wxCURSOR_BULLSEYE") }, // wxCURSOR_BULLSEYE
394 { true, IDC_ARROW }, // wxCURSOR_CHAR
395 { true, IDC_CROSS }, // wxCURSOR_CROSS
396 { false, _T("wxCURSOR_HAND") }, // wxCURSOR_HAND
397 { true, IDC_IBEAM }, // wxCURSOR_IBEAM
398 { true, IDC_ARROW }, // wxCURSOR_LEFT_BUTTON
399 { false, _T("wxCURSOR_MAGNIFIER") }, // wxCURSOR_MAGNIFIER
400 { true, IDC_ARROW }, // wxCURSOR_MIDDLE_BUTTON
401 { true, IDC_NO }, // wxCURSOR_NO_ENTRY
402 { false, _T("wxCURSOR_PAINT_BRUSH") }, // wxCURSOR_PAINT_BRUSH
403 { false, _T("wxCURSOR_PENCIL") }, // wxCURSOR_PENCIL
404 { false, _T("wxCURSOR_POINT_LEFT") }, // wxCURSOR_POINT_LEFT
405 { false, _T("wxCURSOR_POINT_RIGHT") }, // wxCURSOR_POINT_RIGHT
406 { true, IDC_HELP }, // wxCURSOR_QUESTION_ARROW
407 { true, IDC_ARROW }, // wxCURSOR_RIGHT_BUTTON
408 { true, IDC_SIZENESW }, // wxCURSOR_SIZENESW
409 { true, IDC_SIZENS }, // wxCURSOR_SIZENS
410 { true, IDC_SIZENWSE }, // wxCURSOR_SIZENWSE
411 { true, IDC_SIZEWE }, // wxCURSOR_SIZEWE
412 { true, IDC_SIZEALL }, // wxCURSOR_SIZING
413 { false, _T("wxCURSOR_SPRAYCAN") }, // wxCURSOR_SPRAYCAN
414 { true, IDC_WAIT }, // wxCURSOR_WAIT
415 { true, IDC_WAIT }, // wxCURSOR_WATCH
416 { false, _T("wxCURSOR_BLANK") }, // wxCURSOR_BLANK
417 { true, IDC_APPSTARTING }, // wxCURSOR_ARROWWAIT
418
419 // no entry for wxCURSOR_MAX
420 };
421
422 wxCOMPILE_TIME_ASSERT( WXSIZEOF(stdCursors) == wxCURSOR_MAX,
423 CursorsIdArrayMismatch );
424
425 wxCHECK_RET( idCursor > 0 && (size_t)idCursor < WXSIZEOF(stdCursors),
426 _T("invalid cursor id in wxCursor() ctor") );
427
428 const StdCursor& stdCursor = stdCursors[idCursor];
429
430 HCURSOR hcursor = ::LoadCursor(stdCursor.isStd ? NULL : wxGetInstance(),
431 stdCursor.name);
432
433 if ( !hcursor )
434 {
435 wxLogLastError(_T("LoadCursor"));
436 }
437 else
438 {
439 m_refData = new wxCursorRefData(hcursor);
440 }
441 }
442
443 #endif // __WXMICROWIN__/!__WXMICROWIN__
444
445 wxCursor::~wxCursor()
446 {
447 }
448
449 // ----------------------------------------------------------------------------
450 // other wxCursor functions
451 // ----------------------------------------------------------------------------
452
453 bool wxCursor::operator==(const wxCursor& cursor) const
454 {
455 if ( !m_refData )
456 return !cursor.m_refData;
457
458 return cursor.m_refData &&
459 ((wxCursorRefData *)m_refData)->m_hCursor ==
460 ((wxCursorRefData *)cursor.m_refData)->m_hCursor;
461 }
462
463 wxGDIImageRefData *wxCursor::CreateData() const
464 {
465 return new wxCursorRefData;
466 }
467
468 // ----------------------------------------------------------------------------
469 // Global cursor setting
470 // ----------------------------------------------------------------------------
471
472 const wxCursor *wxGetGlobalCursor()
473 {
474 return gs_globalCursor;
475 }
476
477 void wxSetCursor(const wxCursor& cursor)
478 {
479 if ( cursor.Ok() )
480 {
481 ::SetCursor(GetHcursorOf(cursor));
482
483 if ( gs_globalCursor )
484 *gs_globalCursor = cursor;
485 }
486 }
487
488