don't modify position for default border if button is in a native widget
[wxWidgets.git] / src / gtk / button.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/button.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_BUTTON
14
15 #ifndef WX_PRECOMP
16 #include "wx/button.h"
17 #endif
18
19 #include "wx/stockitem.h"
20
21 #include "wx/gtk/private.h"
22
23 //-----------------------------------------------------------------------------
24 // data
25 //-----------------------------------------------------------------------------
26
27 extern bool g_blockEventsOnDrag;
28
29 //-----------------------------------------------------------------------------
30 // "clicked"
31 //-----------------------------------------------------------------------------
32
33 extern "C" {
34 static void gtk_button_clicked_callback( GtkWidget *WXUNUSED(widget), wxButton *button )
35 {
36 if (!button->m_hasVMT) return;
37 if (g_blockEventsOnDrag) return;
38
39 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, button->GetId());
40 event.SetEventObject(button);
41 button->HandleWindowEvent(event);
42 }
43 }
44
45 //-----------------------------------------------------------------------------
46 // "style_set" from m_widget
47 //-----------------------------------------------------------------------------
48
49 extern "C" {
50 static void
51 gtk_button_style_set_callback(GtkWidget* widget, GtkStyle*, wxButton* win)
52 {
53 /* the default button has a border around it */
54 wxWindow* parent = win->GetParent();
55 if (parent && parent->m_wxwindow && GTK_WIDGET_CAN_DEFAULT(widget))
56 {
57 GtkBorder* border = NULL;
58 gtk_widget_style_get(widget, "default_border", &border, NULL);
59 if (border)
60 {
61 win->MoveWindow(
62 win->m_x - border->left,
63 win->m_y - border->top,
64 win->m_width + border->left + border->right,
65 win->m_height + border->top + border->bottom);
66 gtk_border_free(border);
67 }
68 }
69 }
70 }
71
72 //-----------------------------------------------------------------------------
73 // wxButton
74 //-----------------------------------------------------------------------------
75
76 IMPLEMENT_DYNAMIC_CLASS(wxButton,wxControl)
77
78 wxButton::wxButton()
79 {
80 }
81
82 wxButton::~wxButton()
83 {
84 }
85
86 bool wxButton::Create(wxWindow *parent,
87 wxWindowID id,
88 const wxString &label,
89 const wxPoint& pos,
90 const wxSize& size,
91 long style,
92 const wxValidator& validator,
93 const wxString& name)
94 {
95 if (!PreCreation( parent, pos, size ) ||
96 !CreateBase( parent, id, pos, size, style, validator, name ))
97 {
98 wxFAIL_MSG( wxT("wxButton creation failed") );
99 return false;
100 }
101
102 m_widget = gtk_button_new_with_mnemonic("");
103
104 float x_alignment = 0.5;
105 if (HasFlag(wxBU_LEFT))
106 x_alignment = 0.0;
107 else if (HasFlag(wxBU_RIGHT))
108 x_alignment = 1.0;
109
110 float y_alignment = 0.5;
111 if (HasFlag(wxBU_TOP))
112 y_alignment = 0.0;
113 else if (HasFlag(wxBU_BOTTOM))
114 y_alignment = 1.0;
115
116 gtk_button_set_alignment(GTK_BUTTON(m_widget), x_alignment, y_alignment);
117
118 SetLabel(label);
119
120 if (style & wxNO_BORDER)
121 gtk_button_set_relief( GTK_BUTTON(m_widget), GTK_RELIEF_NONE );
122
123 g_signal_connect_after (m_widget, "clicked",
124 G_CALLBACK (gtk_button_clicked_callback),
125 this);
126
127 g_signal_connect_after (m_widget, "style_set",
128 G_CALLBACK (gtk_button_style_set_callback),
129 this);
130
131 m_parent->DoAddChild( this );
132
133 PostCreation(size);
134
135 return true;
136 }
137
138
139 wxWindow *wxButton::SetDefault()
140 {
141 wxWindow *oldDefault = wxButtonBase::SetDefault();
142
143 GTK_WIDGET_SET_FLAGS( m_widget, GTK_CAN_DEFAULT );
144 gtk_widget_grab_default( m_widget );
145
146 // resize for default border
147 gtk_button_style_set_callback( m_widget, NULL, this );
148
149 return oldDefault;
150 }
151
152 /* static */
153 wxSize wxButtonBase::GetDefaultSize()
154 {
155 static wxSize size = wxDefaultSize;
156 if (size == wxDefaultSize)
157 {
158 // NB: Default size of buttons should be same as size of stock
159 // buttons as used in most GTK+ apps. Unfortunately it's a little
160 // tricky to obtain this size: stock button's size may be smaller
161 // than size of button in GtkButtonBox and vice versa,
162 // GtkButtonBox's minimal button size may be smaller than stock
163 // button's size. We have to retrieve both values and combine them.
164
165 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
166 GtkWidget *box = gtk_hbutton_box_new();
167 GtkWidget *btn = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
168 gtk_container_add(GTK_CONTAINER(box), btn);
169 gtk_container_add(GTK_CONTAINER(wnd), box);
170 GtkRequisition req;
171 gtk_widget_size_request(btn, &req);
172
173 gint minwidth, minheight;
174 gtk_widget_style_get(box,
175 "child-min-width", &minwidth,
176 "child-min-height", &minheight,
177 NULL);
178
179 size.x = wxMax(minwidth, req.width);
180 size.y = wxMax(minheight, req.height);
181
182 gtk_widget_destroy(wnd);
183 }
184 return size;
185 }
186
187 void wxButton::SetLabel( const wxString &lbl )
188 {
189 wxCHECK_RET( m_widget != NULL, wxT("invalid button") );
190
191 wxString label(lbl);
192
193 if (label.empty() && wxIsStockID(m_windowId))
194 label = wxGetStockLabel(m_windowId);
195
196 wxControl::SetLabel(label);
197
198 if (wxIsStockID(m_windowId) && wxIsStockLabel(m_windowId, label))
199 {
200 const char *stock = wxGetStockGtkID(m_windowId);
201 if (stock)
202 {
203 gtk_button_set_label(GTK_BUTTON(m_widget), stock);
204 gtk_button_set_use_stock(GTK_BUTTON(m_widget), TRUE);
205 return;
206 }
207 }
208
209 const wxString labelGTK = GTKConvertMnemonics(label);
210 gtk_button_set_label(GTK_BUTTON(m_widget), wxGTK_CONV(labelGTK));
211 gtk_button_set_use_stock(GTK_BUTTON(m_widget), FALSE);
212
213 ApplyWidgetStyle( false );
214 }
215
216 bool wxButton::Enable( bool enable )
217 {
218 if ( !wxControl::Enable( enable ) )
219 return false;
220
221 gtk_widget_set_sensitive(GTK_BIN(m_widget)->child, enable);
222
223 return true;
224 }
225
226 GdkWindow *wxButton::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
227 {
228 return GTK_BUTTON(m_widget)->event_window;
229 }
230
231 void wxButton::DoApplyWidgetStyle(GtkRcStyle *style)
232 {
233 gtk_widget_modify_style(m_widget, style);
234 GtkWidget *child = GTK_BIN(m_widget)->child;
235 gtk_widget_modify_style(child, style);
236
237 // for buttons with images, the path to the label is (at least in 2.12)
238 // GtkButton -> GtkAlignment -> GtkHBox -> GtkLabel
239 if ( GTK_IS_ALIGNMENT(child) )
240 {
241 GtkWidget *box = GTK_BIN(child)->child;
242 if ( GTK_IS_BOX(box) )
243 {
244 GList *items = gtk_container_get_children(GTK_CONTAINER(box));
245 for ( GList *item = items; item; item = item->next )
246 gtk_widget_modify_style(GTK_WIDGET(item->data), style);
247 }
248 }
249 }
250
251 wxSize wxButton::DoGetBestSize() const
252 {
253 // the default button in wxGTK is bigger than the other ones because of an
254 // extra border around it, but we don't want to take it into account in
255 // our size calculations (otherwsie the result is visually ugly), so
256 // always return the size of non default button from here
257 const bool isDefault = GTK_WIDGET_HAS_DEFAULT(m_widget);
258 if ( isDefault )
259 {
260 // temporarily unset default flag
261 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_DEFAULT );
262 }
263
264 wxSize ret( wxControl::DoGetBestSize() );
265
266 if ( isDefault )
267 {
268 // set it back again
269 GTK_WIDGET_SET_FLAGS( m_widget, GTK_CAN_DEFAULT );
270 }
271
272 if (!HasFlag(wxBU_EXACTFIT))
273 {
274 wxSize defaultSize = GetDefaultSize();
275 if (ret.x < defaultSize.x) ret.x = defaultSize.x;
276 if (ret.y < defaultSize.y) ret.y = defaultSize.y;
277 }
278
279 CacheBestSize(ret);
280 return ret;
281 }
282
283 // static
284 wxVisualAttributes
285 wxButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
286 {
287 return GetDefaultAttributesFromGTKWidget(gtk_button_new);
288 }
289
290 #endif // wxUSE_BUTTON