Fix for TextCtrl problem as reported by Vegh
[wxWidgets.git] / src / gtk / listbox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: listbox.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 "listbox.h"
13 #endif
14
15 #include "wx/dynarray.h"
16 #include "wx/listbox.h"
17 #include "wx/utils.h"
18 #include <wx/intl.h>
19
20 //-----------------------------------------------------------------------------
21 // data
22 //-----------------------------------------------------------------------------
23
24 extern bool g_blockEventsOnDrag;
25
26 //-----------------------------------------------------------------------------
27 // "select" and "deselect"
28 //-----------------------------------------------------------------------------
29
30 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox )
31 {
32 if (!listbox->HasVMT()) return;
33 if (g_blockEventsOnDrag) return;
34
35 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
36
37 wxArrayInt aSelections;
38 int count = listbox->GetSelections(aSelections);
39 if ( count > 0 )
40 {
41 event.m_commandInt = aSelections[0] ;
42 event.m_clientData = listbox->GetClientData(event.m_commandInt);
43 wxString str(listbox->GetString(event.m_commandInt));
44 if (str != "")
45 event.m_commandString = copystring((char *)(const char *)str);
46 }
47 else
48 {
49 event.m_commandInt = -1 ;
50 event.m_commandString = copystring("") ;
51 }
52
53 event.SetEventObject( listbox );
54
55 listbox->GetEventHandler()->ProcessEvent( event );
56 if (event.m_commandString) delete[] event.m_commandString ;
57 }
58
59 //-----------------------------------------------------------------------------
60 // wxListBox
61 //-----------------------------------------------------------------------------
62
63 IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
64
65 wxListBox::wxListBox(void)
66 {
67 m_list = (GtkList *) NULL;
68 }
69
70 bool wxListBox::Create( wxWindow *parent, wxWindowID id,
71 const wxPoint &pos, const wxSize &size,
72 int n, const wxString choices[],
73 long style, const wxValidator& validator, const wxString &name )
74 {
75 m_needParent = TRUE;
76
77 PreCreation( parent, id, pos, size, style, name );
78
79 SetValidator( validator );
80
81 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
82 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
83 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
84
85 m_list = GTK_LIST( gtk_list_new() );
86
87 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
88 if (style & wxLB_MULTIPLE)
89 mode = GTK_SELECTION_MULTIPLE;
90 else if (style & wxLB_EXTENDED)
91 mode = GTK_SELECTION_EXTENDED;
92
93 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
94
95 gtk_container_add (GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
96 gtk_widget_show( GTK_WIDGET(m_list) );
97
98 wxSize newSize = size;
99 if (newSize.x == -1) newSize.x = 100;
100 if (newSize.y == -1) newSize.y = 110;
101 SetSize( newSize.x, newSize.y );
102
103 for (int i = 0; i < n; i++)
104 {
105 GtkWidget *list_item;
106 list_item = gtk_list_item_new_with_label( choices[i] );
107
108 gtk_container_add( GTK_CONTAINER(m_list), list_item );
109
110 gtk_signal_connect( GTK_OBJECT(list_item), "select",
111 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
112
113 if (style & wxLB_MULTIPLE)
114 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
115 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
116
117 ConnectWidget( list_item );
118
119 m_clientData.Append( (wxObject*)NULL );
120
121 gtk_widget_show( list_item );
122 }
123
124 m_parent->AddChild( this );
125
126 (m_parent->m_insertCallback)( m_parent, this );
127
128 PostCreation();
129
130 gtk_widget_realize( GTK_WIDGET(m_list) );
131
132 SetBackgroundColour( parent->GetBackgroundColour() );
133 SetForegroundColour( parent->GetForegroundColour() );
134
135 Show( TRUE );
136
137 return TRUE;
138 }
139
140 void wxListBox::Append( const wxString &item )
141 {
142 Append( item, (char*)NULL );
143 }
144
145 void wxListBox::Append( const wxString &item, char *clientData )
146 {
147 wxCHECK_RET( m_list != NULL, "invalid listbox" );
148
149 GtkWidget *list_item = gtk_list_item_new_with_label( item );
150
151 gtk_signal_connect( GTK_OBJECT(list_item), "select",
152 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
153
154 if (GetWindowStyleFlag() & wxLB_MULTIPLE)
155 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
156 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
157
158 ConnectWidget( list_item );
159
160 m_clientData.Append( (wxObject*)clientData );
161
162 gtk_container_add( GTK_CONTAINER(m_list), list_item );
163
164 if (m_widgetStyle) ApplyWidgetStyle();
165
166 gtk_widget_show( list_item );
167
168 ConnectWidget( list_item );
169
170 ConnectDnDWidget( list_item );
171 }
172
173 void wxListBox::Clear(void)
174 {
175 wxCHECK_RET( m_list != NULL, "invalid listbox" );
176
177 gtk_list_clear_items( m_list, 0, Number() );
178
179 m_clientData.Clear();
180 }
181
182 void wxListBox::Delete( int n )
183 {
184 wxCHECK_RET( m_list != NULL, "invalid listbox" );
185
186 GList *child = g_list_nth( m_list->children, n );
187
188 if (!child)
189 {
190 wxFAIL_MSG("wrong listbox index");
191 return;
192 }
193
194 GList *list = g_list_append( NULL, child->data );
195 gtk_list_remove_items( m_list, list );
196 g_list_free( list );
197
198 wxNode *node = m_clientData.Nth( n );
199 if (!node)
200 {
201 wxFAIL_MSG("wrong listbox index");
202 }
203 else
204 m_clientData.DeleteNode( node );
205 }
206
207 void wxListBox::Deselect( int n )
208 {
209 wxCHECK_RET( m_list != NULL, "invalid listbox" );
210
211 gtk_list_unselect_item( m_list, n );
212 }
213
214 int wxListBox::FindString( const wxString &item ) const
215 {
216 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
217
218 GList *child = m_list->children;
219 int count = 0;
220 while (child)
221 {
222 GtkBin *bin = GTK_BIN( child->data );
223 GtkLabel *label = GTK_LABEL( bin->child );
224 if (item == label->label) return count;
225 count++;
226 child = child->next;
227 }
228
229 // it's not an error if the string is not found - this function may be used to
230 // test for existence of the string in the listbox, so don't give any
231 // errors/assert failures.
232
233 return -1;
234 }
235
236 char *wxListBox::GetClientData( int n ) const
237 {
238 wxCHECK_MSG( m_list != NULL, (char*) NULL, "invalid listbox" );
239
240 wxNode *node = m_clientData.Nth( n );
241 if (node) return ((char*)node->Data());
242
243 wxFAIL_MSG("wrong listbox index");
244 return (char *) NULL;
245 }
246
247 int wxListBox::GetSelection(void) const
248 {
249 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
250
251 GList *child = m_list->children;
252 int count = 0;
253 while (child)
254 {
255 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED) return count;
256 count++;
257 child = child->next;
258 }
259 return -1;
260 }
261
262 int wxListBox::GetSelections(wxArrayInt& aSelections) const
263 {
264 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
265
266 // get the number of selected items first
267 GList *child = m_list->children;
268 int count = 0;
269 for ( child = m_list->children; child != NULL; child = child->next )
270 {
271 if ( GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED )
272 count++;
273 }
274
275 aSelections.Empty();
276
277 if ( count > 0 ) {
278 // now fill the list
279 aSelections.Alloc(count); // optimization attempt
280 int i = 0;
281 for ( child = m_list->children; child != NULL; child = child->next, i++ )
282 {
283 if ( GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED )
284 aSelections.Add(i);
285 }
286 }
287
288 return count;
289 }
290
291 wxString wxListBox::GetString( int n ) const
292 {
293 wxCHECK_MSG( m_list != NULL, "", "invalid listbox" );
294
295 GList *child = g_list_nth( m_list->children, n );
296 if (child)
297 {
298 GtkBin *bin = GTK_BIN( child->data );
299 GtkLabel *label = GTK_LABEL( bin->child );
300 return label->label;
301 }
302 wxFAIL_MSG("wrong listbox index");
303 return "";
304 }
305
306 wxString wxListBox::GetStringSelection(void) const
307 {
308 wxCHECK_MSG( m_list != NULL, "", "invalid listbox" );
309
310 GList *selection = m_list->selection;
311 if (selection)
312 {
313 GtkBin *bin = GTK_BIN( selection->data );
314 wxString tmp = GTK_LABEL( bin->child )->label;
315 return tmp;
316 }
317 wxFAIL_MSG("no listbox selection available");
318 return "";
319 }
320
321 int wxListBox::Number(void)
322 {
323 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
324
325 GList *child = m_list->children;
326 int count = 0;
327 while (child) { count++; child = child->next; }
328 return count;
329 }
330
331 bool wxListBox::Selected( int n )
332 {
333 wxCHECK_MSG( m_list != NULL, FALSE, "invalid listbox" );
334
335 GList *target = g_list_nth( m_list->children, n );
336 if (target)
337 {
338 GList *child = m_list->selection;
339 while (child)
340 {
341 if (child->data == target->data) return TRUE;
342 child = child->next;
343 }
344 }
345 wxFAIL_MSG("wrong listbox index");
346 return FALSE;
347 }
348
349 void wxListBox::Set( int WXUNUSED(n), const wxString *WXUNUSED(choices) )
350 {
351 wxFAIL_MSG("wxListBox::Set not implemented");
352 }
353
354 void wxListBox::SetClientData( int n, char *clientData )
355 {
356 wxCHECK_RET( m_list != NULL, "invalid listbox" );
357
358 wxNode *node = m_clientData.Nth( n );
359 if (node)
360 {
361 node->SetData( (wxObject*)clientData );
362 }
363 else
364 {
365 wxFAIL_MSG("wrong listbox index");
366 }
367 }
368
369 void wxListBox::SetFirstItem( int WXUNUSED(n) )
370 {
371 wxFAIL_MSG("wxListBox::SetFirstItem not implemented");
372 }
373
374 void wxListBox::SetFirstItem( const wxString &WXUNUSED(item) )
375 {
376 wxFAIL_MSG("wxListBox::SetFirstItem not implemented");
377 }
378
379 void wxListBox::SetSelection( int n, bool select )
380 {
381 wxCHECK_RET( m_list != NULL, "invalid listbox" );
382
383 if (select)
384 gtk_list_select_item( m_list, n );
385 else
386 gtk_list_unselect_item( m_list, n );
387 }
388
389 void wxListBox::SetString( int n, const wxString &string )
390 {
391 wxCHECK_RET( m_list != NULL, "invalid listbox" );
392
393 GList *child = g_list_nth( m_list->children, n );
394 if (child)
395 {
396 GtkBin *bin = GTK_BIN( child->data );
397 GtkLabel *label = GTK_LABEL( bin->child );
398 gtk_label_set( label, string );
399 }
400 else
401 {
402 wxFAIL_MSG("wrong listbox index");
403 }
404 }
405
406 void wxListBox::SetStringSelection( const wxString &string, bool select )
407 {
408 wxCHECK_RET( m_list != NULL, "invalid listbox" );
409
410 SetSelection( FindString(string), select );
411 }
412
413 int wxListBox::GetIndex( GtkWidget *item ) const
414 {
415 if (item)
416 {
417 GList *child = m_list->children;
418 int count = 0;
419 while (child)
420 {
421 if (GTK_WIDGET(child->data) == item) return count;
422 count++;
423 child = child->next;
424 }
425 }
426 return -1;
427 }
428
429 void wxListBox::SetDropTarget( wxDropTarget *dropTarget )
430 {
431 wxCHECK_RET( m_list != NULL, "invalid listbox" );
432
433 GList *child = m_list->children;
434 while (child)
435 {
436 DisconnectDnDWidget( GTK_WIDGET( child->data ) );
437 child = child->next;
438 }
439
440 wxWindow::SetDropTarget( dropTarget );
441
442 child = m_list->children;
443 while (child)
444 {
445 ConnectDnDWidget( GTK_WIDGET( child->data ) );
446 child = child->next;
447 }
448 }
449
450 GtkWidget *wxListBox::GetConnectWidget(void)
451 {
452 return GTK_WIDGET(m_list);
453 }
454
455 bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
456 {
457 if (wxWindow::IsOwnGtkWindow( window )) return TRUE;
458
459 GList *child = m_list->children;
460 while (child)
461 {
462 GtkWidget *bin = GTK_WIDGET( child->data );
463 if (bin->window == window) return TRUE;
464 child = child->next;
465 }
466
467 return FALSE;
468 }
469
470 void wxListBox::ApplyWidgetStyle()
471 {
472 SetWidgetStyle();
473
474 GdkWindow *window = GTK_WIDGET(m_list)->window;
475 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
476 gdk_window_set_background( window, m_backgroundColour.GetColor() );
477 gdk_window_clear( window );
478
479 GList *child = m_list->children;
480 while (child)
481 {
482 gtk_widget_set_style( GTK_BIN(child->data)->child, m_widgetStyle );
483 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
484 child = child->next;
485 }
486 }