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