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