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