Ensure that info bar message uses the set font/colours in wxGTK.
[wxWidgets.git] / src / gtk / infobar.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/infobar.cpp
3 // Purpose: wxInfoBar implementation for GTK
4 // Author: Vadim Zeitlin
5 // Created: 2009-09-27
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 #include "wx/infobar.h"
27
28 #if wxUSE_INFOBAR && defined(wxHAS_NATIVE_INFOBAR)
29
30 #ifndef WX_PRECOMP
31 #endif // WX_PRECOMP
32
33 #include "wx/vector.h"
34
35 #include "wx/gtk/private.h"
36 #include "wx/gtk/private/messagetype.h"
37
38 // ----------------------------------------------------------------------------
39 // local classes
40 // ----------------------------------------------------------------------------
41
42 class wxInfoBarGTKImpl
43 {
44 public:
45 wxInfoBarGTKImpl()
46 {
47 m_label = NULL;
48 m_close = NULL;
49 }
50
51 // label for the text shown in the bar
52 GtkWidget *m_label;
53
54 // the default close button, NULL if not needed (m_buttons is not empty) or
55 // not created yet
56 GtkWidget *m_close;
57
58 // information about the buttons added using AddButton()
59 struct Button
60 {
61 Button(GtkWidget *button_, int id_)
62 : button(button_),
63 id(id_)
64 {
65 }
66
67 GtkWidget *button;
68 int id;
69 };
70 typedef wxVector<Button> Buttons;
71
72 Buttons m_buttons;
73 };
74
75 // ----------------------------------------------------------------------------
76 // local functions
77 // ----------------------------------------------------------------------------
78
79 namespace
80 {
81
82 inline bool UseNative()
83 {
84 // native GtkInfoBar widget is only available in GTK+ 2.18 and later
85 return gtk_check_version(2, 18, 0) == 0;
86 }
87
88 } // anonymous namespace
89
90 extern "C"
91 {
92
93 static void wxgtk_infobar_response(GtkInfoBar * WXUNUSED(infobar),
94 gint btnid,
95 wxInfoBar *win)
96 {
97 win->GTKResponse(btnid);
98 }
99
100 static void wxgtk_infobar_close(GtkInfoBar * WXUNUSED(infobar),
101 wxInfoBar *win)
102 {
103 win->GTKResponse(wxID_CANCEL);
104 }
105
106 } // extern "C" section with GTK+ callbacks
107
108 // ============================================================================
109 // wxInfoBar implementation
110 // ============================================================================
111
112 bool wxInfoBar::Create(wxWindow *parent, wxWindowID winid)
113 {
114 if ( !UseNative() )
115 return wxInfoBarGeneric::Create(parent, winid);
116
117 m_impl = new wxInfoBarGTKImpl;
118
119 // this control is created initially hidden
120 Hide();
121 if ( !CreateBase(parent, winid) )
122 return false;
123
124 // create the info bar widget itself
125 m_widget = gtk_info_bar_new();
126 wxCHECK_MSG( m_widget, false, "failed to create GtkInfoBar" );
127 g_object_ref(m_widget);
128
129 // also create a label which will be used to show our message
130 m_impl->m_label = gtk_label_new("");
131 gtk_widget_show(m_impl->m_label);
132
133 GtkWidget * const
134 contentArea = gtk_info_bar_get_content_area(GTK_INFO_BAR(m_widget));
135 wxCHECK_MSG( contentArea, false, "failed to get GtkInfoBar content area" );
136 gtk_container_add(GTK_CONTAINER(contentArea), m_impl->m_label);
137
138 // finish creation and connect to all the signals we're interested in
139 m_parent->DoAddChild(this);
140
141 PostCreation(wxDefaultSize);
142
143 GTKConnectWidget("response", G_CALLBACK(wxgtk_infobar_response));
144 GTKConnectWidget("close", G_CALLBACK(wxgtk_infobar_close));
145
146 return false;
147 }
148
149 wxInfoBar::~wxInfoBar()
150 {
151 delete m_impl;
152 }
153
154 void wxInfoBar::ShowMessage(const wxString& msg, int flags)
155 {
156 if ( !UseNative() )
157 {
158 wxInfoBarGeneric::ShowMessage(msg, flags);
159 return;
160 }
161
162 // if we don't have any buttons, create a standard close one to give the
163 // user at least some way to close the bar
164 if ( m_impl->m_buttons.empty() && !m_impl->m_close )
165 {
166 m_impl->m_close = GTKAddButton(wxID_CLOSE);
167 }
168
169 GtkMessageType type;
170 if ( wxGTKImpl::ConvertMessageTypeFromWX(flags, &type) )
171 gtk_info_bar_set_message_type(GTK_INFO_BAR(m_widget), type);
172 gtk_label_set_text(GTK_LABEL(m_impl->m_label), wxGTK_CONV(msg));
173
174 if ( !IsShown() )
175 Show();
176
177 UpdateParent();
178 }
179
180 void wxInfoBar::Dismiss()
181 {
182 if ( !UseNative() )
183 {
184 wxInfoBarGeneric::Dismiss();
185 return;
186 }
187
188 Hide();
189
190 UpdateParent();
191 }
192
193 void wxInfoBar::GTKResponse(int btnid)
194 {
195 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, btnid);
196 event.SetEventObject(this);
197
198 if ( !HandleWindowEvent(event) )
199 Dismiss();
200 }
201
202 GtkWidget *wxInfoBar::GTKAddButton(wxWindowID btnid, const wxString& label)
203 {
204 // as GTK+ lays out the buttons vertically, adding another button changes
205 // our best size (at least in vertical direction)
206 InvalidateBestSize();
207
208 GtkWidget *button = gtk_info_bar_add_button
209 (
210 GTK_INFO_BAR(m_widget),
211 label.empty()
212 ? GTKConvertMnemonics(wxGetStockGtkID(btnid))
213 : label,
214 btnid
215 );
216
217 wxASSERT_MSG( button, "unexpectedly failed to add button to info bar" );
218
219 return button;
220 }
221
222 void wxInfoBar::AddButton(wxWindowID btnid, const wxString& label)
223 {
224 if ( !UseNative() )
225 {
226 wxInfoBarGeneric::AddButton(btnid, label);
227 return;
228 }
229
230 // if we had created the default close button before, remove it now that we
231 // have some user-defined button
232 if ( m_impl->m_close )
233 {
234 gtk_widget_destroy(m_impl->m_close);
235 m_impl->m_close = NULL;
236 }
237
238 GtkWidget * const button = GTKAddButton(btnid, label);
239 if ( button )
240 m_impl->m_buttons.push_back(wxInfoBarGTKImpl::Button(button, btnid));
241 }
242
243 void wxInfoBar::RemoveButton(wxWindowID btnid)
244 {
245 if ( !UseNative() )
246 {
247 wxInfoBarGeneric::RemoveButton(btnid);
248 return;
249 }
250
251 // as in the generic version, look for the button starting from the end
252 wxInfoBarGTKImpl::Buttons& buttons = m_impl->m_buttons;
253 for ( wxInfoBarGTKImpl::Buttons::reverse_iterator i = buttons.rbegin();
254 i != buttons.rend();
255 ++i )
256 {
257 gtk_widget_destroy(i->button);
258 buttons.erase(i.base());
259
260 // see comment in GTKAddButton()
261 InvalidateBestSize();
262
263 return;
264 }
265
266 wxFAIL_MSG( wxString::Format("button with id %d not found", btnid) );
267 }
268
269 void wxInfoBar::DoApplyWidgetStyle(GtkRcStyle *style)
270 {
271 wxInfoBarGeneric::DoApplyWidgetStyle(style);
272
273 if ( UseNative() )
274 gtk_widget_modify_style(m_impl->m_label, style);
275 }
276
277 #endif // wxUSE_INFOBAR