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: cursor.cpp 46594 2007-06-21 18:14:29Z VZ $ 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// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#include "wx/cursor.h" 28 29#ifndef WX_PRECOMP 30 #include "wx/msw/missing.h" // IDC_HAND 31 #include "wx/utils.h" 32 #include "wx/app.h" 33 #include "wx/bitmap.h" 34 #include "wx/icon.h" 35 #include "wx/settings.h" 36 #include "wx/intl.h" 37 #include "wx/image.h" 38 #include "wx/module.h" 39#endif 40 41#include "wx/msw/private.h" 42 43// define functions missing in MicroWin 44#ifdef __WXMICROWIN__ 45 static inline void DestroyCursor(HCURSOR) { } 46 static inline void SetCursor(HCURSOR) { } 47#endif // __WXMICROWIN__ 48 49// ---------------------------------------------------------------------------- 50// private classes 51// ---------------------------------------------------------------------------- 52 53class WXDLLEXPORT wxCursorRefData : public wxGDIImageRefData 54{ 55public: 56 // the second parameter is used to tell us to delete the cursor when we're 57 // done with it (normally we shouldn't call DestroyCursor() this is why it 58 // doesn't happen by default) 59 wxCursorRefData(HCURSOR hcursor = 0, bool takeOwnership = false); 60 61 virtual ~wxCursorRefData() { Free(); } 62 63 virtual void Free(); 64 65 66 // return the size of the standard cursor: notice that the system only 67 // supports the cursors of this size 68 static wxCoord GetStandardWidth(); 69 static wxCoord GetStandardHeight(); 70 71private: 72 bool m_destroyCursor; 73 74 // standard cursor size, computed on first use 75 static wxSize ms_sizeStd; 76}; 77 78// ---------------------------------------------------------------------------- 79// wxWin macros 80// ---------------------------------------------------------------------------- 81 82IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxGDIObject) 83 84// ---------------------------------------------------------------------------- 85// globals 86// ---------------------------------------------------------------------------- 87 88// Current cursor, in order to hang on to cursor handle when setting the cursor 89// globally 90static wxCursor *gs_globalCursor = NULL; 91 92// ---------------------------------------------------------------------------- 93// private classes 94// ---------------------------------------------------------------------------- 95 96class wxCursorModule : public wxModule 97{ 98public: 99 virtual bool OnInit() 100 { 101 gs_globalCursor = new wxCursor; 102 103 return true; 104 } 105 106 virtual void OnExit() 107 { 108 delete gs_globalCursor; 109 gs_globalCursor = (wxCursor *)NULL; 110 } 111}; 112 113// ============================================================================ 114// implementation 115// ============================================================================ 116 117// ---------------------------------------------------------------------------- 118// wxCursorRefData 119// ---------------------------------------------------------------------------- 120 121wxSize wxCursorRefData::ms_sizeStd; 122 123wxCoord wxCursorRefData::GetStandardWidth() 124{ 125 if ( !ms_sizeStd.x ) 126 ms_sizeStd.x = wxSystemSettings::GetMetric(wxSYS_CURSOR_X); 127 128 return ms_sizeStd.x; 129} 130 131wxCoord wxCursorRefData::GetStandardHeight() 132{ 133 if ( !ms_sizeStd.y ) 134 ms_sizeStd.y = wxSystemSettings::GetMetric(wxSYS_CURSOR_Y); 135 136 return ms_sizeStd.y; 137} 138 139wxCursorRefData::wxCursorRefData(HCURSOR hcursor, bool destroy) 140{ 141 m_hCursor = (WXHCURSOR)hcursor; 142 143 if ( m_hCursor ) 144 { 145 m_width = GetStandardWidth(); 146 m_height = GetStandardHeight(); 147 } 148 149 m_destroyCursor = destroy; 150} 151 152void wxCursorRefData::Free() 153{ 154 if ( m_hCursor ) 155 { 156#ifndef __WXWINCE__ 157 if ( m_destroyCursor ) 158 ::DestroyCursor((HCURSOR)m_hCursor); 159#endif 160 161 m_hCursor = 0; 162 } 163} 164 165// ---------------------------------------------------------------------------- 166// Cursors 167// ---------------------------------------------------------------------------- 168 169wxCursor::wxCursor() 170{ 171} 172 173#if wxUSE_IMAGE 174wxCursor::wxCursor(const wxImage& image) 175{ 176 // image has to be of the standard cursor size, otherwise we won't be able 177 // to create it 178 const int w = wxCursorRefData::GetStandardWidth(); 179 const int h = wxCursorRefData::GetStandardHeight(); 180 181 int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X); 182 int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y); 183 int image_w = image.GetWidth(); 184 int image_h = image.GetHeight(); 185 186 wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < image_w && 187 hotSpotY >= 0 && hotSpotY < image_h, 188 _T("invalid cursor hot spot coordinates") ); 189 190 wxImage imageSized(image); // final image of correct size 191 192 // if image is too small then place it in the center, resize it if too big 193 if ((w > image_w) && (h > image_h)) 194 { 195 wxPoint offset((w - image_w)/2, (h - image_h)/2); 196 hotSpotX = hotSpotX + offset.x; 197 hotSpotY = hotSpotY + offset.y; 198 199 imageSized = image.Size(wxSize(w, h), offset); 200 } 201 else if ((w != image_w) || (h != image_h)) 202 { 203 hotSpotX = int(hotSpotX * double(w) / double(image_w)); 204 hotSpotY = int(hotSpotY * double(h) / double(image_h)); 205 206 imageSized = image.Scale(w, h); 207 } 208 209 HCURSOR hcursor = wxBitmapToHCURSOR( wxBitmap(imageSized), 210 hotSpotX, hotSpotY ); 211 if ( !hcursor ) 212 { 213 wxLogWarning(_("Failed to create cursor.")); 214 return; 215 } 216 217 m_refData = new wxCursorRefData(hcursor, true /* delete it later */); 218} 219#endif // wxUSE_IMAGE 220 221wxCursor::wxCursor(const char WXUNUSED(bits)[], 222 int WXUNUSED(width), 223 int WXUNUSED(height), 224 int WXUNUSED(hotSpotX), int WXUNUSED(hotSpotY), 225 const char WXUNUSED(maskBits)[]) 226{ 227} 228 229// MicroWin doesn't have support needed for the other ctors 230#ifdef __WXMICROWIN__ 231 232wxCursor::wxCursor(const wxString& WXUNUSED(filename), 233 long WXUNUSED(kind), 234 int WXUNUSED(hotSpotX), 235 int WXUNUSED(hotSpotY)) 236{ 237} 238 239wxCursor::wxCursor(int WXUNUSED(cursor_type)) 240{ 241} 242 243#else // !__WXMICROWIN__ 244 245wxCursor::wxCursor(const wxString& filename, 246 long kind, 247 int hotSpotX, 248 int hotSpotY) 249{ 250 HCURSOR hcursor; 251 switch ( kind ) 252 { 253 case wxBITMAP_TYPE_CUR_RESOURCE: 254 hcursor = ::LoadCursor(wxGetInstance(), filename); 255 break; 256 257#ifndef __WXWINCE__ 258 case wxBITMAP_TYPE_CUR: 259 hcursor = ::LoadCursorFromFile(filename); 260 break; 261#endif 262 263 case wxBITMAP_TYPE_ICO: 264 hcursor = wxBitmapToHCURSOR 265 ( 266 wxIcon(filename, wxBITMAP_TYPE_ICO), 267 hotSpotX, 268 hotSpotY 269 ); 270 break; 271 272 case wxBITMAP_TYPE_BMP: 273 hcursor = wxBitmapToHCURSOR 274 ( 275 wxBitmap(filename, wxBITMAP_TYPE_BMP), 276 hotSpotX, 277 hotSpotY 278 ); 279 break; 280 281 default: 282 wxFAIL_MSG( _T("unknown cursor resource type") ); 283 284 hcursor = NULL; 285 } 286 287 if ( hcursor ) 288 { 289 m_refData = new wxCursorRefData(hcursor, true /* delete it later */); 290 } 291} 292 293// Cursors by stock number 294wxCursor::wxCursor(int idCursor) 295{ 296 // all wxWidgets standard cursors 297 static const struct StdCursor 298 { 299 // is this a standard Windows cursor? 300 bool isStd; 301 302 // the cursor name or id 303 LPCTSTR name; 304 } stdCursors[] = 305 { 306 { true, NULL }, // wxCURSOR_NONE 307 { true, IDC_ARROW }, // wxCURSOR_ARROW 308 { false, _T("WXCURSOR_RIGHT_ARROW") }, // wxCURSOR_RIGHT_ARROW 309 { false, _T("WXCURSOR_BULLSEYE") }, // wxCURSOR_BULLSEYE 310 { true, IDC_ARROW }, // WXCURSOR_CHAR 311 312 // Displays as an I-beam on XP, so use a cursor file 313// { true, IDC_CROSS }, // WXCURSOR_CROSS 314 { false, _T("WXCURSOR_CROSS") }, // WXCURSOR_CROSS 315 316 // See special handling below for wxCURSOR_HAND 317// { false, _T("WXCURSOR_HAND") }, // wxCURSOR_HAND 318 { true, IDC_HAND }, // wxCURSOR_HAND 319 320 { true, IDC_IBEAM }, // WXCURSOR_IBEAM 321 { true, IDC_ARROW }, // WXCURSOR_LEFT_BUTTON 322 { false, _T("WXCURSOR_MAGNIFIER") }, // wxCURSOR_MAGNIFIER 323 { true, IDC_ARROW }, // WXCURSOR_MIDDLE_BUTTON 324 { true, IDC_NO }, // WXCURSOR_NO_ENTRY 325 { false, _T("WXCURSOR_PBRUSH") }, // wxCURSOR_PAINT_BRUSH 326 { false, _T("WXCURSOR_PENCIL") }, // wxCURSOR_PENCIL 327 { false, _T("WXCURSOR_PLEFT") }, // wxCURSOR_POINT_LEFT 328 { false, _T("WXCURSOR_PRIGHT") }, // wxCURSOR_POINT_RIGHT 329 { true, IDC_HELP }, // WXCURSOR_QUESTION_ARROW 330 { true, IDC_ARROW }, // WXCURSOR_RIGHT_BUTTON 331 { true, IDC_SIZENESW }, // WXCURSOR_SIZENESW 332 { true, IDC_SIZENS }, // WXCURSOR_SIZENS 333 { true, IDC_SIZENWSE }, // WXCURSOR_SIZENWSE 334 { true, IDC_SIZEWE }, // WXCURSOR_SIZEWE 335 { true, IDC_SIZEALL }, // WXCURSOR_SIZING 336 { false, _T("WXCURSOR_PBRUSH") }, // wxCURSOR_SPRAYCAN 337 { true, IDC_WAIT }, // WXCURSOR_WAIT 338 { true, IDC_WAIT }, // WXCURSOR_WATCH 339 { false, _T("WXCURSOR_BLANK") }, // wxCURSOR_BLANK 340 { true, IDC_APPSTARTING }, // wxCURSOR_ARROWWAIT 341 342 // no entry for wxCURSOR_MAX 343 }; 344 345 wxCOMPILE_TIME_ASSERT( WXSIZEOF(stdCursors) == wxCURSOR_MAX, 346 CursorsIdArrayMismatch ); 347 348 wxCHECK_RET( idCursor > 0 && (size_t)idCursor < WXSIZEOF(stdCursors), 349 _T("invalid cursor id in wxCursor() ctor") ); 350 351 const StdCursor& stdCursor = stdCursors[idCursor]; 352 bool deleteLater = !stdCursor.isStd; 353 354 HCURSOR hcursor = ::LoadCursor(stdCursor.isStd ? NULL : wxGetInstance(), 355 stdCursor.name); 356 357 // IDC_HAND may not be available on some versions of Windows. 358 if ( !hcursor && idCursor == wxCURSOR_HAND) 359 { 360 hcursor = ::LoadCursor(wxGetInstance(), _T("WXCURSOR_HAND")); 361 deleteLater = true; 362 } 363 364 if ( !hcursor ) 365 { 366 wxLogLastError(_T("LoadCursor")); 367 } 368 else 369 { 370 m_refData = new wxCursorRefData(hcursor, deleteLater); 371 } 372} 373 374#endif // __WXMICROWIN__/!__WXMICROWIN__ 375 376wxCursor::~wxCursor() 377{ 378} 379 380// ---------------------------------------------------------------------------- 381// other wxCursor functions 382// ---------------------------------------------------------------------------- 383 384wxGDIImageRefData *wxCursor::CreateData() const 385{ 386 return new wxCursorRefData; 387} 388 389// ---------------------------------------------------------------------------- 390// Global cursor setting 391// ---------------------------------------------------------------------------- 392 393const wxCursor *wxGetGlobalCursor() 394{ 395 return gs_globalCursor; 396} 397 398void wxSetCursor(const wxCursor& cursor) 399{ 400 if ( cursor.Ok() ) 401 { 402 ::SetCursor(GetHcursorOf(cursor)); 403 404 if ( gs_globalCursor ) 405 *gs_globalCursor = cursor; 406 } 407} 408