Update list operators, s/TRUE/true/ etc.
[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 #endif
188 // __MICROWIN__
189
190 // ============================================================================
191 // implementation
192 // ============================================================================
193
194 wxList wxGDIImage::ms_handlers;
195
196 // ----------------------------------------------------------------------------
197 // wxGDIImage functions forwarded to wxGDIImageRefData
198 // ----------------------------------------------------------------------------
199
200 bool wxGDIImage::FreeResource(bool WXUNUSED(force))
201 {
202 if ( !IsNull() )
203 {
204 GetGDIImageData()->Free();
205 GetGDIImageData()->m_handle = 0;
206 }
207
208 return true;
209 }
210
211 WXHANDLE wxGDIImage::GetResourceHandle() const
212 {
213 return GetHandle();
214 }
215
216 // ----------------------------------------------------------------------------
217 // wxGDIImage handler stuff
218 // ----------------------------------------------------------------------------
219
220 void wxGDIImage::AddHandler(wxGDIImageHandler *handler)
221 {
222 ms_handlers.Append(handler);
223 }
224
225 void wxGDIImage::InsertHandler(wxGDIImageHandler *handler)
226 {
227 ms_handlers.Insert(handler);
228 }
229
230 bool wxGDIImage::RemoveHandler(const wxString& name)
231 {
232 wxGDIImageHandler *handler = FindHandler(name);
233 if ( handler )
234 {
235 ms_handlers.DeleteObject(handler);
236 return true;
237 }
238 else
239 return false;
240 }
241
242 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& name)
243 {
244 wxNode *node = ms_handlers.GetFirst();
245 while ( node )
246 {
247 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->GetData();
248 if ( handler->GetName() == name )
249 return handler;
250 node = node->GetNext();
251 }
252
253 return NULL;
254 }
255
256 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& extension,
257 long type)
258 {
259 wxNode *node = ms_handlers.GetFirst();
260 while ( node )
261 {
262 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->GetData();
263 if ( (handler->GetExtension() = extension) &&
264 (type == -1 || handler->GetType() == type) )
265 {
266 return handler;
267 }
268
269 node = node->GetNext();
270 }
271 return NULL;
272 }
273
274 wxGDIImageHandler *wxGDIImage::FindHandler(long type)
275 {
276 wxNode *node = ms_handlers.GetFirst();
277 while ( node )
278 {
279 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->GetData();
280 if ( handler->GetType() == type )
281 return handler;
282
283 node = node->GetNext();
284 }
285
286 return NULL;
287 }
288
289 void wxGDIImage::CleanUpHandlers()
290 {
291 wxNode *node = ms_handlers.GetFirst();
292 while ( node )
293 {
294 wxGDIImageHandler *handler = (wxGDIImageHandler *)node->GetData();
295 wxNode *next = node->GetNext();
296 delete handler;
297 delete node;
298 node = next;
299 }
300 }
301
302 void wxGDIImage::InitStandardHandlers()
303 {
304 #ifndef __WXMICROWIN__
305 AddHandler(new wxBMPResourceHandler);
306 AddHandler(new wxBMPFileHandler);
307 AddHandler(new wxICOResourceHandler);
308 AddHandler(new wxICOFileHandler);
309 #endif
310 }
311
312 #ifndef __WXMICROWIN__
313
314 // ----------------------------------------------------------------------------
315 // wxBitmap handlers
316 // ----------------------------------------------------------------------------
317
318 bool wxBMPResourceHandler::LoadFile(wxBitmap *bitmap,
319 const wxString& name, long WXUNUSED(flags),
320 int WXUNUSED(desiredWidth),
321 int WXUNUSED(desiredHeight))
322 {
323 // TODO: load colourmap.
324 bitmap->SetHBITMAP((WXHBITMAP)::LoadBitmap(wxGetInstance(), name));
325
326 if ( !bitmap->Ok() )
327 {
328 // it's probably not found
329 wxLogError(wxT("Can't load bitmap '%s' from resources! Check .rc file."),
330 name.c_str());
331
332 return false;
333 }
334
335 BITMAP bm;
336 if ( !::GetObject(GetHbitmapOf(*bitmap), sizeof(BITMAP), (LPSTR) &bm) )
337 {
338 wxLogLastError(wxT("GetObject(HBITMAP)"));
339 }
340
341 bitmap->SetWidth(bm.bmWidth);
342 bitmap->SetHeight(bm.bmHeight);
343 bitmap->SetDepth(bm.bmBitsPixel);
344
345 return true;
346 }
347
348 bool wxBMPFileHandler::LoadFile(wxBitmap *bitmap,
349 const wxString& name, long WXUNUSED(flags),
350 int WXUNUSED(desiredWidth),
351 int WXUNUSED(desiredHeight))
352 {
353 #if wxUSE_IMAGE_LOADING_IN_MSW
354 wxPalette *palette = NULL;
355 bool success = wxLoadIntoBitmap(WXSTRINGCAST name, bitmap, &palette) != 0;
356
357 #if wxUSE_PALETTE
358 if ( success && palette )
359 {
360 bitmap->SetPalette(*palette);
361 }
362
363 // it was copied by the bitmap if it was loaded successfully
364 delete palette;
365 #endif // wxUSE_PALETTE
366
367 return success;
368 #else
369 return false;
370 #endif
371 }
372
373 bool wxBMPFileHandler::SaveFile(wxBitmap *bitmap,
374 const wxString& name,
375 int WXUNUSED(type),
376 const wxPalette *pal)
377 {
378 #if wxUSE_IMAGE_LOADING_IN_MSW
379
380 #if wxUSE_PALETTE
381 wxPalette *actualPalette = (wxPalette *)pal;
382 if ( !actualPalette )
383 actualPalette = bitmap->GetPalette();
384 #else
385 wxPalette *actualPalette = NULL;
386 #endif // wxUSE_PALETTE
387
388 return wxSaveBitmap(WXSTRINGCAST name, bitmap, actualPalette) != 0;
389 #else
390 return false;
391 #endif
392 }
393
394 // ----------------------------------------------------------------------------
395 // wxIcon handlers
396 // ----------------------------------------------------------------------------
397
398 bool wxICOFileHandler::LoadIcon(wxIcon *icon,
399 const wxString& name,
400 long WXUNUSED(flags),
401 int desiredWidth, int desiredHeight)
402 {
403 #if wxUSE_RESOURCE_LOADING_IN_MSW
404 icon->UnRef();
405
406 // actual size
407 wxSize size;
408
409 #ifdef __WIN32__
410 HICON hicon = NULL;
411
412 // Parse the filename: it may be of the form "filename;n" in order to
413 // specify the nth icon in the file.
414 //
415 // For the moment, ignore the issue of possible semicolons in the
416 // filename.
417 int iconIndex = 0;
418 wxString nameReal(name);
419 wxString strIconIndex = name.AfterLast(wxT(';'));
420 if (strIconIndex != name)
421 {
422 iconIndex = wxAtoi(strIconIndex);
423 nameReal = name.BeforeLast(wxT(';'));
424 }
425
426 #if 0
427 // If we don't know what size icon we're looking for,
428 // try to find out what's there.
429 // Unfortunately this doesn't work, because ExtractIconEx
430 // will scale the icon to the 'desired' size, even if that
431 // size of icon isn't explicitly stored. So we would have
432 // to parse the icon file outselves.
433 if ( desiredWidth == -1 &&
434 desiredHeight == -1)
435 {
436 // Try loading a large icon first
437 if ( ::ExtractIconEx(nameReal, iconIndex, &hicon, NULL, 1) == 1)
438 {
439 }
440 // Then try loading a small icon
441 else if ( ::ExtractIconEx(nameReal, iconIndex, NULL, &hicon, 1) == 1)
442 {
443 }
444 }
445 else
446 #endif
447 // were we asked for a large icon?
448 if ( desiredWidth == ::GetSystemMetrics(SM_CXICON) &&
449 desiredHeight == ::GetSystemMetrics(SM_CYICON) )
450 {
451 // get the specified large icon from file
452 if ( !::ExtractIconEx(nameReal, iconIndex, &hicon, NULL, 1) )
453 {
454 // it is not an error, but it might still be useful to be informed
455 // about it optionally
456 wxLogTrace(_T("iconload"),
457 _T("No large icons found in the file '%s'."),
458 name.c_str());
459 }
460 }
461 else if ( desiredWidth == ::GetSystemMetrics(SM_CXSMICON) &&
462 desiredHeight == ::GetSystemMetrics(SM_CYSMICON) )
463 {
464 // get the specified small icon from file
465 if ( !::ExtractIconEx(nameReal, iconIndex, NULL, &hicon, 1) )
466 {
467 wxLogTrace(_T("iconload"),
468 _T("No small icons found in the file '%s'."),
469 name.c_str());
470 }
471 }
472 //else: not standard size, load below
473
474 if ( !hicon )
475 {
476 // take any size icon from the file by index
477 hicon = ::ExtractIcon(wxGetInstance(), nameReal, iconIndex);
478 }
479
480 if ( !hicon )
481 {
482 wxLogSysError(_T("Failed to load icon from the file '%s'"),
483 name.c_str());
484
485 return false;
486 }
487
488 size = wxGetHiconSize(hicon);
489 #else // Win16
490 HICON hicon = ReadIconFile((wxChar *)name.c_str(),
491 wxGetInstance(),
492 &size.x, &size.y);
493 #endif // Win32/Win16
494
495 if ( (desiredWidth != -1 && desiredWidth != size.x) ||
496 (desiredHeight != -1 && desiredHeight != size.y) )
497 {
498 wxLogTrace(_T("iconload"),
499 _T("Returning false from wxICOFileHandler::Load because of the size mismatch: actual (%d, %d), requested (%d, %d)"),
500 size.x, size.y,
501 desiredWidth, desiredHeight);
502
503 ::DestroyIcon(hicon);
504
505 return false;
506 }
507
508 icon->SetHICON((WXHICON)hicon);
509 icon->SetSize(size.x, size.y);
510
511 return icon->Ok();
512 #else
513 return false;
514 #endif
515 }
516
517 bool wxICOResourceHandler::LoadIcon(wxIcon *icon,
518 const wxString& name,
519 long WXUNUSED(flags),
520 int desiredWidth, int desiredHeight)
521 {
522 HICON hicon;
523
524 // do we need the icon of the specific size or would any icon do?
525 bool hasSize = desiredWidth != -1 || desiredHeight != -1;
526
527 wxASSERT_MSG( !hasSize || (desiredWidth != -1 && desiredHeight != -1),
528 _T("width and height should be either both -1 or not") );
529
530 // try to load the icon from this program first to allow overriding the
531 // standard icons (although why one would want to do it considering that
532 // we already have wxApp::GetStdIcon() is unclear)
533
534 // note that we can't just always call LoadImage() because it seems to do
535 // some icon rescaling internally which results in very ugly 16x16 icons
536 #if defined(__WIN32__) && !defined(__SC__)
537 if ( hasSize )
538 {
539 hicon = (HICON)::LoadImage(wxGetInstance(), name, IMAGE_ICON,
540 desiredWidth, desiredHeight,
541 LR_DEFAULTCOLOR);
542 }
543 else
544 #endif // Win32/!Win32
545 {
546 hicon = ::LoadIcon(wxGetInstance(), name);
547 }
548
549 // next check if it's not a standard icon
550 if ( !hicon && !hasSize )
551 {
552 static const struct
553 {
554 const wxChar *name;
555 LPTSTR id;
556 } stdIcons[] =
557 {
558 { wxT("wxICON_QUESTION"), IDI_QUESTION },
559 { wxT("wxICON_WARNING"), IDI_EXCLAMATION },
560 { wxT("wxICON_ERROR"), IDI_HAND },
561 { wxT("wxICON_INFORMATION"), IDI_ASTERISK },
562 };
563
564 for ( size_t nIcon = 0; !hicon && nIcon < WXSIZEOF(stdIcons); nIcon++ )
565 {
566 if ( name == stdIcons[nIcon].name )
567 {
568 hicon = ::LoadIcon((HINSTANCE)NULL, stdIcons[nIcon].id);
569 }
570 }
571 }
572
573 wxSize size = wxGetHiconSize(hicon);
574 icon->SetSize(size.x, size.y);
575
576 icon->SetHICON((WXHICON)hicon);
577
578 return icon->Ok();
579 }
580
581 // ----------------------------------------------------------------------------
582 // private functions
583 // ----------------------------------------------------------------------------
584
585 wxSize wxGetHiconSize(HICON hicon)
586 {
587 wxSize size(32, 32); // default
588
589 #ifdef __WIN32__
590 // Win32s doesn't have GetIconInfo function...
591 if ( hicon && wxGetOsVersion() != wxWIN32S )
592 {
593 ICONINFO info;
594 if ( !::GetIconInfo(hicon, &info) )
595 {
596 wxLogLastError(wxT("GetIconInfo"));
597 }
598 else
599 {
600 HBITMAP hbmp = info.hbmMask;
601 if ( hbmp )
602 {
603 BITMAP bm;
604 if ( ::GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm) )
605 {
606 size = wxSize(bm.bmWidth, bm.bmHeight);
607 }
608
609 ::DeleteObject(info.hbmMask);
610 }
611 if ( info.hbmColor )
612 ::DeleteObject(info.hbmColor);
613 }
614 }
615 #endif
616
617 return size;
618 }
619 #endif
620 // __WXMICROWIN__