Include wx/frame.h according to precompiled headers of wx/wx.h (with other minor...
[wxWidgets.git] / src / gtk1 / radiobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/radiobox.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_RADIOBOX
14
15 #include "wx/radiobox.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/log.h"
19 #include "wx/frame.h"
20 #endif
21
22 #include "wx/dialog.h"
23
24 #include "wx/gtk1/private.h"
25 #include <gdk/gdkkeysyms.h>
26
27 #include "wx/gtk1/win_gtk.h"
28
29 //-----------------------------------------------------------------------------
30 // idle system
31 //-----------------------------------------------------------------------------
32
33 extern void wxapp_install_idle_handler();
34 extern bool g_isIdle;
35
36 //-----------------------------------------------------------------------------
37 // data
38 //-----------------------------------------------------------------------------
39
40 extern bool g_blockEventsOnDrag;
41 extern wxWindowGTK *g_delayedFocus;
42
43 //-----------------------------------------------------------------------------
44 // "clicked"
45 //-----------------------------------------------------------------------------
46
47 extern "C" {
48 static void gtk_radiobutton_clicked_callback( GtkToggleButton *button, wxRadioBox *rb )
49 {
50 if (g_isIdle) wxapp_install_idle_handler();
51
52 if (!rb->m_hasVMT) return;
53 if (g_blockEventsOnDrag) return;
54
55 if (!button->active) return;
56
57 wxCommandEvent event( wxEVT_COMMAND_RADIOBOX_SELECTED, rb->GetId() );
58 event.SetInt( rb->GetSelection() );
59 event.SetString( rb->GetStringSelection() );
60 event.SetEventObject( rb );
61 rb->GetEventHandler()->ProcessEvent(event);
62 }
63 }
64
65 //-----------------------------------------------------------------------------
66 // "key_press_event"
67 //-----------------------------------------------------------------------------
68
69 extern "C" {
70 static gint gtk_radiobox_keypress_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxRadioBox *rb )
71 {
72 if (g_isIdle)
73 wxapp_install_idle_handler();
74
75 if (!rb->m_hasVMT) return FALSE;
76 if (g_blockEventsOnDrag) return FALSE;
77
78 if ((gdk_event->keyval != GDK_Up) &&
79 (gdk_event->keyval != GDK_Down) &&
80 (gdk_event->keyval != GDK_Left) &&
81 (gdk_event->keyval != GDK_Right))
82 {
83 return FALSE;
84 }
85
86 wxList::compatibility_iterator node = rb->m_boxes.Find( (wxObject*) widget );
87 if (!node)
88 {
89 return FALSE;
90 }
91
92 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
93
94 if ((gdk_event->keyval == GDK_Up) ||
95 (gdk_event->keyval == GDK_Left))
96 {
97 if (node == rb->m_boxes.GetFirst())
98 node = rb->m_boxes.GetLast();
99 else
100 node = node->GetPrevious();
101 }
102 else
103 {
104 if (node == rb->m_boxes.GetLast())
105 node = rb->m_boxes.GetFirst();
106 else
107 node = node->GetNext();
108 }
109
110 GtkWidget *button = (GtkWidget*) node->GetData();
111
112 gtk_widget_grab_focus( button );
113
114 return TRUE;
115 }
116 }
117
118 extern "C" {
119 static gint gtk_radiobutton_focus_in( GtkWidget *widget,
120 GdkEvent *WXUNUSED(event),
121 wxRadioBox *win )
122 {
123 if ( win->m_lostFocus )
124 {
125 // no, we didn't really lose it
126 win->m_lostFocus = FALSE;
127 }
128 else if ( !win->m_hasFocus )
129 {
130 win->m_hasFocus = true;
131
132 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
133 event.SetEventObject( win );
134
135 // never stop the signal emission, it seems to break the kbd handling
136 // inside the radiobox
137 (void)win->GetEventHandler()->ProcessEvent( event );
138 }
139
140 return FALSE;
141 }
142 }
143
144 extern "C" {
145 static gint gtk_radiobutton_focus_out( GtkWidget *widget,
146 GdkEvent *WXUNUSED(event),
147 wxRadioBox *win )
148 {
149 // wxASSERT_MSG( win->m_hasFocus, _T("got focus out without any focus in?") );
150 // Replace with a warning, else we dump core a lot!
151 // if (!win->m_hasFocus)
152 // wxLogWarning(_T("Radiobox got focus out without any focus in.") );
153
154 // we might have lost the focus, but may be not - it may have just gone to
155 // another button in the same radiobox, so we'll check for it in the next
156 // idle iteration (leave m_hasFocus == true for now)
157 win->m_lostFocus = true;
158
159 return FALSE;
160 }
161 }
162
163 //-----------------------------------------------------------------------------
164 // wxRadioBox
165 //-----------------------------------------------------------------------------
166
167 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox,wxControl)
168
169 void wxRadioBox::Init()
170 {
171 m_needParent = true;
172 m_acceptsFocus = true;
173
174 m_hasFocus =
175 m_lostFocus = false;
176 }
177
178 bool wxRadioBox::Create( wxWindow *parent, wxWindowID id,
179 const wxString& title,
180 const wxPoint &pos, const wxSize &size,
181 const wxArrayString& choices, int majorDim,
182 long style, const wxValidator& validator,
183 const wxString &name )
184 {
185 wxCArrayString chs(choices);
186
187 return Create( parent, id, title, pos, size, chs.GetCount(),
188 chs.GetStrings(), majorDim, style, validator, name );
189 }
190
191 bool wxRadioBox::Create( wxWindow *parent, wxWindowID id, const wxString& title,
192 const wxPoint &pos, const wxSize &size,
193 int n, const wxString choices[], int majorDim,
194 long style, const wxValidator& validator,
195 const wxString &name )
196 {
197 if (!PreCreation( parent, pos, size ) ||
198 !CreateBase( parent, id, pos, size, style, validator, name ))
199 {
200 wxFAIL_MSG( wxT("wxRadioBox creation failed") );
201 return false;
202 }
203
204 m_widget = gtk_frame_new(NULL);
205 SetLabel(title);
206
207 // majorDim may be 0 if all trailing parameters were omitted, so don't
208 // assert here but just use the correct value for it
209 SetMajorDim(majorDim == 0 ? n : majorDim, style);
210
211
212 unsigned int num_of_cols = GetColumnCount();
213 unsigned int num_of_rows = GetRowCount();
214
215 GtkRadioButton *m_radio = (GtkRadioButton*) NULL;
216
217 GtkWidget *table = gtk_table_new( num_of_rows, num_of_cols, FALSE );
218 gtk_table_set_col_spacings( GTK_TABLE(table), 1 );
219 gtk_table_set_row_spacings( GTK_TABLE(table), 1 );
220 gtk_widget_show( table );
221 gtk_container_add( GTK_CONTAINER(m_widget), table );
222
223 wxString label;
224 GSList *radio_button_group = (GSList *) NULL;
225 for (int i = 0; i < n; i++)
226 {
227 if ( i != 0 )
228 radio_button_group = gtk_radio_button_group( GTK_RADIO_BUTTON(m_radio) );
229
230 label.Empty();
231 for ( const wxChar *pc = choices[i]; *pc; pc++ )
232 {
233 if ( *pc != wxT('&') )
234 label += *pc;
235 }
236
237 m_radio = GTK_RADIO_BUTTON( gtk_radio_button_new_with_label( radio_button_group, wxGTK_CONV( label ) ) );
238 gtk_widget_show( GTK_WIDGET(m_radio) );
239
240 gtk_signal_connect( GTK_OBJECT(m_radio), "key_press_event",
241 GTK_SIGNAL_FUNC(gtk_radiobox_keypress_callback), (gpointer)this );
242
243 m_boxes.Append( (wxObject*) m_radio );
244
245 if (HasFlag(wxRA_SPECIFY_COLS))
246 {
247 int left = i%num_of_cols;
248 int right = (i%num_of_cols) + 1;
249 int top = i/num_of_cols;
250 int bottom = (i/num_of_cols)+1;
251 gtk_table_attach( GTK_TABLE(table), GTK_WIDGET(m_radio), left, right, top, bottom,
252 GTK_FILL, GTK_FILL, 1, 1 );
253 }
254 else
255 {
256 int left = i/num_of_rows;
257 int right = (i/num_of_rows) + 1;
258 int top = i%num_of_rows;
259 int bottom = (i%num_of_rows)+1;
260 gtk_table_attach( GTK_TABLE(table), GTK_WIDGET(m_radio), left, right, top, bottom,
261 GTK_FILL, GTK_FILL, 1, 1 );
262 }
263
264 ConnectWidget( GTK_WIDGET(m_radio) );
265
266 if (!i) gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(m_radio), TRUE );
267
268 gtk_signal_connect( GTK_OBJECT(m_radio), "clicked",
269 GTK_SIGNAL_FUNC(gtk_radiobutton_clicked_callback), (gpointer*)this );
270
271 gtk_signal_connect( GTK_OBJECT(m_radio), "focus_in_event",
272 GTK_SIGNAL_FUNC(gtk_radiobutton_focus_in), (gpointer)this );
273
274 gtk_signal_connect( GTK_OBJECT(m_radio), "focus_out_event",
275 GTK_SIGNAL_FUNC(gtk_radiobutton_focus_out), (gpointer)this );
276 }
277
278 m_parent->DoAddChild( this );
279
280 PostCreation(size);
281
282 return true;
283 }
284
285 wxRadioBox::~wxRadioBox()
286 {
287 wxList::compatibility_iterator node = m_boxes.GetFirst();
288 while (node)
289 {
290 GtkWidget *button = GTK_WIDGET( node->GetData() );
291 gtk_widget_destroy( button );
292 node = node->GetNext();
293 }
294 }
295
296 bool wxRadioBox::Show(bool show)
297 {
298 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
299
300 if (!wxControl::Show(show))
301 {
302 // nothing to do
303 return false;
304 }
305
306 if ( HasFlag(wxNO_BORDER) )
307 gtk_widget_hide( m_widget );
308
309 wxList::compatibility_iterator node = m_boxes.GetFirst();
310 while (node)
311 {
312 GtkWidget *button = GTK_WIDGET( node->GetData() );
313
314 if (show)
315 gtk_widget_show( button );
316 else
317 gtk_widget_hide( button );
318
319 node = node->GetNext();
320 }
321
322 return true;
323 }
324
325 void wxRadioBox::SetFocus()
326 {
327 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
328
329 if (m_boxes.GetCount() == 0) return;
330
331 wxList::compatibility_iterator node = m_boxes.GetFirst();
332 while (node)
333 {
334 GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData() );
335 if (button->active)
336 {
337 gtk_widget_grab_focus( GTK_WIDGET(button) );
338 return;
339 }
340 node = node->GetNext();
341 }
342 }
343
344 void wxRadioBox::SetSelection( int n )
345 {
346 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
347
348 wxList::compatibility_iterator node = m_boxes.Item( n );
349
350 wxCHECK_RET( node, wxT("radiobox wrong index") );
351
352 GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData() );
353
354 GtkDisableEvents();
355
356 gtk_toggle_button_set_active( button, 1 );
357
358 GtkEnableEvents();
359 }
360
361 int wxRadioBox::GetSelection(void) const
362 {
363 wxCHECK_MSG( m_widget != NULL, wxNOT_FOUND, wxT("invalid radiobox") );
364
365 int count = 0;
366
367 wxList::compatibility_iterator node = m_boxes.GetFirst();
368 while (node)
369 {
370 GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData() );
371 if (button->active) return count;
372 count++;
373 node = node->GetNext();
374 }
375
376 wxFAIL_MSG( wxT("wxRadioBox none selected") );
377
378 return wxNOT_FOUND;
379 }
380
381 wxString wxRadioBox::GetString(unsigned int n) const
382 {
383 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid radiobox") );
384
385 wxList::compatibility_iterator node = m_boxes.Item( n );
386
387 wxCHECK_MSG( node, wxEmptyString, wxT("radiobox wrong index") );
388
389 GtkLabel *label = GTK_LABEL( BUTTON_CHILD(node->GetData()) );
390
391 wxString str( label->label );
392
393 return str;
394 }
395
396 void wxRadioBox::SetLabel( const wxString& label )
397 {
398 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
399
400 GTKSetLabelForFrame(GTK_FRAME(m_widget), label);
401 }
402
403 void wxRadioBox::SetString(unsigned int item, const wxString& label)
404 {
405 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
406
407 wxList::compatibility_iterator node = m_boxes.Item( item );
408
409 wxCHECK_RET( node, wxT("radiobox wrong index") );
410
411 GtkLabel *g_label = GTK_LABEL( BUTTON_CHILD(node->GetData()) );
412
413 gtk_label_set( g_label, wxGTK_CONV( label ) );
414 }
415
416 bool wxRadioBox::Enable( bool enable )
417 {
418 if ( !wxControl::Enable( enable ) )
419 return false;
420
421 wxList::compatibility_iterator node = m_boxes.GetFirst();
422 while (node)
423 {
424 GtkButton *button = GTK_BUTTON( node->GetData() );
425 GtkLabel *label = GTK_LABEL( BUTTON_CHILD(button) );
426
427 gtk_widget_set_sensitive( GTK_WIDGET(button), enable );
428 gtk_widget_set_sensitive( GTK_WIDGET(label), enable );
429 node = node->GetNext();
430 }
431
432 return true;
433 }
434
435 bool wxRadioBox::Enable(unsigned int item, bool enable)
436 {
437 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
438
439 wxList::compatibility_iterator node = m_boxes.Item( item );
440
441 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
442
443 GtkButton *button = GTK_BUTTON( node->GetData() );
444 GtkLabel *label = GTK_LABEL( BUTTON_CHILD(button) );
445
446 gtk_widget_set_sensitive( GTK_WIDGET(button), enable );
447 gtk_widget_set_sensitive( GTK_WIDGET(label), enable );
448
449 return true;
450 }
451
452 bool wxRadioBox::IsItemEnabled(unsigned int item) const
453 {
454 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
455
456 wxList::compatibility_iterator node = m_boxes.Item( item );
457
458 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
459
460 GtkButton *button = GTK_BUTTON( node->GetData() );
461
462 // don't use GTK_WIDGET_IS_SENSITIVE() here, we want to return true even if
463 // the parent radiobox is disabled
464 return GTK_WIDGET_SENSITIVE(GTK_WIDGET(button));
465 }
466
467 bool wxRadioBox::Show(unsigned int item, bool show)
468 {
469 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
470
471 wxList::compatibility_iterator node = m_boxes.Item( item );
472
473 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
474
475 GtkWidget *button = GTK_WIDGET( node->GetData() );
476
477 if (show)
478 gtk_widget_show( button );
479 else
480 gtk_widget_hide( button );
481
482 return true;
483 }
484
485 bool wxRadioBox::IsItemShown(unsigned int item) const
486 {
487 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
488
489 wxList::compatibility_iterator node = m_boxes.Item( item );
490
491 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
492
493 GtkButton *button = GTK_BUTTON( node->GetData() );
494
495 return GTK_WIDGET_VISIBLE(GTK_WIDGET(button));
496 }
497
498 unsigned int wxRadioBox::GetCount() const
499 {
500 return m_boxes.GetCount();
501 }
502
503 void wxRadioBox::GtkDisableEvents()
504 {
505 wxList::compatibility_iterator node = m_boxes.GetFirst();
506 while (node)
507 {
508 gtk_signal_disconnect_by_func( GTK_OBJECT(node->GetData()),
509 GTK_SIGNAL_FUNC(gtk_radiobutton_clicked_callback), (gpointer*)this );
510
511 node = node->GetNext();
512 }
513 }
514
515 void wxRadioBox::GtkEnableEvents()
516 {
517 wxList::compatibility_iterator node = m_boxes.GetFirst();
518 while (node)
519 {
520 gtk_signal_connect( GTK_OBJECT(node->GetData()), "clicked",
521 GTK_SIGNAL_FUNC(gtk_radiobutton_clicked_callback), (gpointer*)this );
522
523 node = node->GetNext();
524 }
525 }
526
527 void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle *style)
528 {
529 gtk_widget_modify_style( m_widget, style );
530
531 wxList::compatibility_iterator node = m_boxes.GetFirst();
532 while (node)
533 {
534 GtkWidget *widget = GTK_WIDGET( node->GetData() );
535
536 gtk_widget_modify_style( widget, style );
537 gtk_widget_modify_style( BUTTON_CHILD(node->GetData()), style );
538
539 node = node->GetNext();
540 }
541 }
542
543 #if wxUSE_TOOLTIPS
544 void wxRadioBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
545 {
546 wxList::compatibility_iterator node = m_boxes.GetFirst();
547 while (node)
548 {
549 GtkWidget *widget = GTK_WIDGET( node->GetData() );
550 gtk_tooltips_set_tip( tips, widget, wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
551 node = node->GetNext();
552 }
553 }
554 #endif // wxUSE_TOOLTIPS
555
556 bool wxRadioBox::IsOwnGtkWindow( GdkWindow *window )
557 {
558 if (window == m_widget->window)
559 return true;
560
561 wxList::compatibility_iterator node = m_boxes.GetFirst();
562 while (node)
563 {
564 GtkWidget *button = GTK_WIDGET( node->GetData() );
565
566 if (window == button->window)
567 return true;
568
569 node = node->GetNext();
570 }
571
572 return false;
573 }
574
575 void wxRadioBox::OnInternalIdle()
576 {
577 if ( m_lostFocus )
578 {
579 m_hasFocus = false;
580 m_lostFocus = false;
581
582 wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
583 event.SetEventObject( this );
584
585 (void)GetEventHandler()->ProcessEvent( event );
586 }
587
588 if (g_delayedFocus == this)
589 {
590 if (GTK_WIDGET_REALIZED(m_widget))
591 {
592 g_delayedFocus = NULL;
593 SetFocus();
594 }
595 }
596 }
597
598 // static
599 wxVisualAttributes
600 wxRadioBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
601 {
602 wxVisualAttributes attr;
603 // NB: we need toplevel window so that GTK+ can find the right style
604 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
605 GtkWidget* widget = gtk_radio_button_new_with_label(NULL, "");
606 gtk_container_add(GTK_CONTAINER(wnd), widget);
607 attr = GetDefaultAttributesFromGTKWidget(widget);
608 gtk_widget_destroy(wnd);
609 return attr;
610 }
611
612 #endif // wxUSE_RADIOBOX