]> git.saurik.com Git - wxWidgets.git/blob - src/msw/gdiimage.cpp
Patch [ 1816051 ] MSW DrawEllipticArc inconsistent with other platforms
[wxWidgets.git] / src / msw / gdiimage.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/gdiimage.cpp
3 // Purpose: wxGDIImage implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.11.99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
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 #ifndef WX_PRECOMP
28 #include "wx/string.h"
29 #include "wx/log.h"
30 #include "wx/app.h"
31 #include "wx/bitmap.h"
32 #endif // WX_PRECOMP
33
34 #include "wx/msw/private.h"
35
36 #include "wx/msw/gdiimage.h"
37
38 #if wxUSE_WXDIB
39 #include "wx/msw/dib.h"
40 #endif
41
42 #ifdef __WXWINCE__
43 #include <winreg.h>
44 #include <shellapi.h>
45 #endif
46
47 #include "wx/file.h"
48
49 #include "wx/listimpl.cpp"
50 WX_DEFINE_LIST(wxGDIImageHandlerList)
51
52 // ----------------------------------------------------------------------------
53 // private classes
54 // ----------------------------------------------------------------------------
55
56 #ifndef __WXMICROWIN__
57
58 // all image handlers are declared/defined in this file because the outside
59 // world doesn't have to know about them (but only about wxBITMAP_TYPE_XXX ids)
60
61 class WXDLLEXPORT wxBMPFileHandler : public wxBitmapHandler
62 {
63 public:
64 wxBMPFileHandler() : wxBitmapHandler(_T("Windows bitmap file"), _T("bmp"),
65 wxBITMAP_TYPE_BMP)
66 {
67 }
68
69 virtual bool LoadFile(wxBitmap *bitmap,
70 const wxString& name, long flags,
71 int desiredWidth, int desiredHeight);
72 virtual bool SaveFile(wxBitmap *bitmap,
73 const wxString& name, int type,
74 const wxPalette *palette = NULL);
75
76 private:
77 DECLARE_DYNAMIC_CLASS(wxBMPFileHandler)
78 };
79
80 class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler
81 {
82 public:
83 wxBMPResourceHandler() : wxBitmapHandler(_T("Windows bitmap resource"),
84 wxEmptyString,
85 wxBITMAP_TYPE_BMP_RESOURCE)
86 {
87 }
88
89 virtual bool LoadFile(wxBitmap *bitmap,
90 const wxString& name, long flags,
91 int desiredWidth, int desiredHeight);
92
93 private:
94 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler)
95 };
96
97 class WXDLLEXPORT wxIconHandler : public wxGDIImageHandler
98 {
99 public:
100 wxIconHandler(const wxString& name, const wxString& ext, long type)
101 : wxGDIImageHandler(name, ext, type)
102 {
103 }
104
105 // creating and saving icons is not supported
106 virtual bool Create(wxGDIImage *WXUNUSED(image),
107 const void* WXUNUSED(data),
108 long WXUNUSED(flags),
109 int WXUNUSED(width),
110 int WXUNUSED(height),
111 int WXUNUSED(depth) = 1)
112 {
113 return false;
114 }
115
116 virtual bool Save(wxGDIImage *WXUNUSED(image),
117 const wxString& WXUNUSED(name),
118 int WXUNUSED(type))
119 {
120 return false;
121 }
122
123 virtual bool Load(wxGDIImage *image,
124 const wxString& name,
125 long flags,
126 int desiredWidth, int desiredHeight)
127 {
128 wxIcon *icon = wxDynamicCast(image, wxIcon);
129 wxCHECK_MSG( icon, false, _T("wxIconHandler only works with icons") );
130
131 return LoadIcon(icon, name, flags, desiredWidth, desiredHeight);
132 }
133
134 protected:
135 virtual bool LoadIcon(wxIcon *icon,
136 const wxString& name, long flags,
137 int desiredWidth = -1, int desiredHeight = -1) = 0;
138 };
139
140 class WXDLLEXPORT wxICOFileHandler : public wxIconHandler
141 {
142 public:
143 wxICOFileHandler() : wxIconHandler(_T("ICO icon file"),
144 _T("ico"),
145 wxBITMAP_TYPE_ICO)
146 {
147 }
148
149 protected:
150 virtual bool LoadIcon(wxIcon *icon,
151 const wxString& name, long flags,
152 int desiredWidth = -1, int desiredHeight = -1);
153
154 private:
155 DECLARE_DYNAMIC_CLASS(wxICOFileHandler)
156 };
157
158 class WXDLLEXPORT wxICOResourceHandler: public wxIconHandler
159 {
160 public:
161 wxICOResourceHandler() : wxIconHandler(_T("ICO resource"),
162 _T("ico"),
163 wxBITMAP_TYPE_ICO_RESOURCE)
164 {
165 }
166
167 protected:
168 virtual bool LoadIcon(wxIcon *icon,
169 const wxString& name, long flags,
170 int desiredWidth = -1, int desiredHeight = -1);
171
172 private:
173 DECLARE_DYNAMIC_CLASS(wxICOResourceHandler)
174 };
175
176 // ----------------------------------------------------------------------------
177 // wxWin macros
178 // ----------------------------------------------------------------------------
179
180 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler, wxBitmapHandler)
181 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler)
182 IMPLEMENT_DYNAMIC_CLASS(wxICOFileHandler, wxObject)
183 IMPLEMENT_DYNAMIC_CLASS(wxICOResourceHandler, wxObject)
184
185 // ----------------------------------------------------------------------------
186 // private functions
187 // ----------------------------------------------------------------------------
188
189 #endif
190 // __MICROWIN__
191
192 // ============================================================================
193 // implementation
194 // ============================================================================
195
196 wxGDIImageHandlerList wxGDIImage::ms_handlers;
197
198 // ----------------------------------------------------------------------------
199 // wxGDIImage functions forwarded to wxGDIImageRefData
200 // ----------------------------------------------------------------------------
201
202 bool wxGDIImage::FreeResource(bool WXUNUSED(force))
203 {
204 if ( !IsNull() )
205 {
206 GetGDIImageData()->Free();
207 GetGDIImageData()->m_handle = 0;
208 }
209
210 return true;
211 }
212
213 WXHANDLE wxGDIImage::GetResourceHandle() const
214 {
215 return GetHandle();
216 }
217
218 // ----------------------------------------------------------------------------
219 // wxGDIImage handler stuff
220 // ----------------------------------------------------------------------------
221
222 void wxGDIImage::AddHandler(wxGDIImageHandler *handler)
223 {
224 ms_handlers.Append(handler);
225 }
226
227 void wxGDIImage::InsertHandler(wxGDIImageHandler *handler)
228 {
229 ms_handlers.Insert(handler);
230 }
231
232 bool wxGDIImage::RemoveHandler(const wxString& name)
233 {
234 wxGDIImageHandler *handler = FindHandler(name);
235 if ( handler )
236 {
237 ms_handlers.DeleteObject(handler);
238 return true;
239 }
240 else
241 return false;
242 }
243
244 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& name)
245 {
246 wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
247 while ( node )
248 {
249 wxGDIImageHandler *handler = node->GetData();
250 if ( handler->GetName() == name )
251 return handler;
252 node = node->GetNext();
253 }
254
255 return NULL;
256 }
257
258 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& extension,
259 long type)
260 {
261 wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
262 while ( node )
263 {
264 wxGDIImageHandler *handler = node->GetData();
265 if ( (handler->GetExtension() == extension) &&
266 (type == -1 || handler->GetType() == type) )
267 {
268 return handler;
269 }
270
271 node = node->GetNext();
272 }
273 return NULL;
274 }
275
276 wxGDIImageHandler *wxGDIImage::FindHandler(long type)
277 {
278 wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
279 while ( node )
280 {
281 wxGDIImageHandler *handler = node->GetData();
282 if ( handler->GetType() == type )
283 return handler;
284
285 node = node->GetNext();
286 }
287
288 return NULL;
289 }
290
291 void wxGDIImage::CleanUpHandlers()
292 {
293 wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
294 while ( node )
295 {
296 wxGDIImageHandler *handler = node->GetData();
297 wxGDIImageHandlerList::compatibility_iterator next = node->GetNext();
298 delete handler;
299 ms_handlers.Erase( node );
300 node = next;
301 }
302 }
303
304 void wxGDIImage::InitStandardHandlers()
305 {
306 #ifndef __WXMICROWIN__
307 AddHandler(new wxBMPResourceHandler);
308 AddHandler(new wxBMPFileHandler);
309 AddHandler(new wxICOResourceHandler);
310 AddHandler(new wxICOFileHandler);
311 #endif
312 }
313
314 #ifndef __WXMICROWIN__
315
316 // ----------------------------------------------------------------------------
317 // wxBitmap handlers
318 // ----------------------------------------------------------------------------
319
320 bool wxBMPResourceHandler::LoadFile(wxBitmap *bitmap,
321 const wxString& name, long WXUNUSED(flags),
322 int WXUNUSED(desiredWidth),
323 int WXUNUSED(desiredHeight))
324 {
325 // TODO: load colourmap.
326 bitmap->SetHBITMAP((WXHBITMAP)::LoadBitmap(wxGetInstance(), name.wx_str()));
327
328 if ( !bitmap->Ok() )
329 {
330 // it's probably not found
331 wxLogError(wxT("Can't load bitmap '%s' from resources! Check .rc file."),
332 name.c_str());
333
334 return false;
335 }
336
337 BITMAP bm;
338 if ( !::GetObject(GetHbitmapOf(*bitmap), sizeof(BITMAP), (LPSTR) &bm) )
339 {
340 wxLogLastError(wxT("GetObject(HBITMAP)"));
341 }
342
343 bitmap->SetWidth(bm.bmWidth);
344 bitmap->SetHeight(bm.bmHeight);
345 bitmap->SetDepth(bm.bmBitsPixel);
346
347 // use 0xc0c0c0 as transparent colour by default
348 bitmap->SetMask(new wxMask(*bitmap, *wxLIGHT_GREY));
349
350 return true;
351 }
352
353 bool wxBMPFileHandler::LoadFile(wxBitmap *bitmap,
354 const wxString& name, long WXUNUSED(flags),
355 int WXUNUSED(desiredWidth),
356 int WXUNUSED(desiredHeight))
357 {
358 #if wxUSE_WXDIB
359 wxCHECK_MSG( bitmap, false, _T("NULL bitmap in LoadFile") );
360
361 wxDIB dib(name);
362
363 return dib.IsOk() && bitmap->CopyFromDIB(dib);
364 #else
365 return false;
366 #endif
367 }
368
369 bool wxBMPFileHandler::SaveFile(wxBitmap *bitmap,
370 const wxString& name,
371 int WXUNUSED(type),
372 const wxPalette * WXUNUSED(pal))
373 {
374 #if wxUSE_WXDIB
375 wxCHECK_MSG( bitmap, false, _T("NULL bitmap in SaveFile") );
376
377 wxDIB dib(*bitmap);
378
379 return dib.Save(name);
380 #else
381 return false;
382 #endif
383 }
384
385 // ----------------------------------------------------------------------------
386 // wxIcon handlers
387 // ----------------------------------------------------------------------------
388
389 bool wxICOFileHandler::LoadIcon(wxIcon *icon,
390 const wxString& name,
391 long WXUNUSED(flags),
392 int desiredWidth, int desiredHeight)
393 {
394 icon->UnRef();
395
396 // actual size
397 wxSize size;
398
399 HICON hicon = NULL;
400
401 // Parse the filename: it may be of the form "filename;n" in order to
402 // specify the nth icon in the file.
403 //
404 // For the moment, ignore the issue of possible semicolons in the
405 // filename.
406 int iconIndex = 0;
407 wxString nameReal(name);
408 wxString strIconIndex = name.AfterLast(wxT(';'));
409 if (strIconIndex != name)
410 {
411 iconIndex = wxAtoi(strIconIndex);
412 nameReal = name.BeforeLast(wxT(';'));
413 }
414
415 #if 0
416 // If we don't know what size icon we're looking for,
417 // try to find out what's there.
418 // Unfortunately this doesn't work, because ExtractIconEx
419 // will scale the icon to the 'desired' size, even if that
420 // size of icon isn't explicitly stored. So we would have
421 // to parse the icon file outselves.
422 if ( desiredWidth == -1 &&
423 desiredHeight == -1)
424 {
425 // Try loading a large icon first
426 if ( ::ExtractIconEx(nameReal, iconIndex, &hicon, NULL, 1) == 1)
427 {
428 }
429 // Then try loading a small icon
430 else if ( ::ExtractIconEx(nameReal, iconIndex, NULL, &hicon, 1) == 1)
431 {
432 }
433 }
434 else
435 #endif
436 // were we asked for a large icon?
437 if ( desiredWidth == ::GetSystemMetrics(SM_CXICON) &&
438 desiredHeight == ::GetSystemMetrics(SM_CYICON) )
439 {
440 // get the specified large icon from file
441 if ( !::ExtractIconEx(nameReal.wx_str(), iconIndex, &hicon, NULL, 1) )
442 {
443 // it is not an error, but it might still be useful to be informed
444 // about it optionally
445 wxLogTrace(_T("iconload"),
446 _T("No large icons found in the file '%s'."),
447 name.c_str());
448 }
449 }
450 else if ( desiredWidth == ::GetSystemMetrics(SM_CXSMICON) &&
451 desiredHeight == ::GetSystemMetrics(SM_CYSMICON) )
452 {
453 // get the specified small icon from file
454 if ( !::ExtractIconEx(nameReal.wx_str(), iconIndex, NULL, &hicon, 1) )
455 {
456 wxLogTrace(_T("iconload"),
457 _T("No small icons found in the file '%s'."),
458 name.c_str());
459 }
460 }
461 //else: not standard size, load below
462
463 #ifndef __WXWINCE__
464 if ( !hicon )
465 {
466 // take any size icon from the file by index
467 hicon = ::ExtractIcon(wxGetInstance(), nameReal.wx_str(), iconIndex);
468 }
469 #endif
470
471 if ( !hicon )
472 {
473 wxLogSysError(_T("Failed to load icon from the file '%s'"),
474 name.c_str());
475
476 return false;
477 }
478
479 size = wxGetHiconSize(hicon);
480
481 if ( (desiredWidth != -1 && desiredWidth != size.x) ||
482 (desiredHeight != -1 && desiredHeight != size.y) )
483 {
484 wxLogTrace(_T("iconload"),
485 _T("Returning false from wxICOFileHandler::Load because of the size mismatch: actual (%d, %d), requested (%d, %d)"),
486 size.x, size.y,
487 desiredWidth, desiredHeight);
488
489 ::DestroyIcon(hicon);
490
491 return false;
492 }
493
494 icon->SetHICON((WXHICON)hicon);
495 icon->SetSize(size.x, size.y);
496
497 return icon->Ok();
498 }
499
500 bool wxICOResourceHandler::LoadIcon(wxIcon *icon,
501 const wxString& name,
502 long WXUNUSED(flags),
503 int desiredWidth, int desiredHeight)
504 {
505 HICON hicon;
506
507 // do we need the icon of the specific size or would any icon do?
508 bool hasSize = desiredWidth != -1 || desiredHeight != -1;
509
510 wxASSERT_MSG( !hasSize || (desiredWidth != -1 && desiredHeight != -1),
511 _T("width and height should be either both -1 or not") );
512
513 // try to load the icon from this program first to allow overriding the
514 // standard icons (although why one would want to do it considering that
515 // we already have wxApp::GetStdIcon() is unclear)
516
517 // note that we can't just always call LoadImage() because it seems to do
518 // some icon rescaling internally which results in very ugly 16x16 icons
519 if ( hasSize )
520 {
521 hicon = (HICON)::LoadImage(wxGetInstance(), name.wx_str(), IMAGE_ICON,
522 desiredWidth, desiredHeight,
523 LR_DEFAULTCOLOR);
524 }
525 else
526 {
527 hicon = ::LoadIcon(wxGetInstance(), name.wx_str());
528 }
529
530 // next check if it's not a standard icon
531 #ifndef __WXWINCE__
532 if ( !hicon && !hasSize )
533 {
534 static const struct
535 {
536 const wxChar *name;
537 LPTSTR id;
538 } stdIcons[] =
539 {
540 { wxT("wxICON_QUESTION"), IDI_QUESTION },
541 { wxT("wxICON_WARNING"), IDI_EXCLAMATION },
542 { wxT("wxICON_ERROR"), IDI_HAND },
543 { wxT("wxICON_INFORMATION"), IDI_ASTERISK },
544 };
545
546 for ( size_t nIcon = 0; !hicon && nIcon < WXSIZEOF(stdIcons); nIcon++ )
547 {
548 if ( name == stdIcons[nIcon].name )
549 {
550 hicon = ::LoadIcon((HINSTANCE)NULL, stdIcons[nIcon].id);
551 }
552 }
553 }
554 #endif
555
556 wxSize size = wxGetHiconSize(hicon);
557 icon->SetSize(size.x, size.y);
558
559 icon->SetHICON((WXHICON)hicon);
560
561 return icon->Ok();
562 }
563
564 // ----------------------------------------------------------------------------
565 // private functions
566 // ----------------------------------------------------------------------------
567
568 wxSize wxGetHiconSize(HICON WXUNUSED_IN_WINCE(hicon))
569 {
570 wxSize size;
571
572 #ifndef __WXWINCE__
573 if ( hicon )
574 {
575 ICONINFO info;
576 if ( !::GetIconInfo(hicon, &info) )
577 {
578 wxLogLastError(wxT("GetIconInfo"));
579 }
580 else
581 {
582 HBITMAP hbmp = info.hbmMask;
583 if ( hbmp )
584 {
585 BITMAP bm;
586 if ( ::GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm) )
587 {
588 size = wxSize(bm.bmWidth, bm.bmHeight);
589 }
590
591 ::DeleteObject(info.hbmMask);
592 }
593 if ( info.hbmColor )
594 ::DeleteObject(info.hbmColor);
595 }
596 }
597
598 if ( !size.x )
599 #endif // !__WXWINCE__
600 {
601 // use default icon size on this hardware
602 size.x = ::GetSystemMetrics(SM_CXICON);
603 size.y = ::GetSystemMetrics(SM_CYICON);
604 }
605
606 return size;
607 }
608
609 #endif // __WXMICROWIN__