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