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