1. some fixes for wxSortedArrayString
[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 #if wxUSE_CHOICE
18
19 #include "gdk/gdk.h"
20 #include "gtk/gtk.h"
21
22 //-----------------------------------------------------------------------------
23 // idle system
24 //-----------------------------------------------------------------------------
25
26 extern void wxapp_install_idle_handler();
27 extern bool g_isIdle;
28
29 //-----------------------------------------------------------------------------
30 // data
31 //-----------------------------------------------------------------------------
32
33 extern bool g_blockEventsOnDrag;
34
35 //-----------------------------------------------------------------------------
36 // "activate"
37 //-----------------------------------------------------------------------------
38
39 static void gtk_choice_clicked_callback( GtkWidget *WXUNUSED(widget), wxChoice *choice )
40 {
41 if (g_isIdle)
42 wxapp_install_idle_handler();
43
44 if (!choice->m_hasVMT) return;
45
46 if (g_blockEventsOnDrag) return;
47
48 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, choice->GetId() );
49 event.SetInt( choice->GetSelection() );
50 event.SetString( choice->GetStringSelection() );
51 event.SetEventObject(choice);
52 choice->GetEventHandler()->ProcessEvent(event);
53 }
54
55 //-----------------------------------------------------------------------------
56 // wxChoice
57 //-----------------------------------------------------------------------------
58
59 IMPLEMENT_DYNAMIC_CLASS(wxChoice,wxControl)
60
61 wxChoice::wxChoice()
62 {
63 m_strings = (wxSortedArrayString *)NULL;
64 }
65
66 bool wxChoice::Create( wxWindow *parent, wxWindowID id,
67 const wxPoint &pos, const wxSize &size,
68 int n, const wxString choices[],
69 long style, const wxValidator& validator, const wxString &name )
70 {
71 m_needParent = TRUE;
72 #if (GTK_MINOR_VERSION > 0)
73 m_acceptsFocus = TRUE;
74 #endif
75
76 if (!PreCreation( parent, pos, size ) ||
77 !CreateBase( parent, id, pos, size, style, validator, name ))
78 {
79 wxFAIL_MSG( wxT("wxChoice creation failed") );
80 return FALSE;
81 }
82
83 m_widget = gtk_option_menu_new();
84
85 wxSize newSize(size);
86 if (newSize.x == -1)
87 newSize.x = 80;
88 if (newSize.y == -1)
89 newSize.y = 26;
90 SetSize( newSize.x, newSize.y );
91
92 if ( style & wxCB_SORT )
93 {
94 // if our m_strings != NULL, DoAppend() will check for it and insert
95 // items in the correct order
96 m_strings = new wxSortedArrayString;
97 }
98
99 GtkWidget *menu = gtk_menu_new();
100
101 for (int i = 0; i < n; i++)
102 {
103 AppendHelper(menu, choices[i]);
104 }
105
106 gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget), menu );
107
108 m_parent->DoAddChild( this );
109
110 PostCreation();
111
112 SetBackgroundColour( parent->GetBackgroundColour() );
113 SetForegroundColour( parent->GetForegroundColour() );
114 SetFont( parent->GetFont() );
115
116 Show( TRUE );
117
118 return TRUE;
119 }
120
121 wxChoice::~wxChoice()
122 {
123 Clear();
124
125 delete m_strings;
126 }
127
128 int wxChoice::DoAppend( const wxString &item )
129 {
130 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice") );
131
132 GtkWidget *menu = gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) );
133
134 return AppendHelper(menu, item);
135 }
136
137 void wxChoice::DoSetClientData( int n, void* clientData )
138 {
139 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
140
141 wxNode *node = m_clientList.Nth( n );
142 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetClientData") );
143
144 node->SetData( (wxObject*) clientData );
145 }
146
147 void* wxChoice::DoGetClientData( int n ) const
148 {
149 wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid combobox") );
150
151 wxNode *node = m_clientList.Nth( n );
152 wxCHECK_MSG( node, NULL, wxT("invalid index in wxChoice::DoGetClientData") );
153
154 return node->Data();
155 }
156
157 void wxChoice::DoSetClientObject( int n, wxClientData* clientData )
158 {
159 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
160
161 wxNode *node = m_clientList.Nth( n );
162 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetClientObject") );
163
164 wxClientData *cd = (wxClientData*) node->Data();
165 delete cd;
166
167 node->SetData( (wxObject*) clientData );
168 }
169
170 wxClientData* wxChoice::DoGetClientObject( int n ) const
171 {
172 wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid combobox") );
173
174 wxNode *node = m_clientList.Nth( n );
175 wxCHECK_MSG( node, (wxClientData *)NULL,
176 wxT("invalid index in wxChoice::DoGetClientObject") );
177
178 return (wxClientData*) node->Data();
179 }
180
181 void wxChoice::Clear()
182 {
183 wxCHECK_RET( m_widget != NULL, wxT("invalid choice") );
184
185 gtk_option_menu_remove_menu( GTK_OPTION_MENU(m_widget) );
186 GtkWidget *menu = gtk_menu_new();
187 gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget), menu );
188
189 if (m_clientDataItemsType == ClientData_Object)
190 {
191 wxNode *node = m_clientList.First();
192 while (node)
193 {
194 wxClientData *cd = (wxClientData*)node->Data();
195 if (cd) delete cd;
196 node = node->Next();
197 }
198 }
199 m_clientList.Clear();
200 }
201
202 void wxChoice::Delete( int WXUNUSED(n) )
203 {
204 wxFAIL_MSG( wxT("wxChoice:Delete not implemented") );
205 }
206
207 int wxChoice::FindString( const wxString &string ) const
208 {
209 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice") );
210
211 // If you read this code once and you think you understand
212 // it, then you are very wrong. Robert Roebling.
213
214 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
215 int count = 0;
216 GList *child = menu_shell->children;
217 while (child)
218 {
219 GtkBin *bin = GTK_BIN( child->data );
220 GtkLabel *label = (GtkLabel *) NULL;
221 if (bin->child) label = GTK_LABEL(bin->child);
222 if (!label) label = GTK_LABEL( GTK_BUTTON(m_widget)->child );
223
224 wxASSERT_MSG( label != NULL , wxT("wxChoice: invalid label") );
225
226 if (string == wxString(label->label,*wxConvCurrent))
227 return count;
228
229 child = child->next;
230 count++;
231 }
232
233 return -1;
234 }
235
236 int wxChoice::GetSelection() const
237 {
238 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid choice") );
239
240 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
241 int count = 0;
242 GList *child = menu_shell->children;
243 while (child)
244 {
245 GtkBin *bin = GTK_BIN( child->data );
246 if (!bin->child) return count;
247 child = child->next;
248 count++;
249 }
250
251 return -1;
252 }
253
254 wxString wxChoice::GetString( int n ) const
255 {
256 wxCHECK_MSG( m_widget != NULL, wxT(""), wxT("invalid choice") );
257
258 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
259 int count = 0;
260 GList *child = menu_shell->children;
261 while (child)
262 {
263 GtkBin *bin = GTK_BIN( child->data );
264 if (count == n)
265 {
266 GtkLabel *label = (GtkLabel *) NULL;
267 if (bin->child) label = GTK_LABEL(bin->child);
268 if (!label) label = GTK_LABEL( GTK_BUTTON(m_widget)->child );
269
270 wxASSERT_MSG( label != NULL , wxT("wxChoice: invalid label") );
271
272 return wxString(label->label,*wxConvCurrent);
273 }
274 child = child->next;
275 count++;
276 }
277
278 wxFAIL_MSG( wxT("wxChoice: invalid index in GetString()") );
279
280 return wxT("");
281 }
282
283 int wxChoice::GetCount() const
284 {
285 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid choice") );
286
287 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
288 int count = 0;
289 GList *child = menu_shell->children;
290 while (child)
291 {
292 count++;
293 child = child->next;
294 }
295 return count;
296 }
297
298 void wxChoice::SetSelection( int n )
299 {
300 wxCHECK_RET( m_widget != NULL, wxT("invalid choice") );
301
302 int tmp = n;
303 gtk_option_menu_set_history( GTK_OPTION_MENU(m_widget), (gint)tmp );
304 }
305
306 void wxChoice::DisableEvents()
307 {
308 /*
309 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
310 GList *child = menu_shell->children;
311 while (child)
312 {
313 gtk_signal_disconnect_by_func( GTK_OBJECT( child->data ),
314 GTK_SIGNAL_FUNC(gtk_choice_clicked_callback), (gpointer*)this );
315
316 child = child->next;
317 }
318 */
319 }
320
321 void wxChoice::EnableEvents()
322 {
323 /*
324 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
325 GList *child = menu_shell->children;
326 while (child)
327 {
328 gtk_signal_connect( GTK_OBJECT( child->data ), "activate",
329 GTK_SIGNAL_FUNC(gtk_choice_clicked_callback), (gpointer*)this );
330
331 child = child->next;
332 }
333 */
334 }
335
336 void wxChoice::ApplyWidgetStyle()
337 {
338 SetWidgetStyle();
339
340 GtkMenuShell *menu_shell = GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget) ) );
341
342 gtk_widget_set_style( m_widget, m_widgetStyle );
343 gtk_widget_set_style( GTK_WIDGET( menu_shell ), m_widgetStyle );
344
345 GList *child = menu_shell->children;
346 while (child)
347 {
348 gtk_widget_set_style( GTK_WIDGET( child->data ), m_widgetStyle );
349
350 GtkBin *bin = GTK_BIN( child->data );
351 GtkWidget *label = (GtkWidget *) NULL;
352 if (bin->child) label = bin->child;
353 if (!label) label = GTK_BUTTON(m_widget)->child;
354
355 gtk_widget_set_style( label, m_widgetStyle );
356
357 child = child->next;
358 }
359 }
360
361 size_t wxChoice::AppendHelper(GtkWidget *menu, const wxString& item)
362 {
363 GtkWidget *menu_item = gtk_menu_item_new_with_label( item.mbc_str() );
364
365 size_t index;
366 if ( m_strings )
367 {
368 // sorted control, need to insert at the correct index
369 index = m_strings->Add(item);
370
371 gtk_menu_insert( GTK_MENU(menu), menu_item, index );
372
373 if ( index )
374 {
375 m_clientList.Insert( m_clientList.Item(index - 1),
376 (wxObject*) NULL );
377 }
378 else
379 {
380 // can't use Insert() :-(
381 m_clientList.Append( (wxObject*) NULL );
382 }
383 }
384 else
385 {
386 // normal control, just append
387 gtk_menu_append( GTK_MENU(menu), menu_item );
388
389 m_clientList.Append( (wxObject*) NULL );
390
391 // don't call wxChoice::GetCount() from here because it doesn't work
392 // if we're called from ctor (and GtkMenuShell is still NULL)
393 index = m_clientList.GetCount();
394 }
395
396 if (GTK_WIDGET_REALIZED(m_widget))
397 {
398 gtk_widget_realize( menu_item );
399 gtk_widget_realize( GTK_BIN(menu_item)->child );
400
401 if (m_widgetStyle) ApplyWidgetStyle();
402 }
403
404 gtk_signal_connect( GTK_OBJECT( menu_item ), "activate",
405 GTK_SIGNAL_FUNC(gtk_choice_clicked_callback), (gpointer*)this );
406
407 gtk_widget_show( menu_item );
408
409 // return the index of the item in the control
410 return index;
411 }
412
413 #endif