]> git.saurik.com Git - wxWidgets.git/blame - src/generic/bannerwindow.cpp
Disable wxUSE_ENH_METAFILE for wxGTK builds.
[wxWidgets.git] / src / generic / bannerwindow.cpp
CommitLineData
ea11bf3a
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: wx/bannerwindow.h
3// Purpose: wxBannerWindow class implementation
4// Author: Vadim Zeitlin
5// Created: 2011-08-16
6// RCS-ID: $Id$
7// Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
17#if wxUSE_BANNERWINDOW
18
19#include "wx/bannerwindow.h"
20
21#ifndef WX_PRECOMP
22 #include "wx/bitmap.h"
23 #include "wx/colour.h"
24#endif
25
26#include "wx/dcbuffer.h"
27
28namespace
29{
30
31// Some constants for banner layout, currently they're hard coded but we could
32// easily make them configurable if needed later.
33const int MARGIN_X = 5;
34const int MARGIN_Y = 5;
35
36} // anonymous namespace
37
94ed214d 38const char wxBannerWindowNameStr[] = "bannerwindow";
ea11bf3a
VZ
39
40BEGIN_EVENT_TABLE(wxBannerWindow, wxWindow)
41 EVT_SIZE(wxBannerWindow::OnSize)
42 EVT_PAINT(wxBannerWindow::OnPaint)
43END_EVENT_TABLE()
44
45void wxBannerWindow::Init()
46{
47 m_direction = wxLEFT;
48
49 m_colStart = *wxWHITE;
50 m_colEnd = *wxBLUE;
51}
52
53bool
54wxBannerWindow::Create(wxWindow* parent,
55 wxWindowID winid,
56 wxDirection dir,
57 const wxPoint& pos,
58 const wxSize& size,
59 long style,
60 const wxString& name)
61{
62 if ( !wxWindow::Create(parent, winid, pos, size, style, name) )
63 return false;
64
65 wxASSERT_MSG
66 (
67 dir == wxLEFT || dir == wxRIGHT || dir == wxTOP || dir == wxBOTTOM,
68 wxS("Invalid banner direction")
69 );
70
71 m_direction = dir;
72
73 SetBackgroundStyle(wxBG_STYLE_PAINT);
74
75 return true;
76}
77
78void wxBannerWindow::SetBitmap(const wxBitmap& bmp)
79{
80 m_bitmap = bmp;
81
4e2b91bb
VZ
82 m_colBitmapBg = wxColour();
83
ea11bf3a
VZ
84 InvalidateBestSize();
85
86 Refresh();
87}
88
89void wxBannerWindow::SetText(const wxString& title, const wxString& message)
90{
91 m_title = title;
92 m_message = message;
93
94 InvalidateBestSize();
95
96 Refresh();
97}
98
99void wxBannerWindow::SetGradient(const wxColour& start, const wxColour& end)
100{
101 m_colStart = start;
102 m_colEnd = end;
103
104 Refresh();
105}
106
107wxFont wxBannerWindow::GetTitleFont() const
108{
109 wxFont font = GetFont();
110 font.MakeBold().MakeLarger();
111 return font;
112}
113
114wxSize wxBannerWindow::DoGetBestClientSize() const
115{
116 if ( m_bitmap.IsOk() )
117 {
118 return m_bitmap.GetSize();
119 }
120 else
121 {
122 wxClientDC dc(const_cast<wxBannerWindow *>(this));
123 const wxSize sizeText = dc.GetMultiLineTextExtent(m_message);
124
125 dc.SetFont(GetTitleFont());
126
127 const wxSize sizeTitle = dc.GetTextExtent(m_title);
128
129 wxSize sizeWin(wxMax(sizeTitle.x, sizeText.x), sizeTitle.y + sizeText.y);
130
131 // If we draw the text vertically width and height are swapped.
132 if ( m_direction == wxLEFT || m_direction == wxRIGHT )
133 wxSwap(sizeWin.x, sizeWin.y);
134
135 sizeWin += 2*wxSize(MARGIN_X, MARGIN_Y);
136
137 return sizeWin;
138 }
139}
140
141void wxBannerWindow::OnSize(wxSizeEvent& event)
142{
143 Refresh();
144
145 event.Skip();
146}
147
148void wxBannerWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
149{
150 if ( m_bitmap.IsOk() && m_title.empty() && m_message.empty() )
151 {
152 // No need for buffering in this case.
153 wxPaintDC dc(this);
154
155 DrawBitmapBackground(dc);
156 }
157 else // We need to compose our contents ourselves.
158 {
159 wxAutoBufferedPaintDC dc(this);
160
161 // Deal with the background first.
162 if ( m_bitmap.IsOk() )
163 {
164 DrawBitmapBackground(dc);
165 }
166 else // Draw gradient background.
167 {
168 wxDirection gradientDir;
169 if ( m_direction == wxLEFT )
170 {
171 gradientDir = wxTOP;
172 }
173 else if ( m_direction == wxRIGHT )
174 {
175 gradientDir = wxBOTTOM;
176 }
177 else // For both wxTOP and wxBOTTOM.
178 {
179 gradientDir = wxRIGHT;
180 }
181
182 dc.GradientFillLinear(GetClientRect(), m_colStart, m_colEnd,
183 gradientDir);
184 }
185
186 // Now draw the text on top of it.
187 dc.SetFont(GetTitleFont());
188
189 wxPoint pos(MARGIN_X, MARGIN_Y);
190 DrawBannerTextLine(dc, m_title, pos);
191 pos.y += dc.GetTextExtent(m_title).y;
192
193 dc.SetFont(GetFont());
194
195 wxArrayString lines = wxSplit(m_message, '\n', '\0');
196 const unsigned numLines = lines.size();
197 for ( unsigned n = 0; n < numLines; n++ )
198 {
199 const wxString& line = lines[n];
200
201 DrawBannerTextLine(dc, line, pos);
202 pos.y += dc.GetTextExtent(line).y;
203 }
204 }
205}
206
4e2b91bb 207wxColour wxBannerWindow::GetBitmapBg()
ea11bf3a 208{
4e2b91bb
VZ
209 if ( m_colBitmapBg.IsOk() )
210 return m_colBitmapBg;
211
212 // Determine the colour to use to extend the bitmap. It's the colour of the
213 // bitmap pixels at the edge closest to the area where it can be extended.
214 wxImage image(m_bitmap.ConvertToImage());
215
216 // The point we get the colour from. The choice is arbitrary and in general
217 // the bitmap should have the same colour on the entire edge of this point
218 // for extending it to look good.
219 wxPoint p;
220
221 wxSize size = image.GetSize();
222 size.x--;
223 size.y--;
224
ea11bf3a
VZ
225 switch ( m_direction )
226 {
227 case wxTOP:
228 case wxBOTTOM:
4e2b91bb
VZ
229 // The bitmap will be extended to the right.
230 p.x = size.x;
231 p.y = 0;
232 break;
233
234 case wxLEFT:
235 // The bitmap will be extended from the top.
236 p.x = 0;
237 p.y = 0;
238 break;
239
ea11bf3a 240 case wxRIGHT:
4e2b91bb
VZ
241 // The bitmap will be extended to the bottom.
242 p.x = 0;
243 p.y = size.y;
244 break;
245
246 // This case is there only to prevent g++ warnings about not handling
247 // some enum elements in the switch, it can't really happen.
248 case wxALL:
249 wxFAIL_MSG( wxS("Unreachable") );
250 }
251
252 m_colBitmapBg.Set(image.GetRed(p.x, p.y),
253 image.GetGreen(p.x, p.y),
254 image.GetBlue(p.x, p.y));
255
256 return m_colBitmapBg;
257}
258
259void wxBannerWindow::DrawBitmapBackground(wxDC& dc)
260{
261 // We may need to fill the part of the background not covered by the bitmap
262 // with the solid colour extending the bitmap, this rectangle will hold the
263 // area to be filled (which could be empty if the bitmap is big enough).
264 wxRect rectSolid;
265
266 const wxSize size = GetClientSize();
267
268 switch ( m_direction )
269 {
270 case wxTOP:
271 case wxBOTTOM:
272 // Draw the bitmap at the origin, its rightmost could be truncated,
273 // as it's meant to be.
ea11bf3a 274 dc.DrawBitmap(m_bitmap, 0, 0);
4e2b91bb
VZ
275
276 rectSolid.x = m_bitmap.GetWidth();
277 rectSolid.width = size.x - rectSolid.x;
278 rectSolid.height = size.y;
ea11bf3a
VZ
279 break;
280
281 case wxLEFT:
282 // The top most part of the bitmap may be truncated but its bottom
283 // must be always visible so intentionally draw it possibly partly
284 // outside of the window.
4e2b91bb
VZ
285 rectSolid.width = size.x;
286 rectSolid.height = size.y - m_bitmap.GetHeight();
287 dc.DrawBitmap(m_bitmap, 0, rectSolid.height);
288 break;
289
290 case wxRIGHT:
291 // Draw the bitmap at the origin, possibly truncating its
292 // bottommost part.
293 dc.DrawBitmap(m_bitmap, 0, 0);
294
295 rectSolid.y = m_bitmap.GetHeight();
296 rectSolid.height = size.y - rectSolid.y;
297 rectSolid.width = size.x;
ea11bf3a
VZ
298 break;
299
300 // This case is there only to prevent g++ warnings about not handling
301 // some enum elements in the switch, it can't really happen.
302 case wxALL:
303 wxFAIL_MSG( wxS("Unreachable") );
304 }
4e2b91bb
VZ
305
306 if ( rectSolid.width > 0 && rectSolid.height > 0 )
307 {
308 dc.SetPen(*wxTRANSPARENT_PEN);
309 dc.SetBrush(GetBitmapBg());
310 dc.DrawRectangle(rectSolid);
311 }
ea11bf3a
VZ
312}
313
314void
315wxBannerWindow::DrawBannerTextLine(wxDC& dc,
316 const wxString& str,
317 const wxPoint& pos)
318{
319 switch ( m_direction )
320 {
321 case wxTOP:
322 case wxBOTTOM:
323 // The simple case: we just draw the text normally.
324 dc.DrawText(str, pos);
325 break;
326
327 case wxLEFT:
328 // We draw the text vertically and start from the lower left
329 // corner and not the upper left one as usual.
330 dc.DrawRotatedText(str, pos.y, GetClientSize().y - pos.x, 90);
331 break;
332
333 case wxRIGHT:
334 // We also draw the text vertically but now we start from the upper
335 // right corner and draw it from top to bottom.
336 dc.DrawRotatedText(str, GetClientSize().x - pos.y, pos.x, -90);
337 break;
338
339 case wxALL:
340 wxFAIL_MSG( wxS("Unreachable") );
341 }
342}
343
344#endif // wxUSE_BANNERWINDOW