1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/infobar.cpp
3 // Purpose: generic wxInfoBar implementation
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
27 #include "wx/infobar.h"
30 #include "wx/bmpbuttn.h"
31 #include "wx/button.h"
32 #include "wx/dcmemory.h"
33 #include "wx/settings.h"
34 #include "wx/statbmp.h"
35 #include "wx/stattext.h"
39 #include "wx/artprov.h"
40 #include "wx/scopeguard.h"
42 BEGIN_EVENT_TABLE(wxInfoBarGeneric
, wxInfoBarBase
)
43 EVT_BUTTON(wxID_ANY
, wxInfoBarGeneric::OnButton
)
46 // ============================================================================
48 // ============================================================================
50 void wxInfoBarGeneric::Init()
57 m_hideEffect
= wxSHOW_EFFECT_MAX
;
59 // use default effect duration
63 bool wxInfoBarGeneric::Create(wxWindow
*parent
, wxWindowID winid
)
65 // calling Hide() before Create() ensures that we're created initially
68 if ( !wxWindow::Create(parent
, winid
) )
71 // use special, easy to notice, colours
72 const wxColour colBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK
);
73 SetBackgroundColour(colBg
);
74 SetOwnForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT
));
76 // create the controls: icon, text and the button to dismiss the
79 // the icon is not shown unless it's assigned a valid bitmap
80 m_icon
= new wxStaticBitmap(this, wxID_ANY
, wxNullBitmap
);
82 m_text
= new wxStaticText(this, wxID_ANY
, "");
84 m_button
= wxBitmapButton::NewCloseButton(this, wxID_ANY
);
85 m_button
->SetToolTip(_("Hide this notification message."));
87 // center the text inside the sizer with an icon to the left of it and a
88 // button at the very right
90 // NB: AddButton() relies on the button being the last control in the sizer
91 // and being preceded by a spacer
92 wxSizer
* const sizer
= new wxBoxSizer(wxHORIZONTAL
);
93 sizer
->Add(m_icon
, wxSizerFlags().Centre().Border());
94 sizer
->Add(m_text
, wxSizerFlags().Centre());
95 sizer
->AddStretchSpacer();
96 sizer
->Add(m_button
, wxSizerFlags().Centre().Border());
102 bool wxInfoBarGeneric::SetFont(const wxFont
& font
)
104 if ( !wxInfoBarBase::SetFont(font
) )
107 // check that we're not called before Create()
109 m_text
->SetFont(font
);
114 wxInfoBarGeneric::BarPlacement
wxInfoBarGeneric::GetBarPlacement() const
116 wxSizer
* const sizer
= GetContainingSizer();
118 return BarPlacement_Unknown
;
120 // FIXME-VC6: can't compare "const wxInfoBarGeneric *" and "wxWindow *",
121 // so need this workaround
122 wxWindow
* const self
= const_cast<wxInfoBarGeneric
*>(this);
123 const wxSizerItemList
& siblings
= sizer
->GetChildren();
124 if ( siblings
.GetFirst()->GetData()->GetWindow() == self
)
125 return BarPlacement_Top
;
126 else if ( siblings
.GetLast()->GetData()->GetWindow() == self
)
127 return BarPlacement_Bottom
;
129 return BarPlacement_Unknown
;
132 wxShowEffect
wxInfoBarGeneric::GetShowEffect() const
134 if ( m_showEffect
!= wxSHOW_EFFECT_MAX
)
137 switch ( GetBarPlacement() )
139 case BarPlacement_Top
:
140 return wxSHOW_EFFECT_SLIDE_TO_BOTTOM
;
142 case BarPlacement_Bottom
:
143 return wxSHOW_EFFECT_SLIDE_TO_TOP
;
146 wxFAIL_MSG( "unknown info bar placement" );
149 case BarPlacement_Unknown
:
150 return wxSHOW_EFFECT_NONE
;
154 wxShowEffect
wxInfoBarGeneric::GetHideEffect() const
156 if ( m_hideEffect
!= wxSHOW_EFFECT_MAX
)
159 switch ( GetBarPlacement() )
161 case BarPlacement_Top
:
162 return wxSHOW_EFFECT_SLIDE_TO_TOP
;
164 case BarPlacement_Bottom
:
165 return wxSHOW_EFFECT_SLIDE_TO_BOTTOM
;
168 wxFAIL_MSG( "unknown info bar placement" );
171 case BarPlacement_Unknown
:
172 return wxSHOW_EFFECT_NONE
;
176 void wxInfoBarGeneric::UpdateParent()
178 wxWindow
* const parent
= GetParent();
182 void wxInfoBarGeneric::DoHide()
184 HideWithEffect(GetHideEffect(), GetEffectDuration());
189 void wxInfoBarGeneric::DoShow()
191 // re-layout the parent first so that the window expands into an already
192 // unoccupied by the other controls area: for this we need to change our
193 // internal visibility flag to force Layout() to take us into account (an
194 // alternative solution to this hack would be to temporarily set
195 // wxRESERVE_SPACE_EVEN_IF_HIDDEN flag but it's not really batter)
197 // just change the internal flag indicating that the window is visible,
198 // without really showing it
199 wxWindowBase::Show();
201 // adjust the parent layout to account for us
204 // reset the flag back before really showing the window or it wouldn't be
205 // shown at all because it would believe itself already visible
206 wxWindowBase::Show(false);
209 // finally do really show the window.
210 ShowWithEffect(GetShowEffect(), GetEffectDuration());
213 void wxInfoBarGeneric::ShowMessage(const wxString
& msg
, int flags
)
215 // first update the controls
216 const int icon
= flags
& wxICON_MASK
;
217 if ( !icon
|| (icon
== wxICON_NONE
) )
221 else // do show an icon
223 m_icon
->SetBitmap(wxArtProvider::GetBitmap(
224 wxArtProvider::GetMessageBoxIconId(flags
),
229 // notice the use of EscapeMnemonics() to ensure that "&" come through
231 m_text
->SetLabel(wxControl::EscapeMnemonics(msg
));
234 // then show this entire window if not done yet
239 else // we're already shown
241 // just update the layout to correspond to the new message
246 void wxInfoBarGeneric::Dismiss()
251 void wxInfoBarGeneric::AddButton(wxWindowID btnid
, const wxString
& label
)
253 wxSizer
* const sizer
= GetSizer();
254 wxCHECK_RET( sizer
, "must be created first" );
256 // user-added buttons replace the standard close button so remove it if we
257 // hadn't done it yet
258 if ( sizer
->Detach(m_button
) )
263 wxButton
* const button
= new wxButton(this, btnid
, label
);
266 // smaller buttons look better in the (narrow) info bar under OS X
267 button
->SetWindowVariant(wxWINDOW_VARIANT_SMALL
);
270 sizer
->Add(button
, wxSizerFlags().Centre().DoubleBorder());
273 void wxInfoBarGeneric::RemoveButton(wxWindowID btnid
)
275 wxSizer
* const sizer
= GetSizer();
276 wxCHECK_RET( sizer
, "must be created first" );
278 // iterate over the sizer items in reverse order to find the last added
279 // button with this id (ids of all buttons should be unique anyhow but if
280 // they are repeated removing the last added one probably makes more sense)
281 const wxSizerItemList
& items
= sizer
->GetChildren();
282 for ( wxSizerItemList::compatibility_iterator node
= items
.GetLast();
283 node
!= items
.GetFirst();
284 node
= node
->GetPrevious() )
286 const wxSizerItem
* const item
= node
->GetData();
288 // if we reached the spacer separating the buttons from the text
289 // preceding them without finding our button, it must mean it's not
291 if ( item
->IsSpacer() )
293 wxFAIL_MSG( wxString::Format("button with id %d not found", btnid
) );
297 // check if we found our button
298 if ( item
->GetWindow()->GetId() == btnid
)
300 delete item
->GetWindow();
305 // check if there are any custom buttons left
306 if ( sizer
->GetChildren().GetLast()->GetData()->IsSpacer() )
308 // if the last item is the spacer, none are left so restore the
309 // standard close button
310 sizer
->Add(m_button
, wxSizerFlags().Centre().DoubleBorder());
315 void wxInfoBarGeneric::OnButton(wxCommandEvent
& WXUNUSED(event
))
320 #endif // wxUSE_INFOBAR