Compilation fix for VC6 in wxInfoBarGeneric code.
[wxWidgets.git] / src / generic / infobar.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/infobar.cpp
3 // Purpose: generic wxInfoBar implementation
4 // Author: Vadim Zeitlin
5 // Created: 2009-07-28
6 // RCS-ID: $Id: wxhead.cpp,v 1.10 2009-06-29 10:23:04 zeitlin Exp $
7 // Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
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_INFOBAR
27
28 #ifndef WX_PRECOMP
29 #include "wx/bmpbuttn.h"
30 #include "wx/button.h"
31 #include "wx/settings.h"
32 #include "wx/statbmp.h"
33 #include "wx/stattext.h"
34 #endif // WX_PRECOMP
35
36 #include "wx/infobar.h"
37
38 #include "wx/artprov.h"
39 #include "wx/renderer.h"
40 #include "wx/scopeguard.h"
41 #include "wx/sizer.h"
42
43 BEGIN_EVENT_TABLE(wxInfoBarGeneric, wxInfoBarBase)
44 EVT_BUTTON(wxID_ANY, wxInfoBarGeneric::OnButton)
45 END_EVENT_TABLE()
46
47 // ----------------------------------------------------------------------------
48 // local helpers
49 // ----------------------------------------------------------------------------
50
51 namespace
52 {
53
54 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
55
56 wxBitmap
57 GetCloseButtonBitmap(wxWindow *win,
58 const wxSize& size,
59 const wxColour& colBg,
60 int flags = 0)
61 {
62 wxBitmap bmp(size);
63 wxMemoryDC dc(bmp);
64 dc.SetBackground(colBg);
65 dc.Clear();
66 wxRendererNative::Get().
67 DrawTitleBarBitmap(win, dc, size, wxTITLEBAR_BUTTON_CLOSE, flags);
68 return bmp;
69 }
70
71 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
72
73 } // anonymous namespace
74
75 // ============================================================================
76 // implementation
77 // ============================================================================
78
79 void wxInfoBarGeneric::Init()
80 {
81 m_icon = NULL;
82 m_text = NULL;
83 m_button = NULL;
84
85 m_showEffect =
86 m_hideEffect = wxSHOW_EFFECT_MAX;
87
88 // use default effect duration
89 m_effectDuration = 0;
90 }
91
92 bool wxInfoBarGeneric::Create(wxWindow *parent, wxWindowID winid)
93 {
94 // calling Hide() before Create() ensures that we're created initially
95 // hidden
96 Hide();
97 if ( !wxWindow::Create(parent, winid) )
98 return false;
99
100 // use special, easy to notice, colours
101 const wxColour colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK);
102 SetBackgroundColour(colBg);
103 SetOwnForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
104
105 // create the controls: icon, text and the button to dismiss the
106 // message.
107
108 // the icon is not shown unless it's assigned a valid bitmap
109 m_icon = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
110
111 m_text = new wxStaticText(this, wxID_ANY, "");
112
113 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
114 const wxSize sizeBmp = wxArtProvider::GetSizeHint(wxART_BUTTON);
115 wxBitmap bmp = GetCloseButtonBitmap(this, sizeBmp, colBg);
116 #else // !wxHAS_DRAW_TITLE_BAR_BITMAP
117 wxBitmap bmp = wxArtProvider::GetBitmap(wxART_CLOSE, wxART_BUTTON);
118 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
119 m_button = new wxBitmapButton
120 (
121 this,
122 wxID_ANY,
123 bmp,
124 wxDefaultPosition,
125 wxDefaultSize,
126 wxBORDER_NONE
127 );
128
129 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
130 m_button->SetBitmapPressed(
131 GetCloseButtonBitmap(this, sizeBmp, colBg, wxCONTROL_PRESSED));
132
133 m_button->SetBitmapCurrent(
134 GetCloseButtonBitmap(this, sizeBmp, colBg, wxCONTROL_CURRENT));
135 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
136
137 m_button->SetBackgroundColour(colBg);
138 m_button->SetToolTip(_("Hide this notification message."));
139
140 // center the text inside the sizer with an icon to the left of it and a
141 // button at the very right
142 //
143 // NB: AddButton() relies on the button being the last control in the sizer
144 // and being preceded by a spacer
145 wxSizer * const sizer = new wxBoxSizer(wxHORIZONTAL);
146 sizer->Add(m_icon, wxSizerFlags().Centre().Border());
147 sizer->Add(m_text, wxSizerFlags().Centre());
148 sizer->AddStretchSpacer();
149 sizer->Add(m_button, wxSizerFlags().Centre().Border());
150 SetSizer(sizer);
151
152 return true;
153 }
154
155 bool wxInfoBarGeneric::SetFont(const wxFont& font)
156 {
157 if ( !wxInfoBarBase::SetFont(font) )
158 return false;
159
160 // check that we're not called before Create()
161 if ( m_text )
162 m_text->SetFont(font);
163
164 return true;
165 }
166
167 wxInfoBarGeneric::BarPlacement wxInfoBarGeneric::GetBarPlacement() const
168 {
169 wxSizer * const sizer = GetContainingSizer();
170 if ( !sizer )
171 return BarPlacement_Unknown;
172
173 // FIXME-VC6: can't compare "const wxInfoBarGeneric *" and "wxWindow *",
174 // so need this workaround
175 wxWindow * const self = const_cast<wxInfoBarGeneric *>(this);
176 const wxSizerItemList& siblings = sizer->GetChildren();
177 if ( siblings.GetFirst()->GetData()->GetWindow() == self )
178 return BarPlacement_Top;
179 else if ( siblings.GetLast()->GetData()->GetWindow() == self )
180 return BarPlacement_Bottom;
181 else
182 return BarPlacement_Unknown;
183 }
184
185 wxShowEffect wxInfoBarGeneric::GetShowEffect() const
186 {
187 if ( m_showEffect != wxSHOW_EFFECT_MAX )
188 return m_showEffect;
189
190 switch ( GetBarPlacement() )
191 {
192 case BarPlacement_Top:
193 return wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
194
195 case BarPlacement_Bottom:
196 return wxSHOW_EFFECT_SLIDE_TO_TOP;
197
198 default:
199 wxFAIL_MSG( "unknown info bar placement" );
200 // fall through
201
202 case BarPlacement_Unknown:
203 return wxSHOW_EFFECT_NONE;
204 }
205 }
206
207 wxShowEffect wxInfoBarGeneric::GetHideEffect() const
208 {
209 if ( m_hideEffect != wxSHOW_EFFECT_MAX )
210 return m_hideEffect;
211
212 switch ( GetBarPlacement() )
213 {
214 case BarPlacement_Top:
215 return wxSHOW_EFFECT_SLIDE_TO_TOP;
216
217 case BarPlacement_Bottom:
218 return wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
219
220 default:
221 wxFAIL_MSG( "unknown info bar placement" );
222 // fall through
223
224 case BarPlacement_Unknown:
225 return wxSHOW_EFFECT_NONE;
226 }
227 }
228
229 void wxInfoBarGeneric::UpdateParent()
230 {
231 wxWindow * const parent = wxGetTopLevelParent(GetParent());
232 parent->Layout();
233 }
234
235 void wxInfoBarGeneric::DoHide()
236 {
237 HideWithEffect(GetHideEffect(), GetEffectDuration());
238
239 UpdateParent();
240 }
241
242 void wxInfoBarGeneric::DoShow()
243 {
244 // re-layout the parent first so that the window expands into an already
245 // unoccupied by the other controls area: for this we need to change our
246 // internal visibility flag to force Layout() to take us into account (an
247 // alternative solution to this hack would be to temporarily set
248 // wxRESERVE_SPACE_EVEN_IF_HIDDEN flag but it's not really batter)
249
250 // just change the internal flag indicating that the window is visible,
251 // without really showing it
252 wxWindowBase::Show();
253
254 // adjust the parent layout to account for us
255 UpdateParent();
256
257 // reset the flag back before really showing the window or it wouldn't be
258 // shown at all because it would believe itself already visible
259 wxWindowBase::Show(false);
260
261
262 // finally do really show the window.
263 ShowWithEffect(GetShowEffect(), GetEffectDuration());
264 }
265
266 void wxInfoBarGeneric::ShowMessage(const wxString& msg, int flags)
267 {
268 // first update the controls
269 const int icon = flags & wxICON_MASK;
270 if ( !icon || (icon == wxICON_NONE) )
271 {
272 m_icon->Hide();
273 }
274 else // do show an icon
275 {
276 m_icon->SetBitmap(wxArtProvider::GetBitmap(
277 wxArtProvider::GetMessageBoxIconId(flags),
278 wxART_BUTTON));
279 m_icon->Show();
280 }
281
282 // notice the use of EscapeMnemonics() to ensure that "&" come through
283 // correctly
284 m_text->SetLabel(wxControl::EscapeMnemonics(msg));
285
286
287 // then show this entire window if not done yet
288 if ( !IsShown() )
289 {
290 DoShow();
291 }
292 else // we're already shown
293 {
294 // just update the layout to correspond to the new message
295 Layout();
296 }
297 }
298
299 void wxInfoBarGeneric::Dismiss()
300 {
301 DoHide();
302 }
303
304 void wxInfoBarGeneric::AddButton(wxWindowID btnid, const wxString& label)
305 {
306 wxSizer * const sizer = GetSizer();
307 wxCHECK_RET( sizer, "must be created first" );
308
309 // user-added buttons replace the standard close button so remove it if we
310 // hadn't done it yet
311 if ( sizer->Detach(m_button) )
312 {
313 m_button->Hide();
314 }
315
316 wxButton * const button = new wxButton(this, btnid, label);
317
318 #ifdef __WXMAC__
319 // smaller buttons look better in the (narrow) info bar under OS X
320 button->SetWindowVariant(wxWINDOW_VARIANT_SMALL);
321 #endif // __WXMAC__
322
323 sizer->Add(button, wxSizerFlags().Centre().DoubleBorder());
324 }
325
326 void wxInfoBarGeneric::RemoveButton(wxWindowID btnid)
327 {
328 wxSizer * const sizer = GetSizer();
329 wxCHECK_RET( sizer, "must be created first" );
330
331 // iterate over the sizer items in reverse order to find the last added
332 // button with this id (ids of all buttons should be unique anyhow but if
333 // they are repeated removing the last added one probably makes more sense)
334 const wxSizerItemList& items = sizer->GetChildren();
335 for ( wxSizerItemList::compatibility_iterator node = items.GetLast();
336 node != items.GetFirst();
337 node = node->GetPrevious() )
338 {
339 const wxSizerItem * const item = node->GetData();
340
341 // if we reached the spacer separating the buttons from the text
342 // preceding them without finding our button, it must mean it's not
343 // there at all
344 if ( item->IsSpacer() )
345 {
346 wxFAIL_MSG( wxString::Format("button with id %d not found", btnid) );
347 return;
348 }
349
350 // check if we found our button
351 if ( item->GetWindow()->GetId() == btnid )
352 {
353 delete item->GetWindow();
354 break;
355 }
356 }
357
358 // check if there are any custom buttons left
359 if ( sizer->GetChildren().GetLast()->GetData()->IsSpacer() )
360 {
361 // if the last item is the spacer, none are left so restore the
362 // standard close button
363 sizer->Add(m_button, wxSizerFlags().Centre().DoubleBorder());
364 m_button->Show();
365 }
366 }
367
368 void wxInfoBarGeneric::OnButton(wxCommandEvent& WXUNUSED(event))
369 {
370 DoHide();
371 }
372
373 #endif // wxUSE_INFOBAR