]> git.saurik.com Git - wxWidgets.git/blame - src/msw/cursor.cpp
Only send two EVT_BUTTON events when double clicking a button, not three
[wxWidgets.git] / src / msw / cursor.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
eff4ffbf 2// Name: src/msw/cursor.cpp
2bda0e17
KB
3// Purpose: wxCursor class
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
eff4ffbf
VZ
8// Copyright: (c) 1997-2003 Julian Smart and Vadim Zeitlin
9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
0d0512bd
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17 20#ifdef __GNUG__
0d0512bd 21 #pragma implementation "cursor.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
0d0512bd 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
0d0512bd
VZ
32 #include "wx/list.h"
33 #include "wx/utils.h"
34 #include "wx/app.h"
fef15b42 35 #include "wx/bitmap.h"
0d0512bd 36 #include "wx/icon.h"
fef15b42 37 #include "wx/cursor.h"
ed39ff57 38 #include "wx/settings.h"
2bda0e17
KB
39#endif
40
eff4ffbf
VZ
41#include "wx/ptr_scpd.h"
42
2b0b4c55 43#include "wx/module.h"
6cab7411 44#include "wx/image.h"
2bda0e17 45#include "wx/msw/private.h"
eff4ffbf 46
04ef50df 47#ifndef __WXMICROWIN__
eff4ffbf 48 #include "wx/msw/dib.h"
04ef50df 49#endif
2bda0e17 50
47d67540 51#if wxUSE_RESOURCE_LOADING_IN_MSW
0d0512bd
VZ
52 #include "wx/msw/curico.h"
53 #include "wx/msw/curicop.h"
2bda0e17
KB
54#endif
55
eff4ffbf
VZ
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
0d0512bd
VZ
91// ----------------------------------------------------------------------------
92// wxWin macros
93// ----------------------------------------------------------------------------
94
621b3e21 95IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxGDIObject)
bfbd6dc1
VZ
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
eff4ffbf
VZ
126// ----------------------------------------------------------------------------
127// other types
128// ----------------------------------------------------------------------------
129
130wxDECLARE_SCOPED_ARRAY(unsigned char, ByteArray);
131wxDEFINE_SCOPED_ARRAY(unsigned char, ByteArray);
132
bfbd6dc1
VZ
133// ============================================================================
134// implementation
135// ============================================================================
2bda0e17 136
0d0512bd
VZ
137// ----------------------------------------------------------------------------
138// wxCursorRefData
139// ----------------------------------------------------------------------------
140
eff4ffbf
VZ
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()
2bda0e17 152{
eff4ffbf
VZ
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 }
0d0512bd 168
eff4ffbf 169 m_destroyCursor = destroy;
2bda0e17
KB
170}
171
0d0512bd 172void wxCursorRefData::Free()
2bda0e17 173{
032af30f
VZ
174 if ( m_hCursor )
175 {
176 if ( m_destroyCursor )
177 ::DestroyCursor((HCURSOR)m_hCursor);
178
179 m_hCursor = 0;
180 }
2bda0e17
KB
181}
182
0d0512bd 183// ----------------------------------------------------------------------------
2bda0e17 184// Cursors
0d0512bd
VZ
185// ----------------------------------------------------------------------------
186
187wxCursor::wxCursor()
2bda0e17
KB
188{
189}
190
eff4ffbf 191wxCursor::wxCursor(const wxImage& image)
bff4ec63 192{
eff4ffbf
VZ
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 {
bff4ec63
VZ
213 bits[i] = 0;
214 i8 = i * 8;
eff4ffbf 215 // unlike gtk, the pixels go in the opposite order in the bytes
bff4ec63 216 cMask = 128;
eff4ffbf 217 for ( j = 0; j < 8; j++ )
bff4ec63 218 {
eff4ffbf
VZ
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 }
bff4ec63 230
eff4ffbf
VZ
231 // now the AND one
232 if ( image32.HasMask() )
233 {
234 unsigned char r = image32.GetMaskRed(),
235 g = image32.GetMaskGreen(),
236 b = image32.GetMaskBlue();
bff4ec63 237
eff4ffbf 238 for ( i = 0; i < imagebitcount; i++ )
bff4ec63 239 {
eff4ffbf
VZ
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 }
bff4ec63 255 }
eff4ffbf
VZ
256 }
257 else // no mask in the image
258 {
259 memset(maskBits.get(), 0, sizeof(unsigned char)*imagebitcount);
260 }
bff4ec63 261
eff4ffbf 262 // determine where should the cursors hot spot be
bff4ec63
VZ
263 int hotSpotX = image32.GetOptionInt(wxCUR_HOTSPOT_X);
264 int hotSpotY = image32.GetOptionInt(wxCUR_HOTSPOT_Y);
265 if (hotSpotX < 0 || hotSpotX >= w)
eff4ffbf 266 hotSpotX = 0;
bff4ec63 267 if (hotSpotY < 0 || hotSpotY >= h)
eff4ffbf
VZ
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 }
bff4ec63
VZ
288}
289
0d0512bd
VZ
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)[])
2bda0e17
KB
295{
296}
297
eff4ffbf 298// MicroWin doesn't have support needed for the other ctors
04ef50df 299#ifdef __WXMICROWIN__
2bda0e17 300
eff4ffbf
VZ
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 )
0d0512bd 321 {
eff4ffbf
VZ
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
47d67540 330#if wxUSE_RESOURCE_LOADING_IN_MSW
677a9e28 331 case wxBITMAP_TYPE_ICO:
eff4ffbf
VZ
332 hcursor = IconToCursor((wxChar *)filename.c_str(),
333 wxGetInstance(),
334 hotSpotX, hotSpotY,
335 NULL, NULL);
eff4ffbf
VZ
336 break;
337
338 case wxBITMAP_TYPE_BMP:
339 {
eff4ffbf
VZ
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);
eff4ffbf
VZ
352 }
353 else
354 {
355 hcursor = NULL;
356 }
357 }
358 break;
677a9e28 359#endif // wxUSE_RESOURCE_LOADING_IN_MSW
eff4ffbf
VZ
360
361 default:
362 wxFAIL_MSG( _T("unknown cursor resource type") );
363
364 hcursor = NULL;
0d0512bd 365 }
eff4ffbf
VZ
366
367 if ( hcursor )
0d0512bd 368 {
eff4ffbf 369 m_refData = new wxCursorRefData(hcursor, true /* delete it later */);
0d0512bd
VZ
370
371#if WXWIN_COMPATIBILITY_2
83911a5a 372 ((wxCursorRefData *)m_refData)->SetOk();
0d0512bd 373#endif // WXWIN_COMPATIBILITY_2
eff4ffbf 374 }
2bda0e17
KB
375}
376
377// Cursors by stock number
eff4ffbf 378wxCursor::wxCursor(int idCursor)
2bda0e17 379{
eff4ffbf
VZ
380 // all wxWindows standard cursors
381 static const struct StdCursor
2bda0e17 382 {
eff4ffbf
VZ
383 // is this a standard Windows cursor?
384 bool isStd;
385
386 // the cursor name or id
387 LPCTSTR name;
388 } stdCursors[] =
2bda0e17 389 {
eff4ffbf
VZ
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 )
2bda0e17 434 {
eff4ffbf 435 wxLogLastError(_T("LoadCursor"));
2bda0e17 436 }
eff4ffbf 437 else
15dadf31 438 {
eff4ffbf 439 m_refData = new wxCursorRefData(hcursor);
15dadf31 440 }
2bda0e17
KB
441}
442
eff4ffbf
VZ
443#endif // __WXMICROWIN__/!__WXMICROWIN__
444
0d0512bd 445wxCursor::~wxCursor()
2bda0e17 446{
2bda0e17
KB
447}
448
eff4ffbf
VZ
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
0d0512bd 468// ----------------------------------------------------------------------------
2bda0e17 469// Global cursor setting
0d0512bd
VZ
470// ----------------------------------------------------------------------------
471
bfbd6dc1 472const wxCursor *wxGetGlobalCursor()
2bda0e17 473{
bfbd6dc1
VZ
474 return gs_globalCursor;
475}
2bda0e17 476
bfbd6dc1
VZ
477void wxSetCursor(const wxCursor& cursor)
478{
479 if ( cursor.Ok() )
6bf57206 480 {
bfbd6dc1 481 ::SetCursor(GetHcursorOf(cursor));
6bf57206 482
bfbd6dc1
VZ
483 if ( gs_globalCursor )
484 *gs_globalCursor = cursor;
6bf57206 485 }
2bda0e17
KB
486}
487
488