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