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