fixed loading the icons with non default size
[wxWidgets.git] / src / msw / gdiimage.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "gdiimage.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/string.h"
33 #include "wx/log.h"
34 #endif // WX_PRECOMP
35
36 #include "wx/msw/private.h"
37
38 #include "wx/app.h"
39
40 #ifndef __WXMICROWIN__
41 #include "wx/msw/dib.h"
42 #endif
43
44 #include "wx/msw/bitmap.h"
45 #include "wx/msw/gdiimage.h"
46 #include "wx/bitmap.h"
47
48 #ifdef __WIN16__
49 # include "wx/msw/curico.h"
50 #endif // __WIN16__
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 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 virtual bool LoadIcon(wxIcon *icon,
150 const wxString& name, long flags,
151 int desiredWidth = -1, int desiredHeight = -1);
152
153 private:
154 DECLARE_DYNAMIC_CLASS(wxICOFileHandler)
155 };
156
157 class WXDLLEXPORT wxICOResourceHandler: public wxIconHandler
158 {
159 public:
160 wxICOResourceHandler() : wxIconHandler(_T("ICO resource"),
161 _T("ico"),
162 wxBITMAP_TYPE_ICO_RESOURCE)
163 {
164 }
165
166 virtual bool LoadIcon(wxIcon *icon,
167 const wxString& name, long flags,
168 int desiredWidth = -1, int desiredHeight = -1);
169
170 private:
171 DECLARE_DYNAMIC_CLASS(wxICOResourceHandler)
172 };
173
174 // ----------------------------------------------------------------------------
175 // wxWin macros
176 // ----------------------------------------------------------------------------
177
178 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler, wxBitmapHandler)
179 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler)
180 IMPLEMENT_DYNAMIC_CLASS(wxICOFileHandler, wxObject)
181 IMPLEMENT_DYNAMIC_CLASS(wxICOResourceHandler, wxObject)
182
183 // ----------------------------------------------------------------------------
184 // private functions
185 // ----------------------------------------------------------------------------
186
187 static wxSize GetHiconSize(HICON hicon);
188 #endif
189 // __MICROWIN__
190
191 // ============================================================================
192 // implementation
193 // ============================================================================
194
195 wxList wxGDIImage::ms_handlers;
196
197 // ----------------------------------------------------------------------------
198 // wxGDIImage functions forwarded to wxGDIImageRefData
199 // ----------------------------------------------------------------------------
200
201 bool wxGDIImage::FreeResource(bool WXUNUSED(force))
202 {
203 if ( !IsNull() )
204 {
205 GetGDIImageData()->Free();
206 GetGDIImageData()->m_handle = 0;
207 }
208
209 return TRUE;
210 }
211
212 WXHANDLE wxGDIImage::GetResourceHandle()
213 {
214 return GetHandle();
215 }
216
217 // ----------------------------------------------------------------------------
218 // wxGDIImage handler stuff
219 // ----------------------------------------------------------------------------
220
221 void wxGDIImage::AddHandler(wxGDIImageHandler *handler)
222 {
223 ms_handlers.Append(handler);
224 }
225
226 void wxGDIImage::InsertHandler(wxGDIImageHandler *handler)
227 {
228 ms_handlers.Insert(handler);
229 }
230
231 bool wxGDIImage::RemoveHandler(const wxString& name)
232 {
233 wxGDIImageHandler *handler = FindHandler(name);
234 if ( handler )
235 {
236 ms_handlers.DeleteObject(handler);
237 return TRUE;
238 }
239 else
240 return FALSE;
241 }
242
243 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& name)
244 {
245 wxNode *node = ms_handlers.First();
246 while ( node )
247 {
248 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->Data();
249 if ( handler->GetName() == name )
250 return handler;
251 node = node->Next();
252 }
253
254 return NULL;
255 }
256
257 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& extension,
258 long type)
259 {
260 wxNode *node = ms_handlers.First();
261 while ( node )
262 {
263 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->Data();
264 if ( (handler->GetExtension() = extension) &&
265 (type == -1 || handler->GetType() == type) )
266 {
267 return handler;
268 }
269
270 node = node->Next();
271 }
272 return NULL;
273 }
274
275 wxGDIImageHandler *wxGDIImage::FindHandler(long type)
276 {
277 wxNode *node = ms_handlers.First();
278 while ( node )
279 {
280 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->Data();
281 if ( handler->GetType() == type )
282 return handler;
283
284 node = node->Next();
285 }
286
287 return NULL;
288 }
289
290 void wxGDIImage::CleanUpHandlers()
291 {
292 wxNode *node = ms_handlers.First();
293 while ( node )
294 {
295 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->Data();
296 wxNode *next = node->Next();
297 delete handler;
298 delete node;
299 node = next;
300 }
301 }
302
303 void wxGDIImage::InitStandardHandlers()
304 {
305 #ifndef __WXMICROWIN__
306 AddHandler(new wxBMPResourceHandler);
307 AddHandler(new wxBMPFileHandler);
308 AddHandler(new wxICOResourceHandler);
309 AddHandler(new wxICOFileHandler);
310 #endif
311 }
312
313 #ifndef __WXMICROWIN__
314
315 // ----------------------------------------------------------------------------
316 // wxBitmap handlers
317 // ----------------------------------------------------------------------------
318
319 bool wxBMPResourceHandler::LoadFile(wxBitmap *bitmap,
320 const wxString& name, long WXUNUSED(flags),
321 int WXUNUSED(desiredWidth),
322 int WXUNUSED(desiredHeight))
323 {
324 // TODO: load colourmap.
325 bitmap->SetHBITMAP((WXHBITMAP)::LoadBitmap(wxGetInstance(), name));
326
327 wxBitmapRefData *data = bitmap->GetBitmapData();
328 if ( bitmap->Ok() )
329 {
330 BITMAP bm;
331 if ( !::GetObject(GetHbitmapOf(*bitmap), sizeof(BITMAP), (LPSTR) &bm) )
332 {
333 wxLogLastError(wxT("GetObject(HBITMAP)"));
334 }
335
336 data->m_width = bm.bmWidth;
337 data->m_height = bm.bmHeight;
338 data->m_depth = bm.bmBitsPixel;
339 }
340 else
341 {
342 // it's probably not found
343 wxLogError(wxT("Can't load bitmap '%s' from resources! Check .rc file."),
344 name.c_str());
345 }
346
347 return bitmap->Ok();
348 }
349
350 bool wxBMPFileHandler::LoadFile(wxBitmap *bitmap,
351 const wxString& name, long WXUNUSED(flags),
352 int WXUNUSED(desiredWidth),
353 int WXUNUSED(desiredHeight))
354 {
355 #if wxUSE_IMAGE_LOADING_IN_MSW
356 wxPalette *palette = NULL;
357 bool success = wxLoadIntoBitmap(WXSTRINGCAST name, bitmap, &palette) != 0;
358
359 #if wxUSE_PALETTE
360 if ( success && palette )
361 {
362 bitmap->SetPalette(*palette);
363 }
364
365 // it was copied by the bitmap if it was loaded successfully
366 delete palette;
367 #endif // wxUSE_PALETTE
368
369 return success;
370 #else
371 return FALSE;
372 #endif
373 }
374
375 bool wxBMPFileHandler::SaveFile(wxBitmap *bitmap,
376 const wxString& name,
377 int WXUNUSED(type),
378 const wxPalette *pal)
379 {
380 #if wxUSE_IMAGE_LOADING_IN_MSW
381
382 #if wxUSE_PALETTE
383 wxPalette *actualPalette = (wxPalette *)pal;
384 if ( !actualPalette )
385 actualPalette = bitmap->GetPalette();
386 #else
387 wxPalette *actualPalette = NULL;
388 #endif // wxUSE_PALETTE
389
390 return wxSaveBitmap(WXSTRINGCAST name, bitmap, actualPalette) != 0;
391 #else
392 return FALSE;
393 #endif
394 }
395
396 // ----------------------------------------------------------------------------
397 // wxIcon handlers
398 // ----------------------------------------------------------------------------
399
400 bool wxICOFileHandler::LoadIcon(wxIcon *icon,
401 const wxString& name,
402 long WXUNUSED(flags),
403 int desiredWidth, int desiredHeight)
404 {
405 #if wxUSE_RESOURCE_LOADING_IN_MSW
406 icon->UnRef();
407
408 // actual size
409 wxSize size;
410
411 #ifdef __WIN32__
412 HICON hicon = NULL;
413
414 // Parse the filename: it may be of the form "filename;n" in order to
415 // specify the nth icon in the file.
416 //
417 // For the moment, ignore the issue of possible semicolons in the
418 // filename.
419 int iconIndex = 0;
420 wxString nameReal(name);
421 wxString strIconIndex = name.AfterLast(wxT(';'));
422 if (strIconIndex != name)
423 {
424 iconIndex = wxAtoi(strIconIndex);
425 nameReal = name.BeforeLast(wxT(';'));
426 }
427
428 // were we asked for a large icon?
429 if ( desiredWidth == ::GetSystemMetrics(SM_CXICON) &&
430 desiredHeight == ::GetSystemMetrics(SM_CYICON) )
431 {
432 // get the specified large icon from file
433 if ( !::ExtractIconEx(nameReal, iconIndex, &hicon, NULL, 1) )
434 {
435 // it is not an error, but it might still be useful to be informed
436 // about it optionally
437 wxLogTrace(_T("iconload"),
438 _T("No large icons found in the file '%s'."),
439 name.c_str());
440 }
441 }
442 else if ( desiredWidth == ::GetSystemMetrics(SM_CXSMICON) &&
443 desiredHeight == ::GetSystemMetrics(SM_CYSMICON) )
444 {
445 // get the specified small icon from file
446 if ( !::ExtractIconEx(nameReal, iconIndex, NULL, &hicon, 1) )
447 {
448 wxLogTrace(_T("iconload"),
449 _T("No small icons found in the file '%s'."),
450 name.c_str());
451 }
452 }
453 //else: not standard size, load below
454
455 if ( !hicon )
456 {
457 // take any (the first one) icon from the file by default
458 hicon = ::ExtractIcon(wxGetInstance(), nameReal, 0 /* first */);
459 }
460
461 if ( !hicon )
462 {
463 wxLogSysError(_T("Failed to load icon from the file '%s'"),
464 name.c_str());
465
466 return FALSE;
467 }
468
469 size = GetHiconSize(hicon);
470 #else // Win16
471 HICON hicon = ReadIconFile((wxChar *)name.c_str(),
472 wxGetInstance(),
473 &size.x, &size.y);
474 #endif // Win32/Win16
475
476 if ( (desiredWidth != -1 && desiredWidth != size.x) ||
477 (desiredHeight != -1 && desiredHeight != size.y) )
478 {
479 wxLogTrace(_T("iconload"),
480 _T("Returning FALSE from wxICOFileHandler::Load because of the size mismatch: actual (%d, %d), requested (%d, %d)"),
481 size.x, size.y,
482 desiredWidth, desiredHeight);
483
484 ::DestroyIcon(hicon);
485
486 return FALSE;
487 }
488
489 icon->SetHICON((WXHICON)hicon);
490 icon->SetSize(size.x, size.y);
491
492 return icon->Ok();
493 #else
494 return FALSE;
495 #endif
496 }
497
498 bool wxICOResourceHandler::LoadIcon(wxIcon *icon,
499 const wxString& name,
500 long WXUNUSED(flags),
501 int desiredWidth, int desiredHeight)
502 {
503 HICON hicon;
504
505 // do we need the icon of the specific size or would any icon do?
506 bool hasSize = desiredWidth != -1 || desiredHeight != -1;
507
508 wxASSERT_MSG( !hasSize || (desiredWidth != -1 && desiredHeight != -1),
509 _T("width and height should be either both -1 or not") );
510
511 // try to load the icon from this program first to allow overriding the
512 // standard icons (although why one would want to do it considering that
513 // we already have wxApp::GetStdIcon() is unclear)
514 #if defined(__WIN32__) && !defined(__SC__)
515 if ( !hasSize )
516 {
517 // use the actual size of the resource (as we don't specify
518 // LR_DEFAULTSIZE)
519 desiredWidth =
520 desiredHeight = 0;
521 }
522
523 hicon = (HICON)::LoadImage(wxGetInstance(), name, IMAGE_ICON,
524 desiredWidth, desiredHeight,
525 LR_DEFAULTCOLOR);
526 #else // !Win32
527 hicon = ::LoadIcon(wxGetInstance(), name);
528 #endif // Win32/!Win32
529
530 // next check if it's not a standard icon
531 if ( !hicon && !hasSize )
532 {
533 static const struct
534 {
535 const wxChar *name;
536 LPTSTR id;
537 } stdIcons[] =
538 {
539 { wxT("wxICON_QUESTION"), IDI_QUESTION },
540 { wxT("wxICON_WARNING"), IDI_EXCLAMATION },
541 { wxT("wxICON_ERROR"), IDI_HAND },
542 { wxT("wxICON_INFO"), IDI_ASTERISK },
543 };
544
545 for ( size_t nIcon = 0; !hicon && nIcon < WXSIZEOF(stdIcons); nIcon++ )
546 {
547 if ( name == stdIcons[nIcon].name )
548 {
549 hicon = ::LoadIcon((HINSTANCE)NULL, stdIcons[nIcon].id);
550 }
551 }
552 }
553
554 wxSize size = GetHiconSize(hicon);
555 icon->SetSize(size.x, size.y);
556
557 // Override the found values with desired values
558 if ( hasSize )
559 {
560 icon->SetSize(desiredWidth, desiredHeight);
561 }
562
563 icon->SetHICON((WXHICON)hicon);
564
565 return icon->Ok();
566 }
567
568 // ----------------------------------------------------------------------------
569 // private functions
570 // ----------------------------------------------------------------------------
571
572 static wxSize GetHiconSize(HICON hicon)
573 {
574 wxSize size(32, 32); // default
575
576 #ifdef __WIN32__
577 // Win32s doesn't have GetIconInfo function...
578 if ( hicon && wxGetOsVersion() != wxWIN32S )
579 {
580 ICONINFO info;
581 if ( !::GetIconInfo(hicon, &info) )
582 {
583 wxLogLastError(wxT("GetIconInfo"));
584 }
585 else
586 {
587 HBITMAP hbmp = info.hbmMask;
588 if ( hbmp )
589 {
590 BITMAP bm;
591 if ( ::GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm) )
592 {
593 size = wxSize(bm.bmWidth, bm.bmHeight);
594 }
595
596 ::DeleteObject(info.hbmMask);
597 }
598 if ( info.hbmColor )
599 ::DeleteObject(info.hbmColor);
600 }
601 }
602 #endif
603
604 return size;
605 }
606 #endif
607 // __WXMICROWIN__