New idle handling. Only that.
[wxWidgets.git] / src / gtk1 / choice.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: choice.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "choice.h"
13 #endif
14
15 #include "wx/choice.h"
16
17 #include "gdk/gdk.h"
18 #include "gtk/gtk.h"
19
20 //-----------------------------------------------------------------------------
21 // idle system
22 //-----------------------------------------------------------------------------
23
24 extern void wxapp_install_idle_handler();
25 extern bool g_isIdle;
26
27 //-----------------------------------------------------------------------------
28 // data
29 //-----------------------------------------------------------------------------
30
31 extern bool g_blockEventsOnDrag;
32
33 //-----------------------------------------------------------------------------
34 // "activate"
35 //-----------------------------------------------------------------------------
36
37 static void gtk_choice_clicked_callback( GtkWidget *WXUNUSED(widget), wxChoice *choice )
38 {
39 if (g_isIdle) wxapp_install_idle_handler();
40
41 if (!choice->HasVMT()) return;
42
43 if (g_blockEventsOnDrag) return;
44
45 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, choice->GetId() );
46 event.SetInt( choice->GetSelection() );
47 event.SetString( choice->GetStringSelection() );
48 event.SetEventObject(choice);
49 choice->GetEventHandler()->ProcessEvent(event);
50 }
51
52 //-----------------------------------------------------------------------------
53 // wxChoice
54 //-----------------------------------------------------------------------------
55
56 IMPLEMENT_DYNAMIC_CLASS(wxChoice,wxControl)
57
58 wxChoice::wxChoice()
59 {
60 }
61
62 bool wxChoice::Create( wxWindow *parent, wxWindowID id,
63 const wxPoint &pos, const wxSize &size,
64 int n, const wxString choices[],
65 long style, const wxValidator& validator, const wxString &name )
66 {
67 m_needParent = TRUE;
68 #if (GTK_MINOR_VERSION > 0)
69 m_acceptsFocus = TRUE;
70 #endif
71
72 PreCreation( parent, id, pos, size, style, name );
73
74 SetValidator( validator );
75
76 m_widget = gtk_option_menu_new();
77
78 wxSize newSize(size);
79 if (newSize.x == -1)
80 newSize.x = 80;
81 if (newSize.y == -1)
82 newSize.y = 26;
83 SetSize( newSize.x, newSize.y );
84
85 GtkWidget *menu = gtk_menu_new();
86
87 for (int i = 0; i < n; i++)
88 {
89 m_clientDataList.Append( (wxObject*) NULL );
90 m_clientObjectList.Append( (wxObject*) NULL );
91
92 GtkWidget *item = gtk_menu_item_new_with_label( choices[i].mbc_str() );
93 gtk_menu_append( GTK_MENU(menu), item );
94
95 gtk_widget_show( item );
96
97 gtk_signal_connect( GTK_OBJECT( item ), "activate",
98 GTK_SIGNAL_FUNC(gtk_choice_clicked_callback), (gpointer*)this );
99 }
100 gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget), menu );
101
102 m_parent->AddChild( this );
103
104 (m_parent->m_insertCallback)( m_parent, this );
105
106 PostCreation();
107
108 SetBackgroundColour( parent->GetBackgroundColour() );
109 SetForegroundColour( parent->GetForegroundColour() );
110 SetFont( parent->GetFont() );
111
112 Show( TRUE );
113
114 return TRUE;
115 }
116
117 wxChoice::~wxChoice()
118 {
119 Clear();
120 }
121
122 void wxChoice::AppendCommon( const wxString &item )
123 {
124 wxCHECK_RET( m_widget != NULL, _T("invalid choice") );
125
126 GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
127 GtkWidget *menu_item = gtk_menu_item_new_with_label( item.mbc_str() );
128
129 gtk_menu_append( GTK_MENU(menu), menu_item );
130
131 if (GTK_WIDGET_REALIZED(m_widget))
132 {
133 gtk_widget_realize( menu_item );
134 gtk_widget_realize( GTK_BIN(menu_item)->child );
135
136 if (m_widgetStyle) ApplyWidgetStyle();
137 }
138
139 gtk_signal_connect( GTK_OBJECT( menu_item ), "activate",
140 GTK_SIGNAL_FUNC(gtk_choice_clicked_callback), (gpointer*)this );
141
142 gtk_widget_show( menu_item );
143 }
144
145 void wxChoice::Append( const wxString &item )
146 {
147 m_clientDataList.Append( (wxObject*) NULL );
148 m_clientObjectList.Append( (wxObject*) NULL );
149
150 AppendCommon( item );
151 }
152
153 void wxChoice::Append( const wxString &item, void *clientData )
154 {
155 m_clientDataList.Append( (wxObject*) clientData );
156 m_clientObjectList.Append( (wxObject*) NULL );
157
158 AppendCommon( item );
159 }
160
161 void wxChoice::Append( const wxString &item, wxClientData *clientData )
162 {
163 m_clientObjectList.Append( (wxObject*) clientData );
164 m_clientDataList.Append( (wxObject*) NULL );
165
166 AppendCommon( item );
167 }
168
169 void wxChoice::SetClientData( int n, void* clientData )
170 {
171 wxCHECK_RET( m_widget != NULL, _T("invalid combobox") );
172
173 wxNode *node = m_clientDataList.Nth( n );
174 if (!node) return;
175
176 node->SetData( (wxObject*) clientData );
177 }
178
179 void* wxChoice::GetClientData( int n )
180 {
181 wxCHECK_MSG( m_widget != NULL, NULL, _T("invalid combobox") );
182
183 wxNode *node = m_clientDataList.Nth( n );
184 if (!node) return NULL;
185
186 return node->Data();
187 }
188
189 void wxChoice::SetClientObject( int n, wxClientData* clientData )
190 {
191 wxCHECK_RET( m_widget != NULL, _T("invalid combobox") );
192
193 wxNode *node = m_clientObjectList.Nth( n );
194 if (!node) return;
195
196 wxClientData *cd = (wxClientData*) node->Data();
197 if (cd) delete cd;
198
199 node->SetData( (wxObject*) clientData );
200 }
201
202 wxClientData* wxChoice::GetClientObject( int n )
203 {
204 wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, _T("invalid combobox") );
205
206 wxNode *node = m_clientObjectList.Nth( n );
207 if (!node) return (wxClientData*) NULL;
208
209 return (wxClientData*) node->Data();
210 }
211
212 void wxChoice::Clear()
213 {
214 wxCHECK_RET( m_widget != NULL, _T("invalid choice") );
215
216 gtk_option_menu_remove_menu( GTK_OPTION_MENU(m_widget) );
217 GtkWidget *menu = gtk_menu_new();
218 gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget), menu );
219
220 wxNode *node = m_clientObjectList.First();
221 while (node)
222 {
223 wxClientData *cd = (wxClientData*)node->Data();
224 if (cd) delete cd;
225 node = node->Next();
226 }
227 m_clientObjectList.Clear();
228
229 m_clientDataList.Clear();
230 }
231
232 void wxChoice::Delete( int WXUNUSED(n) )
233 {
234 wxFAIL_MSG( _T("wxChoice:Delete not implemented") );
235 }
236
237 int wxChoice::FindString( const wxString &string ) const
238 {
239 wxCHECK_MSG( m_widget != NULL, -1, _T("invalid choice") );
240
241 // If you read this code once and you think you understand
242 // it, then you are very wrong. Robert Roebling.
243
244 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
245 int count = 0;
246 GList *child = menu_shell->children;
247 while (child)
248 {
249 GtkBin *bin = GTK_BIN( child->data );
250 GtkLabel *label = (GtkLabel *) NULL;
251 if (bin->child) label = GTK_LABEL(bin->child);
252 if (!label) label = GTK_LABEL( GTK_BUTTON(m_widget)->child );
253
254 wxASSERT_MSG( label != NULL , _T("wxChoice: invalid label") );
255
256 if (string == label->label)
257 return count;
258
259 child = child->next;
260 count++;
261 }
262
263 return -1;
264 }
265
266 int wxChoice::GetColumns() const
267 {
268 return 1;
269 }
270
271 int wxChoice::GetSelection()
272 {
273 wxCHECK_MSG( m_widget != NULL, -1, _T("invalid choice") );
274
275 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
276 int count = 0;
277 GList *child = menu_shell->children;
278 while (child)
279 {
280 GtkBin *bin = GTK_BIN( child->data );
281 if (!bin->child) return count;
282 child = child->next;
283 count++;
284 }
285
286 wxFAIL_MSG( _T("wxChoice: no selection") );
287
288 return -1;
289 }
290
291 wxString wxChoice::GetString( int n ) const
292 {
293 wxCHECK_MSG( m_widget != NULL, _T(""), _T("invalid choice") );
294
295 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
296 int count = 0;
297 GList *child = menu_shell->children;
298 while (child)
299 {
300 GtkBin *bin = GTK_BIN( child->data );
301 if (count == n)
302 {
303 GtkLabel *label = (GtkLabel *) NULL;
304 if (bin->child) label = GTK_LABEL(bin->child);
305 if (!label) label = GTK_LABEL( GTK_BUTTON(m_widget)->child );
306
307 wxASSERT_MSG( label != NULL , _T("wxChoice: invalid label") );
308
309 return label->label;
310 }
311 child = child->next;
312 count++;
313 }
314
315 wxFAIL_MSG( _T("wxChoice: invalid index in GetString()") );
316
317 return "";
318 }
319
320 wxString wxChoice::GetStringSelection() const
321 {
322 wxCHECK_MSG( m_widget != NULL, _T(""), _T("invalid choice") );
323
324 GtkLabel *label = GTK_LABEL( GTK_BUTTON(m_widget)->child );
325
326 wxASSERT_MSG( label != NULL , _T("wxChoice: invalid label") );
327
328 return label->label;
329 }
330
331 int wxChoice::Number() const
332 {
333 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid choice") );
334
335 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
336 int count = 0;
337 GList *child = menu_shell->children;
338 while (child)
339 {
340 count++;
341 child = child->next;
342 }
343 return count;
344 }
345
346 void wxChoice::SetColumns( int WXUNUSED(n) )
347 {
348 }
349
350 void wxChoice::SetSelection( int n )
351 {
352 wxCHECK_RET( m_widget != NULL, _T("invalid choice") );
353
354 int tmp = n;
355 gtk_option_menu_set_history( GTK_OPTION_MENU(m_widget), (gint)tmp );
356
357 gtk_choice_clicked_callback( (GtkWidget *) NULL, this );
358 }
359
360 void wxChoice::SetStringSelection( const wxString &string )
361 {
362 wxCHECK_RET( m_widget != NULL, _T("invalid choice") );
363
364 int n = FindString( string );
365 if (n != -1) SetSelection( n );
366 }
367
368 void wxChoice::ApplyWidgetStyle()
369 {
370 SetWidgetStyle();
371
372 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
373
374 gtk_widget_set_style( m_widget, m_widgetStyle );
375 gtk_widget_set_style( GTK_WIDGET( menu_shell ), m_widgetStyle );
376
377 GList *child = menu_shell->children;
378 while (child)
379 {
380 gtk_widget_set_style( GTK_WIDGET( child->data ), m_widgetStyle );
381
382 GtkBin *bin = GTK_BIN( child->data );
383 GtkWidget *label = (GtkWidget *) NULL;
384 if (bin->child) label = bin->child;
385 if (!label) label = GTK_BUTTON(m_widget)->child;
386
387 gtk_widget_set_style( label, m_widgetStyle );
388
389 child = child->next;
390 }
391 }
392