1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/statbmp.cpp
3 // Purpose:     wxStaticBitmap
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     04/01/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14 
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #if wxUSE_STATBMP
27 
28 #include "wx/statbmp.h"
29 
30 #ifndef WX_PRECOMP
31     #include "wx/app.h"
32     #include "wx/window.h"
33     #include "wx/icon.h"
34     #include "wx/dcclient.h"
35 #endif
36 
37 #include "wx/msw/private.h"
38 #include "wx/msw/dib.h"
39 
40 #include "wx/sysopt.h"
41 
42 #include <stdio.h>
43 
44 // ---------------------------------------------------------------------------
45 // macros
46 // ---------------------------------------------------------------------------
47 
wxBEGIN_EVENT_TABLE(wxStaticBitmap,wxStaticBitmapBase)48 wxBEGIN_EVENT_TABLE(wxStaticBitmap, wxStaticBitmapBase)
49     EVT_SIZE(wxStaticBitmap::WXHandleSize)
50 wxEND_EVENT_TABLE()
51 
52 // ===========================================================================
53 // implementation
54 // ===========================================================================
55 
56 // ---------------------------------------------------------------------------
57 // wxStaticBitmap
58 // ---------------------------------------------------------------------------
59 
60 // we may have either bitmap or icon: if a bitmap with mask is passed, we
61 // will transform it to an icon ourselves because otherwise the mask will
62 // be ignored by Windows
63 // note that this function will create a new object every time
64 // it is called even if the image needs no conversion
65 
66 static wxGDIImage* ConvertImage( const wxGDIImage& bitmap )
67 {
68     bool isIcon = bitmap.IsKindOf( wxCLASSINFO(wxIcon) );
69 
70     if( !isIcon )
71     {
72         wxASSERT_MSG( wxDynamicCast(&bitmap, wxBitmap),
73                       wxT("not an icon and not a bitmap?") );
74 
75         const wxBitmap& bmp = (const wxBitmap&)bitmap;
76         wxMask *mask = bmp.GetMask();
77         if ( mask && mask->GetMaskBitmap() )
78         {
79             wxIcon* icon = new wxIcon;
80             icon->CopyFromBitmap(bmp);
81 
82             return icon;
83         }
84 
85         return new wxBitmap( bmp );
86     }
87 
88     // copying a bitmap is a cheap operation
89     return new wxIcon( (const wxIcon&)bitmap );
90 }
91 
Create(wxWindow * parent,wxWindowID id,const wxGDIImage & bitmap,const wxPoint & pos,const wxSize & size,long style,const wxString & name)92 bool wxStaticBitmap::Create(wxWindow *parent,
93                             wxWindowID id,
94                             const wxGDIImage& bitmap,
95                             const wxPoint& pos,
96                             const wxSize& size,
97                             long style,
98                             const wxString& name)
99 {
100     if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
101         return false;
102 
103     // we may have either bitmap or icon: if a bitmap with mask is passed, we
104     // will transform it to an icon ourselves because otherwise the mask will
105     // be ignored by Windows
106     m_isIcon = bitmap.IsKindOf(wxCLASSINFO(wxIcon));
107 
108     wxGDIImage *image = ConvertImage( bitmap );
109     m_isIcon = image->IsKindOf( wxCLASSINFO(wxIcon) );
110 
111     // create the native control
112     if ( !MSWCreateControl(wxT("STATIC"), wxEmptyString, pos, size) )
113     {
114         // control creation failed
115         return false;
116     }
117 
118     // no need to delete the new image
119     SetImageNoCopy(image);
120 
121     // GetBestSize will work properly now, so set the best size if needed
122     SetInitialSize(size);
123 
124     // painting manually is reported not to work under Windows CE (see #10093),
125     // so don't do it there even if this probably means that alpha is not
126     // supported there -- but at least bitmaps without alpha appear correctly
127 #ifndef __WXWINCE__
128     // Windows versions before XP (and even XP if the application has no
129     // manifest and so the old comctl32.dll is used) don't draw correctly the
130     // images with alpha channel so we need to draw them ourselves and it's
131     // easier to just always do it rather than check if we have an image with
132     // alpha or not
133     if ( wxTheApp->GetComCtl32Version() < 600 )
134     {
135         Connect(wxEVT_PAINT, wxPaintEventHandler(wxStaticBitmap::DoPaintManually));
136     }
137 #endif // !__WXWINCE__
138 
139     return true;
140 }
141 
MSWGetStyle(long style,WXDWORD * exstyle) const142 WXDWORD wxStaticBitmap::MSWGetStyle(long style, WXDWORD *exstyle) const
143 {
144     WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
145 
146     // what kind of control are we?
147     msStyle |= m_isIcon ? SS_ICON : SS_BITMAP;
148 
149     // we use SS_CENTERIMAGE to prevent the control from resizing the bitmap to
150     // fit to its size -- this is unexpected and doesn't happen in other ports
151     //
152     // and SS_NOTIFY is necessary to receive mouse events
153     msStyle |= SS_CENTERIMAGE | SS_NOTIFY;
154 
155     return msStyle;
156 }
157 
ImageIsOk() const158 bool wxStaticBitmap::ImageIsOk() const
159 {
160     return m_image && m_image->IsOk();
161 }
162 
GetIcon() const163 wxIcon wxStaticBitmap::GetIcon() const
164 {
165     wxCHECK_MSG( m_image, wxIcon(), wxT("no image in wxStaticBitmap") );
166 
167     // we can't ask for an icon if all we have is a bitmap
168     wxCHECK_MSG( m_isIcon, wxIcon(), wxT("no icon in this wxStaticBitmap") );
169 
170     return *(wxIcon *)m_image;
171 }
172 
GetBitmap() const173 wxBitmap wxStaticBitmap::GetBitmap() const
174 {
175     if ( m_isIcon )
176     {
177         // don't fail because we might have replaced the bitmap with icon
178         // ourselves internally in ConvertImage() to keep the transparency but
179         // the user code doesn't know about it so it still can use GetBitmap()
180         // to retrieve the bitmap
181         return wxBitmap(GetIcon());
182     }
183     else // we have a bitmap
184     {
185         wxCHECK_MSG( m_image, wxBitmap(), wxT("no image in wxStaticBitmap") );
186 
187         return *(wxBitmap *)m_image;
188     }
189 }
190 
Free()191 void wxStaticBitmap::Free()
192 {
193     MSWReplaceImageHandle(0);
194 
195     wxDELETE(m_image);
196 }
197 
DoGetBestClientSize() const198 wxSize wxStaticBitmap::DoGetBestClientSize() const
199 {
200     wxSize size;
201     if ( ImageIsOk() )
202     {
203         size = m_image->GetSize();
204     }
205     else // No image yet
206     {
207         // this is completely arbitrary
208         size.x =
209         size.y = 16;
210     }
211 
212     return size;
213 }
214 
WXHandleSize(wxSizeEvent & event)215 void wxStaticBitmap::WXHandleSize(wxSizeEvent& event)
216 {
217     // Invalidate everything when our size changes as the image position (it's
218     // drawn centred in the window client area) changes.
219     Refresh();
220 
221     event.Skip();
222 }
223 
224 #ifndef __WXWINCE__
225 
DoPaintManually(wxPaintEvent & WXUNUSED (event))226 void wxStaticBitmap::DoPaintManually(wxPaintEvent& WXUNUSED(event))
227 {
228     wxPaintDC dc(this);
229 
230     const wxSize size(GetSize());
231     const wxBitmap bmp(GetBitmap());
232 
233     // Clear the background: notice that we're supposed to be transparent, so
234     // use the parent background colour if we don't have our own instead of
235     // falling back to the default
236     const wxWindow *win = UseBgCol() ? this : GetParent();
237     dc.SetBrush(win->GetBackgroundColour());
238     dc.SetPen(*wxTRANSPARENT_PEN);
239     dc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());
240 
241     // Draw the image in the middle
242     dc.DrawBitmap(bmp,
243                   (size.GetWidth() - bmp.GetWidth()) / 2,
244                   (size.GetHeight() - bmp.GetHeight()) / 2,
245                   true /* use mask */);
246 }
247 
248 #endif // !__WXWINCE__
249 
SetImage(const wxGDIImage * image)250 void wxStaticBitmap::SetImage( const wxGDIImage* image )
251 {
252     wxGDIImage* convertedImage = ConvertImage( *image );
253     SetImageNoCopy( convertedImage );
254 }
255 
MSWReplaceImageHandle(WXLPARAM handle)256 void wxStaticBitmap::MSWReplaceImageHandle(WXLPARAM handle)
257 {
258     HGDIOBJ oldHandle = (HGDIOBJ)::SendMessage(GetHwnd(), STM_SETIMAGE,
259                   m_isIcon ? IMAGE_ICON : IMAGE_BITMAP, (LPARAM)handle);
260     // detect if this is still the handle we passed before or
261     // if the static-control made a copy of the bitmap!
262     if (oldHandle != 0 && oldHandle != (HGDIOBJ) m_currentHandle)
263     {
264         // the static control made a copy and we are responsible for deleting it
265         ::DeleteObject((HGDIOBJ) oldHandle);
266     }
267 }
268 
SetImageNoCopy(wxGDIImage * image)269 void wxStaticBitmap::SetImageNoCopy( wxGDIImage* image)
270 {
271     Free();
272     InvalidateBestSize();
273 
274     m_isIcon = image->IsKindOf( wxCLASSINFO(wxIcon) );
275     // the image has already been copied
276     m_image = image;
277 
278     int x, y;
279     int w, h;
280     GetPosition(&x, &y);
281     GetSize(&w, &h);
282 
283 #ifdef __WIN32__
284     HANDLE handle = (HANDLE)m_image->GetHandle();
285 
286     AutoHBITMAP hbmpRelease;
287     if ( !m_isIcon )
288     {
289         // wxBitmap normally stores alpha in pre-multiplied format but
290         // apparently STM_SETIMAGE message handler does pre-multiplication
291         // internally so we need to undo the pre-multiplication here for a
292         // while (this is similar to what we do in ImageList::Add()).
293         const wxBitmap& bmp = static_cast<wxBitmap&>(*image);
294         if ( bmp.HasAlpha() )
295         {
296             // For bitmap with alpha channel create temporary DIB with
297             // not-premultiplied alpha values.
298             handle = wxDIB(bmp.ConvertToImage(),
299                            wxDIB::PixelFormat_NotPreMultiplied).Detach();
300 
301             // Ensure that this temporary HBITMAP will be destroyed.
302             hbmpRelease.Init((HBITMAP)handle);
303         }
304     }
305     LONG style = ::GetWindowLong( (HWND)GetHWND(), GWL_STYLE ) ;
306     ::SetWindowLong( (HWND)GetHWND(), GWL_STYLE, ( style & ~( SS_BITMAP|SS_ICON ) ) |
307                      ( m_isIcon ? SS_ICON : SS_BITMAP ) );
308 
309     MSWReplaceImageHandle((WXLPARAM)handle);
310 
311     // Save bitmap handle only if it's not a temporary one, otherwise it's
312     // going to be destroyed right now anyhow.
313     if ( !hbmpRelease )
314         m_currentHandle = (WXHANDLE)handle;
315 
316 #endif // Win32
317 
318     if ( ImageIsOk() )
319     {
320         int width = image->GetWidth(),
321             height = image->GetHeight();
322         if ( width && height )
323         {
324             w = width;
325             h = height;
326 
327             ::MoveWindow(GetHwnd(), x, y, width, height, FALSE);
328         }
329     }
330 
331     RECT rect;
332     rect.left   = x;
333     rect.top    = y;
334     rect.right  = x + w;
335     rect.bottom = y + h;
336     ::InvalidateRect(GetHwndOf(GetParent()), &rect, TRUE);
337 }
338 
339 #endif // wxUSE_STATBMP
340