]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/cursor.cpp
Only send two EVT_BUTTON events when double clicking a button, not three
[wxWidgets.git] / src / msw / cursor.cpp
... / ...
CommitLineData
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
66class WXDLLEXPORT wxCursorRefData : public wxGDIImageRefData
67{
68public:
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
84private:
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
95IMPLEMENT_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
103static wxCursor *gs_globalCursor = NULL;
104
105// ----------------------------------------------------------------------------
106// private classes
107// ----------------------------------------------------------------------------
108
109class wxCursorModule : public wxModule
110{
111public:
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
130wxDECLARE_SCOPED_ARRAY(unsigned char, ByteArray);
131wxDEFINE_SCOPED_ARRAY(unsigned char, ByteArray);
132
133// ============================================================================
134// implementation
135// ============================================================================
136
137// ----------------------------------------------------------------------------
138// wxCursorRefData
139// ----------------------------------------------------------------------------
140
141wxSize wxCursorRefData::ms_sizeStd;
142
143wxCoord 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
151wxCoord 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
159wxCursorRefData::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
172void 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
187wxCursor::wxCursor()
188{
189}
190
191wxCursor::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
290wxCursor::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
301wxCursor::wxCursor(const wxString& WXUNUSED(filename),
302 long WXUNUSED(kind),
303 int WXUNUSED(hotSpotX),
304 int WXUNUSED(hotSpotY))
305{
306}
307
308wxCursor::wxCursor(int WXUNUSED(cursor_type))
309{
310}
311
312#else // !__WXMICROWIN__
313
314wxCursor::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
378wxCursor::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
445wxCursor::~wxCursor()
446{
447}
448
449// ----------------------------------------------------------------------------
450// other wxCursor functions
451// ----------------------------------------------------------------------------
452
453bool 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
463wxGDIImageRefData *wxCursor::CreateData() const
464{
465 return new wxCursorRefData;
466}
467
468// ----------------------------------------------------------------------------
469// Global cursor setting
470// ----------------------------------------------------------------------------
471
472const wxCursor *wxGetGlobalCursor()
473{
474 return gs_globalCursor;
475}
476
477void 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